Files
kunlun/app/grapp/iot_at.c
2024-09-28 14:24:04 +08:00

5745 lines
171 KiB
C

/****************************************************************************
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
be copied by any method or incorporated into another program without
the express written consent of Aerospace C.Power. This Information or any portion
thereof remains the property of Aerospace C.Power. The Information contained herein
is believed to be accurate and Aerospace C.Power assumes no responsibility or
liability for its use in any way and conveys no license or title under
any patent or copyright and makes no representation or warranty that this
Information is free from patent or copyright infringement.
****************************************************************************/
#include "iot_string_api.h"
#include "os_task_api.h"
#include "os_event_api.h"
#include "os_timer_api.h"
#include "os_utils_api.h"
#include "iot_task_api.h"
#include "iot_module_api.h"
#include "os_lock_api.h"
#include "iot_plc_cco_api.h"
#include "iot_config_api.h"
#include "iot_app_api.h"
#include "iot_errno_api.h"
#include "iot_io_api.h"
#include "iot_uart_api.h"
#include "iot_utils_api.h"
#include "iot_board_api.h"
#include "iot_grapp.h"
#include "iot_plctxrx.h"
#include "iot_proto_common.h"
#include "iot_system_api.h"
#include "iot_version_api.h"
#include "iot_oem_api.h"
#include "iot_flash_api.h"
#include "iot_crc_api.h"
#include "iot_spi_api.h"
#include "iot_gpio_api.h"
#include "iot_i2c_api.h"
#define plctxrx_force_skip_resp(p_resp) \
((0xFFFF == p_resp->index.current) && (0xFFFF == p_resp->index.total))
#if IOT_GR_APP_ENABLE
#if INCLUDE_AT_COMMAND_MODULE
#define IOT_AT_MODULE_VERSION "1.0.005"
/* The priority of commands */
#define AT_PRIO_MIN 5
#define AT_PRIO_NOR 7
#define AT_PRIO_MAX 9
#define AT_DEF_TIMEOUT 15
#define AT_DEF_PRIO AT_PRIO_NOR
/* Message queue items count. */
#define AT_TASK_MSG_CNT 32
#define AT_LIST_ITEMS_PER_COMMAND 10
#define AT_LIST_ITEMS_CONTINUE "\r\nPress <ENTER> to continue..."
#define TRANSPARENT_KEYWORDS "###\r\n"
#define TRANSPARENT_KEYWORDS_LEN 5
#define STRING_ENABLE "\"E\""
#define AT_TMR_CHECK_END_PMODE (1000 * 3) // //unit ms
const uint8_t INVALID_MACADDR_6BYTE[IOT_MAC_ADDR_LEN] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint8_t IOT_AT_BROADCAST_MAC_6BYTES[IOT_MAC_ADDR_LEN] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static uint32_t recv_blen = 0;
/* Uniform flash struct used by GE and AT layer. */
static custom_flash_info_t uniform_flashinfo_at;
/* AT command name string, reference to enum at_command_id_list_e */
char *at_command_name[AT_CID_MAX]={
"HELP", /*
Show the command items of this table.
Query: AT+HELP?
*/
"MEMORY", /*
Show a block of memory:
Query: AT+MEMORY?ADDRESS
Set : AT+MEMORY=ADDRESS,VALUE
ADDRESS is the memory address in 32 bits,VALUE is the value in
32 bits too.
*/
"TASK", /*
Show current task list.
Query: AT+TASK?
*/
"TIME", /*
Set or query system time.(Realtime.)
Query: AT+TIME?
Set : AT+TIME=YEAR-MOUNTH-DAY,HOUR:MIN:SEC
*/
"SYSINFO", /*
Show the system information like:
1. OS running time.
2. Last boot reason.
3. Total boot time.
4. Firmware version & built time.
5. RAM / CPU utilization percentage.
Query: AT+SYSINFO?
Clear: AT+SYSINFO=
*/
"UART", /*
Show or set the configuration of current uart port.
Query: AT+UART?
Set : AT+UART=BRATE,DLEN,STOP,PARITY
DLEN is the data length, <5-8>.
STOP is the stop bit, 1 -> 1 bits, 2 -> 1.5 bits, 3 -> 2 bits.
PARITY is the parity, 0 -> none, 1 -> odd, 2 -> even.
*/
"MAC", /*
Set or query MAC address.
Query: AT+MAC?
Set : AT+MAC="xx:xx:xx:xx:xx:xx"
*/
"TOPO", /*
Show the topo of current network.
Query: AT+TOPO?
*/
"PING", /*
Ping a target device with mac address.
Excute: AT+PING="xx:xx:xx:xx:xx:xx",SIZE,TIMES,TIMEOUT
*/
"SEND", /*
Send data to remote device.
Excute: AT+SEND="xx:xx:xx:xx:xx:xx","XX XX XX..."[,try_times]
*/
"REBOOT", /*
Reboot a target device with mac address.
Excute: AT+REBOOT="xx:xx:xx:xx:xx:xx"
Current device will reboot if mac address is NULL.
*/
"WHO", /*
Show basic information about me:
1. Role.
2. MAC address.
3. NID.
Query: AT+WHO?
*/
"RFPOWER", /*
Set or query TX power.
Query: AT+RFPOWER?
Set : AT+RFPOWER=xx
xx is the power value <85-137>.
*/
"WHITELIST",/*
Set or query white list.
Query: AT+WHITELIST?
Excute: AT+WHITELIST= "A or D","xx:xx:xx:xx:xx:xx"
A: Add. D: Delete.
*/
"NETWORK", /*
Show avaliable network:
Query: AT+NETWORK?
Only for STA ,connect/disconnect to an avalibale network
with its MAC.This will case STA join/leave a valid network.
Excute: AT+NETWORK="A or D","xx:xx:xx:xx:xx:xx"
*/
"FLASH", /*
Query/Read/Write customer flash info saved in the AT layer:
Query: AT+FLASH?
Excute:AT+FLASH="R", OFFSET, LEN
AT+FLASH="W", OFFSET, "XX XX XX..."
R: Read; W: Write.
*/
"PMODE", /*
SET transparent mode, data received from UART will be
transparent transmitted to remote device .
Set: AT+PMODE="E","xx:xx:xx:xx:xx:xx" or
Set: AT+PMODE="E"
*/
"SPI", /*
SPI device Query/Set/Read/Write operation:
Query: AT+SPI?
Set: AT+SPI=CLK_PIN, CS_PIN, MISO_PIN, MOSI_PIN,
"DEV_TYPE | TRS_MODE<<2 | FRM_FMT<<4
| DFRM_SZ<<6 | CS_EN << 11",
FRQ, RX_THD, TX_RHD
Excute:AT+SPI="R", LEN
AT+SPI="W", "XX XX XX..."
R: Read; W: Write.
*/
"IIC", /*
Query/Set/Read/Write IIC:
Query: AT+IIC?
Set: AT+IIC=PORT, SPEED, SDA_PIN, SCL_PIN,
NAK_WAIT_NUM,REG_ADDR_LEN
Excute:AT+IIC="R", SLAVE_ADDR, REG_ADDR, LEN
AT+IIC="W", SLAVE_ADDR, REG_ADDR, VALUE
R: Read; W: Write.
*/
"GPIOCFG", /*
Config GPIO pin,
Config : AT+GPIOCFG=gpio_x,"I or O","U or D"
I : input, O : output.
U : pull-up, D : pull-down.
*/
"GPIOVAL", /*
Read / set the value of GPIO.
Set : AT+GPIOVAL=gpio_x,VAL.
Query: AT+GPIOVAL?gpio_x.
*/
"SWMODE", /*
SWITCH uart mode to GR_MCU_OP_MODE
Excute:AT+SWMODE="E"
*/
"NETGROUP", /*
Start/End group network.
Excute:AT+NETGROUP="S" or "E"
S: start; E: end.
*/
"HOSTPORT", /*
Set host port
Query: AT+HOSTPORT?
Excute:AT+HOSTPORT="UART" or "ETH"
*/
};
/* Return status of this command. */
enum at_command_response_e
{
AT_RESP_OK,
AT_RESP_ERROR,
AT_RESP_BUSY,
AT_RESP_UNKNOWN_CMD,
AT_RESP_INVALID_ARGUMENT,
AT_RESP_WAIT_RESP_TIMEOUT,
AT_RESP_SET_FINISH_WITHOUT_ECHO,
AT_RESP_FORCE_ECHO
};
/* Message type of at command module. */
enum at_command_message_type_e
{
AT_MSG_TYPE_COMMAND = 0x1 << 4, /* This message is a command. */
AT_MSG_TYPE_RESPONSE = 0x2 << 4, /* This message is a response. */
AT_MSG_TYPE_TIMEOUT = 0x3 << 4
};
/*
This defined the sources of message handled in this module.
It's filled in the msg_id block for AT_MSG_TYPE_COMMAND/AT_MSG_TYPE_RESPONSE.
*/
enum at_command_message_source_e
{
AT_MSG_SOURCE_LOCAL = 0x1, /* This message comes from this module. */
AT_MSG_SOURCE_PLCTXRX = 0x2, /* This message comes from plc module. */
AT_MSG_SOURCE_UART = 0x3 /* This message comes from uart flow. */
};
/* Message.type = at_command_message_type_e | at_command_message_source_e */
#define MSG_TYPE(type) ((type) & 0x0000FFF0)
#define MSG_SRC(type) ((type) & 0x0000000F)
#define SET_TRANSP_MODE(type) ((type) | (1 << 15))
#define GET_TRANSP_MODE(type) ((type) >> 15)
#define GET_PAYLOAD_TYPE(type) ((type) & 0x7FFF)
#define AT_RESP_STR_OK "\r\n<%2.64s> response OK.\r\n"
#define AT_RESP_STR_ERROR "\r\n<%2.64s> response ERROR.\r\n"
#define AT_RESP_STR_BUSY "\r\n<%2.64s> response BUSY.Command dropped.\r\n"
#define AT_RESP_STR_UNKNOWN "\r\nCommand not found.\r\n"
#define AT_RESP_STR_INVALID_ARG "\r\n<%2.64s> response Invalid arguments.\r\n"
#define AT_RESP_STR_TIMEOUT "\r\n<%2.64s> response Time out.\r\n"
/* Recommended buffer size. */
#define AT_SMALL_BUF_SIZE 64
#define AT_MID_BUF_SIZE 128
#define AT_LARGE_BUF_SIZE 256
#define USER_INPUT_ADD_STR "A"
#define USER_INPUT_DEL_STR "D"
#define USER_INPUT_READ_STR "R"
#define USER_INPUT_WRITE_STR "W"
#define USER_INPUT_GPIOCFG_INPUT_STR "I"
#define USER_INPUT_GPIOCFG_OUTPUT_STR "O"
#define USER_INPUT_GPIOCFG_PULLUP_STR "U"
#define USER_INPUT_GPIOCFG_PULLDOWN_STR "D"
#define USER_INPUT_NETGROUP_START_STR "S"
#define USER_INPUT_NETGROUP_END_STR "E"
#define USER_INPUT_HOST_PORT_UART_STR "UART"
#define USER_INPUT_HOST_PORT_ETH_STR "ETH"
/* Operatopn code for downlayer */
enum at_command_opcode_e
{
AT_OP_TEST, /* Queries the Set Commands internal parameters and
their range of values. AT+<x>=? */
AT_OP_QUERY, /* Returns the current value of parameters. AT+<x>? */
AT_OP_SET, /* Sets the value of user-defined parameters in commands,
and runs these commands. AT+<x>=... */
AT_OP_EXECUTE, /* Runs commands with no user-defined parameters. AT+<x> */
AT_OP_INVALID
};
#define AT_SEND_DEF_RETRY_TIME 0
/*
AT command down flow:
at_fn_send_to_at_t (AT registerd to uplayer.
Put command string to AT)
-> at_fn_handle_send_t (AT local functions in commands table.
Convert command string to at_arg_t.)
-> at_fn_send_from_at_t (downlayer registerd to AT.
Post at_arg_t to downlayer )
AT command up flow :
at_fn_response_to_at_t (AT registerd to downlayer.
Put at_resp_t to AT)
-> at_fn_handle_resp_t (AT local functions in commands table.
Convert at_arg_t to response string)
-> at_fn_response_from_at_t (uplayer registerd to AT
Post response string to uplayer)
*/
#define AT_COMMAND_MID 0 /* TODO */
typedef struct _at_command_message_t
{
iot_task_msg_t msg; /* The main entity of message. */
iot_pkt_t *data; /* The pointer of message. */
}at_msg_t;
typedef enum _at_send_payload_type_e
{
/* transparent app data, plc forward */
AT_PAYLOAD_RAWDATA = 1,
/* at ping req, at internal msg. at in charge to handle */
AT_PAYLOAD_PING = 2,
/* at ping reply, at internal msg, at in charge to handle*/
AT_PAYLOAD_PING_REPLY = 3
}at_pl_type_e;
typedef struct _at_send_payload_t
{
/* Length of payload data. Hint: move len ahead, for easy txrx aggr */
uint16_t dlen;
/* Type of payload. Ref-to _at_send_payload_type_e */
uint16_t type;
/* Data of payload. */
uint8_t data[0];
}at_payload_t;
typedef struct _at_send_ping_t
{
uint8_t org_mac[IOT_MAC_ADDR_LEN];
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
uint32_t stamp; /* Timestamp from sender. */
uint16_t index; /* Ping packet index. */
uint16_t dlen; /* Data length. */
uint8_t data[0];
}at_ping_t;
struct at_ping_host_data
{
uint8_t dst_mac[IOT_MAC_ADDR_LEN];
volatile uint16_t started;
volatile uint16_t reply_index;
volatile uint32_t stamp;
}g_ping_host;
typedef struct _at_iic_gpio_sel
{
uint16_t scl; /* SCL pin. */
uint16_t sda; /* SDA pin. */
} at_iic_gpio_sel_t;
typedef struct _at_command_iic_cfg_t
{
uint32_t inited; /* IIC initialization completed? 0, not yet, 1, done. */
uint32_t port; /* IIC port number. */
uint32_t baud; /* IIC baudrate, unit is Kb. */
uint32_t nack_wait_num; /* wait nack number. */
at_iic_gpio_sel_t gpio; /* gpio number select. */
uint32_t reg_addr_len; /* read/write register address length. */
} at_iic_cfg_t;
typedef struct _at_command_uart_cfg_t
{
uint8_t port; /* The uart port num. */
uint8_t dlen; /* The uart data length. */
uint8_t stop; /* The uart stop bit. */
uint8_t parity; /* The uart parity bit. */
uint32_t brate; /* The uart baudrate. */
}at_uart_cfg_t;
typedef struct _at_command_spi_cfg_t
{
uint32_t inited; /* SPI initialization completed? 0, not yet, 1, done. */
int port; /* SPI device port number. */
iot_spi_gpio_sel_t gpio; /* SPI gpio select config. */
spi_cfg cfg; /* SPI config. */
tm_cfg tm; /* SPI timing. */
}at_spi_cfg_t;
/* The whitelist action type, ensure each item value same with proto defined. */
typedef enum _at_whitelist_action_type_e
{
AT_WL_ACTION_DEL,
AT_WL_ACTION_ADD,
AT_WL_ACTION_DISABLE,
AT_WL_ACTION_ENABLE,
AT_WL_ACTION_NONE,
}at_wl_action_type;
typedef struct _at_whitelist_operation_info_t
{
/* Whitelist add or delete signle device info. */
at_dev_t signle_dev;
/* The latest whitelist action type.*/
at_wl_action_type latest_wl_action;
}at_wl_op_t;
/* The AT command context. */
static at_context_t at_command_context;
#define AT_IIC_INIT_COMPLETED 1
#define AT_IIC_INIT_UNCOMPLETED 0
#define AT_IIC_DEF_PORT 0 /* Port#0 or port#1 */
#define AT_IIC_DEF_SPEED 50 /* 50K */
#define AT_IIC_DEF_NACK_NUM 1 /* N-ACK number */
#define AT_IIC_DEF_GPIO_SCL 35 /* UART1_RX*/
#define AT_IIC_DEF_GPIO_SDA 34 /* UART1_TX */
/* Maximum of the iic one time read or write operation. */
#define AT_IIC_MAX_RD_WR_BYTES 32
/* The common len and max val used in IIC read/write operation, for reg addr and data. */
#define AT_IIC_OP_COMMON_LEN_1BYTE 1
#define AT_IIC_OP_COMMON_LEN_2BYTE 2
#define AT_IIC_OP_MAX_VAL_1BYTE 0xFF
#define AT_IIC_OP_MAX_VAL_2BYTE 0xFFFF
/* The iic config of AT layer. */
static at_iic_cfg_t at_command_iic_cfg =
{
AT_IIC_INIT_UNCOMPLETED, /* IIC initialization uncompleted. */
AT_IIC_DEF_PORT, /* IIC device port number. */
AT_IIC_DEF_SPEED, /* Baudrate, unit is Kb. */
AT_IIC_DEF_NACK_NUM, /* Wait nack number. */
{
AT_IIC_DEF_GPIO_SCL, /* SCL pin. */
AT_IIC_DEF_GPIO_SDA /* SDA pin. */
},
AT_IIC_OP_COMMON_LEN_1BYTE, /* Register address length. */
};
/* The uart config of AT layer. */
static at_uart_cfg_t at_command_uart_cfg =
{
0, /* UART Port num. */
IOT_UART_DLEN_8_BITS, /* UART Data length. */
IOT_UART_STOP_1_BITS, /* UART Stop bit. */
IOT_UART_PARITY_NONE, /* UART Parity bit. */
IOT_UART_BANDRATE_DEFAULT, /* UART baudrate. */
};
#define AT_SPI_INIT_COMPLETED 1
#define AT_SPI_INIT_UNCOMPLETED 0
/* Maximum of the spi one time read or write operation. */
#define AT_SPI_MAX_RD_WR_BYTES 32
/* Max size of the spi one time write operation buffer. */
#define AT_SPI_MAX_WR_BUF_SIZE (AT_SPI_MAX_RD_WR_BYTES + 1)
/* SPI read or write dummy data in at layer. */
#define AT_SPI_RD_WR_DUMMY_DATA 0x5A
/* The spi config of AT layer, initialized to the default configuration. */
static at_spi_cfg_t at_command_spi_cfg =
{
AT_SPI_INIT_UNCOMPLETED, /* SPI initialization uncompleted. */
DEVICE_SPI0_MASTER, /* SPI device port number. */
/* 35<->CLK, 34<-> CS, 8<->MISO, 9<->MOSI */
{35, 34, 8, 9},
{
SPI_MASTER, /* Master or slaver. */
TMOD_TRANCIEVER, /* Trans_mode. */
FRM_STD, /* Frame_format. */
SPI_DFRAME_SIZE_8, /* Data frame size. */
DEVICE_SPI_DEFAULT_CS_EN, /* Slave select enable*/
0, /* Reserved. */
DEVICE_SPI_DEFAULT_FREQUENCY, /* Device frequency. */
DEVICE_SPI_DEFAULT_RX_THRESHOULD, /* Threshold for reviecing fifo. */
DEVICE_SPI_DEFAULT_TX_THRESHOULD /* Threshold for transmitting fifo. */
},
/* scpol bit: 0, scph bit: 0, scph_tgl bit: 0, sste bit: 1, reserved: 0. */
{0, 0, 0, 1, 0},
};
/* The whitelist operation info recorded in AT layer*/
static at_wl_op_t at_command_wl_op;
#define AT_WL_OP_DELAY_MS (1000) /* The unit of delay time is ms. */
#define at_sem_lock() os_acquire_mutex(at_command_context.sem)
#define at_sem_release() os_release_mutex(at_command_context.sem)
#define at_is_firedup() (0x569a4323 == at_command_context.mkey)
#define at_fire_now() (at_command_context.mkey = 0x569a4323)
#define AT_MAX_ARGC 30
#define CR_OR_LF(ch) (('\r' == ch) || ('\n' == ch))
#define CH_EOS '\0'
#define CH_SET '='
#define CH_QUR '?'
#define CH_SPL ','
#define ISSPACE(ch) ((CR_OR_LF(ch) || ' ' == ch || '\t' == ch || '\v' == ch\
|| '\f' == ch) ? 1 : 0)
#define AT_MAX_SEND_BYTES 256
#define AT_MAX_PING_BYTES 64
#define AT_DEF_PING_TIMES 3
#define CH_IS_SPLIT(ch) (((':' == (ch)) || ('-' == (ch))\
|| (' ' == (ch))) ? 1 : 0)
#if !defined(min)
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#if !defined(max)
#define max(a, b) (((a) < (b)) ? (b) : (a))
#endif
/* The macro for add AT command. */
#define AT_CMD(id, timout, prio, handle_send, handle_resp)\
{&at_command_name[id], 0, timout, prio, handle_send, handle_resp}
/* The AT command table. */
static at_cmd_t at_command_table[AT_CID_MAX] = {
AT_CMD(AT_CID_HELP, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_help, NULL),
AT_CMD(AT_CID_MEMORY, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_memory, NULL),
AT_CMD(AT_CID_TASK, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_task, NULL),
AT_CMD(AT_CID_TIME, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_time, at_handle_response_time),
AT_CMD(AT_CID_SYSTEMINFO, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_systeminfo, at_handle_response_systeminfo),
AT_CMD(AT_CID_UART, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_uart, at_handle_response_uart),
AT_CMD(AT_CID_MAC, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_mac, at_handle_response_mac),
AT_CMD(AT_CID_TOPO, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_topo, at_handle_response_topo),
AT_CMD(AT_CID_PING, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_ping, NULL),
AT_CMD(AT_CID_SEND, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_send, at_handle_response_send_receive),
AT_CMD(AT_CID_REBOOT, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_reboot, at_handle_response_reboot),
AT_CMD(AT_CID_WHO, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_who, at_handle_response_who),
AT_CMD(AT_CID_RFPOWER, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_rfpower, at_handle_response_rfpower),
AT_CMD(AT_CID_WHITELIST, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_whitelist, at_handle_response_whitelist),
AT_CMD(AT_CID_NETWORK, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_network, at_handle_response_network),
AT_CMD(AT_CID_FLASH, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_flash, NULL),
AT_CMD(AT_CID_PMODE, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_pmode, NULL),
AT_CMD(AT_CID_SPI, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_spi, NULL),
AT_CMD(AT_CID_IIC, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_iic, NULL),
AT_CMD(AT_CID_GPIOCFG, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_gpiocfg, NULL),
AT_CMD(AT_CID_GPIOVAL, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_gpioval, NULL),
AT_CMD(AT_CID_SWMODE, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_cmd_sw_uartmode, NULL),
AT_CMD(AT_CID_NETGROUP, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_netgroup, NULL),
#if SUPPORT_HOST_PORT_ETH
AT_CMD(AT_CID_HOSTPORT, AT_DEF_TIMEOUT, AT_DEF_PRIO, at_handle_command_host_port, NULL),
#endif
};
/* Offset the start addr by 0 bytes, same with proto flash info. */
#define AT_CUST_FLASH_START_OFFSET 0
/* Customer flash start offset addr that users do read or write operation. */
#define AT_CUST_FLASH_USER_OP_START_OFFSET \
(AT_CUST_FLASH_START_OFFSET + sizeof(custom_flash_info_t))
/* Customer flash maximum size that users do read and write operation. */
#define AT_CUST_FLASH_USER_OP_MAX_SIZE \
(custom_dev_query_rw_size() - AT_CUST_FLASH_USER_OP_START_OFFSET)
/* Maximum of the one time read or write operation. */
#define AT_CUST_FLASH_MAX_RD_WR_BYTES 48
/* Max size of the one time flash operation buffer. */
#define AT_CUST_FLASH_MAX_OP_BUF_SIZE (AT_CUST_FLASH_MAX_RD_WR_BYTES + 1)
/* The number of flash read data are displayed on the same row. */
#define AT_FLASH_DIS_ON_SAME_ROW_DATA_NUM 8
void at_command_at_response_to_proto
(uint32_t resp, uint8_t* buf, uint32_t blen, uint16_t resp_finished);
void iot_common_bin_dump(uint8_t *data, uint32_t dlen);
void at_command_cvg_wl_add_del(uint8_t action, uint8_t *mac, bool_t need_ack_cfm);
void at_command_cvg_wl_en_disable(uint8_t action, bool_t need_ack_cfm);
/*
* at_command_spi_write_data() - write data using spi module, this function is excuted when
* cs pin is controled by customs
* @data: pointer to write data buf
* @len: data lenth
* @return ERR_OK -- Operation Successful, ERR_FAIL -- Operation failed.
*/
uint32_t at_command_spi_write_data(char *data, uint16_t len)
{
char spi_rx_buf[AT_SPI_MAX_RD_WR_BYTES];
xfer_buf spi_tx;
if ((NULL == data) || (0 == len))
{
return ERR_FAIL;
}
spi_tx.p_nt = NULL;
spi_tx.txbuf = data;
spi_tx.rxbuf = spi_rx_buf;
spi_tx.size = len;
os_mem_set(spi_rx_buf, AT_SPI_RD_WR_DUMMY_DATA, AT_SPI_MAX_RD_WR_BYTES);
/* before reading, enalbe the cs pin-- pull low */
if(ERR_FAIL == iot_spi_poll_transfer(at_command_spi_cfg.port, &spi_tx))
{
return ERR_FAIL;
}
/* after read, disable the cs pin-- pull high */
return ERR_OK;
}
/*
* at_command_spi_read_data() - read data using spi module, this function is excuted when
* cs pin is controled by customs
* @data: pointer to received data buf
* @len: data lenth
* @return ERR_OK -- Operation Successful, ERR_FAIL -- Operation failed.
*/
uint32_t at_command_spi_read_data(char *data, uint16_t len)
{
int cnt;
char spi_tx_buf[AT_SPI_MAX_RD_WR_BYTES];
xfer_buf spi_rx;
if ((NULL == data) || (0 == len))
{
return ERR_FAIL;
}
spi_rx.p_nt = NULL;
spi_rx.txbuf = spi_tx_buf;
spi_rx.rxbuf = data;
spi_rx.size = len;
os_mem_set(spi_tx_buf, AT_SPI_RD_WR_DUMMY_DATA, AT_SPI_MAX_RD_WR_BYTES);
(void)iot_spi_get_rx_data_cnt(at_command_spi_cfg.port, &cnt);
DINFOR("cnt:%d", cnt);
/* clear fifo */
(void)iot_spi_read_data(at_command_spi_cfg.port, NULL, cnt);
/* before reading, enalbe the cs pin-- pull low */
if(ERR_FAIL == iot_spi_poll_transfer(at_command_spi_cfg.port, &spi_rx))
{
return ERR_FAIL;
}
/* after read, disable the cs pin-- pull high */
return ERR_OK;
}
/* To dump our config info on flash. */
void at_command_dump_uniform_flash(custom_flash_info_t* p_info)
{
uint8_t i;
proto_dev_t *p_dev_table;
if (NULL == p_info)
{
DERROR("Invalid argument!");
return;
}
p_dev_table = p_info->dev_tbl;
DINFOR("The whitelist table number = %d",
p_info->dev_cnt);
for (i = 0; i < p_info->dev_cnt; i++)
{
DINFOR("WL table#%02d,Role:%d,MAC:%02x-%02x-%02x-%02x-%02x-%02x.",
i, p_dev_table->dev_role,
p_dev_table->mac[0], p_dev_table->mac[1],
p_dev_table->mac[2], p_dev_table->mac[3],
p_dev_table->mac[4], p_dev_table->mac[5]);
p_dev_table++;
}
DINFOR("load transpmode = %d,mac=%02X,%02X,%02X,%02X,%02X,%02X",
p_info->transp.transpmode,
p_info->transp.trans_addr[0],p_info->transp.trans_addr[1],
p_info->transp.trans_addr[2],p_info->transp.trans_addr[3],
p_info->transp.trans_addr[4],p_info->transp.trans_addr[5]);
return;
}
/* This will write data onto customer flash area. */
uint32_t at_command_flash_write
(uint32_t write_offset, uint32_t write_len, void *p_write_buf)
{
#if (HW_PLATFORM == HW_PLATFORM_SIMU)
(void)write_offset;
(void)write_len;
(void)p_write_buf;
#else
int fd;
if ((NULL == p_write_buf)
|| ((write_offset + write_len) > custom_dev_query_rw_size()))
{
DERROR("Invalid argument!");
return ERR_FAIL;
}
if (-1 == (fd = custom_dev_open()))
{
DERROR("Cannot open flash!");
return ERR_FAIL;
}
if (-1 == custom_dev_seek
(fd, write_offset, DEV_SEEK_SET))
{
DERROR("Cannot seek flash!");
(void)custom_dev_close(fd);
return ERR_FAIL;
}
if (-1 == custom_dev_write(fd, (void*)p_write_buf, write_len))
{
DERROR("Cannot write flash!");
(void)custom_dev_close(fd);
return ERR_FAIL;
}
(void)custom_dev_close(fd);
#endif
return ERR_OK;
}
/* Load config from customer flash. */
uint32_t at_command_flash_read
(uint32_t read_offset, uint32_t read_len, void *p_read_buf)
{
#if (HW_PLATFORM == HW_PLATFORM_SIMU)
(void)read_offset;
(void)read_len;
(void)p_read_buf;
#else
int fd;
if ((NULL == p_read_buf)
|| ((read_offset + read_len) > custom_dev_query_rw_size()))
{
DERROR("Invalid argument!");
return ERR_FAIL;
}
if (-1 == (fd = custom_dev_open()))
{
DERROR("Cannot open flash!");
return ERR_FAIL;
}
if (-1 == custom_dev_seek
(fd, read_offset, DEV_SEEK_SET))
{
DERROR("Cannot seek flash!");
(void)custom_dev_close(fd);
return ERR_FAIL;
}
if (-1 == custom_dev_read(fd, (void*)p_read_buf, read_len))
{
DERROR("Cannot write flash!");
(void)custom_dev_close(fd);
return ERR_FAIL;
}
(void)custom_dev_close(fd);
#endif
return ERR_OK;
}
/* This will store config onto customer flash area. */
uint32_t at_command_uniform_flashsave(custom_flash_info_t *p_info)
{
if (NULL == p_info) {
DERROR("Invalid argument!");
return ERR_FAIL;
}
return at_command_flash_write(AT_CUST_FLASH_START_OFFSET,
sizeof(*p_info), p_info);
}
/* Load config from customer flash. */
uint32_t at_command_uniform_flashload(custom_flash_info_t *p_info)
{
if (NULL == p_info)
{
DERROR("Invalid argument!");
return ERR_FAIL;
}
return at_command_flash_read(AT_CUST_FLASH_START_OFFSET,
sizeof(*p_info), p_info);
}
/* Check the magic code to tell if our config damaged. */
uint32_t at_command_uniform_flashinfo_check(custom_flash_info_t *p_info)
{
int32_t magic1, magic2;
if (NULL == p_info)
{
DERROR("Invalid argument!");
return ERR_FAIL;
}
magic1 = (p_info->magic1[0] << 24) | (p_info->magic1[1] << 16)
| (p_info->magic1[2] << 8) | p_info->magic1[3];
magic2 = (p_info->magic2[0] << 24) | (p_info->magic2[1] << 16)
| (p_info->magic2[2] << 8) | p_info->magic2[3];
DINFOR("Magic = 0x%08x, 0x%08x!", magic1, magic2);
if ((IOT_PROTO_CUST_FLASHINFO_MAGIC1 != magic1)
||(IOT_PROTO_CUST_FLASHINFO_MAGIC2 != magic2))
{
DERROR("Magic dismatch!");
return ERR_FAIL;
}
return ERR_OK;
}
/* Repair this config when it is damaged. */
void at_command_uniform_flashinfo_repair(custom_flash_info_t *p_info)
{
if (NULL == p_info)
{
DERROR("Invalid argument!");
return;
}
os_mem_set(p_info, 0x0, sizeof(*p_info));
p_info->magic1[0] = (IOT_PROTO_CUST_FLASHINFO_MAGIC1 >> 24) & 0xFF;
p_info->magic1[1] = (IOT_PROTO_CUST_FLASHINFO_MAGIC1 >> 16) & 0xFF;
p_info->magic1[2] = (IOT_PROTO_CUST_FLASHINFO_MAGIC1 >> 8) & 0xFF;
p_info->magic1[3] = (IOT_PROTO_CUST_FLASHINFO_MAGIC1) & 0xFF;
p_info->magic2[0] = (IOT_PROTO_CUST_FLASHINFO_MAGIC2 >> 24) & 0xFF;
p_info->magic2[1] = (IOT_PROTO_CUST_FLASHINFO_MAGIC2 >> 16) & 0xFF;
p_info->magic2[2] = (IOT_PROTO_CUST_FLASHINFO_MAGIC2 >> 8) & 0xFF;
p_info->magic2[3] = (IOT_PROTO_CUST_FLASHINFO_MAGIC2) & 0xFF;
/* Write flash. */
if(ERR_OK == at_command_uniform_flashsave(p_info))
{
DINFOR("Repair flash successfully!");
}
else
{
DERROR("Repair flash failed!");
}
return;
}
void at_command_uniform_flashinfo_init(void)
{
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
DINFOR("sizeof(custom_flash_info_t) = %d", sizeof(custom_flash_info_t));
/* Load and check flash info. */
if ((ERR_FAIL == at_command_uniform_flashload(p_flash))
|| (ERR_FAIL == at_command_uniform_flashinfo_check(p_flash)))
{
DERROR("Cannot get uniform custom flash info!");
at_command_uniform_flashinfo_repair(p_flash);
}
else
{
/* transpmode load */
at_command_context.transp.transpmode = p_flash->transp.transpmode;
iot_mac_addr_cpy(at_command_context.transp.trans_addr,
p_flash->transp.trans_addr);
}
at_command_dump_uniform_flash(p_flash);
return;
}
uint32_t at_command_cid_convert_from_plc(iot_pkt_t* p_resp_pkt)
{
plctxrx_cmd_resp_t *resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
uint32_t cid;
/* TODO : THE LIST OF PLC COMMAND IDs. */
switch(resp->cid.cid)
{
case PLCTXRX_CID_GRAPP_REG_CONF:
case PLCTXRX_CID_MAC:
cid = AT_CID_MAC;
break;
case PLCTXRX_CID_UART:
cid = AT_CID_UART;
break;
case PLCTXRX_CID_TOPO:
cid = AT_CID_TOPO;
break;
case PLCTXRX_CID_SYSTEMINFO:
cid = AT_CID_SYSTEMINFO;
break;
case PLCTXRX_CID_SEND:
cid = AT_CID_SEND;
break;
case PLCTXRX_CID_WHITELIST:
cid = AT_CID_WHITELIST;
break;
case PLCTXRX_CID_TX_PWR:
cid = AT_CID_RFPOWER;
break;
case PLCTXRX_CID_JOIN_NETWORK:
case PLCTXRX_CID_LEAVE_NETWORK:
case PLCTXRX_CID_FIND_NETWORK:
cid = AT_CID_NETWORK;
break;
default:
cid = 0xFFFFFFFF;
}
return cid;
}
static uint8_t at_command_get_name_lenth(uint8_t *pCmd, uint16_t cmd_length)
{
uint8_t i = 0, *p_ch = pCmd;
for( i = 0; i < cmd_length; i++)
{
if (CR_OR_LF(p_ch[i]) || (p_ch[i] == CH_QUR) || (p_ch[i] == CH_SET)
|| ((p_ch[i] >= '0') && (p_ch[i] <= '9')) || p_ch[i] == CH_EOS)
{
return i;
}
}
return 0;
}
at_cmd_t *at_command_get_cmd_handle_by_name(uint8_t *name, uint16_t len)
{
uint8_t head_len;
uint16_t i = 0;
at_cmd_t *p_cmd_handle, *p_cmd_return = NULL;
head_len = at_command_get_name_lenth(name, len);
if (head_len > 0)
{
for (i = 0; i < AT_CID_MAX; i++)
{
p_cmd_handle = &(at_command_context.at_table[i]);
if(p_cmd_handle->head_len == head_len - 3)
if (os_mem_cmp(name + 3, *(p_cmd_handle->name), \
p_cmd_handle->head_len) == 0)
{
p_cmd_return = p_cmd_handle;
break;
}
}
}
return p_cmd_return;
}
at_cmd_t *at_command_get_cmd_handle_by_cid(uint32_t cid)
{
return (cid < AT_CID_MAX) ? (&(at_command_context.at_table[cid])) : NULL;
}
static inline uint32_t at_command_status_is_busy(void)
{
at_status_t *p_status = &(at_command_context.status);
uint32_t busy_now = 1;
at_sem_lock();
if((NULL == p_status->cur_cmd)
|| ((p_status->resp_finished)
&& (p_status->handle_runout)))
{
busy_now = 0;
}
at_sem_release();
return busy_now;
}
uint32_t at_command_get_opcode(uint8_t *name, uint16_t len)
{
uint8_t head_len;
uint32_t opcode;
head_len = at_command_get_name_lenth(name, len);
if(CR_OR_LF(name[head_len]))
{
opcode = AT_OP_EXECUTE;
}
else if(CH_QUR == name[head_len])
{
opcode = AT_OP_QUERY;
}
else if((CH_SET == name[head_len])
&& (CH_QUR == name[head_len + 1]))
{
opcode = AT_OP_TEST;
}
else if(CH_SET == name[head_len])
{
opcode = AT_OP_SET;
}
else
{
opcode = AT_OP_INVALID;
}
return opcode;
}
/*
e.g.:
AT+EXAMPLE_PING="192.168.1.1,800",128,4,10
IP = 192.168.1.1
PORT = 800
SIZE = 128
TIMEOUT = 4
TIMES = 10
return:
argc = 4
argv[]:
argv[0] = "192.168.1.1,800"
argv[1] = 128
argv[2] = 4
argv[3] = 10
argv[n] has type of string.
*/
uint32_t at_command_argument_process
(uint8_t *cmd_str, uint32_t len, uint8_t *argv[])
{
uint8_t *p_search, *p_standalone = cmd_str + len;
uint32_t argc = 0, in_quotes = 0, i;
p_search = cmd_str;
/* Search the real tail of command string. */
while((!CR_OR_LF(*p_search)) && (p_search < p_standalone)) p_search++;
if(p_search == p_standalone)
{
return argc;
}
p_standalone = p_search;
/* Make the tail as EOS. */
*p_standalone = CH_EOS;
p_search = cmd_str;
/* Searching the 1st argments, start with '=' or '?' */
while(p_search < p_standalone)
{
if((CH_QUR == *p_search) || (CH_SET == *p_search))
{
break;
}
p_search++;
}
/* Check "?=" */
if((CH_QUR == *p_search) && (CH_SET == *(p_search + 1)))
{
p_search++;
}
if(p_search >= p_standalone)
{
return argc;
}
argv[argc++] = ++p_search;
/* Searching the following argments, start with ',' */
do
{
if('"' == *p_search)
{
in_quotes = !in_quotes;
}
if(!in_quotes)
{
if(CH_SPL == *p_search)
{
if(argc > AT_MAX_ARGC)
{
break;
}
/* Set ',' as EOS. */
*p_search = CH_EOS;
if(p_search + 1 < p_standalone)
{
argv[argc++] = p_search + 1;
}
}
}
}while(++p_search < p_standalone);
/* Remove pre- & post- white space chars. */
for(i = 0; i < argc; i++)
{
p_search = argv[i];
/* Remove pre-chars those are white-space. */
while(CH_EOS != (*p_search) && ISSPACE(*p_search)) p_search++;
argv[i] = p_search;
/* Remove post-chars those are white-space. */
p_standalone = p_search;
while(CH_EOS != *p_standalone) p_standalone++;
/* More than 2 chars, one is EOS and the other is p_search. */
if(p_standalone > p_search + 1)
{
/* One char back. */
p_standalone--;
while((p_standalone > p_search) && ISSPACE(*p_standalone))
{
p_standalone--;
}
*(++p_standalone) = CH_EOS;
}
}
/* More than one white space char may case one arg exits. */
if((1 == argc) && (CH_EOS == *argv[0]))
{
argc = 0;
}
return argc;
}
void at_command_cmd_message_handle(iot_pkt_t *p_str_pkt, uint16_t source)
{
at_cmd_t *p_at_cmd;
uint8_t *p_cmd_name, *argv[AT_MAX_ARGC];
uint32_t cmd_name_len, opcode, argc;
at_status_t *p_status = &(at_command_context.status);
(void)source;
if(NULL == p_str_pkt)
{
DERROR("Message data is NULL.");
return;
}
p_cmd_name = iot_pkt_data(p_str_pkt);
cmd_name_len = iot_pkt_data_len(p_str_pkt);
p_at_cmd = at_command_get_cmd_handle_by_name
(p_cmd_name, (uint16_t)cmd_name_len);
opcode = at_command_get_opcode(p_cmd_name, (uint16_t)cmd_name_len);
/* Check command table again. */
if((NULL == p_at_cmd)
|| (AT_OP_INVALID == opcode))
{
DERROR("Invalid command string : %2.64s.", p_cmd_name);
at_command_at_response_to_proto
(AT_RESP_UNKNOWN_CMD, p_cmd_name, cmd_name_len, 1);
return;
}
DINFOR("Command:%s, opcode:%d.", *(p_at_cmd->name), opcode);
at_sem_lock();
p_status->cur_cmd = p_at_cmd;
p_status->resp_index = 0;
p_status->resp_total = 0;
p_status->resp_finished = 0;
p_status->handle_runout = 0;
at_sem_release();
argc = at_command_argument_process
(p_cmd_name + p_at_cmd->head_len, cmd_name_len - p_at_cmd->head_len,
argv);
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
/* Just for debug. */
for(cmd_name_len = 0; cmd_name_len < argc; cmd_name_len++)
{
DINFOR("argv(%d):%s", cmd_name_len, argv[cmd_name_len]);
}
#endif
p_at_cmd->fn_send(opcode, argc, argv);
at_sem_lock();
p_status->handle_runout = 1;
at_sem_release();
if((0 != p_at_cmd->timeout)
&& (!p_status->resp_finished))
{
os_start_timer(at_command_context.tmr, p_at_cmd->timeout * 1000);
}
return;
}
void at_command_resp_message_handle(iot_pkt_t *p_resp_pkt, uint16_t source)
{
uint32_t cid;
at_cmd_t *p_at_cmd;
if(AT_MSG_SOURCE_PLCTXRX == source)
{
cid = at_command_cid_convert_from_plc(p_resp_pkt);
}
else
{
DERROR("Unknown message source %d.", source);
return;
}
p_at_cmd = at_command_get_cmd_handle_by_cid(cid);
if(NULL == p_at_cmd)
{
DERROR("Invalid AT cid %d.", cid);
return;
}
if(NULL != p_at_cmd->fn_resp)
{
p_at_cmd->fn_resp(p_resp_pkt);
}
else
{
DERROR("No response handle for cid %d.", cid);
}
return;
}
void at_command_timeout_message_handle(void)
{
at_command_at_response_to_proto(AT_RESP_WAIT_RESP_TIMEOUT, NULL, 0, 1);
at_sem_lock();
at_command_context.status.resp_finished = 1;
at_sem_release();
}
void at_command_message_handle(iot_task_h task_h, iot_task_msg_t *msg)
{
at_msg_t *dm_msg = (at_msg_t *)msg;
DINFOR("Message type=%d, id=%d.", dm_msg->msg.type, dm_msg->msg.id);
if(AT_MSG_TYPE_COMMAND == MSG_TYPE(dm_msg->msg.type))
{
at_command_cmd_message_handle(dm_msg->data, MSG_SRC(dm_msg->msg.type));
if(NULL != dm_msg->data)
{
iot_pkt_free(dm_msg->data);
}
}
else if(AT_MSG_TYPE_RESPONSE == MSG_TYPE(dm_msg->msg.type))
{
at_command_resp_message_handle(dm_msg->data, MSG_SRC(dm_msg->msg.type));
if(NULL != dm_msg->data)
{
iot_pkt_free(dm_msg->data);
}
}
else if(AT_MSG_TYPE_TIMEOUT == MSG_TYPE(dm_msg->msg.type))
{
at_command_timeout_message_handle();
}
else
{
if(NULL != dm_msg->data)
{
iot_pkt_free(dm_msg->data);
}
DERROR("Invalid message type %d.", dm_msg->msg.type);
}
iot_task_free_msg(task_h, &(dm_msg->msg));
return;
}
void at_command_message_cancel(iot_task_h task_h, iot_task_msg_t *msg)
{
at_msg_t *dm_msg = (at_msg_t *)msg;
(void)task_h;
if(NULL == dm_msg)
{
DERROR("Null message !!");
return;
}
switch(dm_msg->msg.id)
{
case PLCTXRX_CID_SEND:
{
if(AT_MSG_SOURCE_PLCTXRX == MSG_SRC(dm_msg->msg.type))
{
at_handle_response_send_receive(dm_msg->data);
}
break;
}
default:
{
break;
}
}
iot_pkt_free(dm_msg->data);
iot_task_free_msg(task_h, &(dm_msg->msg));
return;
}
void at_command_event_handle(iot_task_h task_h, uint32_t event)
{
(void)task_h;
(void)event;
/* No event implements yet. */
return;
}
void at_command_post_message(uint16_t m_type, uint16_t m_id, iot_pkt_t *data)
{
at_msg_t *task_msg;
task_msg = (at_msg_t*)iot_task_alloc_msg_with_reserved
(at_command_context.task, 0);
if(NULL == task_msg)
{
if(NULL != data)
{
iot_pkt_free(data);
}
DERROR("Alloc message failed !!");
return;
}
task_msg->msg.type = m_type;
task_msg->msg.id = m_id;
task_msg->data = data;
iot_task_queue_msg(at_command_context.task, &task_msg->msg, 0);
return;
}
/* return 1 : found a completed AT command, 0 : AT command not completed yet */
uint32_t at_command_at_buffer_hook(uint8_t* buffer, uint16_t buffer_len)
{
uint16_t index, len = buffer_len;
at_buf_t *buf = &(at_command_context.at_buffer);
iot_pkt_t *p_pkt;
uint8_t *rsp_data;
uint32_t rsp_data_len;
if((buffer_len < 3)
&& (('\r' == buffer[0]) || ('\n' == buffer[0]))
&& (buf->cmd_flushed))
{
/* Loop this command. */
return 1;
}
if(buf->cmd_flushed)
{
buf->cmd_flushed = 0;
buf->index = 0;
}
for(index = 0; index < buffer_len; index++)
{
if (buffer[index] > 127)
{
DERROR("Input invisible character, ASCII:%d.", buffer[index]);
at_command_at_response_to_proto(AT_RESP_UNKNOWN_CMD,
NULL, 0, true);
return 0;
}
if(('\r' == buffer[index])
||('\n' == buffer[index]))
{
len = index + 1;
break;
}
}
if(buf->index + len > AT_HOOK_BUFFER_LEN)
{
/* Drop this command. */
buf->index = 0;
DERROR("Command string overlength.");
return 0;
}
os_mem_cpy(buf->c + buf->index, buffer, len);
buf->index += len;
if(index < buffer_len)
{
buf->cmd_flushed = 1;
buf->c[buf->index] = CH_EOS;
DINFOR("Completed command:%s", buf->c);
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_LARGE_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return 1;
}
rsp_data = iot_pkt_data(p_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\n%s", buf->c);
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
rsp_data, rsp_data_len, true);
iot_pkt_free(p_pkt);
return 1;
}
DINFOR("Incompleted command.");
return 0;
}
void at_command_at_response_to_proto
(uint32_t resp, uint8_t* buf, uint32_t blen, uint16_t resp_finished)
{
at_status_t *p_status = &(at_command_context.status);
char *p_resp_str;
uint32_t ret_pkt_len;
iot_pkt_t *p_resp_pkt;
uint8_t *p_pkt_buf;
if(((!resp_finished) && ((NULL == buf) || (0 == blen)))
|| (NULL == at_command_context.fn_callback.fn_resp))
{
DINFOR("Nothing to response.");
return;
}
switch(resp)
{
case AT_RESP_OK:
{
p_resp_str = AT_RESP_STR_OK;
break;
}
case AT_RESP_BUSY:
{
p_resp_str = AT_RESP_STR_BUSY;
break;
}
case AT_RESP_UNKNOWN_CMD:
{
p_resp_str = AT_RESP_STR_UNKNOWN;
break;
}
case AT_RESP_INVALID_ARGUMENT:
{
p_resp_str = AT_RESP_STR_INVALID_ARG;
break;
}
case AT_RESP_WAIT_RESP_TIMEOUT:
{
p_resp_str = AT_RESP_STR_TIMEOUT;
break;
}
case AT_RESP_SET_FINISH_WITHOUT_ECHO:
{
/* We just set finish-flag if NOT_REPORT */
if(resp_finished)
{
at_sem_lock();
p_status->resp_finished = resp_finished;
at_sem_release();
}
DINFOR("AT response nothing.");
return;
}
case AT_RESP_FORCE_ECHO:
case AT_RESP_ERROR:
default:
{
p_resp_str = AT_RESP_STR_ERROR;
break;
}
}
ret_pkt_len = iot_strlen(p_resp_str) + AT_HOOK_BUFFER_LEN + blen;
if(NULL == (p_resp_pkt = iot_pkt_alloc(ret_pkt_len, AT_COMMAND_MID)))
{
DERROR("Cannot get packet len#%d!!", ret_pkt_len);
return;
}
p_pkt_buf = iot_pkt_data(p_resp_pkt);
ret_pkt_len = 0;
if((blen > 0) && (NULL != buf))
{
os_mem_cpy(p_pkt_buf, buf, blen);
ret_pkt_len += blen;
p_pkt_buf += blen;
}
if((AT_RESP_BUSY != resp)
&& (AT_RESP_FORCE_ECHO != resp))
{
if (os_is_timer_active(at_command_context.tmr))
{
os_stop_timer(at_command_context.tmr);
iot_task_clean_msg(at_command_context.task,
AT_MSG_TYPE_TIMEOUT | AT_MSG_SOURCE_LOCAL, 0);
}
if(!resp_finished)
{
if (NULL == p_status->cur_cmd) {
DERROR("p_status's field:cur_cmd is NULL");
} else {
os_start_timer
(at_command_context.tmr, p_status->cur_cmd->timeout * 1000);
}
}
}
if(resp_finished)
{
if(AT_RESP_FORCE_ECHO != resp)
{
if((NULL != p_status->cur_cmd)
&& (NULL != *(p_status->cur_cmd->name)))
{
ret_pkt_len += iot_sprintf((char *)p_pkt_buf, p_resp_str,
*(p_status->cur_cmd->name));
}
else
{
ret_pkt_len += iot_sprintf((char *)p_pkt_buf, p_resp_str, "N/A");
}
}
at_sem_lock();
p_status->resp_finished = resp_finished;
at_sem_release();
}
DINFOR("AT response datalen=%d, string=%s.", ret_pkt_len, p_pkt_buf);
iot_pkt_put(p_resp_pkt, ret_pkt_len);
at_command_context.fn_callback.fn_resp(p_resp_pkt);
return;
}
void at_command_timer_func(timer_id_t timer_id, void * arg)
{
(void)timer_id;
(void)arg;
at_command_post_message(AT_MSG_TYPE_TIMEOUT | AT_MSG_SOURCE_LOCAL, 0, NULL);
return;
}
void at_command_end_pmode_timer_func(timer_id_t timer_id, void * arg)
{
(void)timer_id;
(void)arg;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
uint8_t *p_data;
uint32_t data_len;
iot_pkt_t *p_pkt;
DINFOR("end_pmode time out");
/* clean transpmode if not recv data after set end_pmode_timer */
if (recv_blen == 0) {
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
at_command_context.transp.transpmode = false;
os_mem_set(at_command_context.transp.trans_addr, 0, IOT_MAC_ADDR_LEN);
data_len = iot_sprintf((char *)p_data,
"data recv from UART will be transparent as command\n");
p_flash->transp.transpmode = false;
/* Write flash. */
if (ERR_OK == at_command_uniform_flashsave(p_flash)){
DINFOR("Whitelist save to flash successfully!");
} else {
DERROR("Whitelist save to flash failed!");
}
/* Just finish transpmode with response. */
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
p_data, data_len, true);
iot_pkt_free(p_pkt);
}
return;
}
int at_command_char_2_digtal(char ch)
{
int ch_ret = -1;
if('0' <= ch && '9' >= ch)
{
ch_ret = (((int)ch) & 0xFF) - '0';
}
else if('a' <= ch && 'z' >= ch)
{
ch_ret = (((int)ch) & 0xFF) - 'a' + 0xA;
}
else if('A' <= ch && 'Z' >= ch)
{
ch_ret = (((int)ch) & 0xFF) - 'A' + 0xA;
}
return ch_ret;
}
uint32_t at_command_uint32_2_digtal(uint8_t *string_ptr, uint32_t *output_ptr)
{
uint32_t temp_output;
uint8_t *input_ptr;
uint32_t result = 0;
int ret_ch;
input_ptr = string_ptr;
temp_output = 0;
if ((NULL == input_ptr) || (NULL == input_ptr))
{
return result;
}
/* Find the 1st valid char. */
while(*input_ptr != CH_EOS)
{
ret_ch = at_command_char_2_digtal(*input_ptr);
if(((0 <= ret_ch) && (9 >= ret_ch)))
{
break;
}
input_ptr++;
}
while(true)
{
ret_ch = at_command_char_2_digtal(*input_ptr);
if(((0 > ret_ch) || (9 < ret_ch)))
{
break;
}
if(temp_output <= 429496729)
{
if(temp_output == 429496729)
{
if(ret_ch > 5)
{
break;
}
}
temp_output = temp_output * 10 + ret_ch;
input_ptr++;
result++;
}
else
{
break;
}
}
*output_ptr = temp_output;
return result;
}
/*
if
p_hex_string = "0xefef77K8" or "efef77K8"
then
p_hex_out = 0xefef77
return 6
if
*/
uint32_t at_command_hex_2_digtal(uint8_t *p_hex_string, uint32_t *p_hex_out)
{
uint8_t *p_ch = p_hex_string;
uint32_t chars_in_32bit = 0, value = 0;
int ret_ch;
if((NULL == p_hex_string)
|| (NULL == p_hex_out))
{
return 0;
}
/* Find the 1st valid char. */
while((at_command_char_2_digtal(*p_ch) < 0) && ('\0' != *p_ch)) p_ch++;
/* Check "0x" or "0X". */
if(('0' == *p_ch) && (('x' == *(p_ch + 1)) || ('X' == *(p_ch + 1))))
{
p_ch += 2;
}
while((chars_in_32bit < 8) && '\0' != *p_ch)
{
ret_ch = at_command_char_2_digtal(*p_ch);
/* Exit if a invalid char meets. */
if(ret_ch < 0)
{
break;
}
value = (value << 4) | (ret_ch & 0xF);
p_ch++;
chars_in_32bit++;
}
*p_hex_out = value;
return chars_in_32bit;
}
/*
' ' , ':' and '-' will be regard as split-chars.
if
p_hex_in = "Fe-77:99999 ae-f 55 aa bb"
bytes_2_get = 6
then
byte_out[] = {0xfe, 0x77, 0x99, 0xae, 0xf, 0x55}
return 6
fi
*/
uint32_t at_command_string_2_digtal
(uint8_t *p_hex_in, uint8_t bytes_out[], uint32_t bytes_2_get)
{
uint32_t bytes_valid = 0;
uint8_t *p_ch = p_hex_in, byte;
int ret_ch;
if((NULL == p_hex_in)
||(NULL == bytes_out)
||(0 >= bytes_2_get))
{
/* Nothing to output. */
return 0;
}
/* Find the 1st valid char. */
while((at_command_char_2_digtal(*p_ch) < 0) && ('\0' != *p_ch)) p_ch++;
/* Get digtal bytes start. */
while((bytes_valid < bytes_2_get) && ('\0' != *p_ch))
{
if((ret_ch = at_command_char_2_digtal(*p_ch)) >= 0)
{
p_ch++;
byte = (uint8_t)(ret_ch & 0xF);
if((ret_ch = at_command_char_2_digtal(*p_ch)) >= 0)
{
p_ch++;
byte = (uint8_t)((byte << 4) | (ret_ch & 0xF));
}
bytes_out[bytes_valid++] = byte;
}
else if(!CH_IS_SPLIT(*p_ch))
{
/* Stop if there is char that is not digtal or split. */
break;
}
/* Skip the rest of valid chars. */
while((at_command_char_2_digtal(*p_ch) >= 0) && ('\0' != *p_ch)) p_ch++;
/* Skip the split chars if there is more than one. */
while(CH_IS_SPLIT(*p_ch) && ('\0' != *p_ch)) p_ch++;
}
return bytes_valid;
}
void at_command_send_to_plc(iot_pkt_t *p_pkt)
{
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
plctxrx_cmd_arg_t *p_arg;
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_data(p_pkt);
#endif
if(!at_is_firedup())
{
DERROR("AT module not ready.");
return;
}
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
DINFOR("Command to PLC : CID#0x%x, OPCODE#0x%x.", p_arg->cid.cid,
p_arg->cid.opcode);
#endif
at_command_context.fn_callback.fn_send(p_pkt);
return;
}
uint8_t iot_at_command_proto_send_to_at(uint8_t *buf, uint16_t blen)
{
iot_pkt_t *p_cmd_pkt;
uint8_t *p_cmd_str;
uint16_t cmd_str_len;
at_cmd_t *p_at_cmd;
if(!at_is_firedup())
{
DERROR("AT module not ready.");
return ERR_FAIL;
}
if (at_command_context.transp.transpmode) {
//check TRANSPARENT_KEYWORDS
recv_blen += blen;
if (blen == TRANSPARENT_KEYWORDS_LEN &&
0 == os_mem_cmp((char*)buf, TRANSPARENT_KEYWORDS, blen)) {
/* start end transparent timer */
DINFOR("recv end transpmode string");
if (os_is_timer_active(at_command_context.end_tmode_tmr)) {
os_stop_timer(at_command_context.end_tmode_tmr);
iot_task_clean_msg(at_command_context.task,
AT_MSG_TYPE_TIMEOUT | AT_MSG_SOURCE_LOCAL, 0);
}
os_start_timer(at_command_context.end_tmode_tmr,
AT_TMR_CHECK_END_PMODE);
recv_blen = 0;
return ERR_OK;
}
if (ERR_NOMEM == at_handle_transparent_data(buf, blen)) {
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
} else {
at_command_at_response_to_proto(AT_RESP_SET_FINISH_WITHOUT_ECHO,
NULL, 0, true);
}
return ERR_OK;
}
if(!at_command_at_buffer_hook(buf, blen))
{
return ERR_OK;
}
if(at_command_status_is_busy())
{
DERROR("AT module BUSY.");
at_command_at_response_to_proto(AT_RESP_BUSY, NULL, 0, false);
return ERR_FAIL;
}
p_cmd_str = at_command_context.at_buffer.c;
cmd_str_len = at_command_context.at_buffer.index;
p_at_cmd = at_command_get_cmd_handle_by_name(p_cmd_str, cmd_str_len);
if(NULL == p_at_cmd)
{
DERROR("Cannot find:%s.", p_cmd_str);
at_command_at_response_to_proto
(AT_RESP_UNKNOWN_CMD, p_cmd_str, cmd_str_len, true);
return ERR_OK;
}
at_sem_lock();
/*
Fill current executing command to announce AT has command to executing now.
*/
at_command_context.status.cur_cmd = p_at_cmd;
at_sem_release();
if(NULL == (p_cmd_pkt = iot_pkt_alloc(cmd_str_len, AT_COMMAND_MID)))
{
DERROR("Cannot get packet length=%d.", cmd_str_len);
return ERR_FAIL;
}
os_mem_cpy(iot_pkt_put(p_cmd_pkt, cmd_str_len), p_cmd_str, cmd_str_len);
at_command_post_message(AT_MSG_TYPE_COMMAND | AT_MSG_SOURCE_UART,
0, p_cmd_pkt);
return ERR_OK;
}
uint8_t iot_at_command_plc_send_response_to_at(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
uint16_t index, total;
at_status_t *p_status = &(at_command_context.status);
if(NULL == p_resp_pkt)
{
return ERR_FAIL;
}
if(!at_is_firedup())
{
DERROR("AT module not ready.");
iot_pkt_free(p_resp_pkt);
return ERR_FAIL;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
index = p_resp->index.current;
total = p_resp->index.total;
/* Post before update status. */
at_command_post_message(AT_MSG_TYPE_RESPONSE | AT_MSG_SOURCE_PLCTXRX,
p_resp->cid.cid, p_resp_pkt);
at_sem_lock();
/* Do not care about lost response frames. */
p_status->resp_index = index;
p_status->resp_total = total;
at_sem_release();
DINFOR("Response from PLC : CID#0x%x, OPCODE#0x%x, INDEX#%d/%d.",
p_resp->cid.cid, p_resp->cid.opcode, p_resp->index.current,
p_resp->index.total);
return ERR_OK;
}
uint8_t iot_at_command_fn_register_response_to_uart(at_fn_response_from_at_t fn)
{
if(!at_is_firedup())
{
DERROR("AT module not ready.");
return ERR_FAIL;
}
at_command_context.fn_callback.fn_resp = fn;
return ERR_OK;
}
uint8_t iot_at_command_fn_register_send_to_plc(at_fn_send_from_at_t fn)
{
if(!at_is_firedup())
{
DERROR("AT module not ready.");
return ERR_FAIL;
}
at_command_context.fn_callback.fn_send = fn;
at_command_uniform_flashinfo_init();
return ERR_OK;
}
void iot_at_task_deinit(void)
{
if(NULL != at_command_context.task)
{
iot_task_delete(at_command_context.task);
at_command_context.task = NULL;
}
if(0 != at_command_context.tmr)
{
os_delete_timer(at_command_context.tmr);
at_command_context.tmr = 0;
}
if(NULL != at_command_context.sem)
{
os_delete_mutex(at_command_context.sem);
at_command_context.sem = NULL;
}
os_mem_set(&at_command_context, 0x0, sizeof(at_command_context));
return;
}
void iot_print_config(bool_t enable);
iot_task_h iot_at_task_init(void)
{
iot_task_config_t t_cfg;
int cmd_index;
at_cmd_t *p_cmd;
at_command_uart_cfg.port = iot_board_get_uart(UART_CUS_PORT_0);
if(at_is_firedup())
{
DERROR("AT command module already initialized.");
return at_command_context.task;
}
DINFOR("AT command module initializing...");
os_mem_set(&at_command_context, 0x0, sizeof(at_command_context));
p_cmd = &(at_command_context.at_table[0]);
for(cmd_index = 0; cmd_index < AT_CID_MAX; cmd_index++)
{
p_cmd->head_len = (uint8_t)iot_strlen
(*(at_command_table[cmd_index].name));
p_cmd->name = at_command_table[cmd_index].name;
p_cmd->prio = at_command_table[cmd_index].prio;
p_cmd->timeout = at_command_table[cmd_index].timeout;
p_cmd->fn_send = at_command_table[cmd_index].fn_send;
p_cmd->fn_resp = at_command_table[cmd_index].fn_resp;
DINFOR("Command Add-\r\nname:%s\r\nHead len:%d\r\nPriority:%d\r\n"\
"Timeout:%d\r\nfn_send:0x%08x\r\nfn_resp:0x%08x",
*(p_cmd->name), p_cmd->head_len, p_cmd->prio, p_cmd->timeout,
p_cmd->fn_send, p_cmd->fn_resp);
p_cmd++;
}
t_cfg.stack_size = 0;
t_cfg.task_prio = AT_PRIO_NOR;
t_cfg.msg_size = sizeof(at_msg_t);
t_cfg.msg_cnt = AT_TASK_MSG_CNT;
t_cfg.queue_cnt = 1;
t_cfg.queue_cfg[0].quota = 0;
t_cfg.task_event_func = at_command_event_handle;
t_cfg.msg_exe_func = at_command_message_handle;
t_cfg.msg_cancel_func = at_command_message_cancel;
at_command_context.task = iot_task_create(AT_COMMAND_MID, &t_cfg);
if(NULL == at_command_context.task)
{
DERROR("Create task failed.");
goto init_err_handle;
}
at_command_context.tmr = os_create_timer
(AT_COMMAND_MID, 0, at_command_timer_func, 0);
if(0 == at_command_context.tmr)
{
DERROR("Create timer failed.");
goto init_err_handle;
}
at_command_context.end_tmode_tmr = os_create_timer(AT_COMMAND_MID, 0,
at_command_end_pmode_timer_func, 0);
if (0 == at_command_context.end_tmode_tmr) {
DERROR("Create end_tmode_tmr timer failed.");
goto init_err_handle;
}
at_command_context.sem = os_create_mutex(AT_COMMAND_MID);
if(NULL == at_command_context.sem)
{
DERROR("Create semaphore failed.");
goto init_err_handle;
}
#if PLC_SUPPORT_CCO_ROLE
at_command_context.dev_type = IOT_PLC_DEV_ROLE_CCO;
#else
at_command_context.dev_type = IOT_PLC_DEV_ROLE_STA;
#endif
at_fire_now();
DINFOR("AT command module initailized seccussfully!");
return at_command_context.task;
init_err_handle:
iot_at_task_deinit();
DINFOR("AT command module initailized failed!");
return NULL;
}
at_context_t *iot_at_context_get(void)
{
if(!at_is_firedup())
{
DERROR("AT module not ready.");
return NULL;
}
return &at_command_context;
}
void at_handle_command_help(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
(void)opcode;
(void)argc;
(void)argv;
uint32_t i, send_len = 0;
iot_pkt_t *p_pkt;
uint8_t *r_data;
if (NULL == (p_pkt = iot_pkt_alloc(AT_LARGE_BUF_SIZE, AT_COMMAND_MID))) {
DERROR("alloc memory ERR!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0 , 1);
return;
}
r_data = iot_pkt_data(p_pkt);
for (i = 0; i < AT_CID_MAX; i++) {
send_len += iot_sprintf((char*)r_data + send_len, "\r\n%03d:%s",
(int)i, *(at_command_context.at_table[i].name));
if (0 == (i + 1) % AT_LIST_ITEMS_PER_COMMAND ||
(i+1) == AT_CID_MAX) {
at_command_at_response_to_proto(AT_RESP_OK, r_data, send_len,
((i+1) == AT_CID_MAX) ? 1 : 0);
send_len = 0;
}
}
iot_pkt_free(p_pkt);
return;
}
void at_handle_command_mac(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_MAC);
uint8_t mac[IOT_MAC_ADDR_LEN];
plctxrx_handle_mac_t *p_mac_hd;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
uint8_t *rsp_data;
uint32_t rsp_data_len;
if(((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
||((AT_OP_SET == opcode) && ((argc != 1)
||(IOT_MAC_ADDR_LEN != at_command_string_2_digtal
(argv[0], mac, IOT_MAC_ADDR_LEN)))))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if (AT_OP_SET == opcode)
{
/* Check input MAC address is same with MAC address saved in flash. */
if (1 == iot_mac_addr_cmp(p_flash->local_mac, mac))
{
DINFOR("Set the same mac!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
return;
}
/* Update the AT layer local MAC address. */
iot_mac_addr_cpy(at_command_context.mac, mac);
pkt_len = sizeof(*p_arg) + sizeof(*p_mac_hd);
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_MAC;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = p_cmd_line->prio;
p_arg->dlen = sizeof(*p_mac_hd);
p_arg->need_ack = true;
p_mac_hd = (plctxrx_handle_mac_t *)p_arg->arg;
iot_mac_addr_cpy(p_mac_hd->mac, at_command_context.mac);
p_mac_hd->dev_type = p_flash->local_type;
at_command_send_to_plc(p_pkt);
}
else
{
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nThe device MAC address is:[%02X:%02X:%02X:%02X:%02X:%02X]." \
"\r\nThe device module type is %d.",
p_flash->local_mac[0], p_flash->local_mac[1],
p_flash->local_mac[2], p_flash->local_mac[3],
p_flash->local_mac[4], p_flash->local_mac[5],
p_flash->local_type);
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
iot_pkt_free(p_pkt);
}
return;
}
void at_handle_response_mac(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
iot_pkt_t *p_pkt;
uint8_t *p_data;
uint32_t data_len, ret;
uint32_t pkt_len;
plctxrx_cmd_arg_t *p_arg;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_MAC);
plctxrx_handle_mac_t *p_mac_hd;
iot_oem_base_cfg_t *oem_base_cfg;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
if(NULL == p_resp_pkt)
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
if (PLCTXRX_OP_CFM == p_resp->cid.opcode)
{
/* Update MAC address saved in flash. */
iot_mac_addr_cpy(p_flash->local_mac, at_command_context.mac);
if(ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Local MAC address save to flash failed!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data,
"\r\nSet the device MAC address %s!",
(PLCTXRX_RESP_OK != p_resp->resp) ? "failed" : "successfully");
ret = (PLCTXRX_RESP_OK == p_resp->resp) ? AT_RESP_OK : AT_RESP_ERROR;
at_command_at_response_to_proto(ret, p_data, data_len, true);
/* CCO or STA will enable whitelist if whitelist not empty when power on. */
if (p_flash->dev_cnt > 0)
{
/* Add/Delete whitelist to/from CVG layer.*/
at_command_cvg_wl_add_del(AT_WL_ACTION_ADD, NULL, false);
os_delay(AT_WL_OP_DELAY_MS);
at_command_cvg_wl_en_disable(AT_WL_ACTION_ENABLE, false);
/* Update the whitelist config enable/disable state. */
at_command_context.wl_cfg_state = AT_WL_CFG_STATE_ENABLE;
}
if (at_command_context.transp.transpmode) {
if (iot_mac_addr_cmp(at_command_context.transp.trans_addr,
IOT_AT_BROADCAST_MAC_6BYTES)) {
data_len = iot_sprintf((char *)p_data,"data received from UART"
" will be transparent transmitted as broadcast\n");
} else {
data_len = iot_sprintf((char *)p_data,"data received from UART"
" will be transparent transmitted to "
"%02X:%02X:%02X:%02X:%02X:%02X\n",
at_command_context.transp.trans_addr[0],
at_command_context.transp.trans_addr[1],
at_command_context.transp.trans_addr[2],
at_command_context.transp.trans_addr[3],
at_command_context.transp.trans_addr[4],
at_command_context.transp.trans_addr[5]);
}
DERROR("%s",p_data);
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
p_data, data_len, true);
}
iot_pkt_free(p_pkt);
}
else if (PLCTXRX_OP_INDICATION == p_resp->cid.opcode)
{
/* Get MAC address from flash firstly, need check the MAC address validity. */
if (mac_addr_in_flash_is_valid_addr(p_flash->local_mac))
{
DINFOR("Flash's MAC address valid!");
/* Update the AT layer local MAC address. */
iot_mac_addr_cpy(at_command_context.mac, p_flash->local_mac);
}
else
{
/* If flash's MAC address invalid, get MAC address from OEM secondly. */
(void)iot_oem_get_base_cfg(&oem_base_cfg);
/* Check the MAC address validity. */
if (!mac_addr_in_flash_is_valid_addr(oem_base_cfg->module_mac))
{
DERROR("OEM's MAC address invalid!");
return;
}
/* Update the AT layer local MAC address. */
iot_mac_addr_cpy(at_command_context.mac, oem_base_cfg->module_mac);
}
pkt_len = sizeof(*p_arg) + sizeof(*p_mac_hd);
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_MAC;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = p_cmd_line->prio;
p_arg->dlen = sizeof(*p_mac_hd);
p_arg->need_ack = true;
p_mac_hd = (plctxrx_handle_mac_t *)p_arg->arg;
iot_mac_addr_cpy(p_mac_hd->mac, at_command_context.mac);
p_mac_hd->dev_type = p_flash->local_type;
at_command_send_to_plc(p_pkt);
}
return;
}
void at_handle_command_time(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
(void)opcode;
(void)argc;
(void)argv;
}
void at_handle_response_time(iot_pkt_t *p_resp_pkt)
{
(void)p_resp_pkt;
}
void at_handle_command_systeminfo
(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_arg_pkt;
plctxrx_cmd_arg_t *p_arg;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_SYSTEMINFO);
(void)argv;
(void)argc;
(void)opcode;
if(NULL == (p_arg_pkt = iot_pkt_alloc(sizeof(*p_arg), AT_COMMAND_MID)))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, 1);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_arg_pkt, sizeof(*p_arg));
p_arg->cid.opcode = PLCTXRX_OP_QUERY;
p_arg->cid.cid = PLCTXRX_CID_SYSTEMINFO;
p_arg->prio = p_cmd_line->prio;
p_arg->dlen = 0;
p_arg->need_ack = true;
at_command_send_to_plc(p_arg_pkt);
return;
}
void at_handle_response_systeminfo(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
plctxrx_cmd_systeminfo_t *p_sysinfo;
iot_pkt_t *p_finally_resp_pkt;
uint32_t pkt_len, version, cpu_u, ram_u;
uint8_t *buf;
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
p_sysinfo = (plctxrx_cmd_systeminfo_t *)p_resp->data;
if(PLCTXRX_RESP_OK != p_resp->resp)
{
goto ERROR_HANDLE;
}
p_finally_resp_pkt = iot_pkt_alloc(256, AT_COMMAND_MID);
if(NULL == p_finally_resp_pkt)
{
goto ERROR_HANDLE;
}
version = iot_version_hex();
cpu_u = os_get_cpu_utilization();
ram_u = os_get_mem_utilization();
buf = iot_pkt_data(p_finally_resp_pkt);
pkt_len = iot_sprintf((char *)buf,
"\r\nLast reboot reason:%d." \
"\r\nTotal reboot times:%d." \
"\r\nNetwork running time:%d."\
"\r\nAT module version:%s."\
"\r\nFireware version:%d.%d.%d.build-%d."\
"\r\nCPU utilization:%d%%."\
"\r\nRAM utilization:%d%%.",
(int)p_sysinfo->last_reboot_reason,
(int)p_sysinfo->total_reboot_times,
(int)p_sysinfo->os_running_time,
IOT_AT_MODULE_VERSION,
(version >> 27) & 0x1F, (version >> 20) & 0x7F,
(version >> 16) & 0xF, version & 0xFFFF,
cpu_u, ram_u);
at_command_at_response_to_proto(AT_RESP_OK, buf, pkt_len, 1);
iot_pkt_free(p_finally_resp_pkt);
return;
ERROR_HANDLE:
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, 1);
DERROR("AT sysinfor response error.");
return;
}
void at_handle_command_uart(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_handle_uart_t *p_uart;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_UART);
/*
the uart data length value range: <5-8>.
the uart stop bit value range: 1 -> 1 bits, 2 -> 1.5 bits, 3 -> 2 bits.
the uart parity value range: 0 -> none, 1 -> odd, 2 -> even.
*/
uint32_t bandrate = 0, uart_data_len = 0, stop_bit = 0;
uint32_t parity = IOT_UART_PARITY_EVEN + 1;
uint8_t i;
char *stop_bit_symbol[3] = {"1", "1.5", "2"};
uint8_t stop_bit_options[3] = {
IOT_UART_STOP_1_BITS,
IOT_UART_STOP_1_5_BITS,
IOT_UART_STOP_2_BITS
};
char *parity_symbol[3] = {"N", "O", "E"};
uint8_t parity_options[3] = {
IOT_UART_PARITY_NONE,
IOT_UART_PARITY_ODD,
IOT_UART_PARITY_EVEN
};
uint8_t *rsp_data;
uint32_t rsp_data_len;
if(AT_OP_SET == opcode)
{
if ((argc < 4)
|| (at_command_uint32_2_digtal(argv[0], &bandrate) <= 0)
|| (at_command_uint32_2_digtal(argv[1], &uart_data_len) <= 0))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
for (i = 0; i < 3; i++)
{
if (!iot_strcmp((char *)argv[2], stop_bit_symbol[i]))
{
stop_bit = stop_bit_options[i];
}
}
for (i = 0; i < 3; i++)
{
if (!iot_strcmp((char *)argv[3], parity_symbol[i]))
{
parity = parity_options[i];
}
}
if ((uart_data_len > IOT_UART_DLEN_8_BITS)
|| (uart_data_len < IOT_UART_DLEN_5_BITS)
|| (stop_bit > IOT_UART_STOP_2_BITS)
|| (stop_bit < IOT_UART_STOP_1_BITS)
|| (parity > IOT_UART_PARITY_EVEN)
|| (parity < IOT_UART_PARITY_NONE))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
pkt_len = sizeof(*p_arg) + sizeof(*p_uart);
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_UART;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = p_cmd_line->prio;
p_arg->need_ack = true;
p_arg->dlen = sizeof(*p_uart) ;
p_uart = (plctxrx_handle_uart_t *)p_arg->arg;
p_uart->uart_port = at_command_uart_cfg.port;
p_uart->bandrate = bandrate;
p_uart->data_len =(uint8_t)uart_data_len;
p_uart->stop_bit =(uint8_t)stop_bit;
p_uart->parity = (uint8_t)parity;
/* save the current uart config info to the AT command layer. */
os_mem_set(&at_command_uart_cfg, 0 , sizeof(at_uart_cfg_t));
at_command_uart_cfg.port = p_uart->uart_port;
at_command_uart_cfg.brate = p_uart->bandrate;
at_command_uart_cfg.dlen = p_uart->data_len;
at_command_uart_cfg.stop = p_uart->stop_bit;
at_command_uart_cfg.parity = p_uart->parity;
at_command_send_to_plc(p_pkt);
}
else
{
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nThe uart port %d config is:" \
"\r\nbaudrate:%d" \
"\r\ndata_len:%d" \
"\r\nstop_bit:%s" \
"\r\nparity:%s",
at_command_uart_cfg.port,
at_command_uart_cfg.brate,
at_command_uart_cfg.dlen,
/* convert digital 1~3 to string "1","1.5","2", if invalid show "Unknown". */
((at_command_uart_cfg.stop <= IOT_UART_STOP_2_BITS)
&& (at_command_uart_cfg.stop >= IOT_UART_STOP_1_BITS))
? stop_bit_symbol[at_command_uart_cfg.stop - 1] : "Unknown",
/* convert digital 0~2 to string "N","O","E", if invalid show "Unknown". */
((at_command_uart_cfg.parity <= IOT_UART_PARITY_EVEN)
&& (at_command_uart_cfg.parity >= IOT_UART_PARITY_NONE))
? parity_symbol[at_command_uart_cfg.parity] : "Unknown");
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
iot_pkt_free(p_pkt);
}
return;
}
void at_handle_response_uart(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
iot_pkt_t *p_pkt;
uint8_t *p_data;
uint32_t data_len, ret;
/* Check param validity and select the appropriate buffer size for print buffer. */
if ((NULL == p_resp_pkt)
||(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID))))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data, "\r\nConfig the uart %s!",
(PLCTXRX_RESP_OK != p_resp->resp) ? "failed" : "successfully");
ret = (PLCTXRX_RESP_OK != p_resp->resp) ? AT_RESP_ERROR : AT_RESP_OK;
at_command_at_response_to_proto(ret, p_data, data_len, true);
iot_pkt_free(p_pkt);
return;
}
void at_handle_command_topo(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_query_topo_t *topo_cmd;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_TOPO);
uint8_t *rsp_data;
uint32_t rsp_data_len;
(void)opcode;
(void)argc;
(void)argv;
pkt_len = (IOT_PLC_DEV_ROLE_STA == at_command_context.dev_type)
? AT_SMALL_BUF_SIZE : sizeof(*p_arg);
/* alloc packet for sending cmd */
p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID);
if (p_pkt == NULL) {
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
if (IOT_PLC_DEV_ROLE_STA == at_command_context.dev_type) {
rsp_data = iot_pkt_data(p_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nSTA device query topo func is not supported!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
iot_pkt_free(p_pkt);
return;
}
p_arg = (plctxrx_cmd_arg_t*)iot_pkt_put(cmd_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_TOPO;
p_arg->cid.opcode = PLCTXRX_OP_QUERY;
p_arg->need_ack = true;
p_arg->prio = p_cmd_line->prio;
p_arg->dlen = sizeof(plctxrx_cmd_query_topo_t);
topo_cmd = (plctxrx_cmd_query_topo_t*)p_arg->arg;
topo_cmd->ver = IOT_PLC_CCO_TOPO_REQ_DATA_VER_V1;
topo_cmd->start = 1;
topo_cmd->cnt = STA_DEV_MAX;
at_command_send_to_plc(p_pkt);
return;
}
void at_handle_response_topo(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
plctxrx_handle_topo_t *p_topo_info;
iot_pkt_t *p_pkt;
uint8_t *p_data;
uint32_t data_len, ret;
uint16_t i;
if(NULL == p_resp_pkt)
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
p_topo_info = (plctxrx_handle_topo_t *)p_resp->data;
if(NULL == (p_pkt = iot_pkt_alloc(128, AT_COMMAND_MID)))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
ret = (PLCTXRX_RESP_OK != p_resp->resp) ? AT_RESP_ERROR : AT_RESP_OK;
if (p_topo_info->cnt > 0)
{
for (i = 0; i < p_topo_info->cnt; i++)
{
data_len = iot_sprintf((char *)p_data,
"\r\nRemote #%02d-%02X:%02X:%02X:%02X:%02X:%02X.",
i, p_topo_info->topo[i].mac[0], p_topo_info->topo[i].mac[1],
p_topo_info->topo[i].mac[2], p_topo_info->topo[i].mac[3],
p_topo_info->topo[i].mac[4], p_topo_info->topo[i].mac[5]);
at_command_at_response_to_proto(ret, p_data, data_len, false);
}
data_len = iot_sprintf((char *)p_data,
"\r\nTotal %d remote devices.", p_topo_info->cnt);
}
else
{
data_len = iot_sprintf((char *)p_data, "\r\nCan not find remote device!");
}
at_command_at_response_to_proto(ret, p_data, data_len, true);
iot_pkt_free(p_pkt);
return;
}
uint8_t at_command_send_ping_data
(uint16_t type, uint16_t index, uint32_t stamp, uint8_t *p_dts_mac,
uint8_t * data, uint16_t dlen)
{
uint16_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_handle_send_t *p_send;
at_payload_t *p_load;
at_ping_t *p_ping;
pkt_len = sizeof(*p_arg) + sizeof(*p_send) + sizeof(*p_load)
+ sizeof(*p_ping) + dlen;
if(NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
return ERR_FAIL;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_SEND;
p_arg->cid.opcode = PLCTXRX_OP_EXECUTE;
p_arg->prio = AT_DEF_PRIO;
p_arg->need_ack = true;
p_arg->dlen = pkt_len - sizeof(*p_arg);
p_send = (plctxrx_handle_send_t *)p_arg->arg;
os_mem_cpy(p_send->txinfo.dst_mac, p_dts_mac, IOT_MAC_ADDR_LEN);
os_mem_cpy(p_send->txinfo.org_mac, at_command_context.mac, IOT_MAC_ADDR_LEN);
os_mem_cpy(p_send->txinfo.src_mac, at_command_context.mac, IOT_MAC_ADDR_LEN);
p_send->txinfo.retry_cnt = 0;
p_send->txinfo.need_ack = 0;
p_send->txinfo.retry_intvl = 0;
p_send->txinfo.txpwr = 0;
p_send->txinfo.src_module = IOT_PLCTXRX_MSDU_SRCMODULE_AT;
p_send->txinfo.send_type = PLCTXRX_UNICAST;
p_send->txinfo.sta_cnt = 1;
p_send->dlen =(uint8_t)(pkt_len - sizeof(*p_arg) - sizeof(*p_send));
p_load = (at_payload_t *)p_send->data;
p_load->type = type;
p_load->dlen = sizeof(*p_ping) + dlen+sizeof(at_payload_t);
p_ping = (at_ping_t *)p_load->data;
os_mem_cpy(p_ping->dst_mac, p_dts_mac, IOT_MAC_ADDR_LEN);
os_mem_cpy(p_ping->org_mac, at_command_context.mac, IOT_MAC_ADDR_LEN);
p_ping->stamp = stamp;
p_ping->index = index;
p_ping->dlen = dlen;
os_mem_cpy(p_ping->data, data, dlen);
DINFOR("Ping %s send to %02x:%02x:%02x:%02x:%02x:%02x.",
AT_PAYLOAD_PING == type ? "packet" : "response",
p_dts_mac[0], p_dts_mac[1], p_dts_mac[2],
p_dts_mac[3], p_dts_mac[4], p_dts_mac[5]);
at_command_send_to_plc(p_pkt);
return ERR_OK;
}
/* AT+PING="xx:xx:xx:xx:xx:xx",SIZE,TIMES */
void at_handle_command_ping(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t target_mac[IOT_MAC_ADDR_LEN], *p_resp_buf;
uint32_t pack_size, times_cnt, data_len, error_pkg, delta_ms, check_t, i;
const uint32_t check_times = 400, check_delay_ms = 5, ping_max_cnt = 0x0FFFFFFF;
iot_pkt_t *p_resp_buf_pkt;
static uint32_t index = 1;
if((AT_OP_SET != opcode)
|| (argc < 1)
|| (IOT_MAC_ADDR_LEN != at_command_string_2_digtal
(argv[0], target_mac, IOT_MAC_ADDR_LEN)))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if((argc < 2) || (at_command_uint32_2_digtal(argv[1], &times_cnt) <= 0))
{
times_cnt = AT_DEF_PING_TIMES;
}
else if(times_cnt > ping_max_cnt)
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if((argc < 3) || (at_command_uint32_2_digtal(argv[2], &pack_size) <= 0))
{
pack_size = AT_MAX_PING_BYTES;
}
else
{
pack_size = min(pack_size, AT_MAX_PING_BYTES);
}
if(NULL == (p_resp_buf_pkt = iot_pkt_alloc(128, AT_COMMAND_MID)))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_resp_buf = iot_pkt_data(p_resp_buf_pkt);
error_pkg = 0;
g_ping_host.started = true;
os_mem_cpy(g_ping_host.dst_mac, target_mac, IOT_MAC_ADDR_LEN);
for(i = index; i < times_cnt + index; i++)
{
/* Data for sent locates where p_resp_buf in RAM. Not care about data */
if(ERR_OK != at_command_send_ping_data
(AT_PAYLOAD_PING, (uint16_t)i, os_boot_time32(),
target_mac, p_resp_buf,(uint16_t)pack_size))
{
goto PING_LOCAL_ERROR;
}
/* 0 is an invalid index. */
g_ping_host.reply_index = 0;
for(check_t = 0; check_t < check_times; check_t++)
{
os_delay(check_delay_ms);
iot_task_clean_msg(at_command_context.task,
AT_MSG_TYPE_RESPONSE | AT_MSG_SOURCE_PLCTXRX, PLCTXRX_CID_SEND);
if(g_ping_host.reply_index == i)
{
delta_ms = os_boot_time32();
if(delta_ms >= g_ping_host.stamp)
{
delta_ms = delta_ms - g_ping_host.stamp;
}
else
{
delta_ms = delta_ms
+ ((uint32_t)0xFFFFFFFF - g_ping_host.stamp);
}
/* Single path timing. */
delta_ms = (delta_ms > 3) ? (delta_ms / 2) : 1;
goto PING_OK;
}
}
/* PING_TIMEOUT: */
data_len = iot_sprintf((char *)p_resp_buf,
"Ping#%d %02x:%02x:%02x:%02x:%02x:%02x, timeout!\r\n", i - index,
target_mac[0], target_mac[1], target_mac[2], target_mac[3],
target_mac[4], target_mac[5]);
error_pkg++;
goto PING_CONTINUE;
PING_LOCAL_ERROR:
data_len = iot_sprintf((char *)p_resp_buf,
"Ping#%d error!\r\n", i - index);
error_pkg++;
goto PING_CONTINUE;
PING_OK:
/* Waite for check_delay_ms*check_times then do the next ping. */
os_delay(check_delay_ms * (check_times - check_t));
data_len = iot_sprintf((char *)p_resp_buf,
"Ping#%d %02x:%02x:%02x:%02x:%02x:%02x, delay %d ms.\r\n", i - index,
target_mac[0], target_mac[1], target_mac[2], target_mac[3],
target_mac[4], target_mac[5], delta_ms);
PING_CONTINUE:
at_command_at_response_to_proto(AT_RESP_OK, p_resp_buf, data_len, false);
}
/* Clear or increase the index. */
index = i > ping_max_cnt ? 1 : i;
data_len = iot_sprintf((char *)p_resp_buf,
"Total %d packets, %d lost.\r\n", times_cnt, error_pkg);
at_command_at_response_to_proto(AT_RESP_OK, p_resp_buf, data_len, true);
iot_pkt_free(p_resp_buf_pkt);
g_ping_host.started = false;
return;
}
iot_pkt_t *at_command_sendpkt_prepare(uint8_t *buf, uint16_t blen, uint8_t *target_mac,
uint32_t retry_time)
{
uint32_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_handle_send_t *p_send;
at_payload_t *p_load;
at_cmd_t *p_cmd_line = at_command_get_cmd_handle_by_cid(AT_CID_SEND);
pkt_len = sizeof(plctxrx_cmd_arg_t) + sizeof(plctxrx_handle_send_t) +
sizeof(at_payload_t) + AT_MAX_SEND_BYTES;
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID))) {
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return NULL;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_data(p_pkt);
p_send = (plctxrx_handle_send_t *)p_arg->arg;
p_load = (at_payload_t *)p_send->data;
os_mem_cpy(p_load->data, buf, blen);
DINFOR("data_len=%d p_load->data=%p", blen, p_load->data);
p_arg->cid.cid = PLCTXRX_CID_SEND;
p_arg->cid.opcode = PLCTXRX_OP_EXECUTE;
p_arg->prio = p_cmd_line->prio;
p_arg->need_ack = true;
p_arg->dlen =(uint16_t)(sizeof(plctxrx_handle_send_t) +
sizeof(at_payload_t) + blen);
iot_mac_addr_cpy(p_send->txinfo.dst_mac, target_mac);
iot_mac_addr_cpy(p_send->txinfo.org_mac, at_command_context.mac);
iot_mac_addr_cpy(p_send->txinfo.src_mac, at_command_context.mac);
if (iot_mac_addr_cmp(target_mac, IOT_AT_BROADCAST_MAC_6BYTES) &&
at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO) {
p_send->txinfo.send_type = PLCTXRX_BORADCAST;
p_send->txinfo.sta_cnt = 0xFF;
} else {
p_send->txinfo.send_type = PLCTXRX_UNICAST;
p_send->txinfo.sta_cnt = 1;
}
p_send->txinfo.retry_cnt =(uint8_t)retry_time;
p_send->txinfo.need_ack = 0;
p_send->txinfo.retry_intvl = 200;
p_send->txinfo.txpwr = 0;
p_send->txinfo.src_module = IOT_PLCTXRX_MSDU_SRCMODULE_AT;
p_send->dlen = (uint8_t)(sizeof(at_payload_t) + blen);
p_load->type = AT_PAYLOAD_RAWDATA;
p_load->dlen = (uint16_t)(sizeof(at_payload_t) + blen);
if (at_command_context.transp.transpmode) {
p_load->type = SET_TRANSP_MODE(p_load->type);
}
return p_pkt;
}
uint32_t at_handle_transparent_data(uint8_t *buf, uint16_t blen)
{
iot_pkt_t *p_pkt;
uint16_t send_len = 0;
while (blen > 0) {
send_len = blen > TXRX_AGGR_PKT_LEN - sizeof(at_payload_t) ?
TXRX_AGGR_PKT_LEN - sizeof(at_payload_t) : blen;
DINFOR("blen=%d send_len=%d", blen, send_len);
p_pkt = at_command_sendpkt_prepare(buf, send_len,
at_command_context.transp.trans_addr, AT_SEND_DEF_RETRY_TIME);
if (NULL == p_pkt) {
DERROR("No memory!");
return ERR_NOMEM;
}
at_command_send_to_plc(p_pkt);
buf += send_len;
blen -= send_len;
}
return ERR_OK;
}
/* AT+SEND="xx:xx:xx:xx:xx:xx","xx xx xx xx xx...(less than 64 bytes)"[,TRY-TIMES] */
void at_handle_command_send(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t target_mac[IOT_MAC_ADDR_LEN];
iot_pkt_t *p_pkt;
uint32_t data_len, retry_time;
uint8_t data[AT_MAX_SEND_BYTES];
if ((AT_OP_SET != opcode) || (argc < 2) || (IOT_MAC_ADDR_LEN !=
at_command_string_2_digtal(argv[0],target_mac, IOT_MAC_ADDR_LEN))) {
DERROR("Invalid argument! opcode=%d argc=%d", opcode, argc);
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if (0 == (data_len = at_command_string_2_digtal(argv[1],
data, AT_MAX_SEND_BYTES))) {
DERROR("Invalid argument: data_len error!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if (argc < 2 || at_command_uint32_2_digtal(argv[2], &retry_time) <= 0) {
retry_time = AT_SEND_DEF_RETRY_TIME;
}
p_pkt = at_command_sendpkt_prepare(data, data_len, target_mac, retry_time);
if (NULL == p_pkt) {
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
} else {
at_command_send_to_plc(p_pkt);
/* Just finish AT+SEND with out response. */
at_command_at_response_to_proto(AT_RESP_SET_FINISH_WITHOUT_ECHO,
NULL, 0, true);
}
return;
}
/* AT+PMODE="enable","xx:xx:xx:xx:xx:xx" */
void at_handle_command_pmode(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
uint8_t *p_data;
iot_pkt_t *p_pkt;
uint32_t data_len;
uint8_t target_mac[IOT_MAC_ADDR_LEN];
if ((AT_OP_SET != opcode) || argc < 1 ||
iot_strcmp((char*)argv[0], STRING_ENABLE)) {
DERROR("Invalid argument! opcode=%d argc=%d", opcode, argc);
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
}
if (argc < 2) {
iot_mac_addr_cpy(at_command_context.transp.trans_addr,
(uint8_t*)IOT_AT_BROADCAST_MAC_6BYTES);
} else if (IOT_MAC_ADDR_LEN ==
at_command_string_2_digtal(argv[1], target_mac, IOT_MAC_ADDR_LEN)) {
/* get target_mac*/
if (iot_mac_addr_cmp(target_mac, INVALID_MACADDR_6BYTE)) {
DERROR("Invalid argument! mac invalid");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
} else {
iot_mac_addr_cpy(at_command_context.transp.trans_addr, target_mac);
}
} else {
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
}
at_command_context.transp.transpmode = true;
p_flash->transp.transpmode = true;
iot_mac_addr_cpy(p_flash->transp.trans_addr,
at_command_context.transp.trans_addr);
/* Write flash. */
if (ERR_OK != at_command_uniform_flashsave(p_flash)){
DERROR("save transpmode to flash failed!");
}
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID))) {
DERROR("alloc memory ERR!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0 , 1);
return;
}
p_data = iot_pkt_data(p_pkt);
if (iot_mac_addr_cmp(at_command_context.transp.trans_addr,
IOT_AT_BROADCAST_MAC_6BYTES)) {
data_len = iot_sprintf((char *)p_data,"data received from UART will be"
" transparent transmitted as broadcast\n");
} else {
data_len = iot_sprintf((char *)p_data,"data received from UART will be"
" transparent transmitted to %02X:%02X:%02X:%02X:%02X:%02X\n",
at_command_context.transp.trans_addr[0],
at_command_context.transp.trans_addr[1],
at_command_context.transp.trans_addr[2],
at_command_context.transp.trans_addr[3],
at_command_context.transp.trans_addr[4],
at_command_context.transp.trans_addr[5]);
}
DERROR("%s",p_data);
/* Just finish AT+PMODE with response. */
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
p_data, data_len, true);
iot_pkt_free(p_pkt);
return;
}
void at_command_send_received_data_rawdata(plctxrx_handle_recv_t *p_rcv)
{
iot_pkt_t *p_pkt;
uint8_t *p_data;
uint32_t data_len, pkt_len, i, hex_data;
at_payload_t *p_load;
uint32_t appdata_len;
p_load = (at_payload_t *)p_rcv->data;
appdata_len = p_load->dlen - sizeof(at_payload_t);
if (GET_TRANSP_MODE(p_load->type)) {
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
DINFOR("recv appdata_len=%d", appdata_len);
#endif
if (at_command_context.transp.transpmode) {
pkt_len = appdata_len;
DINFOR("recv rawdata len=%d", p_load->dlen);
if(NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
return;
}
p_data = iot_pkt_data(p_pkt);
os_mem_cpy(p_data, p_load->data, appdata_len);
data_len = appdata_len;
} else {
pkt_len = AT_SMALL_BUF_SIZE;
p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID);
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data,
"recv transpmode data, but local is not in transpmode\r\n");
}
} else {
/* A byte needs 3 chars to show. (_5E) */
pkt_len = AT_SMALL_BUF_SIZE + (p_load->dlen * 3);
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
DINFOR("recv p_load->dlen=%d", p_load->dlen);
#endif
if(NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
return;
}
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data,
"\r\nMessage(%d bytes) from %02x:%02x:%02x:%02x:%02x:%02x :\r\n",
appdata_len,
p_rcv->rxinfo.mac[0], p_rcv->rxinfo.mac[1],
p_rcv->rxinfo.mac[2], p_rcv->rxinfo.mac[3],
p_rcv->rxinfo.mac[4], p_rcv->rxinfo.mac[5]);
for(i = 0; i < appdata_len; i++)
{
hex_data = ((uint32_t)p_load->data[i]) & 0xFF;
data_len += iot_sprintf((char *)(p_data + data_len),
"%02x ", hex_data);
}
data_len += appdata_len;
}
#if INCLUDE_AT_COMMAND_DEBUG_PRINT
DINFOR("report data_len=%d", data_len);
#endif
at_command_at_response_to_proto
(AT_RESP_FORCE_ECHO, p_data, data_len, false);
iot_pkt_free(p_pkt);
return;
}
void at_command_send_received_data_ping(plctxrx_handle_recv_t *p_rcv)
{
at_payload_t *p_load;
at_ping_t *p_ping;
p_load = (at_payload_t *)p_rcv->data;
p_ping = (at_ping_t *)p_load->data;
at_command_send_ping_data(AT_PAYLOAD_PING_REPLY, p_ping->index,
p_ping->stamp, p_ping->org_mac, p_ping->data, p_ping->dlen);
return;
}
void at_command_send_received_data_ping_reply(plctxrx_handle_recv_t *p_rcv)
{
at_payload_t *p_load;
at_ping_t *p_ping;
p_load = (at_payload_t *)p_rcv->data;
p_ping = (at_ping_t *)p_load->data;
if((g_ping_host.started)
&& (0 == os_mem_cmp
(g_ping_host.dst_mac, p_ping->org_mac, IOT_MAC_ADDR_LEN)))
{
g_ping_host.reply_index = p_ping->index;
g_ping_host.stamp = p_ping->stamp;
}
return;
}
void at_handle_response_send_receive(iot_pkt_t *p_resp_pkt)
{
plctxrx_cmd_resp_t *p_resp;
plctxrx_handle_recv_t *p_rcv;
at_payload_t *p_load;
if(NULL == p_resp_pkt)
{
return;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
p_rcv = (plctxrx_handle_recv_t *)p_resp->data;
p_load = (at_payload_t *)p_rcv->data;
if(PLCTXRX_OP_RECEIVE != p_resp->cid.opcode)
{
return;
}
if(AT_PAYLOAD_RAWDATA == GET_PAYLOAD_TYPE(p_load->type))
{
at_command_send_received_data_rawdata(p_rcv);
}
else if(AT_PAYLOAD_PING == p_load->type)
{
at_command_send_received_data_ping(p_rcv);
}
else if(AT_PAYLOAD_PING_REPLY == p_load->type)
{
at_command_send_received_data_ping_reply(p_rcv);
}
else
{
/* Do nothing. */
}
return;
}
void at_handle_command_memory(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t buf_len, value, addr;
uint8_t buf[36];
if(AT_OP_SET == opcode)
{
if((argc < 2)
|| (at_command_hex_2_digtal(argv[0], &addr) <= 0)
|| (true != iot_data_addr_legal(addr))
|| (at_command_hex_2_digtal(argv[1], &value) <= 0))
{
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
}
buf_len = iot_sprintf((char *)buf, "W %08x:%08x->%08x", addr,
*((volatile uint32_t *)addr), value);
*((volatile uint32_t *)addr) = value;
}
else
{
if((argc < 1) || (at_command_hex_2_digtal(argv[0], &addr) <= 0)
|| (true != iot_data_addr_legal(addr)))
{
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
}
addr &= 0xFFFFFFFC;
buf_len = iot_sprintf((char *)buf, "R %08x:%08x", addr,
*((volatile uint32_t *)addr));
}
at_command_at_response_to_proto(AT_RESP_OK, buf, buf_len, true);
return;
}
void at_command_task_show(uint32_t task_id)
{
task_info_t *p_tasks;
iot_pkt_t *p_task_info_pkt, *p_pkt_sprintf_data;
uint32_t task_num, i, data_len;
uint8_t *p_buf;
char *p_state[] = {"RUN", "RDY", "BLK", "SPD", "DEL", "N/A"};
task_num = os_get_toltal_task_cnt();
/* More than one task exists if AT running. */
if((0 == task_num)
|| (NULL == (p_task_info_pkt = iot_pkt_alloc
(sizeof(*p_tasks) * task_num, AT_COMMAND_MID))))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_tasks = (task_info_t *)iot_pkt_data(p_task_info_pkt);
if((0 == (task_num = os_get_task_info(p_tasks, task_num)))
||(NULL == (p_pkt_sprintf_data = iot_pkt_alloc(256, AT_COMMAND_MID))))
{
iot_pkt_free(p_task_info_pkt);
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_buf = iot_pkt_data(p_pkt_sprintf_data);
for(i = 0; i < task_num; i++)
{
p_tasks->status = (p_tasks->status >= IOT_INVALID
|| p_tasks->status < IOT_RUN) ? IOT_INVALID : p_tasks->status;
if((0 == task_id)
||(task_id == p_tasks->id))
{
data_len = iot_sprintf((char *)p_buf,
"\r\n#%2d | ID:0x%08x | PRIO:%2d | STATE:%s | "\
"CPU_R:%2d%% | STACK:0x%08x | LOWEST:%4d | NAME:%-40.40s",
i, p_tasks->id, p_tasks->priority,
(char *)p_state[p_tasks->status],
p_tasks->cpu_time_ratio, p_tasks->stack_base,
p_tasks->stack_warter_mask, p_tasks->name);
at_command_at_response_to_proto(AT_RESP_OK, p_buf, data_len, false);
}
p_tasks++;
}
data_len = iot_sprintf((char *)p_buf, "\r\nTotal %d tasks.", task_num);
at_command_at_response_to_proto(AT_RESP_OK, p_buf, data_len, true);
iot_pkt_free(p_task_info_pkt);
iot_pkt_free(p_pkt_sprintf_data);
return;
}
void at_handle_command_task(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t task_id;
(void)opcode;
if((argc >= 1)
&&(at_command_hex_2_digtal(argv[0], &task_id) > 0))
{
at_command_task_show((int)task_id);
}
else
{
/* Show all */
at_command_task_show(0);
}
return;
}
void at_handle_command_reboot(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t buf[64], t_mac[IOT_MAC_ADDR_LEN];
uint32_t data_len;
if(AT_OP_SET != opcode)
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if(argc <1)
{
data_len = iot_sprintf((char *)buf,
"This systerm will be reboot after 5 seconds!");
at_command_at_response_to_proto(AT_RESP_OK, buf, data_len, true);
/* Reboot delay. */
os_delay(5000);
iot_system_restart(IOT_SYS_RST_REASON_APP_REQ);
}
else
{
if(IOT_MAC_ADDR_LEN != at_command_string_2_digtal
(argv[0], t_mac, IOT_MAC_ADDR_LEN))
{
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
/* TODO: remote reboot. */
data_len = iot_sprintf((char *)buf,
"Cannot reboot remote device %02x:%02x:%02x:%02x:%02x:%02x!",
t_mac[0], t_mac[1], t_mac[2], t_mac[3], t_mac[4], t_mac[5]);
at_command_at_response_to_proto(AT_RESP_ERROR, buf, data_len, true);
}
return;
}
void at_handle_response_reboot(iot_pkt_t *p_resp_pkt)
{
(void)p_resp_pkt;
}
void at_handle_command_who(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
(void)opcode;
(void)argc;
(void)argv;
}
void at_handle_response_who(iot_pkt_t *p_resp_pkt)
{
(void)p_resp_pkt;
}
void at_handle_command_rfpower(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint32_t power = 0, pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_tx_pwr_t *p_txpower;
if(((AT_OP_SET != opcode) && (AT_OP_QUERY != opcode))
||((AT_OP_SET == opcode)
&&((argc < 1) || (at_command_uint32_2_digtal(argv[0], &power) <= 0))))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
pkt_len = sizeof(*p_arg) + sizeof(*p_txpower);
if(NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_TX_PWR;
p_arg->prio = AT_DEF_PRIO;
p_arg->need_ack = true;
if(AT_OP_SET == opcode)
{
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->dlen = sizeof(*p_txpower);
p_txpower = (plctxrx_cmd_tx_pwr_t *)p_arg->arg;
p_txpower->tx_pwr = (uint8_t)(power & 0xFF);
}
else
{
p_arg->cid.opcode = PLCTXRX_OP_QUERY;
p_arg->dlen = 0;
}
at_command_send_to_plc(p_pkt);
return;
}
void at_handle_response_rfpower(iot_pkt_t *p_resp_pkt)
{
uint8_t buf[64], result;
uint32_t ret, data_len;
plctxrx_cmd_resp_t *p_resp;
if(NULL == p_resp_pkt)
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
/* PLCtxrx level has no struct for this. */
result = p_resp->data[0];
ret = (PLCTXRX_RESP_OK == p_resp->resp) ? AT_RESP_OK : AT_RESP_ERROR;
if(PLCTXRX_OP_CFM == p_resp->cid.opcode)
{
data_len = iot_sprintf((char *)buf,
"Config rfpower %s!", result ? "failed" : "successfully");
}
else
{
data_len = iot_sprintf((char *)buf,
"Current rfpower is %d.", ((int)result) & 0xFF);
}
at_command_at_response_to_proto(ret, buf, data_len, true);
return;
}
/* Return the index of mac in the online device table if found, return -1 means not found. */
int32_t at_command_check_online_mac_exists
(uint8_t *p_mac, at_dev_t *p_dev_table, uint8_t valid_cnt)
{
uint8_t i;
if (NULL == p_mac || NULL == p_dev_table)
{
DERROR("Invalid argument!");
return -1;
}
for (i = 0; i < valid_cnt; i++)
{
if (0 == os_mem_cmp(p_dev_table[i].mac, p_mac, IOT_MAC_ADDR_LEN))
{
return i;
}
}
return -1;
}
/* Add new device to online device list. */
void at_command_add_dev_to_online
(at_dev_list_t *p_dev_list, at_dev_t *p_new_dev)
{
uint8_t cnt;
if ((NULL == p_dev_list) || (NULL == p_new_dev))
{
DERROR("Invalid argument!");
return;
}
/* Get a free place to store. */
cnt = p_dev_list->valid_dev_cnt;
if (cnt < AT_STA_DEV_MAX)
{
os_mem_cpy(&(p_dev_list->dev[cnt]), p_new_dev, sizeof(at_dev_t));
p_dev_list->valid_dev_cnt++;
}
return;
}
/**
* @brief Delete existing device from online device list.
* @param p_dev_list: the pointer of device list.
* @param dev_tb_index: the index of device saved in device table that need to delete.
*/
void at_command_del_dev_from_online
(at_dev_list_t *p_dev_list, int32_t dev_tb_index)
{
uint32_t cnt;
at_dev_t *p_dev_table;
if ((NULL == p_dev_list)
|| (dev_tb_index >= AT_STA_DEV_MAX)
|| (dev_tb_index < 0))
{
DERROR("Invalid argument!");
return;
}
p_dev_table = p_dev_list->dev;
/* Clear the contents of the device based on the index value. */
os_mem_set(&p_dev_table[dev_tb_index], 0, sizeof(at_dev_t));
/* Reorg the device table, move the rest device forward one by one. */
for(cnt = dev_tb_index + 1; cnt < p_dev_list->valid_dev_cnt; cnt++)
{
p_dev_table[cnt - 1] = p_dev_table[cnt];
if (cnt == p_dev_list->valid_dev_cnt - 1)
{
/* Clear the contents of the last position as a result of reorg. */
os_mem_set(&p_dev_table[cnt], 0, sizeof(at_dev_t));
}
}
/* Reduce the total valid number. */
p_dev_list->valid_dev_cnt -= 1;
return;
}
/* Return the index of mac in the flash device table if found, return -1 means not found. */
int32_t at_command_check_flash_mac_exists
(uint8_t *p_mac, proto_dev_t *p_dev_table, uint16_t valid_cnt)
{
uint16_t i;
if (NULL == p_mac || NULL == p_dev_table)
{
DERROR("Invalid argument!");
return -1;
}
for (i = 0; i < valid_cnt; i++)
{
if (0 == os_mem_cmp(p_dev_table[i].mac, p_mac, IOT_MAC_ADDR_LEN))
{
return i;
}
}
return -1;
}
/* Add new device to device list saved in flash. */
void at_command_add_dev_to_flash(custom_flash_info_t *p_info, at_dev_t *p_new_dev)
{
uint8_t cnt;
if ((NULL == p_info) || (NULL == p_new_dev))
{
DERROR("Invalid argument!");
return;
}
/* Get a free place to store. */
cnt = p_info->dev_cnt;
if (cnt < AT_STA_DEV_MAX)
{
p_info->dev_tbl[cnt].ip = 0;
p_info->dev_tbl[cnt].dev_role = p_new_dev->dev_role;
iot_mac_addr_cpy(p_info->dev_tbl[cnt].mac, p_new_dev->mac);
p_info->dev_cnt++;
}
return;
}
/**
* @brief Delete existing device from device list saved in flash.
* @param p_dev_list: the pointer of device list.
* @param dev_tb_index: the index of device saved in device table that need to delete.
*/
void at_command_del_dev_from_flash
(custom_flash_info_t *p_info, int32_t dev_tb_index)
{
uint32_t cnt;
proto_dev_t *p_dev_table;
if ((NULL == p_info)
|| (dev_tb_index >= AT_STA_DEV_MAX)
|| (dev_tb_index < 0))
{
DERROR("Invalid argument!");
return;
}
p_dev_table = p_info->dev_tbl;
/* Clear the contents of the device based on the index value. */
os_mem_set(&p_dev_table[dev_tb_index], 0, sizeof(proto_dev_t));
/* Reorg the device table, move the rest device forward one by one. */
for(cnt = dev_tb_index + 1; cnt < p_info->dev_cnt; cnt++)
{
p_dev_table[cnt - 1] = p_dev_table[cnt];
if (cnt == p_info->dev_cnt - 1)
{
/* Clear the contents of the last position when reorg. */
os_mem_set(&p_dev_table[cnt], 0, sizeof(proto_dev_t));
}
}
/* Reduce the total valid number. */
p_info->dev_cnt -= 1;
return;
}
/**
* @brief Add/Delete whitelist to/from CVG layer, based on device list saved in flash.
* @param action : 0 - delete; 1 - add. (same with proto layer defined)
* @param need_ack_cfm : true - plctxrx will ack cfm; false - No ack cfm.
*/
void at_command_cvg_wl_add_del(uint8_t action, uint8_t *mac, bool_t need_ack_cfm)
{
uint8_t i, cnt;
iot_pkt_t *p_pkt;
uint32_t pkt_len;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_whitelist_t *p_wlist_set;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
/* One mac op or the whole valid device table. */
if (mac)
{
cnt = 1;
}
else
{
cnt = p_flash->dev_cnt;
if (0 == cnt)
{
DINFOR("No valid device to add or delete!");
return;
}
}
pkt_len = sizeof(*p_arg) + sizeof(*p_wlist_set) + cnt * IOT_MAC_ADDR_LEN;
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No Memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_WHITELIST;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = 0;
p_arg->need_ack = need_ack_cfm;
p_arg->dlen = sizeof(*p_wlist_set) + cnt * IOT_MAC_ADDR_LEN;
p_wlist_set = (plctxrx_cmd_whitelist_t *)p_arg->arg;
p_wlist_set->action = action;
for (i = 0; i < cnt; i++)
{
iot_mac_addr_cpy(p_wlist_set->maclist[i], p_flash->dev_tbl[i].mac);
DINFOR("Set whitelist %02x:%02x:%02x:%02x:%02x:%02x!",
p_wlist_set->maclist[i][0], p_wlist_set->maclist[i][1],
p_wlist_set->maclist[i][2], p_wlist_set->maclist[i][3],
p_wlist_set->maclist[i][4], p_wlist_set->maclist[i][5]);
}
p_wlist_set->listcnt = cnt;
at_command_send_to_plc(p_pkt);
return;
}
/**
* @brief Enable/disable whitelist in CVG layer, based on device list saved in flash.
* @param action: 2 - disable; 3 - enable (same with proto layer defined)
* @param need_ack_cfm: true - plctxrx will ack cfm; false - No ack cfm.
*/
void at_command_cvg_wl_en_disable(uint8_t action, bool_t need_ack_cfm)
{
iot_pkt_t *p_pkt;
uint32_t pkt_len;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_whitelist_t *p_wlist_set;
pkt_len = sizeof(*p_arg) + sizeof(*p_wlist_set);
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No Memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_WHITELIST;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = AT_DEF_PRIO;
p_arg->need_ack = need_ack_cfm;
p_arg->dlen = sizeof(*p_wlist_set);
p_wlist_set = (plctxrx_cmd_whitelist_t *)p_arg->arg;
p_wlist_set->action = action;
p_wlist_set->listcnt = 0;
at_command_send_to_plc(p_pkt);
}
/* Save online device list to device list saved in flash and add whitelist to CVG layer. */
void at_command_online_dev_list_save2flash(void)
{
uint8_t cnt;
at_dev_list_t *p_dev_list = &(at_command_context.online_dev_list);
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
if (p_dev_list->valid_dev_cnt <= AT_STA_DEV_MAX)
{
p_flash->dev_cnt = p_dev_list->valid_dev_cnt;
for (cnt = 0; cnt < p_dev_list->valid_dev_cnt; cnt++)
{
p_flash->dev_tbl[cnt].ip = 0;
p_flash->dev_tbl[cnt].dev_role = p_dev_list->dev[cnt].dev_role;
iot_mac_addr_cpy(p_flash->dev_tbl[cnt].mac, p_dev_list->dev[cnt].mac);
}
}
/* Write flash. */
if(ERR_OK == at_command_uniform_flashsave(p_flash))
{
DINFOR("Local device list save to flash successfully!");
}
else
{
DERROR("Local device list save to flash failed!");
return;
}
/* Add whitelist to CVG layer.*/
at_command_cvg_wl_add_del(AT_WL_ACTION_ADD, NULL, false);
return;
}
void at_handle_command_whitelist(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t target_mac[IOT_MAC_ADDR_LEN];
uint32_t pkt_len;
iot_pkt_t *p_pkt;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_whitelist_t *p_wl_set;
at_dev_t signle_dev;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
int32_t dev_tb_index;
uint8_t *rsp_data;
uint32_t rsp_data_len;
uint32_t i, wl_total_cnt;
/* Check the validity of the parameters. */
if(((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
||((AT_OP_SET == opcode) && ((argc < 2)
||(IOT_MAC_ADDR_LEN != at_command_string_2_digtal
(argv[1], target_mac, IOT_MAC_ADDR_LEN))
||((iot_strcmp((char *)argv[0], USER_INPUT_ADD_STR))
&& (iot_strcmp((char *)argv[0], USER_INPUT_DEL_STR))))))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
if (AT_OP_SET == opcode)
{
if (at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO)
signle_dev.dev_role= IOT_PLC_DEV_ROLE_STA;
else
signle_dev.dev_role= IOT_PLC_DEV_ROLE_CCO;
os_mem_cpy(signle_dev.mac, target_mac, IOT_MAC_ADDR_LEN);
pkt_len = sizeof(*p_arg) + sizeof(*p_wl_set) + IOT_MAC_ADDR_LEN;
if (NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No Memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_put(p_pkt, pkt_len);
p_arg->cid.cid = PLCTXRX_CID_WHITELIST;
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
p_arg->prio = AT_DEF_PRIO;
p_arg->need_ack = true;
p_arg->dlen = sizeof(*p_wl_set) + IOT_MAC_ADDR_LEN;
p_wl_set = (plctxrx_cmd_whitelist_t *)p_arg->arg;
at_command_wl_op.latest_wl_action = AT_WL_ACTION_NONE;
if (0 == (iot_strcmp((char *)argv[0], USER_INPUT_ADD_STR)))
{
if (p_flash->dev_cnt >= AT_STA_DEV_MAX)
{
DERROR("No free space to store new device!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
iot_pkt_free(p_pkt);
return;
}
if (-1 != (dev_tb_index = at_command_check_flash_mac_exists
(signle_dev.mac, p_flash->dev_tbl, p_flash->dev_cnt)))
{
DERROR("MAC Exist!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
iot_pkt_free(p_pkt);
return;
}
p_wl_set->action = IOT_PLC_WL_ADD;
at_command_wl_op.latest_wl_action = AT_WL_ACTION_ADD;
}
else
{
if (-1 == (dev_tb_index = at_command_check_flash_mac_exists
(signle_dev.mac, p_flash->dev_tbl, p_flash->dev_cnt)))
{
DERROR("MAC Not Exist!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
iot_pkt_free(p_pkt);
return;
}
p_wl_set->action = IOT_PLC_WL_DEL;
at_command_wl_op.latest_wl_action = AT_WL_ACTION_DEL;
}
os_mem_cpy(&(at_command_wl_op.signle_dev), &signle_dev, sizeof(at_dev_t));
/* Sync new device mac to CVG layer whitelist. */
p_wl_set->listcnt = 1;
os_mem_cpy(p_wl_set->maclist[0], signle_dev.mac, IOT_MAC_ADDR_LEN);
at_command_send_to_plc(p_pkt);
}
else
{
/* Select the appropriate buffer size, ensure it is enough for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
wl_total_cnt = p_flash->dev_cnt;
for (i = 0; i < wl_total_cnt; i++)
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\n#%2d | MAC:%02X:%02X:%02X:%02X:%02X:%02X.", i,
p_flash->dev_tbl[i].mac[0], p_flash->dev_tbl[i].mac[1],
p_flash->dev_tbl[i].mac[2], p_flash->dev_tbl[i].mac[3],
p_flash->dev_tbl[i].mac[4], p_flash->dev_tbl[i].mac[5]);
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, false);
}
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nCurrent device role is %s, its whitelist entries total count = %d.",
(1 == PLC_SUPPORT_CCO_ROLE) ? "CCO" : "STA", wl_total_cnt);
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
iot_pkt_free(p_pkt);
}
return;
}
void at_handle_response_whitelist(iot_pkt_t *p_resp_pkt)
{
uint32_t data_len, ret;
uint8_t *p_data;
iot_pkt_t *p_pkt;
plctxrx_cmd_resp_t *p_resp;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
int32_t dev_tb_index;
if(NULL == p_resp_pkt)
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
/* Select the appropriate buffer size, ensure it is enough for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
ret = (PLCTXRX_RESP_OK == p_resp->resp) ? AT_RESP_OK : AT_RESP_ERROR;
if(PLCTXRX_OP_CFM == p_resp->cid.opcode)
{
if (PLCTXRX_RESP_OK == p_resp->resp)
{
if (AT_WL_ACTION_ADD == at_command_wl_op.latest_wl_action)
{
if (-1 == (dev_tb_index = at_command_check_flash_mac_exists
(at_command_wl_op.signle_dev.mac, p_flash->dev_tbl,
p_flash->dev_cnt)))
{
/* Update device list saved in flash, add recorded signle dev info. */
at_command_add_dev_to_flash(p_flash,
&at_command_wl_op.signle_dev);
if (ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Update device list saved in flash failed!");
}
data_len = iot_sprintf((char *)p_data,
"\r\nConfig whitelist successfully!");
}
else
{
data_len = iot_sprintf((char *)p_data,
"\r\nMAC Exist!Config whitelist failed!");
at_command_at_response_to_proto(AT_RESP_ERROR,
p_data, data_len, true);
iot_pkt_free(p_pkt);
at_command_wl_op.latest_wl_action = AT_WL_ACTION_NONE;
return;
}
}
else if (AT_WL_ACTION_DEL == at_command_wl_op.latest_wl_action)
{
if (-1 == (dev_tb_index = at_command_check_flash_mac_exists
(at_command_wl_op.signle_dev.mac, p_flash->dev_tbl,
p_flash->dev_cnt)))
{
data_len = iot_sprintf((char *)p_data,
"\r\nMAC Not Exist!Config whitelist failed!");
at_command_at_response_to_proto(AT_RESP_ERROR,
p_data, data_len, true);
iot_pkt_free(p_pkt);
at_command_wl_op.latest_wl_action = AT_WL_ACTION_NONE;
return;
}
else
{
/* Update device list saved in flash. */
at_command_del_dev_from_flash(p_flash, dev_tb_index);
if (ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Update device list saved in flash failed!");
}
data_len = iot_sprintf((char *)p_data,
"\r\nConfig whitelist successfully!");
}
}
else
{
data_len = iot_sprintf((char *)p_data, "\r\nConfig whitelist failed!");
}
}
else
{
data_len = iot_sprintf((char *)p_data, "\r\nConfig whitelist failed!");
}
at_command_at_response_to_proto(ret, p_data, data_len, true);
}
iot_pkt_free(p_pkt);
at_command_wl_op.latest_wl_action = AT_WL_ACTION_NONE;
return;
}
void at_handle_command_network(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t target_mac[IOT_MAC_ADDR_LEN];
iot_pkt_t *p_pkt;
uint32_t pkt_len;
plctxrx_cmd_arg_t *p_arg;
plctxrx_cmd_join_network_t *p_join;
plctxrx_cmd_leave_net_t *p_leave;
at_dev_t new_dev_info;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
int32_t dev_tb_index;
(void)argc;
(void)argv;
if(((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
||((AT_OP_SET == opcode) && ((argc < 2)
||(IOT_MAC_ADDR_LEN != at_command_string_2_digtal
(argv[1], target_mac, IOT_MAC_ADDR_LEN))
||((iot_strcmp((char *)argv[0], USER_INPUT_ADD_STR))
&& (iot_strcmp((char *)argv[0], USER_INPUT_DEL_STR))))))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
/* Alloc a bigger buffer for all issues. */
pkt_len = sizeof(*p_arg) +
max(sizeof(*p_join), sizeof(*p_leave) + IOT_MAC_ADDR_LEN);
if(NULL == (p_pkt = iot_pkt_alloc(pkt_len, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_arg = (plctxrx_cmd_arg_t *)iot_pkt_data(p_pkt);
if(AT_OP_QUERY == opcode)
{
p_arg->cid.cid = PLCTXRX_CID_FIND_NETWORK;
p_arg->cid.opcode = PLCTXRX_OP_QUERY;
p_arg->dlen = 0;
pkt_len = sizeof(*p_arg);
}
else
{
/* Store new dev info. STA update device list saved in flash and CVG whitelist. */
new_dev_info.dev_role= IOT_PLC_DEV_ROLE_CCO;
iot_mac_addr_cpy(new_dev_info.mac, target_mac);
p_arg->cid.opcode = PLCTXRX_OP_CONFIG;
if(0 == iot_strcmp((char *)argv[0], USER_INPUT_ADD_STR))
{
if (-1 != (dev_tb_index = at_command_check_flash_mac_exists
(new_dev_info.mac, p_flash->dev_tbl, p_flash->dev_cnt)))
{
DERROR("MAC Exist!");
}
else
{
if (p_flash->dev_cnt < AT_STA_DEV_MAX)
{
/* STA update device list saved in flash. */
at_command_add_dev_to_flash(p_flash, &new_dev_info);
if (ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Update device list saved in flash failed!");
}
}
else
{
DERROR("No free space to store new device!");
}
}
p_arg->cid.cid = PLCTXRX_CID_JOIN_NETWORK;
p_arg->dlen = sizeof(*p_join);
pkt_len = sizeof(*p_arg) + sizeof(*p_join);
p_join = (plctxrx_cmd_join_network_t *)p_arg->arg;
/* Clear nid, they are not used. */
p_join->nid = 0;
os_mem_cpy(p_join->mac, target_mac, IOT_MAC_ADDR_LEN);
}
else
{
if (-1 == (dev_tb_index = at_command_check_flash_mac_exists
(new_dev_info.mac, p_flash->dev_tbl, p_flash->dev_cnt)))
{
DERROR("MAC Not Exist!");
}
else
{
/* STA update device list saved in flash. */
at_command_del_dev_from_flash(p_flash, dev_tb_index);
if (ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Update device list saved in flash failed!");
}
}
p_arg->cid.cid = PLCTXRX_CID_LEAVE_NETWORK;
p_arg->dlen = sizeof(*p_leave);
pkt_len = sizeof(*p_arg) + sizeof(*p_leave) + IOT_MAC_ADDR_LEN;
p_leave = (plctxrx_cmd_leave_net_t *)p_arg->arg;
p_leave->cnt = 1;
os_mem_cpy(p_leave->mac[0], target_mac, IOT_MAC_ADDR_LEN);
}
}
p_arg->need_ack = true;
p_arg->prio = AT_DEF_PRIO;
iot_pkt_put(p_pkt, pkt_len);
at_command_send_to_plc(p_pkt);
return;
}
void at_handle_response_network(iot_pkt_t *p_resp_pkt)
{
uint32_t i, total, data_len, ret;
uint8_t *p_buf;
iot_pkt_t *p_pkt;
plctxrx_cmd_resp_t *p_resp;
plctxrx_cmd_network_t *p_net;
plctxrx_cmd_joined_network_t *p_join;
plctxrx_cmd_leave_net_t *p_leave;
at_dev_t new_dev_info;
at_dev_list_t *p_dev_list = &(at_command_context.online_dev_list);
int32_t dev_tb_index;
if (NULL == p_resp_pkt) {
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
/* 128 bytes is enough for print buffer. */
if (NULL == (p_pkt = iot_pkt_alloc(128, AT_COMMAND_MID))) {
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_buf = iot_pkt_data(p_pkt);
p_resp = (plctxrx_cmd_resp_t *)iot_pkt_data(p_resp_pkt);
if (PLCTXRX_OP_INDICATION == p_resp->cid.opcode) {
if (PLCTXRX_CID_FIND_NETWORK == p_resp->cid.cid) {
p_net = (plctxrx_cmd_network_t *)p_resp->data;
total = p_net->count;
for (i = 0; i < total; i++) {
data_len = iot_sprintf((char *)p_buf,
"\r\n#%2d | NID:0x%08x | MAC:%02x:%02x:%02x:%02x:%02x:%02x"\
" | SNR:%d",
i, p_net->node[i].nid, p_net->node[i].mac[0],
p_net->node[i].mac[1], p_net->node[i].mac[2],
p_net->node[i].mac[3], p_net->node[i].mac[4],
p_net->node[i].mac[5], (int)p_net->node[i].snr);
at_command_at_response_to_proto(AT_RESP_OK, p_buf,
data_len, false);
}
data_len = iot_sprintf((char *)p_buf,
"\r\nTotal %d network found!", total);
} else if(PLCTXRX_CID_JOIN_NETWORK == p_resp->cid.cid) {
/* PLCTXRX_CID_JOIN_NETWORK */
p_join = (plctxrx_cmd_joined_network_t *)p_resp->data;
if (at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO) {
data_len = iot_sprintf((char *)p_buf,
"\r\nRemote MAC:%02x:%02x:%02x:%02x:%02x:%02x join network!",
p_join->mac[0], p_join->mac[1], p_join->mac[2],
p_join->mac[3], p_join->mac[4], p_join->mac[5]);
} else {
data_len = iot_sprintf((char *)p_buf,
"\r\nJoin network NID:0x%08x "
"MAC:%02x:%02x:%02x:%02x:%02x:%02x!",
p_join->nid, p_join->mac[0], p_join->mac[1], p_join->mac[2],
p_join->mac[3], p_join->mac[4], p_join->mac[5]);
}
/* Store new device info. CCO and STA update online device list only. */
if (at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO)
{
new_dev_info.dev_role= IOT_PLC_DEV_ROLE_STA;
}
else
{
new_dev_info.dev_role= IOT_PLC_DEV_ROLE_CCO;
}
iot_mac_addr_cpy(new_dev_info.mac, p_join->mac);
if (-1 != (dev_tb_index = at_command_check_online_mac_exists
(new_dev_info.mac, p_dev_list->dev, p_dev_list->valid_dev_cnt)))
{
DERROR("MAC Exist!");
}
else
{
if (p_dev_list->valid_dev_cnt < AT_STA_DEV_MAX)
{
/* CCO and STA update online device list only. */
at_command_add_dev_to_online(p_dev_list, &new_dev_info);
}
else
{
DERROR("No free space to store new device!");
}
}
} else {
/* PLCTXRX_CID_LEAVE_NETWORK */
p_leave = (plctxrx_cmd_leave_net_t *)p_resp->data;
if (at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO) {
total = p_leave->cnt;
for (i = 0; i < total; i++) {
data_len = iot_sprintf((char *)p_buf,
"\r\n#%2d MAC:%02x:%02x:%02x:%02x:%02x:%02x",
i, p_leave->mac[i][0], p_leave->mac[i][1],
p_leave->mac[i][2], p_leave->mac[i][3],
p_leave->mac[i][4], p_leave->mac[i][5]);
at_command_at_response_to_proto(AT_RESP_OK, p_buf,
data_len, false);
}
data_len = iot_sprintf((char *)p_buf,
"\r\nTotal %d network leave!", total);
} else {
data_len = iot_sprintf((char *)p_buf,
"\r\nLeave network MAC:%02x:%02x:%02x:%02x:%02x:%02x!",
p_leave->mac[0][0], p_leave->mac[0][1], p_leave->mac[0][2],
p_leave->mac[0][3], p_leave->mac[0][4], p_leave->mac[0][5]);
}
/* Store new temp device info. CCO and STA update online device list only. */
if (at_command_context.dev_type == IOT_PLC_DEV_ROLE_CCO)
{
total = p_leave->cnt;
for (i = 0; i < total; i++)
{
new_dev_info.dev_role= IOT_PLC_DEV_ROLE_STA;
iot_mac_addr_cpy(new_dev_info.mac, p_leave->mac[i]);
if (-1 == (dev_tb_index = at_command_check_online_mac_exists
(new_dev_info.mac, p_dev_list->dev, p_dev_list->valid_dev_cnt)))
{
DERROR("MAC Not Exist!");
}
else
{
/* CCO update online device list only. */
at_command_del_dev_from_online(p_dev_list, dev_tb_index);
}
}
}
else
{
new_dev_info.dev_role= IOT_PLC_DEV_ROLE_CCO;
iot_mac_addr_cpy(new_dev_info.mac, p_leave->mac[0]);
if (-1 == (dev_tb_index = at_command_check_online_mac_exists
(new_dev_info.mac, p_dev_list->dev, p_dev_list->valid_dev_cnt)))
{
DERROR("MAC Not Exist!");
}
else
{
/* STA update online device list only. */
at_command_del_dev_from_online(p_dev_list, dev_tb_index);
}
}
}
} else {
data_len = iot_sprintf((char *)p_buf,
"\r\nConifg %s network %s!",
(PLCTXRX_CID_JOIN_NETWORK == p_resp->cid.cid) ? "join" : "leave",
(PLCTXRX_RESP_OK == p_resp->resp) ? "successfully" : "failed");
}
ret = (PLCTXRX_RESP_OK == p_resp->resp) ? AT_RESP_OK : AT_RESP_ERROR;
at_command_at_response_to_proto(ret, p_buf, data_len, true);
iot_pkt_free(p_pkt);
return;
}
/* Operating the customer flash info saved in the AT layer. */
void at_handle_command_flash(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_pkt, *p_resp_pkt;
uint32_t i, data_offset, data_len;
uint8_t *op_data;
uint32_t op_ret;
uint8_t *rsp_data;
uint32_t rsp_data_len;
/* Select the appropriate buffer size for print buffer. */
if((NULL == (p_resp_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE, AT_COMMAND_MID)))
|| (NULL == (p_pkt = iot_pkt_alloc(AT_CUST_FLASH_MAX_OP_BUF_SIZE,
AT_COMMAND_MID))))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
op_data = iot_pkt_data(p_pkt);
rsp_data = iot_pkt_data(p_resp_pkt);
/* Check the validity of the parameters. */
if ((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
{
goto ERROR_INVALID_ARG;
}
if(AT_OP_SET == opcode)
{
if (0 == iot_strcmp((char *)argv[0], USER_INPUT_READ_STR))
{
if ((argc != 3)
|| (at_command_uint32_2_digtal(argv[1], &data_offset) <= 0)
|| (at_command_uint32_2_digtal(argv[2], &data_len) <= 0)
|| (data_len < 1)
|| (data_len > AT_CUST_FLASH_MAX_RD_WR_BYTES)
|| (data_offset + data_len > AT_CUST_FLASH_USER_OP_MAX_SIZE))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_flash_read(
AT_CUST_FLASH_USER_OP_START_OFFSET + data_offset,
data_len, op_data);
if (ERR_OK == op_ret)
{
rsp_data_len = 0;
rsp_data_len += iot_sprintf ((char *)(rsp_data + rsp_data_len), "\r\n");
for(i = 0; i < data_len ; i++)
{
/* Reset print cache every 8byte, linefeed added for readability. */
if ((0 == (i % AT_FLASH_DIS_ON_SAME_ROW_DATA_NUM))
&& (i > 0))
{
at_command_at_response_to_proto
(AT_RESP_OK, rsp_data, rsp_data_len, false);
rsp_data_len = 0;
rsp_data_len += iot_sprintf
((char *)(rsp_data + rsp_data_len), "\r\n");
}
rsp_data_len += iot_sprintf((char *)(rsp_data + rsp_data_len),
"%02X ", op_data[i]);
}
at_command_at_response_to_proto
(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nRead failed!");
at_command_at_response_to_proto
( AT_RESP_ERROR, rsp_data, rsp_data_len, true);
}
}
else if (0 == iot_strcmp((char *)argv[0], USER_INPUT_WRITE_STR))
{
if ((argc != 3)
|| (at_command_uint32_2_digtal(argv[1], &data_offset) <= 0)
|| (0 == (data_len = at_command_string_2_digtal
(argv[2], op_data, AT_CUST_FLASH_MAX_OP_BUF_SIZE)))
|| (data_len > AT_CUST_FLASH_MAX_RD_WR_BYTES)
|| (data_offset + data_len > AT_CUST_FLASH_USER_OP_MAX_SIZE))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_flash_write(
AT_CUST_FLASH_USER_OP_START_OFFSET + data_offset,
data_len, op_data);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nWrite %s!", (ERR_OK == op_ret) ? "successfully" : "failed");
at_command_at_response_to_proto
((ERR_OK == op_ret) ? AT_RESP_OK : AT_RESP_ERROR,
rsp_data, rsp_data_len, true);
}
else
{
goto ERROR_INVALID_ARG;
}
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nMax size of customer flash that user can use is %d bytes.",
AT_CUST_FLASH_USER_OP_MAX_SIZE);
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
iot_pkt_free(p_pkt);
iot_pkt_free(p_resp_pkt);
return;
ERROR_INVALID_ARG:
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
iot_pkt_free(p_pkt);
iot_pkt_free(p_resp_pkt);
return;
}
void at_handle_command_spi(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_pkt;
at_spi_cfg_t curr_spi_cfg;
iot_spi_cfg_t spi_gpio;
uint32_t port, clk_pin, cs_pin, miso_pin, mosi_pin;
uint32_t spi_cfg_hex, tm_cfg_hex;
uint8_t dev_type, trs_mode, frm_fmt, dfrm_sz, cs_en;
uint32_t frq, rx_thd, tx_thd;
uint8_t scpol, scph, scph_tgl, sste;
uint32_t i;
uint32_t op_data_len, op_ret;
char rx_buf[AT_SPI_MAX_RD_WR_BYTES];
uint8_t tx_buf[AT_SPI_MAX_WR_BUF_SIZE];
uint8_t *rsp_data;
uint32_t rsp_data_len;
/*
Select the appropriate buffer size for print buffer, when spi read no more than 64 bytes,
one byte needs 3 chars to show (eg. _5E), so need choose the large buf size (256).
*/
if(NULL == (p_pkt = iot_pkt_alloc(AT_LARGE_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
os_mem_set(rx_buf, 0, sizeof(char) * AT_SPI_MAX_RD_WR_BYTES);
os_mem_set(tx_buf, 0, sizeof(uint8_t) * AT_SPI_MAX_WR_BUF_SIZE);
if(AT_OP_SET == opcode)
{
if (0 == iot_strcmp((char *)argv[0], USER_INPUT_READ_STR))
{
if (AT_SPI_INIT_COMPLETED == at_command_spi_cfg.inited)
{
if ((argc != 2)
|| (at_command_uint32_2_digtal(argv[1], &op_data_len) <= 0)
|| (op_data_len > AT_SPI_MAX_RD_WR_BYTES))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_spi_read_data(rx_buf, (uint16_t)op_data_len);
if (ERR_OK == op_ret)
{
rsp_data_len = 0;
for(i = 0; i < op_data_len ; i++)
{
rsp_data_len += iot_sprintf((char *)(rsp_data + rsp_data_len),
"%02X ", rx_buf[i]);
}
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSPI Read failed!");
at_command_at_response_to_proto(AT_RESP_ERROR,
rsp_data, rsp_data_len, true);
}
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSPI init uncompleted!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
}
else if (0 == iot_strcmp((char *)argv[0], USER_INPUT_WRITE_STR))
{
if (AT_SPI_INIT_COMPLETED == at_command_spi_cfg.inited)
{
if ((argc != 2)
|| (0 == (op_data_len = at_command_string_2_digtal
(argv[1], tx_buf, AT_SPI_MAX_WR_BUF_SIZE)))
|| (op_data_len > AT_SPI_MAX_RD_WR_BYTES))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_spi_write_data((char *)tx_buf,
(uint16_t)op_data_len);
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSPI Write %s!",
(ERR_OK == op_ret) ? "successfully" : "failed");
at_command_at_response_to_proto((ERR_OK == op_ret)
? AT_RESP_OK : AT_RESP_ERROR, rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSPI init uncompleted!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
}
else
{
if((argc < 10)
|| (at_command_uint32_2_digtal(argv[0], &port) <= 0)
|| (at_command_uint32_2_digtal(argv[1], &clk_pin) <= 0)
|| (at_command_uint32_2_digtal(argv[2], &cs_pin) <= 0)
|| (at_command_uint32_2_digtal(argv[3], &miso_pin) <= 0)
|| (at_command_uint32_2_digtal(argv[4], &mosi_pin) <= 0))
{
goto ERROR_INVALID_ARG;
}
if ((at_command_hex_2_digtal(argv[5], &spi_cfg_hex) <= 0)
|| (at_command_uint32_2_digtal(argv[6], &frq) <= 0)
|| (at_command_uint32_2_digtal(argv[7], &rx_thd) <= 0)
|| (at_command_uint32_2_digtal(argv[8], &tx_thd) <= 0)
|| (at_command_hex_2_digtal(argv[9], &tm_cfg_hex) <= 0))
{
goto ERROR_INVALID_ARG;
}
/* parse the combine spi config and timing hex string.*/
dev_type = spi_cfg_hex & 0x3;
trs_mode = (spi_cfg_hex >> 2) & 0x3;
frm_fmt = (spi_cfg_hex >> 4) & 0x3;
dfrm_sz = (spi_cfg_hex >> 6) & 0x1F;
cs_en = (spi_cfg_hex >> 11) & 0x1;
scpol = tm_cfg_hex & 0x1;
scph = (tm_cfg_hex >> 1) & 0x1;
scph_tgl = (tm_cfg_hex >> 2) & 0x1;
sste = (tm_cfg_hex >> 3) & 0x1;
if ((DEVICE_SPI0_MASTER != port) && (DEVICE_SPI1_MASTER != port)
&& (DEVICE_SPI0_SLAVER != port))
{
goto ERROR_INVALID_ARG;
}
if (((SPI_SLAVER != dev_type) && (SPI_MASTER != dev_type))
|| (trs_mode > TMOD_RECIEVER)
|| (trs_mode < TMOD_TRANCIEVER)
|| (FRM_STD != frm_fmt)
|| ((SPI_DFRAME_SIZE_8 != dfrm_sz)
&& (SPI_DFRAME_SIZE_16 != dfrm_sz)
&& (SPI_DFRAME_SIZE_32 != dfrm_sz)))
{
goto ERROR_INVALID_ARG;
}
curr_spi_cfg.inited = AT_SPI_INIT_COMPLETED;
curr_spi_cfg.port = port;
curr_spi_cfg.gpio.clk= clk_pin;
curr_spi_cfg.gpio.cs = cs_pin;
curr_spi_cfg.gpio.miso = miso_pin;
curr_spi_cfg.gpio.mosi = mosi_pin;
curr_spi_cfg.cfg.dev_type = dev_type;
curr_spi_cfg.cfg.trs_mode = trs_mode;
curr_spi_cfg.cfg.frm_fmt = frm_fmt;
curr_spi_cfg.cfg.dfrm_sz = dfrm_sz;
curr_spi_cfg.cfg.cs_en= cs_en;
curr_spi_cfg.cfg.frq = (int)frq;
curr_spi_cfg.cfg.rx_thd = (int)rx_thd;
curr_spi_cfg.cfg.tx_thd = (int)tx_thd;
curr_spi_cfg.tm.scpol = scpol;
curr_spi_cfg.tm.scph = scph;
curr_spi_cfg.tm.scph_tgl = scph_tgl;
curr_spi_cfg.tm.sste = sste;
if (0 ==
os_mem_cmp(&at_command_spi_cfg, &curr_spi_cfg, sizeof(spi_cfg)))
{
iot_pkt_free(p_pkt);
DINFOR("Set the same config!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
return;
}
os_mem_cpy(&at_command_spi_cfg, &curr_spi_cfg, sizeof(spi_cfg));
os_mem_cpy(&(spi_gpio.gpio), &(at_command_spi_cfg.gpio),
sizeof(iot_spi_gpio_sel_t));
iot_gpio_open_as_output(at_command_spi_cfg.gpio.clk);
iot_gpio_open_as_output(at_command_spi_cfg.gpio.cs);
iot_gpio_open_as_input(at_command_spi_cfg.gpio.miso);
iot_gpio_open_as_output(at_command_spi_cfg.gpio.mosi);
spi_gpio.port = 0;
(void)iot_spi_module_init(&spi_gpio);
(void)iot_spi_dev_register_detail
(at_command_spi_cfg.port, &(at_command_spi_cfg.cfg), \
&(at_command_spi_cfg.tm), NULL, NULL, 0x0);
rsp_data = iot_pkt_data(p_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nSet spi is OK, spi port %d config is:" \
"\r\nclk_pin:%d, cs_pin:%d, miso_pin:%d, mosi_pin:%d" \
"\r\ndev type:%s, trans mode:%d"
"\r\nframe format:%d, data frame size:%d, cs_en:%d" \
"\r\nfrq:%d, rx thd:%d, tx thd:%d" \
"\r\nscpol:%d, scph:%d, scph_tgl:%d, sste:%d",
at_command_spi_cfg.port,
at_command_spi_cfg.gpio.clk, at_command_spi_cfg.gpio.cs,
at_command_spi_cfg.gpio.miso, at_command_spi_cfg.gpio.mosi,
at_command_spi_cfg.cfg.dev_type ? "Slaver" : "Master",
at_command_spi_cfg.cfg.trs_mode, at_command_spi_cfg.cfg.frm_fmt,
at_command_spi_cfg.cfg.dfrm_sz, at_command_spi_cfg.cfg.cs_en & 0x1,
at_command_spi_cfg.cfg.frq, at_command_spi_cfg.cfg.rx_thd,
at_command_spi_cfg.cfg.tx_thd, (at_command_spi_cfg.tm.scpol & 0x1),
(at_command_spi_cfg.tm.scph & 0x1),
(at_command_spi_cfg.tm.scph_tgl & 0x1),
(at_command_spi_cfg.tm.sste & 0x1));
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
}
else
{
if (AT_SPI_INIT_COMPLETED == at_command_spi_cfg.inited)
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nSPI port %d config is:" \
"\r\nclk_pin:%d, cs_pin:%d, miso_pin:%d, mosi_pin:%d" \
"\r\ndev type:%s, trans mode:%d"
"\r\nframe format:%d, data frame size:%d, cs_en:%d" \
"\r\nfrq:%d, rx thd:%d, tx thd:%d" \
"\r\nscpol:%d, scph:%d, scph_tgl:%d, sste:%d",
at_command_spi_cfg.port,
at_command_spi_cfg.gpio.clk, at_command_spi_cfg.gpio.cs,
at_command_spi_cfg.gpio.miso, at_command_spi_cfg.gpio.mosi,
at_command_spi_cfg.cfg.dev_type ? "Slaver" : "Master",
at_command_spi_cfg.cfg.trs_mode, at_command_spi_cfg.cfg.frm_fmt,
at_command_spi_cfg.cfg.dfrm_sz, at_command_spi_cfg.cfg.cs_en & 0x1,
at_command_spi_cfg.cfg.frq, at_command_spi_cfg.cfg.rx_thd,
at_command_spi_cfg.cfg.tx_thd, (at_command_spi_cfg.tm.scpol & 0x1),
(at_command_spi_cfg.tm.scph & 0x1),
(at_command_spi_cfg.tm.scph_tgl & 0x1),
(at_command_spi_cfg.tm.sste & 0x1));
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSPI init uncompleted!");
}
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
iot_pkt_free(p_pkt);
return;
ERROR_INVALID_ARG:
iot_pkt_free(p_pkt);
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
uint32_t at_command_iic_write_8bit_reg(uint8_t addr, uint8_t reg, uint8_t val)
{
char buf[2];
buf[0] = reg;
buf[1] = val;
if(ERR_OK != iot_i2c_write(at_command_iic_cfg.port, addr, buf, 2))
{
return ERR_FAIL;
}
os_delay(10);
return ERR_OK;
}
uint32_t at_command_iic_write_16bit_reg(uint8_t addr, uint16_t reg, uint16_t val)
{
char buf[4];
buf[0] = (reg >> 8) & 0xFF;
buf[1] = reg & 0xFF;
buf[2] = (val >> 8) & 0xFF;
buf[3] = val & 0xFF;
if(ERR_OK != iot_i2c_write(at_command_iic_cfg.port, addr, buf, 4))
{
return ERR_FAIL;
}
os_delay(10);
return ERR_OK;
}
uint32_t at_command_iic_read_8bit_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len)
{
char buf[1];
buf[0] = reg;
if(ERR_OK != iot_i2c_write(at_command_iic_cfg.port, addr, buf, 1))
{
return ERR_FAIL;
}
os_delay(10);
if(ERR_OK != iot_i2c_read(at_command_iic_cfg.port, addr, (char *)data, len))
{
return ERR_FAIL;
}
return ERR_OK;
}
uint32_t at_command_iic_read_16bit_reg(uint8_t addr, uint16_t reg, uint8_t *data, uint8_t len)
{
char buf[2];
buf[0] = (reg >> 8) & 0xFF;
buf[1] = reg & 0xFF;
if(ERR_OK != iot_i2c_write(at_command_iic_cfg.port, addr, buf, 2))
{
return ERR_FAIL;
}
os_delay(10);
if(ERR_OK != iot_i2c_read(at_command_iic_cfg.port, addr, (char *)data, len))
{
return ERR_FAIL;
}
return ERR_OK;
}
uint32_t at_command_iic_init(at_iic_cfg_t *cfg)
{
if (NULL == cfg)
{
DERROR("Invalid argument!");
return ERR_FAIL;
}
iot_i2c_module_cfg_t iic_cfg;
iic_cfg.baud = cfg->baud;
iic_cfg.gpio.scl = cfg->gpio.scl;
iic_cfg.gpio.sda = cfg->gpio.sda;
iic_cfg.nack_wait_num = cfg->nack_wait_num;
iic_cfg.port = cfg->port;
// iot_gpio_open_as_output can cancel the function bound on the GPIO.
// This is not necessary if those GPIOs are not multiplex.
if((ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.scl))
|| (ERR_OK != iot_gpio_open_as_output(iic_cfg.gpio.sda)))
{
return ERR_FAIL;
}
if(ERR_OK != iot_i2c_module_init(&iic_cfg))
{
return ERR_FAIL;
}
return ERR_OK;
}
/* Operating the IIC. */
void at_handle_command_iic(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_pkt;
at_iic_cfg_t new_iic_cfg;
uint32_t port, speed, nack_wait_num;
uint32_t scl_pin, sda_pin, reg_addr_len;
uint32_t slave_addr, reg_addr;
uint32_t read_data_len, write_val;
uint8_t read_data_buf[AT_IIC_MAX_RD_WR_BYTES];
uint32_t op_ret = ERR_OK;
uint32_t i;
uint8_t *rsp_data;
uint32_t rsp_data_len;
os_mem_set(read_data_buf, 0, AT_IIC_MAX_RD_WR_BYTES);
/*
Select the appropriate buffer size for print buffer, when spi read no more than 64 bytes,
one byte needs 3 chars to show (eg. _5E), so need choose the large buf size (256).
*/
if(NULL == (p_pkt = iot_pkt_alloc(AT_LARGE_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
/* Check the validity of the parameters. */
if ((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
{
goto ERROR_INVALID_ARG;
}
if(AT_OP_SET == opcode)
{
if (0 == iot_strcmp((char *)argv[0], USER_INPUT_READ_STR))
{
if (AT_IIC_INIT_COMPLETED == at_command_iic_cfg.inited)
{
if ((argc != 4)
|| (at_command_hex_2_digtal(argv[1], &slave_addr) <= 0)
|| (at_command_hex_2_digtal(argv[2], &reg_addr) <= 0)
|| (at_command_uint32_2_digtal(argv[3], &read_data_len) <= 0)
|| (read_data_len > AT_IIC_MAX_RD_WR_BYTES))
{
goto ERROR_INVALID_ARG;
}
DINFOR("reg_addr:%X, read_data_len:%d", reg_addr, read_data_len);
if (AT_IIC_OP_COMMON_LEN_1BYTE == at_command_iic_cfg.reg_addr_len)
{
/* 1BYTE reg addr should no more than max val. */
if (reg_addr > AT_IIC_OP_MAX_VAL_1BYTE)
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_iic_read_8bit_reg(slave_addr,
(uint8_t)reg_addr, read_data_buf, read_data_len);
}
else
{
/* 2BYTE reg addr should no more than max val. */
if (reg_addr > AT_IIC_OP_MAX_VAL_2BYTE)
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_iic_read_16bit_reg(slave_addr,
(uint16_t)reg_addr, read_data_buf, read_data_len);
}
if (ERR_OK == op_ret)
{
rsp_data_len = 0;
for(i = 0; i < read_data_len ; i++)
{
rsp_data_len += iot_sprintf((char *)(rsp_data + rsp_data_len),
"%02X ", read_data_buf[i]);
}
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nIIC Read failed!");
at_command_at_response_to_proto(AT_RESP_ERROR,
rsp_data, rsp_data_len, true);
}
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nIIC init uncompleted!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
}
else if (0 == iot_strcmp((char *)argv[0], USER_INPUT_WRITE_STR))
{
if (AT_IIC_INIT_COMPLETED == at_command_iic_cfg.inited)
{
if ((argc != 4)
|| (at_command_hex_2_digtal(argv[1], &slave_addr) <= 0)
|| (at_command_hex_2_digtal(argv[2], &reg_addr) <= 0)
|| (at_command_hex_2_digtal(argv[3], &write_val) <= 0))
{
goto ERROR_INVALID_ARG;
}
if (AT_IIC_OP_COMMON_LEN_1BYTE == at_command_iic_cfg.reg_addr_len)
{
/* 1BYTE reg addr and write value should no more than max val. */
if ((reg_addr > AT_IIC_OP_MAX_VAL_1BYTE)
|| (write_val > AT_IIC_OP_MAX_VAL_1BYTE))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_iic_write_8bit_reg(slave_addr,
(uint8_t)reg_addr, (uint8_t)write_val);
}
else
{
/* 2BYTE reg addr and write value should no more than max val. */
if ((reg_addr > AT_IIC_OP_MAX_VAL_2BYTE)
|| (write_val > AT_IIC_OP_MAX_VAL_2BYTE))
{
goto ERROR_INVALID_ARG;
}
op_ret = at_command_iic_write_16bit_reg(slave_addr,
(uint16_t)reg_addr, (uint16_t)write_val);
}
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nIIC Write %s!",
(ERR_OK == op_ret) ? "successfully" : "failed");
at_command_at_response_to_proto((ERR_OK == op_ret)
? AT_RESP_OK : AT_RESP_ERROR, rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nIIC init uncompleted!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
}
else
{
if ((argc != 6)
|| (at_command_uint32_2_digtal(argv[0], &port) <= 0)
|| (at_command_uint32_2_digtal(argv[1], &speed) <= 0)
|| (at_command_uint32_2_digtal(argv[2], &nack_wait_num) <= 0)
|| (at_command_uint32_2_digtal(argv[3], &scl_pin) <= 0)
|| (at_command_uint32_2_digtal(argv[4], &sda_pin) <= 0))
{
goto ERROR_INVALID_ARG;
}
if ((at_command_uint32_2_digtal(argv[5], &reg_addr_len) <= 0)
||((AT_IIC_OP_COMMON_LEN_1BYTE!= reg_addr_len)
&& (AT_IIC_OP_COMMON_LEN_2BYTE != reg_addr_len)))
{
goto ERROR_INVALID_ARG;
}
new_iic_cfg.inited = AT_IIC_INIT_UNCOMPLETED;
new_iic_cfg.port = port;
new_iic_cfg.baud= speed;
new_iic_cfg.nack_wait_num= nack_wait_num;
new_iic_cfg.gpio.scl= scl_pin;
new_iic_cfg.gpio.sda= sda_pin;
new_iic_cfg.reg_addr_len = reg_addr_len;
op_ret = at_command_iic_init(&new_iic_cfg);
if (ERR_OK == op_ret)
{
new_iic_cfg.inited = AT_IIC_INIT_COMPLETED;
/* save the current iic config info to the AT command layer. */
os_mem_cpy(&at_command_iic_cfg, &new_iic_cfg, sizeof(at_iic_cfg_t));
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nConfig IIC port %d successfully!" \
"\r\nbaudrate:%d kb, wait nack number:%d" \
"\r\nscl_pin:%d, sda_pin:%d, reg_addr_len:%dbyte.",
at_command_iic_cfg.port, at_command_iic_cfg.baud,
at_command_iic_cfg.nack_wait_num, at_command_iic_cfg.gpio.scl,
at_command_iic_cfg.gpio.sda, at_command_iic_cfg.reg_addr_len);
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nConfig IIC port %d failed!", new_iic_cfg.port);
at_command_at_response_to_proto(AT_RESP_ERROR,
rsp_data, rsp_data_len, true);
}
}
}
else
{
if (AT_IIC_INIT_COMPLETED == at_command_iic_cfg.inited)
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nThe IIC port %d config is:" \
"\r\nbaudrate:%d kb, wait nack number:%d" \
"\r\nscl_pin:%d, sda_pin:%d, reg_addr_len:%dbyte.",
at_command_iic_cfg.port, at_command_iic_cfg.baud,
at_command_iic_cfg.nack_wait_num, at_command_iic_cfg.gpio.scl,
at_command_iic_cfg.gpio.sda, at_command_iic_cfg.reg_addr_len);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nIIC init uncompleted!");
}
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
iot_pkt_free(p_pkt);
return;
ERROR_INVALID_ARG:
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
iot_pkt_free(p_pkt);
return;
}
void at_handle_command_gpiocfg(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_pkt;
uint32_t gpio_x;
uint32_t op_ret = ERR_OK;
uint8_t *rsp_data;
uint32_t rsp_data_len;
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
if(AT_OP_SET == opcode)
{
if((argc < 3)
|| (at_command_uint32_2_digtal(argv[0], &gpio_x) <= 0))
{
goto ERROR_INVALID_ARG;
}
if ((0 != iot_strcmp((char *)argv[1], USER_INPUT_GPIOCFG_INPUT_STR))
&& (0 != iot_strcmp((char *)argv[1], USER_INPUT_GPIOCFG_OUTPUT_STR)))
{
goto ERROR_INVALID_ARG;
}
if ((0 != iot_strcmp((char *)argv[2], USER_INPUT_GPIOCFG_PULLUP_STR))
&& (0 != iot_strcmp((char *)argv[2], USER_INPUT_GPIOCFG_PULLDOWN_STR)))
{
goto ERROR_INVALID_ARG;
}
if (0 == iot_strcmp((char *)argv[1], USER_INPUT_GPIOCFG_INPUT_STR))
{
op_ret |= iot_gpio_open_as_input(gpio_x);
}
else
{
op_ret |= iot_gpio_open_as_output(gpio_x);
}
if (0 != iot_strcmp((char *)argv[2], USER_INPUT_GPIOCFG_PULLUP_STR))
{
op_ret |= iot_gpio_set_pull_mode(gpio_x, GPIO_PULL_UP);
}
else
{
op_ret |= iot_gpio_set_pull_mode(gpio_x, GPIO_PULL_DOWN);
}
rsp_data_len = iot_sprintf((char *)rsp_data,"\r\nConfig gpio:%d is %s!",
gpio_x, (ERR_OK != op_ret) ? "failed" : "successfully");
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
else
{
goto ERROR_INVALID_ARG;
}
iot_pkt_free(p_pkt);
return;
ERROR_INVALID_ARG:
iot_pkt_free(p_pkt);
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
void at_handle_command_gpioval(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_pkt;
uint32_t gpio_x, gpio_val;
uint32_t op_ret = ERR_OK;
uint8_t *rsp_data;
uint32_t rsp_data_len;
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_pkt);
if(AT_OP_SET == opcode)
{
if((argc < 2)
|| (at_command_uint32_2_digtal(argv[0], &gpio_x) <= 0)
|| (at_command_uint32_2_digtal(argv[1], &gpio_val) <= 0))
{
goto ERROR_INVALID_ARG;
}
op_ret = iot_gpio_value_set(gpio_x, gpio_val);
rsp_data_len = iot_sprintf((char *)rsp_data, "\r\nSet gpio:%d, value:%d is %s!",
gpio_x, gpio_val, (ERR_OK != op_ret) ? "failed" : "successfully");
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
else
{
if((argc < 1)
|| (at_command_uint32_2_digtal(argv[0], &gpio_x) <= 0))
{
goto ERROR_INVALID_ARG;
}
gpio_val = iot_gpio_value_get(gpio_x);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nAT+GPIOVAL=%d, %d.", gpio_x, gpio_val);
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
}
iot_pkt_free(p_pkt);
return;
ERROR_INVALID_ARG:
iot_pkt_free(p_pkt);
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
#if (IOT_FLASH_SIZE >=2 )
void at_handle_cmd_sw_uartmode(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t *p_data;
uint32_t data_len;
iot_oem_base_cfg_t *oem_base_cfg;
iot_pkt_t *p_pkt;
if ((AT_OP_SET != opcode) || argc < 1 ||
iot_strcmp((char*)argv[0], STRING_ENABLE)) {
DERROR("Invalid argument! opcode=%d argc=%d", opcode, argc);
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT,
NULL, 0, true);
return;
}
/* save uart mode to GR_MCU_OP_MODE oem */
iot_oem_get_base_cfg(&oem_base_cfg);
DINFOR("get iotapp_mode=%d", oem_base_cfg->iotapp_mode);
oem_base_cfg->iotapp_mode = GR_MCU_OP_MODE;
if(iot_oem_set_base_cfg(oem_base_cfg))
{
DERROR("Set OEM UART mode Faild!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
} else {
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data,"system will reboot after "
"three seconds,and then uart will switch to GE mode\n");
DERROR("%s",p_data);
/* Just finish AT+PMODE with response. */
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
p_data, data_len, true);
iot_pkt_free(p_pkt);
/* delay three seconds and then reboot system*/
os_delay(3000);
iot_system_restart(IOT_SYS_RST_REASON_APP_REQ);
return;
}
}
#else
void at_handle_cmd_sw_uartmode(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
uint8_t *p_data;
uint32_t data_len;
iot_pkt_t *p_pkt;
if(NULL == (p_pkt = iot_pkt_alloc(AT_MID_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
p_data = iot_pkt_data(p_pkt);
data_len = iot_sprintf((char *)p_data,
"system not support switch to GE mode\n");
DERROR("%s",p_data);
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
p_data, data_len, true);
iot_pkt_free(p_pkt);
return;
}
#endif
#if PLC_SUPPORT_CCO_ROLE
/* Start/End group network. */
void at_handle_command_netgroup(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_rsp_pkt;
uint8_t *rsp_data;
uint32_t rsp_data_len;
custom_flash_info_t *p_flash = &uniform_flashinfo_at;
/* Check the validity of the parameters. */
if((AT_OP_SET != opcode)
|| (argc != 1)
|| (iot_strcmp((char *)argv[0], USER_INPUT_NETGROUP_START_STR)
&& iot_strcmp((char *)argv[0], USER_INPUT_NETGROUP_END_STR)))
{
DERROR("Invalid argument!");
at_command_at_response_to_proto
(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
return;
}
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_rsp_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE,
AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR,
NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_rsp_pkt);
if (0 == iot_strcmp((char *)argv[0], USER_INPUT_NETGROUP_START_STR))
{
if (AT_WL_CFG_STATE_ENABLE == at_command_context.wl_cfg_state)
{
/* 1st: empty whitelist in CVG layer. */
at_command_cvg_wl_add_del(AT_WL_ACTION_DEL, NULL, false);
/* 2nd: empty device list saved in flash. */
p_flash->dev_cnt = 0;
os_mem_set(&(p_flash->dev_tbl), 0, AT_STA_DEV_MAX * sizeof(proto_dev_t));
if (ERR_OK != at_command_uniform_flashsave(p_flash))
{
DERROR("Update device list saved in flash failed!");
}
/* 3rd: disable whitelist, do not need to handle cmd confirm. */
at_command_cvg_wl_en_disable(AT_WL_ACTION_DISABLE, false);
/* Update the whitelist config enable/disable state. */
at_command_context.wl_cfg_state = AT_WL_CFG_STATE_DISABLE;
}
}
else
{
/* 1st: save online device list to flash whitelist and set to CVG layer. */
at_command_online_dev_list_save2flash();
os_delay(AT_WL_OP_DELAY_MS);
/* 2nd: enable whitelist, do not need to handle cmd confirm. */
at_command_cvg_wl_en_disable(AT_WL_ACTION_ENABLE, false);
/* Update the whitelist config enable/disable state. */
at_command_context.wl_cfg_state = AT_WL_CFG_STATE_ENABLE;
}
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nGroup network, whitelist operation state is ok!");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
iot_pkt_free(p_rsp_pkt);
return;
}
#else
/* Start/End group network. */
void at_handle_command_netgroup(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_rsp_pkt;
uint8_t *rsp_data;
uint32_t rsp_data_len;
(void)opcode;
(void)argc;
(void)argv;
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_rsp_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE,
AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR,
NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_rsp_pkt);
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nAT+NETGROUP, only for CCO, not supported on STA!");
at_command_at_response_to_proto(AT_RESP_OK, rsp_data, rsp_data_len, true);
iot_pkt_free(p_rsp_pkt);
return;
}
#endif
#if SUPPORT_HOST_PORT_ETH
void at_handle_command_host_port(uint32_t opcode, uint32_t argc, uint8_t *argv[])
{
iot_pkt_t *p_rsp_pkt;
uint8_t *rsp_data;
uint32_t rsp_data_len;
uint8_t input_host_port;
iot_oem_base_cfg_t *oem_base_cfg;
/* Select the appropriate buffer size for print buffer. */
if(NULL == (p_rsp_pkt = iot_pkt_alloc(AT_SMALL_BUF_SIZE, AT_COMMAND_MID)))
{
DERROR("No memory!");
at_command_at_response_to_proto(AT_RESP_ERROR, NULL, 0, true);
return;
}
rsp_data = iot_pkt_data(p_rsp_pkt);
/* Check the validity of the parameters. */
if ((AT_OP_QUERY != opcode) && (AT_OP_SET != opcode))
{
goto ERROR_INVALID_ARG;
}
iot_oem_get_base_cfg(&oem_base_cfg);
if(AT_OP_SET == opcode)
{
if((argc != 1)
|| (iot_strcmp((char *)argv[0], USER_INPUT_HOST_PORT_UART_STR)
&& iot_strcmp((char *)argv[0], USER_INPUT_HOST_PORT_ETH_STR)))
{
goto ERROR_INVALID_ARG;
}
if (0 == iot_strcmp((char *)argv[0], USER_INPUT_HOST_PORT_UART_STR))
{
input_host_port = HOST_PORT_UART;
}
else
{
input_host_port = HOST_PORT_ETH;
}
if (oem_base_cfg->host_port == input_host_port)
{
DINFOR("Set the same config!");
at_command_at_response_to_proto(AT_RESP_OK, NULL, 0, true);
}
else
{
/* Save host port to oem. */
oem_base_cfg->host_port = input_host_port;
if (ERR_OK != iot_oem_set_base_cfg(oem_base_cfg))
{
DERROR("set oem cfg host port error\n");
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nSet host port failed!");
at_command_at_response_to_proto(AT_RESP_ERROR,
rsp_data, rsp_data_len, true);
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nSet host port successfully!" \
"\r\nSystem will reboot after 3s, host port will use %s.",
(input_host_port == HOST_PORT_ETH) ? "ETH" : "UART");
/* Just finish AT+HOSTPORT with response. */
at_command_at_response_to_proto(AT_RESP_FORCE_ECHO,
rsp_data, rsp_data_len, true);
iot_pkt_free(p_rsp_pkt);
/* Delay three seconds and then reboot system */
os_delay(3000);
iot_system_restart(IOT_SYS_RST_REASON_APP_REQ);
}
}
}
else
{
rsp_data_len = iot_sprintf((char *)rsp_data,
"\r\nCurrent host port is %s!",
(oem_base_cfg->host_port == HOST_PORT_ETH)
? "ETH" : "UART");
at_command_at_response_to_proto(AT_RESP_OK,
rsp_data, rsp_data_len, true);
}
iot_pkt_free(p_rsp_pkt);
return;
ERROR_INVALID_ARG:
DERROR("Invalid argument!");
at_command_at_response_to_proto(AT_RESP_INVALID_ARGUMENT, NULL, 0, true);
iot_pkt_free(p_rsp_pkt);
return;
}
#endif /* end SUPPORT_HOST_PORT_ETH */
#else /* INCLUDE_AT_COMMAND_MODULE */
uint8_t iot_at_command_plc_send_response_to_at(iot_pkt_t *p_resp_pkt)
{
iot_pkt_free(p_resp_pkt);
return ERR_OK;
}
uint8_t iot_at_command_proto_send_to_at(uint8_t *buf, uint16_t blen)
{
(void)buf;
(void)blen;
return ERR_OK;
}
#endif
#endif