Adapt to module features
After you adapt the hardware link and operating system for the AT driver framework, you must also adapt the module features. This topic describes how to adapt to these features.
Prerequisites
The hardware link and operating system have been adapted. For more information, see Adapt the hardware link and operating system.
Background information
Module features are primarily implemented through the module's AT instructions. These instructions vary among module suppliers. Therefore, you must identify the differences between modules to complete the adaptation.
The AT instructions for module communication can be divided into the following categories:
You can define a module device using these three types of AT instructions. For more information, see Structured definition of an AT module.
Control instructions
Control instructions are sent from the processor to the module in a send-and-receive format. The corresponding logic is then processed based on the response message that is received.
- Control command struct
core_at_cmd_item_t:The AT driver framework provides a processing framework for AT control instructions. To process a specific control instruction, you must define its processing logic according to the standard struct.
typedef struct { /* The format of the AT command to send. Used when the AT command requires input parameters. */ char *fmt; /* The AT command to send. Used when the set AT command does not require input parameters. */ char *cmd; /* The data length of the AT command. No assignment is needed. */ uint32_t cmd_len; /* The expected response data. By default, if this string is matched, the command is considered successful. */ char *rsp; /* The timeout period for receiving a response. If the timeout is reached, the execution fails. The default is 10000 milliseconds (10 seconds). */ uint32_t timeout_ms; /* The user-defined callback function to process the data after a response is received. */ at_rsp_handler_t handler; } core_at_cmd_item_t; - Custom processing function prototype
at_rsp_handler_t:Note- Execution is successful if the function returns the expected value defined by
.rsp. - Execution fails if the function returns an error message.
- Execution fails if the timeout period is reached.
typedef enum rsp_result_t { AT_RSP_SUCCESS, /* The AT command was executed successfully. */ AT_RSP_WAITING, /* Continue to wait for the command response. */ AT_RSP_FAILED, /* The AT command execution failed. */ } at_rsp_result_t; /** * @brief Defines the prototype of the user callback function for processing data after a response is received. * * @param[in] rsp The response data of the AT command. * * @return rsp_result_t */ typedef at_rsp_result_t (*at_rsp_handler_t)(char *rsp); - Execution is successful if the function returns the expected value defined by
- Example:
- To check the device's signal strength, you can send the following instruction from the processor to the module:
AT+CSQ - After the module receives the instruction, it returns the following signal strength information to the processor:
+CSQ: 10,99 OK - The corresponding control command struct is shown in the following example:
{ /* Check signal strength. */ .cmd = "AT+CSQ\r\n", /* No parameters are needed. Define the command. */ .rsp = "OK", /* The expected return string. A return of "OK" indicates success. */ .handler = at_csq_handler, /* Add custom response message processing. This is an optional parameter. */ .timeout_ms= 1000, /* Set a custom timeout of 1 second for this command. This is an optional parameter. */ }, - The custom processing function is shown in the following example:
static at_rsp_result_t at_csq_handler(char *rsp) { at_rsp_result_t res = AT_RSP_WAITING; /* By default, return a waiting status. */ int rssi = 0, ber = 0; char *line = NULL; line = strstr(rsp, "+CSQ"); /* Get the signal strength. If the strength is less than 5, return a failure. Otherwise, return a success. */ if(line != NULL && sscanf(line, "+CSQ: %d,%d\r\n", &rssi, &ber)) { if(rssi < 5) { res = AT_RSP_FAILED; }else { res = AT_RSP_SUCCESS; } } return res; }
- To check the device's signal strength, you can send the following instruction from the processor to the module:
Data reporting
- Structure of the module data reporting header:
/** * @brief The recognizable header for data actively reported by the AT module. */ typedef struct { /* The matching header identifier. A match indicates that data will be reported. */ char *prefix; /* The matching package body. It should include socket_id and data_len, followed by the data. */ char *fmt; } core_at_recv_data_prefix; - Example:
- The module reports the following data instruction to the processor:
+MIPRTCP: 1,4,****Note+MIPRTCP: Indicates a data reporting command.+MIPRTCP: 1,4,****fd: Indicates that the connection with a file descriptor (fd) of1received 4 bytes of data. The****represents the reported TCP/IP data.
- Example code:
static core_at_recv_data_prefix at_recv = { .prefix = "+MIPRTCP", .fmt = "+MIPRTCP: %d,%d,", };
- The module reports the following data instruction to the processor:
Status reporting
The module reports information, such as error messages and network status changes, to the processor. The AT driver framework provides an interface to receive these messages. You can subscribe to the corresponding instructions and write the logic for the callback function to customize how this information is processed.
- Structure of the module status reporting data header:
/** * @brief AT active reporting command. */ typedef struct { /* The matching header for actively reported data. */ char *prefix; /* The user callback function for processing data after a response is received. */ at_urc_handler_t handle; } core_at_urc_item_t; - Example:
The following example shows a module reporting a TCP/IP disconnection to the processor.
- The module reports the following data instruction to the processor:
+MIPCLOSE: 1,0Note+MIPCLOSE: Indicates the reporting keyword.1,0: Indicates the socket number and status information.
- Example code for the status reporting data header structure:
{ .prefix = "+MIPCLOSED:", /* Status reporting match header. */ .handle = socket_status_urc_handle, /* Callback handler after a match. */ }, - Example code for defining the callback function:
static void socket_status_urc_handle(char *line) { int socket_id = 0, status = 0; if(sscanf(line, "+MIPCLOSED: %d,%d\r\n", &socket_id, &status)) { printf("URC id %d, status %d\r\n", socket_id, status); /* Notify the AT driver of the socket status change. */ core_at_socket_status(socket_id, CORE_AT_LINK_DISCONN); } }
- The module reports the following data instruction to the processor:
Structured definition of an AT module
When you define the data structure for an AT module device, note the following:
- A single feature may require multiple commands. Therefore, you must define control commands in a command table.
- Control commands can produce errors. Therefore, you must define a uniform error code
error_prefix. - AT module devices are compatible with the SSL feature. Therefore, you must define
ssl_cmd.
/** * @brief Structured data for an AT device. */ typedef struct { /* The list of module initialization commands. Has a default value. */ core_at_cmd_item_t *module_init_cmd; uint32_t module_init_cmd_size; /* The list of network initialization commands. */ core_at_cmd_item_t *ip_init_cmd; uint32_t ip_init_cmd_size; /* The list for opening a socket network. */ core_at_cmd_item_t *open_cmd; uint32_t open_cmd_size; /* The list of data sending commands. */ core_at_cmd_item_t *send_cmd; uint32_t send_cmd_size; /* The identifier for data actively reported by the module. When data reporting is detected, the data receiving flow is initiated. */ core_at_recv_data_prefix *recv; /* The list of socket closing commands. */ core_at_cmd_item_t *close_cmd; uint32_t close_cmd_size; /* The error identifier. If the error identifier is detected in the data returned by a control command, the execution fails. */ char *error_prefix; /* Subscribe to the processing of actively reported data from the module. Optional. */ core_at_urc_item_t *urc_register; uint32_t urc_register_size; /* The list of commands to enable SSL. Optional. */ core_at_cmd_item_t *ssl_cmd; uint32_t ssl_cmd_size; } at_device_t;- The following list describes the features supported by the AT module driver and provides example code for each feature:
- Module network initialization
/* Module initialization command table. */ static core_at_cmd_item_t at_ip_init_cmd_table[] = { { /* Set identity authentication parameters. */ .cmd = "AT+QICSGP=1,1,\"UNINET\",\"\",\"\",1\r\n", .rsp = "OK", }, { /* Deactivate the scenario. */ .cmd = "AT+QIDEACT=1\r\n", .rsp = "OK", }, { /* Activate the scenario. */ .cmd = "AT+QIACT=1\r\n", .rsp = "OK", }, { /* Query scenario activation. */ .cmd = "AT+QIACT?\r\n", .rsp = "OK", }, }; - Open a socket connection
/* AT command table for establishing a TCP connection. */ static core_at_cmd_item_t at_connect_cmd_table[] = { { /* Establish a TCP connection. TODO: The aiot_at_nwk_connect interface will organize this AT command. */ .fmt = "AT+QIOPEN=1,%d,\"TCP\",\"%s\",%d,0,1\r\n", .rsp = "+QIOPEN", }, }; - Send data
/* AT command table for sending data. */ static core_at_cmd_item_t at_send_cmd_table[] = { { .fmt = "AT+QISEND=%d,%d\r\n", .rsp = ">", }, { /* Pure data, no format. */ .rsp = "SEND OK", }, }; - Define the data receiving format
static core_at_recv_data_prefix at_recv = { .head = "+QIURC: \"recv\"", .body = ",%d,%d", .tail = "\r\n", }; - Close a socket connection
/* AT command table for closing a TCP connection. */ static core_at_cmd_item_t at_disconn_cmd_table[] = { { /* Close the TCP connection. */ .fmt = "AT+QICLOSE=%d\r\n", .rsp = "OK", } }; - Define the module device
at_device_t ec200_at_cmd = { .ip_init_cmd = at_ip_init_cmd_table, .ip_init_cmd_size = sizeof(at_ip_init_cmd_table) / sizeof(core_at_cmd_item_t), .open_cmd = at_connect_cmd_table, .open_cmd_size = sizeof(at_connect_cmd_table) / sizeof(core_at_cmd_item_t), .send_cmd = at_send_cmd_table, .send_cmd_size = sizeof(at_send_cmd_table) / sizeof(core_at_cmd_item_t), .close_cmd = at_disconn_cmd_table, .close_cmd_size = sizeof(at_disconn_cmd_table) / sizeof(core_at_cmd_item_t), .recv = &at_recv, .error_prefix = "ERROR", };
- Module network initialization
Test examples
After you adapt the AT driver framework, you must perform tests. For test examples, see Example 1: STM32+EC200S module.