#include <libLHP_D1W_async.h>


uint8_t D1W_async_inited = 0;

uint64_t D1W_async_devices_ids [ D1W_ASYNC_MAX_DEVICES];
uint64_t D1W_async_devices_value [ D1W_ASYNC_MAX_DEVICES];
uint8_t  D1W_async_devices_know[ D1W_ASYNC_MAX_DEVICES];
uint8_t  D1W_async_devices_port[ D1W_ASYNC_MAX_DEVICES];

D1W_Async_port_t D1W_async_ports[D1W_ASYNC_MAX_PORTS];

#define D1W_ASYNC_TIMER TIM2
#define D1W_ASYNC_TIMER_IRQ NVIC_TIM2_IRQ
#define D1W_ASYNC_TIMER_RPULSE RST_TIM2
#define D1W_ASYNC_TIMER_RCC RCC_TIM2
#define D1W_ASYNC_TIMER_ISR tim2_isr

#define D1W_ASYNC_LONGTIMER TIM3
#define D1W_ASYNC_LONGTIMER_IRQ NVIC_TIM3_IRQ
#define D1W_ASYNC_LONGTIMER_RPULSE RST_TIM3
#define D1W_ASYNC_LONGTIMER_RCC RCC_TIM3
#define D1W_ASYNC_LONGTIMER_ISR tim3_isr

void D1W_async_portwrite(uint8_t num,uint8_t sz,uint64_t val);

#define EVENT_QUEUE_SZ 10
uint8_t D1W_event_pending=0;
uint8_t current_event = 0;
D1W_event event_queue[EVENT_QUEUE_SZ];

uint8_t D1W_async_add_device(uint8_t num,uint64_t dev){
  uint8_t i=0;
  while( (i<D1W_ASYNC_MAX_DEVICES) && (dev != D1W_async_devices_ids[i]) && (D1W_async_devices_know[i]!=0))
    i++;
  if(i == D1W_ASYNC_MAX_DEVICES)
    return 0;
  if(dev == D1W_async_devices_ids[i])
    return 0;
  D1W_async_devices_know[i] = 1;
  D1W_async_devices_ids[i]  = dev;
  D1W_async_devices_port[i] = num;

  printstr_blocking(USART1,"Added dev: ");
  print_hex_64(USART1,D1W_async_devices_ids[i]);

  D1W_device_register(i,dev);
  
  printstr_blocking(USART1," (");
  print_uint(USART1,i);
  printstr_blocking(USART1,")\r\n");
  return 1;
}

uint8_t D1W_async_get_device_count(){
  uint8_t i;
  uint8_t cnt=0;
  while( (i<D1W_ASYNC_MAX_DEVICES)){
    if(D1W_async_devices_know[i]!=0)
      cnt++;
    i++;
  }
  return cnt;
}
uint64_t D1W_async_get_device_id(uint8_t i){
  return D1W_async_devices_ids[i];
}
void D1W_setdevicevalue(uint8_t i,uint64_t val){
  D1W_async_devices_value[i]=val;
}
uint64_t D1W_getdevicevalue(uint8_t i){
  return D1W_async_devices_value[i];
}



uint8_t D1W_protocol_command_evt_handler_D1W_READ_ROM(D1W_event * evt){
  switch(evt->event){
  case C_WRITING_DONE:
    D1W_async_portread64(evt->port_id);
    break;
  case C_READING_DONE:
    D1W_async_add_device(evt->port_id,D1W_get_port_value(evt->port_id));
    return 1;
    break;
  case C_PRESENCE_DETECT_SUCCESS:
    D1W_async_portwrite8(evt->port_id,D1W_READ_ROM);
    break;
  }
  return 0;
}

uint64_t search_rom = 0;
uint64_t search_rom_mask_conflict = 0;
uint8_t  search_curr_rank = 0;

uint8_t D1W_protocol_command_evt_handler_D1W_SEARCH_ROM(D1W_event * evt,uint8_t initial){
  uint64_t msk = 0;
  if(initial){
    search_rom = 0;
    search_rom_mask_conflict = 0;
    search_curr_rank = 0;
  }

  if(search_curr_rank == 64){
    D1W_async_add_device(evt->port_id,search_rom);
    search_rom = 0;
    search_curr_rank = 0;
    D1W_async_start_controler_presence_detect(evt->port_id);
    if(search_rom_mask_conflict == 0){
      return 1;      
    }
    return 0;
  }
  switch(evt->event){
  case C_WRITING_DONE:
    D1W_async_portread2(evt->port_id);
    break;
  case C_READING_DONE:
    switch(D1W_get_port_value(evt->port_id)){
      case 0:
	// conflict
	if(search_rom_mask_conflict &  (1ULL<<search_curr_rank)){
	  // we know this conflict and visited 0
	  search_rom |= (1ULL<<search_curr_rank);
	  msk = (~(0xffffffffffffffffULL>>(63-search_curr_rank)));
	  if( (search_rom_mask_conflict & msk) == 0){
	    // we are the last conflict flag left (a leaf in the binary tree walking)
	    search_rom_mask_conflict &= ~(1ULL<<search_curr_rank); // clear the flag 
	  }
	  D1W_async_portwrite(evt->port_id,1,1);
	}else{
	  GPIOC_ODR ^= (1<<13);
	  GPIOC_ODR ^= (1<<13);
	  // we don't know the conflict
	  search_rom_mask_conflict |=  (1ULL<<search_curr_rank);
	  D1W_async_portwrite(evt->port_id,1,0);
	}
	break;
    case 1:
      // all 1, select 1
      D1W_async_portwrite(evt->port_id,1,1);
      search_rom |= (1ULL<<search_curr_rank);
      break;
    case 2:
      // all 0, select 0
      D1W_async_portwrite(evt->port_id,1,0);
      break;
    }
    search_curr_rank++;

    return 0;
    
    break;
  case C_PRESENCE_DETECT_SUCCESS:
    D1W_async_portwrite8(evt->port_id,D1W_SEARCH_ROM);
    if(initial)
      return 1;
    break;
  }
  return 0;
}

uint8_t match_step = 0;
uint8_t D1W_protocol_command_evt_handler_D1W_MATCH_ROM(D1W_event * evt){
  switch(evt->event){
  case C_WRITING_DONE:
    if(match_step==0){
      match_step = 1;
      D1W_async_portwrite64(evt->port_id,evt->value);
      return 0;
    }else{
      return 1;
    }
    break;
  case C_PRESENCE_DETECT_SUCCESS:
    D1W_async_portwrite8(evt->port_id,D1W_MATCH_ROM);
    match_step=0;
    return 0;
    break;
  }
}

uint8_t D1W_protocol_command_evt_handler(uint8_t protocmd,D1W_event * evt,uint8_t initial){
  switch(protocmd){
  case D1W_READ_ROM:
    return D1W_protocol_command_evt_handler_D1W_READ_ROM(evt);
    break;
  case D1W_SEARCH_ROM:
    return D1W_protocol_command_evt_handler_D1W_SEARCH_ROM(evt,initial);
    break;
  case D1W_SKIP_ROM:
    // do nothing, next step higher
    return 1;
    break;
  case D1W_MATCH_ROM:
    return D1W_protocol_command_evt_handler_D1W_MATCH_ROM(evt);
    break;
  default:
    GPIOC_ODR ^= (1<<13);
    GPIOC_ODR ^= (1<<13);
    // this is not a protocol command we know, let the device specific code handle it
    return D1W_device_command_evt_handler(protocmd,evt,initial);
    break;
  }
  return 0;
}

uint8_t D1W_async_event_pending(){
  return D1W_event_pending;
}

D1W_event * D1W_async_get_next_event(){
  D1W_event * ret;
  if(D1W_event_pending){
    ret=&event_queue[current_event];
    D1W_event_pending--;
    current_event = (current_event+1)%EVENT_QUEUE_SZ ;
    return ret;
  }else{
    return NULL;
  }

}



uint64_t D1W_get_port_value(uint8_t num){
  return D1W_async_ports[num].value;
}

uint8_t D1W_async_event_add(uint8_t port, D1W_event_type etype){
  if(D1W_event_pending>=EVENT_QUEUE_SZ){
    // too much events for the queue, process faster or raise the queue size
    // freeze for detection and blink the led like crazy
    while(1)
      GPIOC_ODR ^= (1<<13);      
  }
  event_queue[(current_event+D1W_event_pending) % EVENT_QUEUE_SZ].port_id = port;
  event_queue[(current_event+D1W_event_pending) % EVENT_QUEUE_SZ].event = etype;
  event_queue[(current_event+D1W_event_pending) % EVENT_QUEUE_SZ].value =  D1W_async_ports[port].value;
    ;
  D1W_event_pending++;
}

void D1W_async_init(){
  int i;
  if(D1W_async_inited)
    return;
  for(i=0;i<D1W_ASYNC_MAX_PORTS;i++){
    D1W_async_ports[i].timer = D1W_ASYNC_TIMER;
    D1W_async_ports[i].active =0;
  }
  for(i=0;i<D1W_ASYNC_MAX_DEVICES;i++){
    D1W_async_devices_know[i]=0;
    D1W_async_devices_ids[i]=0;
  }

  rcc_periph_clock_enable(D1W_ASYNC_TIMER_RCC);
  nvic_enable_irq(D1W_ASYNC_TIMER_IRQ);
  rcc_periph_reset_pulse(D1W_ASYNC_TIMER_RPULSE);
  timer_set_mode(D1W_ASYNC_TIMER, TIM_CR1_CKD_CK_INT ,TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
  TIM_PSC(D1W_ASYNC_TIMER) = 71; // 1 MHz
  TIM_ARR(D1W_ASYNC_TIMER) = 0xffff; // max 16 bits, run as long as possible

  // start timer with the UG event enabled
  TIM_DIER(D1W_ASYNC_TIMER) = TIM_DIER_UIE;
  TIM_CR1(D1W_ASYNC_TIMER)  |= (TIM_CR1_CEN|TIM_CR1_URS);
  // just in case, disable all CC interrupts
  TIM_DIER(D1W_ASYNC_TIMER) &= ~(TIM_DIER_CC1IE|TIM_DIER_CC2IE|TIM_DIER_CC3IE|TIM_DIER_CC4IE);
  TIM_EGR(D1W_ASYNC_TIMER)  |= TIM_EGR_UG;

  rcc_periph_clock_enable(D1W_ASYNC_LONGTIMER_RCC);
  nvic_enable_irq(D1W_ASYNC_LONGTIMER_IRQ);
  rcc_periph_reset_pulse(D1W_ASYNC_LONGTIMER_RPULSE);
  timer_set_mode(D1W_ASYNC_LONGTIMER, TIM_CR1_CKD_CK_INT ,TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
  TIM_PSC(D1W_ASYNC_LONGTIMER) = 35999; // 2kHz = 500us
  TIM_ARR(D1W_ASYNC_LONGTIMER) = 0xffff; // max 16 bits, run as long as possible

  TIM_DIER(D1W_ASYNC_LONGTIMER) = TIM_DIER_UIE;
  TIM_CR1(D1W_ASYNC_LONGTIMER)  |= (TIM_CR1_CEN|TIM_CR1_URS);
  // just in case, disable all CC interrupts
  TIM_DIER(D1W_ASYNC_LONGTIMER) &= ~(TIM_DIER_CC1IE|TIM_DIER_CC2IE|TIM_DIER_CC3IE|TIM_DIER_CC4IE);
  TIM_EGR(D1W_ASYNC_LONGTIMER)  |= TIM_EGR_UG;
  
  
  
  rcc_periph_clock_enable(RCC_AFIO);
  D1W_async_inited=1;
}

void D1W_async_setup(
		     uint8_t num,
		     uint32_t gpio_port,
		     uint8_t gpio_pin,
		     uint8_t is_device
		     )
{
  if(!D1W_async_inited){
    D1W_async_init();
  }
  
  if(num>=D1W_ASYNC_MAX_PORTS)
    return;

  uint32_t exti;
  uint32_t exti_irq;
  
  D1W_async_ports[num].gpio_port = gpio_port;
  D1W_async_ports[num].gpio_pin  = gpio_pin;

  D1W_async_ports[num].is_device = is_device;
  D1W_async_ports[num].active      = 1;
  D1W_async_ports[num].exti_fired  = 0;
  D1W_async_ports[num].value  = 0;
  
  if(is_device){
    D1W_async_ports[num].bes_state = BES_C_IDLE;
  }else{
    D1W_async_ports[num].bes_state = BES_D_IDLE;
  }

  switch(gpio_port){
  case GPIOA:
    rcc_periph_clock_enable(RCC_GPIOA);
  case GPIOB:
    rcc_periph_clock_enable(RCC_GPIOB);
  case GPIOC:
    rcc_periph_clock_enable(RCC_GPIOC);
  case GPIOD:
    rcc_periph_clock_enable(RCC_GPIOD);
  }

  switch(gpio_pin){
  case 0:
    exti = EXTI0;
    exti_irq = NVIC_EXTI0_IRQ;
    break;
  case 1:
    exti=EXTI1;
    exti_irq = NVIC_EXTI1_IRQ;
    break;
  case 2:
    exti=EXTI2;
    exti_irq = NVIC_EXTI2_IRQ;
    break;
  case 3:
    exti=EXTI3;
    exti_irq = NVIC_EXTI3_IRQ;
    break;
  case 4:
    exti=EXTI4;
    exti_irq = NVIC_EXTI4_IRQ;
    break;
  }
  D1W_async_ports[num].exti=exti;
  nvic_enable_irq(exti_irq);
  exti_select_source(exti, gpio_port);
  exti_set_trigger(exti, EXTI_TRIGGER_FALLING);
  
  if(is_device){
    gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_INPUT,
		  GPIO_CNF_INPUT_FLOAT,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
  }else{
    gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_OUTPUT_2_MHZ,
		  GPIO_CNF_OUTPUT_PUSHPULL,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
    
  }
}

void D1W_async_act_next_in_long(uint8_t num,uint16_t ms){
  ms<<=1;
  ms++;
  if(ms<2)
    ms=0xffff;
  switch(num){
  case 0:
    TIM_CCR1(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) -1;
    TIM_SR(D1W_ASYNC_LONGTIMER)   &= ~TIM_SR_CC1IF; // clear a potential flag
    TIM_DIER(D1W_ASYNC_LONGTIMER) |= TIM_DIER_CC1IE; // enable the CC interrupt
    TIM_CCR1(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) + ms;
    break;
  case 1:
    TIM_CCR2(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) -1;
    TIM_SR(D1W_ASYNC_LONGTIMER)   &= ~TIM_SR_CC2IF; // clear a potential flag
    TIM_DIER(D1W_ASYNC_LONGTIMER) |= TIM_DIER_CC2IE; // enable the CC interrupt
    TIM_CCR2(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) + ms;
    break;
  case 2:
    TIM_CCR3(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) -1;
    TIM_SR(D1W_ASYNC_LONGTIMER)   &= ~TIM_SR_CC3IF; // clear a potential flag
    TIM_DIER(D1W_ASYNC_LONGTIMER) |= TIM_DIER_CC3IE; // enable the CC interrupt
    TIM_CCR3(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) + ms;
    break;
  case 3:
    TIM_CCR4(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) -1;
    TIM_SR(D1W_ASYNC_LONGTIMER)   &= ~TIM_SR_CC4IF; // clear a potential flag
    TIM_DIER(D1W_ASYNC_LONGTIMER) |= TIM_DIER_CC4IE; // enable the CC interrupt
    TIM_CCR4(D1W_ASYNC_LONGTIMER)  = TIM_CNT(D1W_ASYNC_LONGTIMER) + ms;
    break;
  }
    
}
  
void D1W_async_act_next_in(uint8_t num,uint16_t us){
  // the rollover of the addition will take care of the timer rollover case
  // since the 3 (ccr,cnt and the us variable) are uint16_t

  // best we can 
  if(us<3)
    us=3;
  switch(num){
  case 0:

    TIM_CCR1(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) -1;
    TIM_SR(D1W_ASYNC_TIMER)   &= ~TIM_SR_CC1IF; // clear a potential flag
    TIM_DIER(D1W_ASYNC_TIMER) |= TIM_DIER_CC1IE; // enable the CC interrupt
    TIM_CCR1(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) + us;
    break;
  case 1:
    TIM_CCR2(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) -1;
    TIM_SR(D1W_ASYNC_TIMER)   &= ~TIM_SR_CC2IF; 
    TIM_DIER(D1W_ASYNC_TIMER) |= TIM_DIER_CC2IE;
    TIM_CCR2(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) + us;
    break;
  case 2:
    TIM_CCR3(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) -1;
    TIM_SR(D1W_ASYNC_TIMER)   &= ~TIM_SR_CC3IF; 
    TIM_DIER(D1W_ASYNC_TIMER) |= TIM_DIER_CC3IE;
    TIM_CCR3(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) + us;
    break;
  case 3:
    TIM_CCR4(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) -1;
    TIM_SR(D1W_ASYNC_TIMER)   &= ~TIM_SR_CC4IF; 
    TIM_DIER(D1W_ASYNC_TIMER) |= TIM_DIER_CC4IE;
    TIM_CCR4(D1W_ASYNC_TIMER)  = TIM_CNT(D1W_ASYNC_TIMER) + us;
    break;
    
  }

}
void D1W_async_start_write(uint8_t num){
  D1W_async_ports[num].bes_state = BES_C_WRITE_ISSUING_SLOT;
  gpio_set_mode(
		D1W_async_ports[num].gpio_port,
		GPIO_MODE_OUTPUT_2_MHZ,
		GPIO_CNF_OUTPUT_PUSHPULL,
		(1<<D1W_async_ports[num].gpio_pin)
		);
   GPIO_ODR(D1W_async_ports[num].gpio_port) &= ~(1<<D1W_async_ports[num].gpio_pin);
   D1W_async_act_next_in(num,3);
}

void D1W_async_start_read(uint8_t num){
  D1W_async_ports[num].bes_state = BES_C_READ_ISSUING_SLOT;
  gpio_set_mode(
		D1W_async_ports[num].gpio_port,
		GPIO_MODE_OUTPUT_2_MHZ,
		GPIO_CNF_OUTPUT_PUSHPULL,
		(1<<D1W_async_ports[num].gpio_pin)
		);
   GPIO_ODR(D1W_async_ports[num].gpio_port) &= ~(1<<D1W_async_ports[num].gpio_pin);
   D1W_async_act_next_in(num,3);
}



void D1W_async_portwrite(uint8_t num,uint8_t sz,uint64_t val){
  D1W_async_ports[num].value = val;
  D1W_async_ports[num].value_sz = sz;
  D1W_async_start_write(num);  
  
}

void D1W_async_portread(uint8_t num,uint8_t sz){
  D1W_async_ports[num].value = 0;
  D1W_async_ports[num].value_sz = sz;
  D1W_async_ports[num]. curr_value_sz = sz;
  D1W_async_start_read(num);  
  
}

void D1W_async_portwrite8(uint8_t num,uint8_t val){
  D1W_async_portwrite(num,8,val);
}
void D1W_async_portwrite16(uint8_t num,uint16_t val){
  D1W_async_portwrite(num,16,val);
}
void D1W_async_portwrite32(uint8_t num,uint32_t val){
  D1W_async_portwrite(num,32,val);
}
void D1W_async_portwrite64(uint8_t num,uint64_t val){
  D1W_async_portwrite(num,64,val);
}

void D1W_async_portread2(uint8_t num){
  D1W_async_portread(num,2);
}
void D1W_async_portread8(uint8_t num){
  D1W_async_portread(num,8);
}
void D1W_async_portread16(uint8_t num){
  D1W_async_portread(num,16);
}
void D1W_async_portread32(uint8_t num){
  D1W_async_portread(num,32);
}
void D1W_async_portread64(uint8_t num){
  D1W_async_portread(num,64);
}


void D1W_async_start_controler_presence_detect(uint8_t num){
  GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);
  GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);
  gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_OUTPUT_2_MHZ,
		  GPIO_CNF_OUTPUT_PUSHPULL,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
  GPIO_ODR(D1W_async_ports[num].gpio_port) &= ~(1<<D1W_async_ports[num].gpio_pin);
  D1W_async_ports[num].bes_state = BES_C_RESET_ISSUING_SLOT;
  D1W_async_ports[num].presence = 0;
  D1W_async_ports[num].exti_fired = 0;

  D1W_async_act_next_in(num,485);
}

void port_bitengine_sm(uint8_t num,uint16_t ccief,uint32_t ccrp){

  
  switch(D1W_async_ports[num].bes_state){
  case BES_C_IDLE:
    TIM_DIER(D1W_ASYNC_TIMER) &= ~ccief;
    return;
    break;
  case BES_C_READ_ISSUING_SLOT:
    gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_INPUT,
		  GPIO_CNF_INPUT_FLOAT,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
    D1W_async_ports[num].bes_state = BES_C_READ_WAITING;
    D1W_async_act_next_in(num,10);    
    break;
  case BES_C_READ_WAITING:
    D1W_async_ports[num].value >>=1;

    D1W_async_ports[num].value |=
      ((uint64_t)
       (((GPIO_IDR(D1W_async_ports[num].gpio_port) & (1<< D1W_async_ports[num].gpio_pin)) >> D1W_async_ports[num].gpio_pin
	 )))<<(D1W_async_ports[num].value_sz-1);

    /*    if(D1W_async_ports[num].value & (1ULL<<D1W_async_ports[num].value_sz-1)){
        GPIOC_ODR ^= (1<<13);
	GPIOC_ODR ^= (1<<13);
	}
    */


    
    D1W_async_ports[num].curr_value_sz--;
    D1W_async_ports[num].bes_state = BES_C_READ_INTERBIT;
    D1W_async_act_next_in(num,50);
    break;
  case BES_C_READ_INTERBIT:
    if(D1W_async_ports[num].curr_value_sz){
      D1W_async_start_read(num);
    }else{
      //      D1W_async_ports[num].value >>= (64-D1W_async_ports[num].value_sz);
      D1W_async_event_add(num,C_READING_DONE);
      D1W_async_ports[num].bes_state = BES_C_IDLE;
    }
    
    break;
  case BES_C_WRITE_ISSUING_SLOT:
    if(D1W_async_ports[num].value & 1){
      gpio_set_mode(
		    D1W_async_ports[num].gpio_port,
		    GPIO_MODE_INPUT,
		    GPIO_CNF_INPUT_FLOAT,
		    (1<<D1W_async_ports[num].gpio_pin)
		    );
    }else{
      gpio_set_mode(
		    D1W_async_ports[num].gpio_port,
		    GPIO_MODE_OUTPUT_2_MHZ,
		    GPIO_CNF_OUTPUT_PUSHPULL,
		    (1<<D1W_async_ports[num].gpio_pin)
		    );
      GPIO_ODR(D1W_async_ports[num].gpio_port) &= ~(1<<D1W_async_ports[num].gpio_pin);
    }
    D1W_async_ports[num].bes_state = BES_C_WRITE_WAITING;
    D1W_async_act_next_in(num,45);
    break;
  case BES_C_WRITE_WAITING:
    D1W_async_ports[num].value >>=1;
    D1W_async_ports[num].value_sz--;
    D1W_async_ports[num].bes_state = BES_C_WRITE_INTERBIT;
    gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_INPUT,
		  GPIO_CNF_INPUT_FLOAT,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
    D1W_async_act_next_in(num,5);
    break;
  case BES_C_WRITE_INTERBIT:
    if(D1W_async_ports[num].value_sz){
      D1W_async_start_write(num);
    }else{
      D1W_async_event_add(num,C_WRITING_DONE);
      D1W_async_ports[num].bes_state = BES_C_IDLE;
      
    }
    
    break;
  case BES_C_RESET_ISSUING_SLOT:
    GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);
    GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);
    gpio_set_mode(
		  D1W_async_ports[num].gpio_port,
		  GPIO_MODE_INPUT,
		  GPIO_CNF_INPUT_FLOAT,
		  (1<<D1W_async_ports[num].gpio_pin)
		  );
    D1W_async_ports[num].exti_fired=0;
    exti_reset_request(D1W_async_ports[num].exti);
    exti_enable_request(D1W_async_ports[num].exti);
    D1W_async_act_next_in(num,240); // max 240us for presence pulse 
    D1W_async_ports[num].bes_state = BES_C_RESET_WAITING;
    break;
  case BES_C_RESET_WAITING:
    if(D1W_async_ports[num].exti_fired){
      D1W_async_ports[num].presence = 1;
      D1W_async_event_add(num,C_PRESENCE_DETECT_SUCCESS);
    }else{
      D1W_async_event_add(num,C_PRESENCE_DETECT_FAIL);
    }
    D1W_async_ports[num].exti_fired =0;
    D1W_async_ports[num].bes_state = BES_C_IDLE;
    D1W_async_act_next_in(num,240); // total rx slot = 480us
    break;

  }

}

void D1W_async_process_events_bitengine(){
  uint16_t evts = 0;

  do{
    evts = (TIM_DIER(D1W_ASYNC_TIMER) & TIM_SR(D1W_ASYNC_TIMER))
      & (TIM_DIER_CC1IE|TIM_DIER_CC2IE|TIM_DIER_CC3IE|TIM_DIER_CC4IE);

    if(evts & TIM_DIER_CC1IE){
      TIM_SR(D1W_ASYNC_TIMER) &= ~TIM_SR_CC1IF; // clear flag
      port_bitengine_sm(0,TIM_DIER_CC1IE,TIM_CCR1(D1W_ASYNC_TIMER));
    }
    if(evts & TIM_DIER_CC2IE){
      TIM_SR(D1W_ASYNC_TIMER) &= ~TIM_SR_CC2IF; // clear flag
      port_bitengine_sm(1,TIM_DIER_CC2IE,TIM_CCR2(D1W_ASYNC_TIMER));
    }
    if(evts & TIM_DIER_CC3IE){
      TIM_SR(D1W_ASYNC_TIMER) &= ~TIM_SR_CC3IF; // clear flag
      port_bitengine_sm(2,TIM_DIER_CC3IE,TIM_CCR3(D1W_ASYNC_TIMER));
    }
    if(evts & TIM_DIER_CC4IE){
      TIM_SR(D1W_ASYNC_TIMER) &= ~TIM_SR_CC4IF; // clear flag
      port_bitengine_sm(3,TIM_DIER_CC4IE,TIM_CCR4(D1W_ASYNC_TIMER));
    }
  }
  while(evts);

}


void D1W_async_process_longevents_bitengine(){
  uint16_t evts = 0;

  do{
    evts = (TIM_DIER(D1W_ASYNC_LONGTIMER) & TIM_SR(D1W_ASYNC_LONGTIMER))
      & (TIM_DIER_CC1IE|TIM_DIER_CC2IE|TIM_DIER_CC3IE|TIM_DIER_CC4IE);

    if(evts & TIM_DIER_CC1IE){
      TIM_SR(D1W_ASYNC_LONGTIMER) &= ~TIM_SR_CC1IF; // clear flag
      D1W_async_event_add(0,N_LONGWAIT);
      
    }
    if(evts & TIM_DIER_CC2IE){
      TIM_SR(D1W_ASYNC_LONGTIMER) &= ~TIM_SR_CC2IF; // clear flag
      D1W_async_event_add(1,N_LONGWAIT);
    }
    if(evts & TIM_DIER_CC3IE){
      TIM_SR(D1W_ASYNC_LONGTIMER) &= ~TIM_SR_CC3IF; // clear flag
      D1W_async_event_add(2,N_LONGWAIT);
    }
    if(evts & TIM_DIER_CC4IE){
      TIM_SR(D1W_ASYNC_LONGTIMER) &= ~TIM_SR_CC4IF; // clear flag
      D1W_async_event_add(3,N_LONGWAIT);
    }
  }
  while(evts);

}

/*

static unsigned char crc8_8540_table[256] = {
    0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
  157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
   35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
  190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
   70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
  219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
  101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
  248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
  140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
   17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
  175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
   50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
  202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
   87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
  233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
  116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
};

uint8_t D1W_getcrc(uint8_t* data,uint8_t len){
  uint8_t res = 0;
  while(len--){
    res = crc8_8540_table[res ^ *data];
    data++;
  }
  return res;
} 

*/

uint8_t D1W_getcrc(uint8_t* data,uint8_t len);


/***********************************************/
#ifdef USING_D1W_ASYNC

void D1W_ASYNC_TIMER_ISR (){
  //  void D1W_ASYNC_TIMER_ISR (){
  
  if(TIM_SR(D1W_ASYNC_TIMER) & TIM_SR_UIF){
     TIM_SR(D1W_ASYNC_TIMER)  &= ~TIM_SR_UIF;
  }
  //    GPIOC_ODR ^= (1<<13);


  // here, manually check that the interrupt is on and the flag set, the flag could be set
  // without the interrupt enabled (manual p 386), leading to confusion if
  // another capture compare hits
  if( (TIM_DIER(D1W_ASYNC_TIMER) & (TIM_SR(D1W_ASYNC_TIMER)) & TIM_SR_CC1IF) ){
      // compare channel 1 hit
      D1W_async_process_events_bitengine();
      // clear flag
      TIM_SR(D1W_ASYNC_TIMER) &= ~TIM_SR_CC1IF;

	
    }

}
void D1W_ASYNC_LONGTIMER_ISR (){
  //  void D1W_ASYNC_TIMER_ISR (){
  
  if(TIM_SR(D1W_ASYNC_LONGTIMER) & TIM_SR_UIF){
     TIM_SR(D1W_ASYNC_LONGTIMER) &= ~TIM_SR_UIF;
  }
  // here, manually check that the interrupt is on and the flag set, the flag could be set
  // without the interrupt enabled (manual p 386), leading to confusion if
  // another capture compare hits
  uint8_t tocall=0;
  if( (TIM_DIER(D1W_ASYNC_LONGTIMER) & (TIM_SR(D1W_ASYNC_LONGTIMER)))
      & (TIM_SR_CC1IF|TIM_SR_CC2IF|TIM_SR_CC3IF|TIM_SR_CC4IF)      
      ){ // compare channel  hit   
    D1W_async_process_longevents_bitengine();
    if((TIM_DIER(D1W_ASYNC_LONGTIMER) & (TIM_SR(D1W_ASYNC_LONGTIMER))) & TIM_SR_CC1IF)
      TIM_DIER(D1W_ASYNC_LONGTIMER) &= ~TIM_DIER_CC1IE;
    if((TIM_DIER(D1W_ASYNC_LONGTIMER) & (TIM_SR(D1W_ASYNC_LONGTIMER))) & TIM_SR_CC2IF)
      TIM_DIER(D1W_ASYNC_LONGTIMER) &= ~TIM_DIER_CC2IE;
    if((TIM_DIER(D1W_ASYNC_LONGTIMER) & (TIM_SR(D1W_ASYNC_LONGTIMER))) & TIM_SR_CC3IF)
      TIM_DIER(D1W_ASYNC_LONGTIMER) &= ~TIM_DIER_CC3IE;
    if((TIM_DIER(D1W_ASYNC_LONGTIMER) & (TIM_SR(D1W_ASYNC_LONGTIMER))) & TIM_SR_CC4IF)
      TIM_DIER(D1W_ASYNC_LONGTIMER) &= ~TIM_DIER_CC4IE;
    
    TIM_SR(D1W_ASYNC_LONGTIMER) &= ~(TIM_SR_CC1IF|TIM_SR_CC2IF|TIM_SR_CC3IF|TIM_SR_CC4IF);    // clear flag
  }

}

void exti0_isr(void)
{
  exti_reset_request(EXTI0);
  GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);
  GPIOC_ODR ^= (1<<13);GPIOC_ODR ^= (1<<13);

  uint8_t i = 0;
  while(i < D1W_ASYNC_MAX_PORTS){
    if(D1W_async_ports[i].active)
    if(D1W_async_ports[i].gpio_pin == 0){
      D1W_async_ports[i].exti_fired = 1;
      exti_disable_request(EXTI0 );
      return;
    }
    i++;
  }
}

#endif
