#ifndef INTERFACE_H
#define INTERFACE_H

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>

#include "bctypes.h"

#if defined(PC)
#include "pc.h"
#elif defined(ARDUINO)
#include "arduino.h"
#else /* PC */
#warning "No architecture could be detected"
#include "pc.h"
#endif /* PC */

#include "config.h"

#if APINS > 255
#error "Maximum number of analog pins is 255"
#endif /* APINS > 255 */

#if DPINS > 255
#error "Maximum number of digital pins is 255"
#endif /* DPINS > 255 */

#if MEMSIZE > UINT16_MAX - 3
#error "Maximum number of memory is 2^16-3"
#endif /* MEMSIZE > UInT16_MAX - 3 */

#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif /* max */
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif /* min */

#ifndef PING
#define PING 0
#endif /* PING */

/* Analog and digital pins */
#if DPINS > 0 || APINS > 0
void set_pinmode(uint16_t p, enum PinMode mode);
uint16_t translate_pin(uint16_t pin);
#endif /* DPINS > 0 || APINS > 0 */

#if DPINS > 0
void write_dpin(uint16_t i, bool b);
bool read_dpin(uint16_t i);
#endif /* DPINS > 0 */

void attach_interrupt(void (*isr)(), uint16_t pin, enum InterruptMode mode);
void detach_interrupt(uint16_t pin);
void (*get_isr(uint16_t pin, enum InterruptMode mode))();

#if APINS > 0
void write_apin(uint16_t i, uint8_t a);
uint8_t read_apin(uint16_t i);
#endif /* APINS > 0 */

#ifdef HAVE_DHT
void *dht_init(struct DHTInfo);
float get_dht_temp(void *);
float get_dht_humidity(void *);
#endif /* HAVE_DHT */

#ifdef HAVE_LEDMATRIX
void *ledmatrix_init(struct LEDMatrixInfo);
void ledmatrix_dot(void *, uint8_t, uint8_t, bool);
void ledmatrix_intensity(void *, uint8_t);
void ledmatrix_clear(void *);
void ledmatrix_display(void *);
#endif /* HAVE_LEDMATRIX */

#ifdef HAVE_I2CBUTTON
void *i2c_init(uint8_t addr);
uint8_t i2c_abutton(void *);
uint8_t i2c_bbutton(void *);
#endif /* HAVE_I2CBUTTON */

#ifdef HAVE_LIGHTSENSOR
void *lightsensor_init(uint8_t addr);
float get_light(void *);
#endif /* HAVE_LIGHTSENSOR */

#ifdef HAVE_AIRQUALITYSENSOR
void *airqualitysensor_init(uint8_t addr);
void set_environmental_data(void *, float, float);
uint16_t get_tvoc(void *);
uint16_t get_co2(void *);
#endif /* HAVE_AIRQUALITYSENSOR */

#ifdef HAVE_GESTURESENSOR
void *gesturesensor_init(uint8_t addr);
uint8_t get_gesture(void *);
#endif /* HAVE_GESTURESENSOR */

#ifdef HAVE_OLEDSHIELD
void print_to_display(const char *msg);
void flush_display();
void clear_display(void);
#endif /* HAVE_OLEDSHIELD */

/* Delay and communication */
uint32_t getmillis(void);
void msdelay(unsigned long ms);

/* Sleep */
void mssleep(unsigned long ms);
void force_wake_up();

/* Auxilliary */
void real_setup(void);
unsigned int get_random(void);

/* Yield function to feed the dogs */
void real_yield(void);

/* Log level: debug */
#if LOGLEVEL == 2
void msg_log(const char *, ...);
#define msg_debug(...) msg_log(__VA_ARGS__)

/* Log level: normal */
#elif LOGLEVEL == 1
void msg_log(const char *, ...);
#define msg_debug(...) {};

/* Log level: quiet */
#else /* LOGLEVEL == 2 */
#define msg_debug(...) {};
#define msg_log(...) {};
#endif /* LOGLEVEL == 2 */

//* Exit with an error message
void die(const char *, ...);
//* Exit with the system's error message
void pdie(char *s);
//* Resets the client
void reset(void);

//* Code fragment placed in main for example to set longjumps
#ifndef RECOVERABLE_ERROR_CODE
#define RECOVERABLE_ERROR_CODE
#endif /* RECOVERABLE_ERROR_CODE */

#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* !INTERFACE_H */

