ATSystem.c
12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/*
* ATSystem.c
*
* Created on: Nov 1, 2019
* Author: Yasin
*/
/*********************************************************************
* INCLUDES
*/
#include "ATSystem.h"
#include <string.h>
/*********************************************************************
* CONSTANTS
*/
#define AT_HEAD_STATE1 0x00
#define AT_HEAD_STATE2 0x01
#define AT_DATA_STATE 0x02
#define AT_FCS_STATE 0x03
#define AT_CMD_BUFF_MAX 150
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void AT_HandleCMD( uint8_t *msg_ptr );
static uint8_t AT_get_next_cmdUnit( AT_CmdUnit* cmdUnit, uint8_t start_point, uint8_t* msg );
static int AT_CmdCmp( AT_CmdUnit* cmdUnit, uint8_t* str2 );
static void AT_UpperCaseCmd( AT_CmdUnit *cmdUnit );
#if AT_FCS_VERIFY
static byte AT_UartCalcFCS( uint8_t *msg_ptr, uint8_t len );
#endif
void AT_Cmd_Help( uint8_t cmd_ptr, uint8_t* msg_ptr );
/*********************************************************************
* LOCAL VARIABLES
*/
uint8_t AT_RxBuffer[AT_CMD_BUFF_MAX]; // UART Rx buffer
uint8_t at_state = AT_HEAD_STATE1; // AT_command_Rx_state
uint8_t AT_templen = 0; // the length of AT_command
const AT_Cmd_t AT_Cmd_Arr[] = {
{"BLOAD", NULL, "Enter The Boot Loader Menu"},
{"HELP", AT_Cmd_Help, "show all the AT commands"},
};
const uint16_t AT_CMD_SZ = sizeof(AT_Cmd_Arr) / sizeof(AT_Cmd_Arr[0]);
/***************************************************************************************************
* @fn AT_Process
*
* @brief | Head | Data | End | FCS |
* | 2 | 0-Len | 1 | 1 |
* | AT | ? | '\r' | verify |
*
* @field processed by AT_HandleCMD() : Data + End('\r')
* @field verified by AT_UartCalcFCS(): Data + End('\r')
*
* Parses the data and send the data to correct place (AT or APP)
*
* @param port - UART port
* @param event - Event that causes the callback
*
*
* @return None
***************************************************************************************************/
void AT_Process(uint8_t ch)
{
/*
* due to the AT_Process may be re-entried during AT_HandleCMD aused by HallUARTPollISR,
* which is denergerous, As a result of some command ERROR, so we prevent the function from being re-entryed
*/
static uint8_t isProcessing = FALSE;
if (isProcessing) return;
isProcessing = TRUE;
switch (at_state) {
case AT_HEAD_STATE1:
if (ch == 'A' || ch == 'a')
at_state = AT_HEAD_STATE2;
break;
case AT_HEAD_STATE2:
if (ch == 'T' || ch == 't')
at_state = AT_DATA_STATE;
else if (ch == 'A' || ch == 'a')
at_state = AT_HEAD_STATE2;
else
at_state = AT_HEAD_STATE1;
break;
case AT_DATA_STATE:
#if AT_UART_BACKSPACE
if (ch == '\b' || ch == '\x7f')
{ // for backspace function, allow user to delete characters
if (AT_templen > 0)
AT_templen--;
break;
}
#endif
if (ch == '\r')
{
AT_RxBuffer[AT_templen++] = '\r';
#if AT_FCS_VERIFY
at_state = AT_FCS_STATE;
break;
#else
AT_HandleCMD(AT_RxBuffer);
memset(AT_RxBuffer, 0x00, AT_templen);
AT_templen = 0;
at_state = AT_HEAD_STATE1;
#endif
}
else
{
if (AT_templen < (AT_CMD_BUFF_MAX - 1)) {
AT_RxBuffer[AT_templen++] = ch;
// still in AT_DATA_STATE;
} else {
memset(AT_RxBuffer, 0, AT_CMD_BUFF_MAX);
AT_templen = 0;
at_state = AT_HEAD_STATE1;
}
}
break;
#if AT_FCS_VERIFY
case AT_FCS_STATE:
/* Make sure it's correct */
if ((AT_UartCalcFCS(AT_RxBuffer, AT_templen) == ch))
{
AT_HandleCMD(AT_RxBuffer);
osal_memset(AT_RxBuffer, 0x00, AT_templen);
AT_templen = 0;
}
else
{
AT_ERROR(AT_FATAL_ERROR); // SEND FCS ERROR MSG AT_FATAL_ERROR
}
/* Reset the state, send or discard the buffers at this point */
at_state = AT_HEAD_STATE1;
break;
#endif
default:
break;
}
isProcessing = FALSE;
}
#if AT_FCS_VERIFY
/***************************************************************************************************
* @fn AT_UartCalcFCS
*
* @brief Calculate the FCS of a message buffer by XOR'ing each byte.
* Remember to NOT include Head fields, so start at the CMD field.
*
* @param byte *msg_ptr - message pointer
* @param byte len - length (in bytes) of message
*
* @return result byte
***************************************************************************************************/
static byte AT_UartCalcFCS( uint8_t *msg_ptr, uint8_t len )
{
byte x;
byte xorResult;
xorResult = 0;
for ( x = 0; x < len; x++, msg_ptr++ )
xorResult = xorResult ^ *msg_ptr;
return ( xorResult );
}
#endif
/***************************************************************************************************
* @fn AT_HandleCMD
*
* @brief Parse the AT_commands and call it's response function
*
* @param byte *msg_ptr - message pointer
*
* @return None
***************************************************************************************************/
static void AT_HandleCMD( uint8_t *msg_ptr )
{
uint8_t cmd_ptr = 0;
uint16_t i;
AT_DEBUG("\r\n", 2);
AT_DEBUG(msg_ptr, strlen((char*)msg_ptr));
// Get next cmdUnit and upper case it
AT_CmdUnit cmdUnit;
cmd_ptr = AT_get_next_cmdUnit(&cmdUnit, cmd_ptr, msg_ptr);
AT_UpperCaseCmd(&cmdUnit);
// process the cmdUnit
if (cmdUnit.symbol == '\r') { // which means there is no followed operator or command
AT_OK();
}
else if (cmdUnit.symbol == '\0') {
AT_ERROR(AT_LACK_OPERATOR);
}
else if (cmdUnit.symbol == '+') {
for (i = 0; i < AT_CMD_SZ; i++) {
if (AT_CmdCmp(&cmdUnit, (uint8_t*)AT_Cmd_Arr[i].AT_Cmd_str) == 0) {
#if AT_DEBUG_INF_SHOW
AT_NEXT_LINE();
AT_RESP(AT_Cmd_Arr[i].ATCmdDescription, strlen(AT_Cmd_Arr[i].ATCmdDescription));
#endif
AT_Cmd_Arr[i].AT_CmdFn(cmd_ptr, msg_ptr);
break;
}
}
if (AT_CMD_SZ == i) {
if (AT_CmdCmp(&cmdUnit, (uint8_t*)"") == 0) {
AT_ERROR(AT_LACK_CMD);
} else {
AT_ERROR(AT_UNKNOWN_CMD);
}
}
}
else {
AT_ERROR(AT_INVALID_PARA);
}
}
/***************************************************************************************************
* @fn AT_UARTWriteErrMsg
*
* @brief Send error messages
* Respose :
* ERROR:<error code>
*
*
* @param uint8_t errCode - indicate different error
* @param uint8_t fn - type of error
*
* @return None
***************************************************************************************************/
void AT_UARTWriteErrMsg( uint8_t errCode )
{
uint8_t* errMsg_t = (uint8_t*)"\r\nERROR:XX\r\n";
uint8_t errMsg[sizeof("\r\nERROR:XX\r\n")];
uint8_t ch;
uint8_t* pStr = &errMsg[sizeof("\r\nERROR:")-1];
for (int i = 0; i < sizeof(errMsg); i++) {
errMsg[i] = errMsg_t[i];
}
ch = (errCode >> 4) & 0x0F;
*pStr++ = ch + ((ch < 10) ? '0' : '7');
ch = errCode & 0x0F;
*pStr++ = ch + ((ch < 10) ? '0' : '7');
AT_RESP(errMsg, sizeof("\r\nERROR:XX\r\n")-1);
}
/***************************************************************************************************
* @fn AT_get_next_cmdUnit
*
* @brief The command have servel unit, this funciton get the next unit
* and save it in cmdUnit(type of AT_CmdUnit, see in AT_UART.h)
*
* @param AT_CmdUnit* cmdUnit - the place to save the cmd unit
* @param uint8_t start_point - the point show the place we start scan the command
* @param uint8_t* msg - the command to scan
*
* @return start_point
***************************************************************************************************/
uint8_t AT_get_next_cmdUnit( AT_CmdUnit* cmdUnit, uint8_t start_point, uint8_t* msg )
{
cmdUnit->unitLen=0;
for(;;start_point++){
if(msg[start_point] == ' '|| msg[start_point] == '\0'){
continue;
}
else if((msg[start_point]<='z' && msg[start_point]>='a') ||
(msg[start_point]<='Z' && msg[start_point]>='A') ||
(msg[start_point]<='9' && msg[start_point]>='0')){
cmdUnit->symbol ='\0'; //indicate no operator
break;
}
else if(msg[start_point] == '\r'){ //indicate the end of one command
cmdUnit->symbol =msg[start_point];
return start_point;
}
else {
cmdUnit->symbol =msg[start_point];
start_point++;
break;
}
}
for(;;start_point++){
if(msg[start_point] == ' '|| msg[start_point] == '\0'){
continue;
}
else while((msg[start_point]<='z' && msg[start_point]>='a') ||
(msg[start_point]<='Z' && msg[start_point]>='A') ||
(msg[start_point]<='9' && msg[start_point]>='0') ) {
if(cmdUnit->unitLen==0) cmdUnit->unit = &msg[start_point];
cmdUnit->unitLen++;
start_point++;
}
return start_point;
}
}
/***************************************************************************************************
* @fn AT_CmdCmp
*
* @brief Compare with str2, if equal, return 0; else return cmdUnit.unit[i] - str2[i]
*
* @param AT_CmdUnit* cmdUnit - the cmd unit need to be upper cased
* @param uint8_t* str2 - the string to compare with
*
* @return int8
***************************************************************************************************/
int AT_CmdCmp( AT_CmdUnit* cmdUnit, uint8_t* str2 )
{
int i;
for(i = 0; i < cmdUnit->unitLen; i++) {
if (cmdUnit->unit[i] != str2[i]) {
return cmdUnit->unit[i] - str2[i];
}
}
return 0 - str2[cmdUnit->unitLen];
}
/***************************************************************************************************
* @fn AT_UpperCaseCmd
*
* @brief Upper case the command
*
* @param AT_CmdUnit* cmdUnit - the cmd unit need to be upper cased
*
* @return None
***************************************************************************************************/
void AT_UpperCaseCmd( AT_CmdUnit *cmdUnit )
{
uint8_t i;
for (i = 0; i < cmdUnit->unitLen; i++) {
if (cmdUnit->unit[i] <= 'z' && cmdUnit->unit[i] >= 'a') {
cmdUnit->unit[i] += ('A' - 'a');
}
}
}
#if AT_CMD_PATTERN_CHECK
static uint8_t AT_Pattern_Check( char* pattern, AT_CmdUnit* cmdUnitArr );
/***************************************************************************************************
* @fn AT_Pattern_Check
*
* @brief Check the command pattern
*
* @param char* pattern - the pattern to be checked
* @param AT_CmdUnit* cmdUnitArr - the command unit
*
* @return uint8_t
***************************************************************************************************/
uint8_t AT_Pattern_Check( char* pattern, AT_CmdUnit* cmdUnitArr )
{
uint8_t i=0;
for(;pattern[i+1]!='\0';i++) {
if(pattern[i] != cmdUnitArr[i].symbol){
if(cmdUnitArr[i].symbol =='\0') return AT_LACK_OPERATOR;
else if(cmdUnitArr[i].symbol =='\r') return AT_LACK_PARA;
else return AT_INVALID_PARA;
}
}
if(pattern[i]=='\r') {
if(cmdUnitArr[i].symbol!='\r') return AT_INVALID_PARA;
}
else{
if(pattern[i] != cmdUnitArr[i].symbol){
if(cmdUnitArr[i].symbol =='\0') return AT_LACK_OPERATOR;
else if(cmdUnitArr[i].symbol =='\r') return AT_LACK_PARA;
else return AT_INVALID_PARA;
}
}
return AT_NO_ERROR;
}
#endif
/*******************************************************************************
* @fn AT_Cmd_Help
*
* @brief AT+HELP - show all the AT commands
*
* @param uint8_t cmd_ptr - the point show the place we start scan the command
* @param uint8_t* msg_ptr - the message pointer
*
* @return None
******************************************************************************/
void AT_Cmd_Help( uint8_t cmd_ptr, uint8_t* msg_ptr )
{
AT_CmdUnit cmdUnitArr[1];
cmd_ptr = AT_get_next_cmdUnit(&cmdUnitArr[0], cmd_ptr, msg_ptr);
AT_PARSE_CMD_PATTERN_ERROR("\r",cmdUnitArr);
uint8_t i;
AT_NEW_LINE();
for(i = 0; i < AT_CMD_SZ; i++) {
// uint8_t j;
AT_NEXT_LINE();
AT_RESP("AT+", 3);
AT_RESP(AT_Cmd_Arr[i].AT_Cmd_str, strlen(AT_Cmd_Arr[i].AT_Cmd_str));
AT_RESP(".................", AT_CMD_HELP_DESC_OFFSET - strlen(AT_Cmd_Arr[i].AT_Cmd_str)-3);
AT_RESP(AT_Cmd_Arr[i].ATCmdDescription, strlen(AT_Cmd_Arr[i].ATCmdDescription));
}
AT_NEW_LINE();
AT_OK();
}