#ifndef __LIBLHP_D1W_ASYNC_H
#define __LIBLHP_D1W_ASYNC_H
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <stddef.h>
#include <libopencm3/stm32/f1/nvic.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/timer.h>
#include <libLHP_UART.h>
#include <libLHP_D1W.h>

#define D1W_ASYNC_MAX_DEVICES 4
#define D1W_ASYNC_MAX_PORTS 4

#define MASK_CONTROLER_EVENT 0x8000
#define MASK_DEVICE_EVENT    0x4000

typedef enum {
	      // giving values to be able to mask myself and avoid long
	      // chains in a single switch
		      BES_C_IDLE               =0x8fff,
		      BES_C_READ_ISSUING_SLOT  =0x8000,
		      BES_C_READ_WAITING       =0x8001 ,
		      BES_C_READ_INTERBIT      =0x8002,
		      BES_C_WRITE_ISSUING_SLOT =0x8003,
		      BES_C_WRITE_WAITING      =0x8004,
		      BES_C_WRITE_INTERBIT     =0x8005,
		      BES_C_RESET_ISSUING_SLOT =0x8006,
		      BES_C_RESET_WAITING      =0x8007,

		      BES_D_IDLE               =0x4fff,
		      BES_D_ISSUED_SLOT        =0x4001,
		      BES_D_CMD_READ_WAITING   =0x4002,
		      BES_D_DATA_READ_WAITING  =0x4003,
		      BES_D_DATA_WRITE_WAITING =0x4004
		      
		      
} bitengine_state_t ;

typedef enum {
	      N_LONGWAIT                      = 0xc000,
	      
	      C_WRITING_DONE                  = 0x8001,
	      C_READING_DONE                  = 0x8002,
	      C_PRESENCE_DETECT_SUCCESS       = 0x8003,
	      C_PRESENCE_DETECT_FAIL          = 0x8004,
	      
	      D_PRESENCE_DETECT_ME            = 0x4001,
	      D_WRITING_DONE                  = 0x4002,
	      D_READING_DONE                  = 0x4003

} D1W_event_type;

typedef struct {
  uint32_t gpio_port;
  uint32_t timer;

  uint32_t exti;
  bitengine_state_t bes_state;
  
  uint64_t value;
  
  uint8_t presence;
  uint8_t gpio_pin;
  uint8_t active;
  uint8_t bit_value;
  uint8_t exti_fired;
  uint8_t is_device;
  uint8_t value_sz;
  uint8_t curr_value_sz;
  

} D1W_Async_port_t;

extern D1W_Async_port_t D1W_async_ports[D1W_ASYNC_MAX_PORTS];


  


typedef struct {
  uint8_t port_id;
  D1W_event_type event;
  uint64_t value;

} D1W_event;





void D1W_async_init();
void D1W_async_setup(
		     uint8_t num,
		     uint32_t gpio_port,
		     uint8_t gpio_pin,
		     uint8_t is_device
		     );
void D1W_async_start_controler_presence_detect(uint8_t num);
D1W_event * D1W_async_get_next_event();
void D1W_async_portwrite8(uint8_t num,uint8_t val);
void D1W_async_portwrite16(uint8_t num,uint16_t val);
void D1W_async_portwrite32(uint8_t num,uint32_t val);
void D1W_async_portwrite64(uint8_t num,uint64_t val);
uint64_t D1W_async_get_device_id(uint8_t i);
uint64_t D1W_getdevicevalue(uint8_t i);
void D1W_async_portread2(uint8_t num);
void D1W_async_portread8(uint8_t num);
void D1W_async_portread16(uint8_t num);
void D1W_async_portread32(uint8_t num);
void D1W_async_portread64(uint8_t num);
void D1W_setdevicevalue(uint8_t i,uint64_t val);
uint64_t D1W_get_port_value(uint8_t num);
uint8_t D1W_protocol_command_evt_handler(uint8_t protocmd,D1W_event * evt,uint8_t initial);
uint8_t D1W_getcrc(uint8_t* data,uint8_t len);
uint8_t D1W_async_get_device_count();
void D1W_async_act_next_in(uint8_t num,uint16_t us);
void D1W_async_act_next_in_long(uint8_t num,uint16_t ms);
  
/*implemented in the device driver*/

extern uint8_t D1W_device_command_evt_handler(uint8_t protocmd,D1W_event * evt,uint8_t initial);
extern void D1W_device_register(uint8_t rnk,uint64_t id);

#endif
