1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-03-30     chenyong     first version
9  * 2018-08-17     chenyong     multiple client support
10  */
11 
12 #ifndef __AT_H__
13 #define __AT_H__
14 
15 #include <stddef.h>
16 #include <rtthread.h>
17 #include <rtdevice.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #define AT_SW_VERSION                  "1.3.1"
24 
25 #define AT_CMD_NAME_LEN                16
26 
27 #ifndef AT_SERVER_RECV_BUFF_LEN
28 #define AT_SERVER_RECV_BUFF_LEN        256
29 #endif
30 
31 #ifndef AT_SERVER_DEVICE
32 #define AT_SERVER_DEVICE               "uart2"
33 #endif
34 
35 /* the maximum number of supported AT clients */
36 #ifndef AT_CLIENT_NUM_MAX
37 #define AT_CLIENT_NUM_MAX              1
38 #endif
39 
40 #define AT_CMD_EXPORT(_name_, _args_expr_, _test_, _query_, _setup_, _exec_)   \
41     rt_used static const struct at_cmd __at_cmd_##_test_##_query_##_setup_##_exec_ rt_section("RtAtCmdTab") = \
42     {                                                                          \
43         _name_,                                                                \
44         _args_expr_,                                                           \
45         _test_,                                                                \
46         _query_,                                                               \
47         _setup_,                                                               \
48         _exec_,                                                                \
49     };
50 
51 enum at_status
52 {
53     AT_STATUS_UNINITIALIZED = 0,
54     AT_STATUS_INITIALIZED,
55     AT_STATUS_CLI,
56 };
57 typedef enum at_status at_status_t;
58 
59 #ifdef AT_USING_SERVER
60 enum at_result
61 {
62     AT_RESULT_OK = 0,                  /* AT result is no error */
63     AT_RESULT_FAILE = -1,              /* AT result have a generic error */
64     AT_RESULT_NULL = -2,               /* AT result not need return */
65     AT_RESULT_CMD_ERR = -3,            /* AT command format error or No way to execute */
66     AT_RESULT_CHECK_FAILE = -4,        /* AT command expression format is error */
67     AT_RESULT_PARSE_FAILE = -5,        /* AT command arguments parse is error */
68 };
69 typedef enum at_result at_result_t;
70 
71 struct at_cmd
72 {
73     char name[AT_CMD_NAME_LEN];
74     char *args_expr;
75     at_result_t (*test)(void);
76     at_result_t (*query)(void);
77     at_result_t (*setup)(const char *args);
78     at_result_t (*exec)(void);
79 };
80 typedef struct at_cmd *at_cmd_t;
81 
82 struct at_server
83 {
84     rt_device_t device;
85 
86     at_status_t status;
87     rt_err_t (*get_char)(struct at_server *server, char *ch, rt_int32_t timeout);
88     rt_bool_t echo_mode;
89 
90     char send_buffer[AT_SERVER_SEND_BUFF_LEN];
91     char recv_buffer[AT_SERVER_RECV_BUFF_LEN];
92     rt_size_t cur_recv_len;
93 
94 #if (!defined(RT_USING_SERIAL_V2))
95     rt_sem_t rx_notice;
96 #endif
97 
98     rt_thread_t parser;
99     void (*parser_entry)(struct at_server *server);
100 };
101 typedef struct at_server *at_server_t;
102 #endif /* AT_USING_SERVER */
103 
104 #ifdef AT_USING_CLIENT
105 enum at_resp_status
106 {
107     AT_RESP_OK = 0,                   /* AT response end is OK */
108     AT_RESP_ERROR = -1,               /* AT response end is ERROR */
109     AT_RESP_TIMEOUT = -2,             /* AT response is timeout */
110     AT_RESP_BUFF_FULL= -3,            /* AT response buffer is full */
111 };
112 typedef enum at_resp_status at_resp_status_t;
113 
114 struct at_response
115 {
116     /* response buffer */
117     char *buf;
118     /* the maximum response buffer size, it set by `at_create_resp()` function */
119     rt_size_t buf_size;
120     /* the length of current response buffer */
121     rt_size_t buf_len;
122     /* the number of setting response lines, it set by `at_create_resp()` function
123      * == 0: the response data will auto return when received 'OK' or 'ERROR'
124      * != 0: the response data will return when received setting lines number data */
125     rt_size_t line_num;
126     /* the count of received response lines */
127     rt_size_t line_counts;
128     /* the maximum response time */
129     rt_int32_t timeout;
130 };
131 
132 typedef struct at_response *at_response_t;
133 
134 struct at_client;
135 
136 /* URC(Unsolicited Result Code) object, such as: 'RING', 'READY' request by AT server */
137 struct at_urc
138 {
139     const char *cmd_prefix;
140     const char *cmd_suffix;
141     void (*func)(struct at_client *client, const char *data, rt_size_t size);
142 };
143 typedef struct at_urc *at_urc_t;
144 
145 struct at_urc_table
146 {
147     size_t urc_size;
148     const struct at_urc *urc;
149 };
150 typedef struct at_urc *at_urc_table_t;
151 
152 struct at_client
153 {
154     rt_device_t device;
155 
156     at_status_t status;
157     char end_sign;
158 
159     char *send_buf;
160     /* The maximum supported send cmd length */
161     rt_size_t send_bufsz;
162     /* The length of last cmd */
163     rt_size_t last_cmd_len;
164 
165     /* the current received one line data buffer */
166     char *recv_line_buf;
167     /* The length of the currently received one line data */
168     rt_size_t recv_line_len;
169     /* The maximum supported receive data length */
170     rt_size_t recv_bufsz;
171 
172     struct rt_event event;
173     struct rt_mutex lock;
174 
175     at_response_t resp;
176     at_resp_status_t resp_status;
177 
178     struct at_urc_table *urc_table;
179     rt_size_t urc_table_size;
180     const struct at_urc *urc;
181 
182     rt_thread_t parser;
183     rt_slist_t  list;
184 };
185 typedef struct at_client *at_client_t;
186 #endif /* AT_USING_CLIENT */
187 
188 #ifdef AT_USING_SERVER
189 /* AT server initialize and start */
190 int at_server_init(void);
191 
192 /* AT server send command execute result to AT device */
193 void at_server_printf(const char *format, ...);
194 void at_server_printfln(const char *format, ...);
195 void at_server_print_result(at_result_t result);
196 rt_size_t at_server_send(at_server_t server, const char *buf, rt_size_t size);
197 rt_size_t at_server_recv(at_server_t server, char *buf, rt_size_t size, rt_int32_t timeout);
198 
199 /* AT server request arguments parse */
200 int at_req_parse_args(const char *req_args, const char *req_expr, ...);
201 #endif /* AT_USING_SERVER */
202 
203 #ifdef AT_USING_CLIENT
204 
205 /* AT client initialize and start*/
206 int at_client_init(const char *dev_name, rt_size_t recv_bufsz, rt_size_t send_bufsz);
207 int at_client_deInit(const char *dev_name);
208 
209 /* ========================== multiple AT client function ============================ */
210 
211 /* get AT client object */
212 at_client_t at_client_get(const char *dev_name);
213 at_client_t at_client_get_first(void);
214 
215 /* AT client wait for connection to external devices. */
216 int at_client_obj_wait_connect(at_client_t client, rt_uint32_t timeout);
217 
218 /* AT client send or receive data */
219 rt_size_t at_client_obj_send(at_client_t client, const char *buf, rt_size_t size);
220 rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout);
221 
222 /* set AT client a line end sign */
223 void at_obj_set_end_sign(at_client_t client, char ch);
224 
225 /* Set URC(Unsolicited Result Code) table */
226 int at_obj_set_urc_table(at_client_t client, const struct at_urc * table, rt_size_t size);
227 
228 /* AT client send commands to AT server and waiter response */
229 int at_obj_exec_cmd(at_client_t client, at_response_t resp, const char *cmd_expr, ...);
230 int at_obj_exec_cmd_format(at_client_t client, at_response_t resp, const char* format, const char *cmd_expr, ...);
231 
232 /* AT response object create and delete */
233 at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout);
234 void at_delete_resp(at_response_t resp);
235 at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout);
236 
237 /* AT response line buffer get and parse response buffer arguments */
238 const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line);
239 const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword);
240 int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char *resp_expr, ...);
241 int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...);
242 
243 /* ========================== single AT client function ============================ */
244 
245 /**
246  * NOTE: These functions can be used directly when there is only one AT client.
247  * If there are multiple AT Client in the program, these functions can operate on the first initialized AT client.
248  */
249 
250 #define at_exec_cmd(resp, ...)                   at_obj_exec_cmd(at_client_get_first(), resp, __VA_ARGS__)
251 #define at_exec_cmd_format(resp, format, ...)    at_obj_exec_cmd_format(at_client_get_first(), resp, format, __VA_ARGS__)
252 #define at_client_wait_connect(timeout)          at_client_obj_wait_connect(at_client_get_first(), timeout)
253 #define at_client_send(buf, size)                at_client_obj_send(at_client_get_first(), buf, size)
254 #define at_client_recv(buf, size, timeout)       at_client_obj_recv(at_client_get_first(), buf, size, timeout)
255 #define at_set_end_sign(ch)                      at_obj_set_end_sign(at_client_get_first(), ch)
256 #define at_set_urc_table(urc_table, table_sz)    at_obj_set_urc_table(at_client_get_first(), urc_table, table_sz)
257 
258 #endif /* AT_USING_CLIENT */
259 
260 /* ========================== User port function ============================ */
261 
262 #ifdef AT_USING_SERVER
263 /* AT server device reset */
264 void at_port_reset(void);
265 
266 /* AT server device factory reset */
267 void at_port_factory_reset(void);
268 #endif
269 
270 #ifdef __cplusplus
271 }
272 #endif
273 
274 #endif /* __AT_H__ */