#ifndef __OMW_CMD_H__
#define __OMW_CMD_H__

#include "omw_config.h"
#include "omw_gpio.h"
#include "omw_uart.h"

extern uint16_t  omw_cmd_uart_fifo_sz;
extern uint8_t * omw_cmd_uart_fifo_buf;

//ok: return len, or return 0
int omw_cmd_uart_it_rx(uint8_t * rx_buf, uint16_t len);
void omw_cmd_uart_enable(uint8_t it_mode);

#ifdef OMW_CMD_CTRL
static inline void
omw_cmd_uart_send(void * pdata, uint32_t len){
    omw_uart_send(OMW_CMD_CTRL_UART, pdata, len);
}

static inline uint32_t
omw_cmd_uart_rx(void * pdata, uint32_t len){
    return omw_uart_rcv(OMW_CMD_CTRL_UART, pdata, len);
}

static inline void
omw_cmd_uart_set_rx_fifo(uint8_t * fifo_buf, uint16_t fifo_sz){
    omw_uart_set_rx_fifo(OMW_CMD_CTRL_UART, fifo_buf, fifo_sz);
    omw_cmd_uart_fifo_sz = fifo_sz;
    omw_cmd_uart_fifo_buf = fifo_buf;
}

static inline uint16_t
omw_cmd_uart_get_rx_fifo_wt(void){
    return omw_uart_get_rx_fifo_wt(OMW_CMD_CTRL_UART);
}

static inline void
omw_cmd_uart_set_rx_fifo_rd(uint16_t n_rd){
    omw_uart_set_rx_fifo_rd(OMW_CMD_CTRL_UART, n_rd);
}
#endif

#ifdef OMW_AT_CMD
#define AT_CMD_TYPE_Q  (1 << 4)
#define AT_CMD_TYPE_S  (1 << 5)
#define AT_CMD_TYPE_N  (1 << 6)
/*
#define AT_CMD_CHAR2DIG(ch_4bits)
({ \
    uint8_t __val = 0; \
    if (ch_4bits >= '0' && ch_4bits <= '9')  __val = ch_4bits - '0'; \
    else if (ch_4bits >= 'a' && ch_4bits <= 'f')  __val = ch_4bits - 'a' + 10; \
    else if (ch_4bits >= 'a' && ch_4bits <= 'f')  __val = ch_4bits - 'A' + 10; \
    __val; \
})

//uint8_t:1/uint16_t:2/uint24_t:3/uint32_t:4
#define AT_CMD_CHARS2DIG(str, n)  \
({ \
    uint32_t __val = 0; \
    for (int i = 0; i < (n << 1); i++) __val = (__val << 4) + AT_CMD_CHAR2DIG(str[i]); \
    __val;
})
*/

typedef void    (* AT_CMD_CB_AFTER_RSP)(void);
typedef uint8_t (* AT_CMD_HANDLE)(char * p_data_str, AT_CMD_CB_AFTER_RSP * cb);

typedef struct
{
    const AT_CMD_HANDLE * at_cmd_hdl_tbl;  //CMD Idx must be >=0 && < at_cmd_nr
    const char    ** at_cmd_name_tbl;
    const uint8_t *  at_cmd_len_tp_tbl;
    uint8_t    at_cmd_nr;
}at_cmd_reg_info_tag;

void at_cmd_init(at_cmd_reg_info_tag * at_info);
void at_cmd_rx_process();
//len: not include '\0'
void at_cmd_rsp_usr_data(char * p_data, uint8_t len);
uint8_t at_cmd_str2value(char * p_str, uint8_t * p_val, uint8_t tp, uint8_t rv_ord, uint8_t * cvt_len);
uint8_t at_cmd_value2str_10(uint32_t val, char * p_str);
uint8_t at_cmd_value2str_16(uint8_t * p_val, char * p_str, uint8_t len, uint8_t rv_ord);
void at_cmd_rsp(int8_t cmd);
#endif

#define DATA_PATTERN          0xA55A

#define CMD_TYPE_SYNC         0
#define CMD_TYPE_ACK          1
#define CMD_TYPE_START        2   //NOT NEED ACK/RSP
#define CMD_TYPE_STOP         3   //NOT NEED ACK/RSP
#define CMD_TYPE_TX_DATA      4
#define CMD_TYPE_RX_DATA      5
#define CMD_TYPE_RX_MRDT      6   //MORE DATA
#define CMD_TYPE_FIN          7   //NOT NEED ACK/RSP
#define CMD_TYPE_USER_ST      (CMD_TYPE_FIN + 1)

#define CMD_ACK_NORMAL        0
#define CMD_ACK_READY         1
#define CMD_ACK_WKST_IDLE     2
#define CMD_ACK_WKST_NSYN     3
#define CMD_ACK_WKST_BUSY     4
#define CMD_ACK_DATA_FULL     5
#define CMD_ACK_DATA_TXOK     6
#define CMD_ACK_DATA_TXTO     7

struct cmd_data_fmt
{
    #ifdef OMW_CMD_EN_PATTEN
    uint16_t  pattern;    //sync flag of packet
    #endif
    uint8_t   dtype;      //packet type
    union
    {
        uint8_t   len;       //when non-CMD_TYPE_ACK CMD
        uint8_t   ack_type;  //when CMD_TYPE_ACK
        uint8_t   user_data; //user define
    };
};

#endif
