/*
 * emaPlay.h
 *
 * Created: 6/24/2019 11:59:32 AM
 *
 * oc_emaLink_at.c
 *
 * Created: 6/24/2019 11:49:48 AM
 * 
 *  ######################################################################################################
 *  DISCLAIMER:
 *  OptConnect Management, LLC provides this documentation in support of its products for the internal use
 *  of its current and prospective customers. The publication of this document does not create any other
 *  right or license in any party to use any content contained in or referred to in this document and any
 *  modification or redistribution of this document is not permitted. While efforts are made to ensure
 *  accuracy, typographical and other errors may exist in this document. OptConnect Management, LLC reserves
 *  the right to modify or discontinue its products and to modify this and any other product documentation
 *  at any time.
 * 
 *  All OptConnect products are sold subject to its published Terms and Conditions and subject to any
 *  separate terms agreed with its customers. No warranty of any type is extended by publication of this
 *  documentation, including, but not limited to, implied warranties of merchantability, fitness for a
 *  particular purpose and non-infringement.
 * 
 *  OptConnect is a trademark, and OptConnect ema is a trademark, of OptConnect Management, LLC. All
 *  trademarks, service marks and similar designations referenced in this document are the property of
 *  their respective owners
 *  #######################################################################################################
 * 
 *  version: 1.0
 * 
 *  History:
 *  Version     Description                                     Date
 *  1.0         Initial Release                                 5/19/2020
 */ 

#ifndef EMAPLAY_H_
#define EMAPLAY_H_

#include <atmel_start.h>
#include <queue.h>
#include "oc_ema_modem_at.h"
#include "oc_emaLink_at.h"
#include "emaPlay_config.h"

#define BIT0    1<<0
#define BIT1    1<<1
#define BIT2    1<<2
#define BIT3    1<<3
#define BIT4    1<<4
#define BIT5    1<<5
#define BIT6    1<<6
#define BIT7    1<<7

/*####### Timer Related Functionlaity #######*/
// theser variables should NEVER be written to
extern uint32_t u32Sys1msTic;
extern uint32_t u32Sys1secTic;
extern uint32_t inlineTimer;  

// polled timer macro
// usage:   1. Snapshot current time ->         var = TIME_ELAPSED_ms(0);
//          2. Compare against desired delay -> if (TIME_ELAPSED_ms(var) > 500) 
//                                              { 
//                                                  do something(at 500 ms interval)
//                                                  // reset timer
//                                                  var = TIME_ELAPSED_ms(0);    
//                                              } 
#define TIME_ELAPSED_ms(x)          u32Sys1msTic - x

// inline/serial delay timer macro
// usage:   1. do something
//          2. TIME_DELAY_ms(250) // delays for 250 ms
//          3. continue to do something
#define TIME_DELAY_ms(x)            inlineTimer = TIME_ELAPSED_ms(0); while ( TIME_ELAPSED_ms(inlineTimer) < x ){asm("NOP");};   

void emaPlay_system_1ms_tick_cb( void );
void emaPlay_init_sys1ms_tick( void );
/*###########################################*/

/*####### Queue Related Functionlaity  ######*/
extern Q_STRUCT modem_uart_sync_rx_q, modem_uart_async_rx_q;
extern Q_STRUCT link_uart_sync_rx_q, link_uart_async_rx_q;
#define AT_RX_Q_BUFF_SIZE       1024
#define EMA_AT_RX_Q_BUFF_SIZE   512
extern char modem_uart_sync_rx_q_buff[AT_RX_Q_BUFF_SIZE];
extern char modem_uart_async_rx_q_buff[AT_RX_Q_BUFF_SIZE];
extern char link_uart_sync_rx_q_buff[EMA_AT_RX_Q_BUFF_SIZE];
extern char link_uart_async_rx_q_buff[EMA_AT_RX_Q_BUFF_SIZE];

void emaPlay_q_init( struct q_struct *q, char *buffer, unsigned buffer_size );
int emaPlay_q_put( Q_STRUCT *q, char data );
int emaPlay_q_get( Q_STRUCT *q,unsigned short timeout );

// q status codes
#define Q_ST_TIMEOUT                -2 
#define Q_ST_EMPTY                  -1
#define Q_ST_NOT_VALID              -1
#define Q_ST_FULL                   0
#define Q_ST_SUCCESS                1
// q flags
#define Q_FL_RETRY_TO_TIMEOUT       BIT0            // retries the q operation until timeout(ms) reached

/*###########################################*/

/*####### modem/ema UART Functionality ######*/
extern struct io_descriptor *ema_modem_uart_io;
extern struct io_descriptor *ema_mgmt_uart_io;

void emaPlay_uart_setup( struct usart_async_descriptor *const uart, struct io_descriptor **io_rw, usart_cb_t tx_callback, usart_cb_t rx_callback );
int emaPlay_modem_uart_send( uint8_t *buffer, uint16_t len, uint16_t timeout, uint8_t flags );
int emaPlay_modem_uart_receive( uint8_t *buffer, uint16_t *len, uint16_t timeout, uint8_t flags, const char* pattern );
void emaPlay_modem_tx_cb ( void );
void emaPlay_modem_rx_cb ( void );
int emaPlay_emaLink_uart_send( uint8_t *buffer, uint16_t len, uint16_t timeout, uint8_t flags );
int emaPlay_emaLink_uart_receive( uint8_t *buffer, uint16_t *len, uint16_t timeout, const char *pattern );
void emaPlay_emaLink_tx_cb ( void );
void emaPlay_emaLink_rx_cb ( void );

// uart status codes
#define UART_ST_TIMEOUT             Q_ST_TIMEOUT
#define UART_ST_TX_SUCCESS          Q_ST_SUCCESS
#define UART_ST_INTERFACE_DOWN      98
#define UART_ST_MODULE_ERROR        99

/*###########################################*/


/*##########  AT cmd Functionality ##########*/
int emaPlay_modem_at_query( struct modem_at_context *at_query, unsigned short tx_timeout, unsigned short res_timeout, const char *res_pattern );
int emaPlay_emaLink_at_query( struct emaLink_context *at_query );
/*###########################################*/

/*##########  ema URC & cmd Functionality ##########*/
void emaPlay_emaLink_URC_handler( struct emaLink_context *handle, struct modem_at_context *modem_handle ); 
void emaPlay_emaLink_process_URC( struct emaLink_context *link_handle, struct modem_at_context *modem_handle, int urc, char *msg, unsigned short len );
//uint8_t emaPlay_waitURC( struct emaLink_context *link_handle, unsigned long URCMask, uint16_t wait_time );
/*###########################################*/

/*###### ema:Play GPIO Functionality  #######*/
enum ema_on_off_state
{
    EMA_ON_OFF_ST_ON = 0,
    EMA_ON_OFF_ST_OFF,
    EMA_ON_OFF_ST_TOGGLE
};

enum ema_power_state
{
    EMA_POWER_ST_ON = 0,
    EMA_POWER_ST_OFF,
    EMA_POWER_ST_TOGGLE
};

void emaPlay_ema_on_off_control( enum ema_on_off_state state );
void emaPlay_ema_power_control( enum ema_power_state state );

void emaPlay_ema_reset( uint16_t reset_time );

/*###########################################*/

/*###### ema:Play App level functions  #######*/
extern uint8_t sw0_pending, sw0_long_press, sw1_pending;
extern uint8_t din0_state, din1_state;
extern uint8_t sts_state;

#define EMA_SN_SIZE     16
#define EMA_FW_SIZE     32
#define EMA_BID_SIZE    64
#define IPV4_SIZE       16
struct ema_status{
    char pri_carrier[CARRIER_SIZE+1];
    char act_carrier[CARRIER_SIZE+1];
    char cell_fw[CELL_FW_SIZE+1];
    char failover_st[FAIL_OVER_EN_DIS_SIZE+1];
    uint32_t uptime;
    uint32_t failover_time_ago;
    uint8_t cntx_id;
    char acc_tech[ACC_TECH_SIZE+1];
    uint8_t reg;
    
    uint8_t rxlev;
    uint8_t ber; 
    uint8_t rscp;
    uint8_t ecno;
    uint8_t rsrq;
    uint8_t rsrp;
    uint8_t calc_sig_q;

    char IP[IPV4_SIZE];

    char board_id[EMA_BID_SIZE+1];
    char fw_ver[EMA_FW_SIZE+1];
    char sn[EMA_SN_SIZE+1]; 
    char model[EMA_MODEL_SIZE+1];
    char oc_services_state[EMA_SERV_ST_SIZE+1];
    
    uint8_t cntx_st;   
};

enum sys_state
{
    SYS_ST_IDLE = 0,
    SYS_ST_NORMAL_OP,
    SYS_ST_ASYNCH_TASK,
    SYS_ST_INIT_EMA_APPLY_POWER,
        #define EMA_APPLY_POWER_WAIT_TIME   5000
    SYS_ST_INIT_EMA_TURN_ON_MODULE,
        #define EMA_MODULE_READY_WAIT_TIME  20000
    SYS_ST_CHECK_NETWORK,
        #define EMA_NETWORK_READY_TIME      30000
    SYS_ST_CHECK_SESSION,
    SYS_ST_START_SESSION,
    SYS_ST_HANDLE_REBOOT,
        #define EMA_REBOOT_WAIT_TIME        30000
    SYS_ST_RECOVER_EMA,
    SYS_ST_TURN_OFF_MODULE,
        #define EMA_MODULE_OFF_WAIT_TIME    60000
    SYS_ST_EMA_REMOVE_POWER,
    SYS_ST_INIT_LEAF,
    SYS_ST_BUILD_LEAF_MSG,
    SYS_ST_SEND_LEAF_MSG,
    SYS_ST_PROCESS_LEAF_CMD,
    SYS_ST_INIT_ERROR,
    SYS_ST_ERROR,
    SYS_ST_REBOOT_EMA_PLAY
};

enum adc_inputs{
    PHOTO_MON = 0,
    EMA_V_MON,
    SYS_V_MON,
    USER_MON,
    MAX_NUM_ADC_INPUTS
};

#define     NUM_ADC_READS_TO_AVG        4


enum emaPlay_ev{
    EV_SW0_PRESS_RELEASE = 0,
    EV_SW1_PRESS_RELEASE,
    EV_DIN0_STATE,
    EV_DIN1_STATE,
    NUM_EMA_PLAY_EV
};
#define EV_JSON_NAME_SIZE   16

// atsame5x unique sn size and location
#define     EMA_PLAY_SN_SIZE     16  
#define     SN_LOC_0            0x008061fc
#define     SN_LOC_1            0x00806010
#define     SN_LOC_2            0x00806014
#define     SN_LOC_3            0x00806018

struct emaPlay_stats{
    // i2c
    float temp;
    float r_hum;

    // adc
    uint16_t light;
    uint16_t ema_v;
    uint16_t sys_v;
    uint16_t user_adc;

    // left/right decimal printable values
    uint16_t t_l, t_r;      // temp
    uint16_t h_l, h_r;      // rel hum
    uint16_t eV_l, eV_r;    // ema V    
    uint16_t sV_l, sV_r;    // sys V

    uint8_t siq_q;
};

struct emaPlay_douts{
    uint16_t duty;
    uint16_t period;
};

struct emaPlay_status{
  
    struct emaPlay_stats stats;
      
    // digital inputs/events
    uint8_t events[NUM_EMA_PLAY_EV];

    // control/digital outputs
    struct emaPlay_douts user_douts[4];

    // board notify pending cmds
    uint8_t pending_cmd;

    // id
    char sn[EMA_PLAY_SN_SIZE];

    // other
    uint8_t leaf_init;
    uint16_t auto_module_reboots;
    uint16_t man_ema_reboots;
};

#define     EV_SW0_PRESS_REL        (1<<0)
#define     EV_SW1_PRESS_REL        (1<<1)
#define     EV_DIN1_STATE_CHANGE    (1<<2)
#define     EV_DIN2_STATE_CHANGE    (1<<3)
struct emaPlay_events{
    uint16_t old_ev_mask;
    uint16_t new_ev_mask;
};

// error codes
#define ERR_CODE_EMA_URC_TIME_OUT       0   // didn't get expected URC in time
#define ERR_CODE_EMA_AT_RESPONSE        1   // didn't get the expected ema AT response
#define ERR_CODE_EMA_MODULE_RESPONSE    2   // didn't get the expected module AT response
#define ERR_CODE_NETWORK_ERROR          3   // couldn't register on the network and/or obtain signal    
#define ERR_CODE_LEAF_RESPONSE          4   // didn't get the expected lead response
#define ERR_CODE_LEAF_INIT              5   // didn't init leaf properly
#define ERR_CODE_SYS_POWER_LOSS         6   // no main input voltage
#define ERR_CODE_EMA_POWER_LOSS         7   // no ema voltage
#define ERR_CODE_PROCESSED              255 // the errro has been processed 

void emaPlay_read_temp_humidiity( struct emaPlay_status *emaPlay );
    #define     ENV_READ_INTERVAL       10000
    #define     TEMP_OFFSET             6   // observed during testing
    #define     HUMIDITY_OFFSET         4   // observed during testing
void emaPlay_scan_analog_inputs( struct emaPlay_status *emaPlay );
    #define     ADC_SCAN_INTERVAL_MS    8   // 8.3ms = 120hz, 8 = 125hz 
void emaPlay_get_chip_SN( char *sn );
uint8_t emaPlay_check_events( struct emaPlay_status *emaPlay );
void emaPlay_leaf_cmd_handler(char *command, char **params, int num_params);
void emaPlay_system_task(struct emaLink_context *link_handle, 
                         struct modem_at_context *modem_handle, 
                         struct ema_status *ema, 
                         struct emaPlay_status *emaPlay,  
                         uint8_t *ev );
    #define SYS_TASK_EXECUTION_INTERVAL     100  // ms
uint8_t emaPlay_check_network( struct modem_at_context *modem_handle, struct ema_status *ema );
uint8_t emaPlay_glimpse( struct emaLink_context *emaLink, struct ema_status *ema );
uint8_t emaPlay_confirm_mobileIP( char *IP );
void emaPlay_init( struct emaPlay_status *emaPlay );
uint8_t emaPlay_check_power( struct emaPlay_stats *stat );
void emaPlay_ema_apply_power( void );
void emaPlay_ema_remove_power( void );
void emaPlay_ema_turn_on( void );
void emaPlay_ema_turn_off( void );
unsigned char emaPlay_ema_qualify_signal( unsigned char rsrq, unsigned char rsrp );
    #define     SIGNAL_UNKNOWN      0
    #define     SIGNAL_POOR         1
    #define     SIGNAL_FAIR         2
    #define     SIGNAL_GOOD         3
    #define     SIGNAL_EXCELLENT    4 
void emaPlay_set_led_array( uint16_t duty_cycle0, uint16_t period0,
                            uint16_t duty_cycle1, uint16_t period1,
                            uint16_t duty_cycle2, uint16_t period2,
                            uint16_t duty_cycle3, uint16_t period3 );
void emaPlay_update_led_graph( uint8_t *sig );
void set_led_blink_pattern( uint8_t idx, uint16_t duty_cycle, uint16_t period );
    #define     NUM_EMA_PLAY_LEDS                   6
    #define     LED_PATTERN_PAIR_SEARCHING          750,1000
    #define     LED_PATTERN_PAIR_UNKNOWN            250,1000
    #define     LED_PATTERN_PAIR_ERROR              500,1000
    #define     LED_PATTERN_PAIR_ON                 500,500
    #define     LED_PATTERN_PAIR_OFF                0,0
void set_user_dout_pattern(uint8_t idx, uint16_t duty_cycle, uint16_t period); 
    #define     NUM_USER_OUTPUTS                    2
void update_led(uint8_t idx);
void debounce_inputs( void );
void update_outputs( void );
void emaPlay_init_ema_cmds( struct emaLink_context *link_handle, struct ema_status *ema, struct emaPlay_status *emaPlay);
void emaPlay_create_ema_board_ID( char *emaPlay_sn, char *ema_sn, char *boardID );
void emaPlay_process_board_notify( char *msg, uint8_t *sys_state, struct emaPlay_status *emaPlay );
    #define     BN_CMD_CONTROL_STR                  "control"
    #define     BN_CMD_REBOOT_EMA_STR               "reboot_ema"
    #define     BN_PENDING_CMD_REBOOT_EMA           0x01
    #define     BN_CMD_REBOOT_EMA_PLAY_STR          "reboot_ema_play"
    #define     BN_PENDING_CMD_REBOOT_EMA_PLAY      0x02
    #define     SW7_SHUTDOWN_EMA                    0x03
void emaPlay_process_leaf_cmd( char *cmd, struct emaPlay_status *emaPlay );
    #define     BN_CMD_CONTROL_STR2                 "set_output"
void emaPlay_convert_to_decimal( struct emaPlay_stats *stat_data );
int emaPlay_check_stat_delta( struct emaPlay_stats *stat_data );

/*###########################################*/

#ifdef DEBUG
/*####### Debug Functionality ######*/
#define     DBG_TASK_INTERVAL     5  // ms 
#define     DBG_Q_BUFF_SIZE       4096
  
extern struct io_descriptor *emaPlay_dbg_uart_io;
extern Q_STRUCT dbg_rx_q, dbg_tx_q;
extern char dbg_q_rx_buff[DBG_Q_BUFF_SIZE];
extern char dbg_q_tx_buff[DBG_Q_BUFF_SIZE];

void emaPlay_dbg_out( char *dbg_data, uint16_t len );
void emaPlay_dbg_tx_cb ( void );
void emaPlay_dbg_rx_cb ( void );
int emaPlay_dbg_uart_send( char *buffer, uint16_t len, uint16_t timeout, uint8_t flags );
void emaPlay_app_debug_send( char *buffer, uint16_t len );
int emaPlay_dbg_uart_receive( uint8_t *buffer, uint16_t *len, uint16_t timeout );
void dbg_task ( struct emaLink_context *link_handle, 
                struct modem_at_context *at_handle,
                struct ema_status *ema, 
                struct emaPlay_status *emaPlay );
/*###########################################*/
#endif

#endif /* EMAPLAY_H_ */
