5745 lines
171 KiB
C
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], ×_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], ®_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], ®_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], ®_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
|