#include "wh-nb73.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "gpio.h"
#include "usart.h"
#include "dht11.h"

#define BUF_LEN 1024
#define NOTIFY_INTVL_20SEC    20000
#define NETWORK_INTVL_2MIN    120000
#define LIFETIME_INTVL_30MIN  3000000


#define NB73_BOOT_INFO        "[WH-NB73]"
#define NB73_CHECK_NETWORK    "AT+CGATT?\r\n"
#define NB73_NETWORK_ATTACHED "+CGATT:1"
#define NB73_NETWORK_DETACHED "+CGATT:0"

typedef enum 
{
	NB73_NONE			= (uint8_t)0x00,
	NB73_NETWORK,
  NB73_ONENET_INIT,
  NB73_RUNNING
} nb_state_t;

char *cis_cmd_table[] = 
{
	CMD_CLOSE,
	CMD_DELETE,
	CMD_CREATE,
	CMD_ADDOBJ_TEMPERATURE,
	CMD_ADDOBJ_HUMIDITY,
	CMD_ADDOBJ_LED,
	CMD_REGISTER,
	NULL
};

/* message id */
uint32_t msgid_temperature;
uint32_t msgid_humidity;
uint32_t msgid_led;

int notify_fail_cnt = 0;

/* observe enable */
bool temperature_enable = false;
bool humidity_enable = false;
bool led_enable = false;

/* run time */
uint32_t report_tick   = 0xffffffff;
uint32_t network_tick  = 0xffffffff;
uint32_t lifetime_tick = 0xffffffff;

/* Network detached counter */
int network_cnt = 0;

char buffer[BUF_LEN];

nb_state_t nb73_state = NB73_NONE;


int NB73_onenet_init(void)
{
	temperature_enable    = false;
	humidity_enable       = false;
	led_enable						= false;
	notify_fail_cnt = 0;

  static int idx = 0;
	
	if(cis_cmd_table[idx] != NULL)
	{
		uart_send_stream(cis_cmd_table[idx]);
		idx++;
		
		return 1;
	}
	else
	{
    idx = 0;
    nb73_state = NB73_RUNNING;
      
		return 0;
	}
}

uint32_t NB73_get_id(char *data, uint8_t index)
{
	int i = 0;
	char *temp = NULL;

	for(i = 0; i < index; i++)
	{
		temp = strstr(data, ",");
		if(temp == NULL)
		{
			temp = strstr(data, ":");
		}
		data = data + (temp - data) + 1;
	}

	return atoi(data);
}

void nb73_task(void)
{
  uint32_t now_tick;
  
  char dht11_temp[8];
	char dht11_hum[8];
  uint8_t dht11_data[5];
  
  char *ptr = (char *)rx_buffer;
  
	if(rx_done == true)
	{
    rx_done = false;
		rx_len = 0;
    
		if(strstr(ptr, NB73_BOOT_INFO))
		{
			nb73_state = NB73_NETWORK;
		}
		else if(strstr(ptr, NB73_NETWORK_ATTACHED))
		{
      if(nb73_state == NB73_NETWORK)
      {
			  nb73_state = NB73_ONENET_INIT;
      }      

      network_cnt = 0;
		}
    else if(strstr(ptr, NB73_NETWORK_DETACHED))
		{
      if(nb73_state == NB73_RUNNING)
      {
			  network_cnt++;
        if(network_cnt > 5)
        {
          HAL_NVIC_SystemReset();
        }
      }      
		}
		else if(strstr(ptr, "+MIPL"))
    {				
    	uint32_t mid;
    	uint32_t oid;
    	//uint32_t iid;
    	//uint32_t rid;
    	
    	uint32_t eid;
    	
    	//uint8_t  value_type;
    	//uint8_t  value_len;
    	uint8_t  value;

    	if(strstr(ptr, "+MIPLDISCOVER"))
    	{
    		
    		mid = NB73_get_id(ptr, 1);
    		oid = NB73_get_id(ptr, 2);
    	
    		if(oid == OBJECT_TEMPERATURE)
    		{
    			sprintf(buffer, CMD_DISCOVERRSP_TEMPERATURE, mid);
    		}
    		else if(oid == OBJECT_HUMIDITY)
    		{
    			sprintf(buffer, CMD_DISCOVERRSP_HUMIDITY, mid);
    		}
    		else if(oid == OBJECT_LED)
    		{
    			sprintf(buffer, CMD_DISCOVERRSP_LED, mid);
    		}
    		else
    		{
    			return;
    		}
    	}
    	else if(strstr(ptr, "+MIPLOBSERVE"))
    	{	
    		
    		mid = NB73_get_id(ptr, 1);			
    		oid = NB73_get_id(ptr, 3);	
    		
    		if(oid == OBJECT_TEMPERATURE)
    		{
    			msgid_temperature = mid;
    			temperature_enable = true;
    		}
    		else if(oid == OBJECT_HUMIDITY)
    		{
    			msgid_humidity = mid;
    			humidity_enable = true;
    		}
    		else if(oid == OBJECT_LED)
    		{
    			msgid_led = mid;
    			led_enable = true;
    		}
    		else
    		{
    			return;
    		}
    		
    		sprintf(buffer, CMD_OBSERVERSP, mid);
    	}
    	else if(strstr(ptr, "+MIPLREAD"))
    	{
    		mid = NB73_get_id(ptr, 1);			
    		oid = NB73_get_id(ptr, 2);

    		if(oid == OBJECT_LED)
    		{
    			sprintf(buffer, CMD_READRSP_LED, mid, get_led_state());
    		}
    		else if((oid == OBJECT_HUMIDITY) || (oid == OBJECT_TEMPERATURE))
    		{
    			if(dht11_read_data(dht11_data))
    			{
            memset(dht11_hum,  0, 8);
            memset(dht11_temp, 0, 8);
    				sprintf(dht11_hum,  "%d.%d", dht11_data[0], dht11_data[1]);
    				sprintf(dht11_temp, "%d.%d", dht11_data[2], dht11_data[3]);
    				
    				if(oid == OBJECT_HUMIDITY)
    				{						
    					sprintf(buffer, CMD_READRSP_HUMIDITY, mid, strlen(dht11_hum), dht11_hum);
    				}
    				else
    				{
    					sprintf(buffer, CMD_READRSP_TEMPERATURE, mid, strlen(dht11_temp), dht11_temp);
    				}
    			}		
    		}
    		else
    		{
    			return;
    		}
    	}
    	else if(strstr(ptr,"+MIPLWRITE"))
    	{
    		mid   = NB73_get_id(ptr, 1);			
    		oid   = NB73_get_id(ptr, 2);			
    		//iid   = NB73_get_id(ptr, 3);
    		//rid   = NB73_get_id(ptr, 4);
    		value = NB73_get_id(ptr, 7);

        if(oid == OBJECT_LED)
        {
      		if(value == 0)
      		{
      			turn_off_led();
      		}
      		else
      		{
      			turn_on_led();
      		}
        }
        
    		sprintf(buffer, CMD_WRITERSP_LED, mid);
    	}
    	else if(strstr(ptr,"+MIPLEVENT"))
    	{
    		eid = NB73_get_id(ptr, 1);

    		switch(eid)
    		{
    			case CIS_EVENT_LIFETIME_TIMEOUT:
    				temperature_enable	= false;
    				humidity_enable			= false;
    				led_enable					= false;
    				notify_fail_cnt   	= 0;  
    			
    				uart_send_stream(CMD_REGISTER);
    				return;
    			
    			case CIS_EVENT_NOTIFY_FAILED:
            
    				notify_fail_cnt++;
    				if(notify_fail_cnt > 10)
    				{
    					notify_fail_cnt = 0;
              nb73_state = NB73_ONENET_INIT;
    				}
            
    				return;

          case CIS_EVENT_REG_SUCCESS:
          
  				  lifetime_tick = HAL_GetTick();
          
  				return;
    			
    			default:
    			
    				return;
    		}
    	}
    	else
    	{
    		return;
    	}
    	
    	uart_send_stream(buffer);

    	return;
    }	
	}
	
	switch(nb73_state)
	{      
		case NB73_NETWORK:
      
			uart_send_stream(NB73_CHECK_NETWORK);
			HAL_Delay(1000);
			break;

    case NB73_ONENET_INIT:
      
      NB73_onenet_init();
      HAL_Delay(300);
      
      break;
		
		case NB73_RUNNING:
      
      now_tick = HAL_GetTick();
      
      if(now_tick - report_tick >= NOTIFY_INTVL_20SEC)
      {
        report_tick = now_tick;

        memset(dht11_hum,  0, 8);
			  memset(dht11_temp, 0, 8);
        if(dht11_read_data(dht11_data))
  			{  
          if(humidity_enable == true)
  				{					
            memset(buffer, 0, BUF_LEN);
            sprintf(dht11_hum, "%d.%d", dht11_data[0], dht11_data[1]);
            
  					sprintf(buffer, CMD_NOTIFY_HUMIDITY, msgid_humidity, strlen(dht11_hum), dht11_hum);
  					
  					uart_send_stream(buffer);
  				}
  				
  				if(temperature_enable == true)
  				{
  					HAL_Delay(200);
  					memset(buffer, 0, BUF_LEN);
            sprintf(dht11_temp, "%d.%d", dht11_data[0], dht11_data[1]);
            
  					sprintf(buffer, CMD_NOTIFY_TEMPERATURE, msgid_temperature, strlen(dht11_temp), dht11_temp);
  					
  					uart_send_stream(buffer);
  				}
  				
  				if(led_enable == true)
  				{
  					HAL_Delay(200);
  					memset(buffer, 0, BUF_LEN);
  					sprintf(buffer, CMD_NOTIFY_LED, msgid_led, 1, get_led_state());
  					
  					uart_send_stream(buffer);
  				}
        }
      }
      else if(now_tick - network_tick >= NETWORK_INTVL_2MIN)
      {
        network_tick = now_tick;
        
        uart_send_stream(NB73_CHECK_NETWORK);    
      }
      else if(now_tick - lifetime_tick >= LIFETIME_INTVL_30MIN)
      {
        HAL_Delay(200);					
        lifetime_tick = now_tick;
				memset(buffer, 0, BUF_LEN);
				sprintf(buffer, CMD_UPDATE_LIFETIME);
				
				uart_send_stream(buffer);    
      }

			break;
		
		default:
			break;
	}
}

