blob: db5744163220c7359807d1c5de98051bb3021f12 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2*(C) Copyright 2008 Marvell International Ltd.
3* All Rights Reserved
4******************************************************************************/
5/*****************************************************************************
6 * Utility Library
7 *
8 * DESCRIPTION
9 * ITU-T V.250 AT-command parser. Parses a stream of text looking for AT
10 * commands to process. When AT-commands are found they are parsed, a table
11 * lookup is performed, and application-supplied call-back functions are
12 * invoked.
13 *
14 * This parser supports both basic and extended AT commands. For basic AT
15 * commands this parser does not distinguish between "action", "set" or
16 * "get" requests, since the basic AT-command syntax does not specify which
17 * result is desired (instead this attribute is intrinsic to each AT-command).
18 * For extended AT commands this parser distinguishes between "action", "set"
19 * "get", and "query syntax" requests.
20 *
21 * OVERALL STRUCTURE
22 *
23 * .--------------. .--------------.
24 * | AT Manager * | | DTE Client * |
25 * | | `--------------'
26 * `--------------' ^
27 * | ^ |AT-commands
28 * | |utlAtGetParameterFunction_P v
29 * | |utlAtSetParameterFunction_P .-------------------------. .-------------------.
30 * | |utlAtSParameterFunction_P | DCE I/O Interface * | | Sound Interface * |
31 * | | `-------------------------' `-------------------'
32 * | | ^ | ^ ^
33 * | | utlAtDceIoConfigFunction_P| |utlAtParse() |utlAtReplyFunction_P |
34 * | | | v | |utlAtSoundConfigFunction_P
35 * | | .-------------------------. |
36 * | | | |-------------------'
37 * | `-----------------------------| AT PARSER (DCE) |<----------------------------.
38 * `------------------------------>| |<---------------. |
39 * utlAtParserOp() | |--------------. | v
40 * `-------------------------' | | ---------------------
41 * ^ | | | AT-commands Table *
42 * utlAtDriverEvent()| |utlAtDriverRequestFunction_P | | ---------------------
43 * utlAtCommandResponse()| |utlAtTxLineDataFunction_P | |
44 * | v | |
45 * .------------------------. | |
46 * | Raw Modem Adaptation * | | |
47 * `------------------------' | |utlAtRetrieveDialStringFunction_P
48 * ^ | |
49 * | utlAtSaveDialStringFunction_P| |
50 * v | |
51 * .--------------. v |
52 * | Raw Modem * | ---------------------
53 * `--------------' Dial String Storage
54 * ---------------------
55 * * == must be supplied by application using this AT parser
56 *******************************************************************************************/
57
58#include <ctype.h>
59#include <math.h>
60#include <stdarg.h>
61#include <stdio.h>
62#include <string.h>
63#include <strings.h>
64
65#include "utlTypes.h"
66#include "utlConvert.h"
67#include "utlError.h"
68#include "utlLinkedList.h"
69#include "utlMalloc.h"
70#include "utlTime.h"
71#include "utlTimer.h"
72#include "utlTrace.h"
73#include "utlVString.h"
74#include "utilities.h"
75
76#include "utlAtParser.h"
77#ifdef utlTEST
78# include <termios.h>
79# include "utlEventHandler.h"
80#endif
81#include "atcmd_mult.h"
82
83
84/*--- Configuration ---------------------------------------------------------*/
85
86/*--- version info ---*/
87#define utlAT_VERSION "2.04"
88
89/*--- maximum length of an AT-command response (in characters) ---*/
90#define utlAT_MAX_RESPONSE_LENGTH ((size_t)400)
91
92/*--- maximum length of connect-text string (in characters) ---*/
93#define utlAT_MAX_CONNECT_TEXT_LENGTH ((size_t)16)
94
95/*--- maximum possible number of parameters in an extended-AT command ---*/
96#define utlAT_MAX_PARAMETERS ((size_t)95)
97
98/*--- array of supported basic-AT command prefix characters ---*/
99#define utlAT_BASIC_COMMAND_PREFIXES "&"
100
101/*--- array of supported extended-AT command prefix characters ---*/
102#define utlAT_EXTENDED_COMMAND_PREFIXES "+*$%^"
103
104/*--- array of characters allowed in dial strings ---*/
105#define utlAT_DIALING_CHARACTERS "0123456789aAbBcCdD#*+,/\">gGiIlLpPsStTwW@!$"
106
107/*--- for tracing AT parsers ---*/
108#define utlTRACE_AT_PARSER "AT parsers"
109
110char revisionId[128] = "unknown";
111
112
113/*--- Data Types ------------------------------------------------------------*/
114
115typedef enum {
116 utlAT_RESULT_CODE_OK = 0,
117 utlAT_RESULT_CODE_CONNECT = 1,
118 utlAT_RESULT_CODE_RING = 2,
119 utlAT_RESULT_CODE_NO_CARRIER = 3,
120 utlAT_RESULT_CODE_ERROR = 4,
121 utlAT_RESULT_CODE_NO_DIAL_TONE = 6,
122 utlAT_RESULT_CODE_BUSY = 7,
123 utlAT_RESULT_CODE_NO_ANSWER = 8,
124 utlAT_RESULT_CODE_SUPPRESS = 100,
125 utlAT_RESULT_CODE_NULL
126} utlAtResultCode_T;
127
128typedef enum {
129 utlAT_STRING_STATE_PASS_THROUGH,
130 utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1,
131 utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2,
132} utlAtStringState_T;
133
134
135/*--- Global Variables ------------------------------------------------------*/
136
137/*--- Local Variables -------------------------------------------------------*/
138
139static utlLinkedList_T parsers = utlEMPTY_LINKED_LIST;
140
141/*****************************************************************************
142* FORWARD DECLARATIONS
143*****************************************************************************/
144
145static utlReturnCode_T utlAtReset(const utlAtParser_P parser_p);
146
147static utlReturnCode_T utlAtDceIoConfigEvent(const utlAtParser_P parser_p);
148
149static utlReturnCode_T utlAtSoundConfigEvent(const utlAtParser_P parser_p);
150
151static utlAtResultCode_T utlProcessSParameter(const utlAtParser_P parser_p,
152 const unsigned int parameter_num,
153 const unsigned int parameter_value);
154
155static utlReturnCode_T utlSendBasicSyntaxResultCode(const utlAtParser_P2c parser_p,
156 const utlAtResultCode_T code,
157 const bool ignore_state);
158
159static utlReturnCode_T utlGenerateFormattedGetResponse(const utlAtParser_P parser_p,
160 const char *command_name_p,
161 const utlAtParameterValue_P2c parameters_p,
162 const size_t num_parameters);
163
164static void utlAbandonAllPendingAsyncResponse(utlAtParser_P parser_p);
165
166unsigned int utlSendToProxy(char * cmdName,utlAtRequestType_T reqType ,const utlAtParser_P parser_p);
167
168/*****************************************************************************
169* APPLICATION-REPLACEABLE STUBS
170*****************************************************************************/
171
172/*--- dial-string storage ---*/
173static struct {
174 char location_name[utlAT_MAX_STORED_LOCATION_NAME_LENGTH + 1];
175 char dial_string[utlAT_MAX_STORED_DIAL_STRING_LENGTH + 1];
176} dial_string_storage[utlAT_MAX_STORED_DIAL_STRINGS];
177static bool dial_string_storage_initialized = false;
178
179char prxy_command_name[18] = {0};
180
181// monitor LPP failure caused by NULL parser_p
182#define LPP_DEBUG
183/*---------------------------------------------------------------------------*
184* FUNCTION
185* utlAtParserInitDialStringStorage()
186* INPUT
187* none
188* OUTPUT
189* none
190* RETURNS
191* nothing
192* DESCRIPTION
193* Initializes the AT Parser's internal dial string storage.
194*---------------------------------------------------------------------------*/
195static void utlAtParserInitDialStringStore(void)
196{
197 size_t i;
198
199 if (dial_string_storage_initialized == true)
200 return;
201
202 /*--- initialize internal static dial-string storage ---*/
203 for (i = 0; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
204 {
205 dial_string_storage[i].location_name[0] = '\0';
206 dial_string_storage[i].dial_string[0] = '\0';
207 }
208
209 dial_string_storage_initialized = true;
210}
211
212/*---------------------------------------------------------------------------*
213* FUNCTION
214* utlAtParserStoreSaveDialString(location_name_p, dial_string_p, arg_p)
215* INPUT
216* location_name_p == location to store dial-string to
217* dial_string_p == NULL pointer, or a pointer to the dial string to be
218* saved expressed as a null-terminated string
219* arg_p == pointer to user-defined data
220* OUTPUT
221* none
222* RETURNS
223* utlSUCCESS for success, otherwise utlFAILED
224* DESCRIPTION
225* Saves the dial string specified by `dial_string_p' to the AT Parser's
226* internal dial-string store. If `dial_string_p' is NULL, clears any
227* dial string previously saved to the specified location.
228*---------------------------------------------------------------------------*/
229static utlReturnCode_T utlAtParserStoreSaveDialString(const char *location_name_p,
230 const char *dial_string_p,
231 void *arg_p UNUSED)
232{
233 size_t i;
234 size_t insertion_i;
235
236 utlAssert(location_name_p != NULL);
237
238 if (dial_string_storage_initialized != true)
239 utlAtParserInitDialStringStore();
240
241 /*--- search for specified dial string (ignoring character case) ---*/
242 insertion_i = -1;
243 for (i = 0; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
244 {
245 int cmp;
246
247 /*--- no more filled entries? ---*/
248 if (dial_string_storage[i].location_name[0] == '\0')
249 break;
250
251 cmp = strcasecmp(location_name_p, dial_string_storage[i].location_name);
252
253 /*--- found an existing entry with the same location name? ---*/
254 if (cmp == 0)
255 {
256
257 /*--- if no dial-string was supplied, clear/remove the specified entry ---*/
258 if ((dial_string_p == NULL) || (strlen(dial_string_p) == (size_t)0))
259 {
260
261 for (; i < (utlAT_MAX_STORED_DIAL_STRINGS - 1); i++)
262 {
263 (void)strcpy(dial_string_storage[i].location_name, dial_string_storage[i + 1].location_name);
264 (void)strcpy(dial_string_storage[i].dial_string, dial_string_storage[i + 1].dial_string);
265 }
266 dial_string_storage[i].location_name[0] = '\0';
267 dial_string_storage[i].dial_string[0] = '\0';
268
269 return utlSUCCESS;
270 }
271
272 /*--- check that dial-string fits into static storage ---*/
273 if (strlen(dial_string_p) > utlAT_MAX_STORED_DIAL_STRING_LENGTH)
274 {
275 utlError(utlAtParserStoreSaveDialString, "Dial-string too long to save.");
276 return utlFAILED;
277 }
278
279 /*--- save dial string--- */
280 (void)strcpy(dial_string_storage[i].dial_string, dial_string_p);
281
282 return utlSUCCESS;
283 }
284
285 /*--- found where to insert new dial string? ---*/
286 if (cmp < 0)
287 {
288 insertion_i = i;
289
290 for (i++; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
291 if (dial_string_storage[i].location_name[0] == '\0')
292 break;
293
294 break;
295 }
296 }
297
298 /*--- was specified dial-string not found and is there no room for another dial string? ---*/
299 if (i >= utlAT_MAX_STORED_DIAL_STRINGS)
300 {
301
302 /*--- were we just going to clear the location anyway? ---*/
303 if ((dial_string_p == NULL) || (strlen(dial_string_p) == (size_t)0))
304 return utlSUCCESS;
305
306 utlError(utlAtParserStoreSaveDialString1, "Dial-string storage full.");
307 return utlFAILED;
308 }
309
310 /*--- check that dial-string fits into static storage ---*/
311 if ((strlen(location_name_p) > utlAT_MAX_STORED_LOCATION_NAME_LENGTH) ||
312 (strlen(dial_string_p) > utlAT_MAX_STORED_DIAL_STRING_LENGTH))
313 {
314 utlError(utlAtParserStoreSaveDialString2, "Location name and/or Dial-string too long to save.");
315 return utlFAILED;
316 }
317
318 /*--- insertion sort ---*/
319 if (insertion_i != (size_t)-1)
320 for (; i > insertion_i; i--)
321 {
322 (void)strcpy(dial_string_storage[i].location_name, dial_string_storage[i - 1].location_name);
323 (void)strcpy(dial_string_storage[i].dial_string, dial_string_storage[i - 1].dial_string);
324 }
325 (void)strcpy(dial_string_storage[i].location_name, location_name_p);
326 (void)strcpy(dial_string_storage[i].dial_string, dial_string_p);
327
328 return utlSUCCESS;
329}
330
331/*---------------------------------------------------------------------------*
332* FUNCTION
333* utlAtParserStoreRetrieveDialString(location_name_pp, dial_string_pp, arg_p)
334* INPUT
335* location_name_pp == pointer to where a location-name pointer resides
336* or a pointer to a NULL pointer
337* dial_string_pp == pointer to where a pointer to the retrieved dial
338* string should be placed
339* arg_p == pointer to user-defined data
340* OUTPUT
341* *location_name_pp == next unread location-name, or NULL
342* *dial_string_pp == pointer to the retrieved dial string, where the
343* dial string is expressed as a null-terminated
344* character string
345* RETURNS
346* utlSUCCESS for success, otherwise utlFAILED
347* DESCRIPTION
348* Retrieves a previously saved dial string from the AT Parser's internal
349* dial-string store. To allow dial strings to be seqentially retrieved
350* when the dial string location names are unknown, the first passed in
351* `location_name_pp' should be set to NULL. Upon return
352* `*location_name_pp' will be set to the next unread location name, and
353* `*dial_string_pp' will be null. All subsequent calls will always set
354* `*location_name_pp' to the next unread location name, and
355* `*dial_string_pp' to the dial string associated with the passed-in
356* location name. When this function returns from reading the last dial
357* string, `*location_name_pp' will be set to NULL.
358*---------------------------------------------------------------------------*/
359static utlReturnCode_T utlAtParserStoreRetrieveDialString(const char **location_name_pp,
360 const char **dial_string_pp,
361 void *arg_p UNUSED)
362{
363 size_t i;
364
365 utlAssert(location_name_pp != NULL);
366
367 if (dial_string_storage_initialized != true)
368 utlAtParserInitDialStringStore();
369
370 /*--- fetch location name for first filled slot? ---*/
371 if (*location_name_pp == NULL)
372 {
373
374 /*--- search for first filled location ---*/
375 for (i = 0; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
376 if (dial_string_storage[i].location_name[0] != '\0')
377 {
378 *location_name_pp = dial_string_storage[i].location_name;
379 break;
380 }
381
382 if ( dial_string_pp != NULL)
383 *dial_string_pp = NULL;
384
385 return utlSUCCESS;
386
387 }
388
389 utlAssert(dial_string_pp != NULL);
390
391 /*--- search for specified dial string (ignoring character case) ---*/
392 for (i = 0; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
393 if (strcasecmp(*location_name_pp, dial_string_storage[i].location_name) == 0)
394 break;
395
396 /*--- nothing found? ---*/
397 if (i >= utlAT_MAX_STORED_DIAL_STRINGS)
398 {
399 *location_name_pp = NULL;
400 *dial_string_pp = NULL;
401
402 return utlSUCCESS;
403 }
404
405 *location_name_pp = NULL;
406 *dial_string_pp = dial_string_storage[i].dial_string;
407
408 /*--- search for next unread dial string (ignoring character case) ---*/
409 for (i++; i < utlAT_MAX_STORED_DIAL_STRINGS; i++)
410 if (dial_string_storage[i].location_name[0] != '\0')
411 {
412 *location_name_pp = dial_string_storage[i].location_name;
413 break;
414 }
415
416 return utlSUCCESS;
417}
418
419/*---------------------------------------------------------------------------*
420* FUNCTION
421* utlNextAvailableXID()
422* INPUT
423* none
424* OUTPUT
425* none
426* RETURNS
427* a transaction ID
428* DESCRIPTION
429* Fetches the next available (unused) transaction ID. The transaction
430* ID is a 32-bit integer that we allow to wrap. We assume that by the
431* time the integer has wrapped, the oldest values are no longer in use.
432* Assuming a consumption rate of 50 transaction ID's per second, the
433* value would wrap in about 990 days.
434*
435* Transaction ID's 0 and utlFAILED are reserved and thus never used.
436*---------------------------------------------------------------------------*/
437static unsigned int utlNextAvailableXID(void)
438{
439 static unsigned int next_free_xid = 1;
440 static pthread_mutex_t xid_mutex = PTHREAD_MUTEX_INITIALIZER;
441
442 unsigned int xid;
443 bool unique;
444
445 do {
446 utlAtParser_P parser_p;
447
448 pthread_mutex_lock(&xid_mutex);
449 next_free_xid++;
450 /*--- fetch next free transaction ID ---*/
451 xid = next_free_xid;
452 pthread_mutex_unlock(&xid_mutex);
453
454 unique = (next_free_xid != (unsigned int)0) &&
455 (next_free_xid != 0xFFFFFFFF);
456
457 /*--- for each parser... ---*/
458 for (parser_p = (utlAtParser_P)parsers.head_p; parser_p != NULL;
459 parser_p = parser_p->next_p)
460 {
461 utlAtAsyncResponse_P async_response_p;
462
463 /*--- for each async response this parser is waiting for... ---*/
464 async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p;
465 for (; async_response_p != NULL; async_response_p = async_response_p->next_p)
466 {
467 if (async_response_p->xid == xid)
468 {
469 unique = false;
470 break;
471 }
472 }
473
474 if (unique == false)
475 break;
476 }
477
478 } while (unique == false);
479
480#ifdef LPP_DEBUG
481 ERRMSG(utlNextAvailableXID477,"%s: xid %u\n", __FUNCTION__, xid);
482#endif
483
484 return xid;
485}
486
487/*****************************************************************************
488* AT-PARSER
489*****************************************************************************/
490
491/*---------------------------------------------------------------------------*
492* FUNCTION
493* utlAtReset(parser_p)
494* INPUT
495* parser_p == an open AT-command parser
496* OUTPUT
497* none
498* RETURNS
499* utlSUCCESS for success, otherwise utlFAILED
500* DESCRIPTION
501* Initializes AT-command parser parameters.
502*---------------------------------------------------------------------------*/
503static utlReturnCode_T utlAtReset(const utlAtParser_P parser_p)
504{
505 utlAssert(parser_p != NULL);
506
507#ifdef LPP_DEBUG
508 ERRMSG(utlAtReset502, "%s: enter\n", __FUNCTION__);
509#endif
510
511 /*--- S-parameters ---*/
512 {
513 size_t i;
514
515 parser_p->parameters.S[utlAT_AUTO_ANSWER] = 0; /* disable auto-answer */
516 parser_p->parameters.S[utlAT_RING_COUNTER] = 0; /* cleared */
517 parser_p->parameters.S[utlAT_ESCAPE_CHAR] = '+';
518 parser_p->parameters.S[utlAT_LINE_TERM_CHAR] = '\015'; /* <carriage-return> */
519 parser_p->parameters.S[utlAT_FORMATTING_CHAR] = '\012'; /* <new-line> */
520 parser_p->parameters.S[utlAT_LINE_EDIT_CHAR] = '\010'; /* <back-space> */
521 parser_p->parameters.S[utlAT_BLIND_DIAL_PAUSE_TIME] = 2; /* 2 seconds */
522 parser_p->parameters.S[utlAT_CONN_COMPLETE_TIMEOUT] = 1; /* 1 second */
523 parser_p->parameters.S[utlAT_DIALING_PAUSE_TIME] = 2; /* 2 seconds */
524 parser_p->parameters.S[utlAT_CARRIER_DETECT_TIME] = 6; /* 0.6 seconds */
525 parser_p->parameters.S[utlAT_CARRIER_LOSS_TIME] = 7; /* 0.7 seconds */
526 parser_p->parameters.S[utlAT_DTMF_TONE_DURATION] = 63; /* 0.63 seconds */
527 parser_p->parameters.S[utlAT_ESCAPE_GUARD_TIME] = 50; /* 1 second */
528 parser_p->parameters.S[utlAT_SEPARATER_CHAR] = ',';
529 parser_p->parameters.S[utlAT_TERMINATER_CHAR] = ';';
530 parser_p->parameters.S[utlAT_XON_CHAR] = 0x11; /* <DC1> */
531 parser_p->parameters.S[utlAT_XOFF_CHAR] = 0x13; /* <DC3> */
532 parser_p->parameters.S[utlAT_SLEEP_TIME] = 0; /* 0 seconds */
533 parser_p->parameters.S[utlAT_DTR_DELAY_TIME] = 10; /* 0.1 seconds */
534 parser_p->parameters.S[utlAT_HOOK_FLASH_TIME] = 5; /* 0.5 seconds */
535 parser_p->parameters.S[utlAT_INACTIVITY_TIME] = 10; /* 100 seconds */
536 parser_p->parameters.S[utlAT_DISCONNECT_WAIT_TIME] = 0; /* 0 seconds */
537
538 /*--- notify application of S-parameter value changes ---*/
539 if (parser_p->call_backs.s_parameter_function_p != NULL)
540 {
541 for (i = 0; i < utlAT_NUM_S_PARAMETERS; i++)
542 if ((parser_p->call_backs.s_parameter_function_p)(i, parser_p->parameters.S[i], parser_p->call_backs.arg_p) != utlSUCCESS)
543 return utlFAILED;
544 }
545 }
546
547 /*--- parameters ---*/
548 {
549 parser_p->parameters.echo_text = false;
550 parser_p->parameters.verbose_results = true;
551 parser_p->parameters.suppress_results = false;
552 parser_p->parameters.include_connect_text = false;
553 parser_p->parameters.detect_dial_tone = false;
554 parser_p->parameters.detect_busy_signal = false;
555 parser_p->parameters.dialing_mode = utlAT_DIALING_MODE_TONE;
556 parser_p->parameters.raw_framing = 3;
557 parser_p->parameters.raw_parity = 3;
558 }
559
560 /*--- buffers ---*/
561 {
562 (void)memset(parser_p->buffers.queue, 0, sizeof(parser_p->buffers.queue));
563
564 parser_p->buffers.echo_p = parser_p->buffers.queue;
565 parser_p->buffers.head_p = parser_p->buffers.queue;
566 parser_p->buffers.tail_p = parser_p->buffers.queue;
567 parser_p->buffers.term_p = parser_p->buffers.queue + utlNumberOf(parser_p->buffers.queue);
568
569 parser_p->buffers.overflow = false;
570
571 (void)strcpy(parser_p->buffers.previous_line, "AT");
572 }
573
574 /*--- DCE I/O config ---*/
575 {
576 parser_p->dce_io_config.data_rate = 0; /* auto-detect */
577 parser_p->dce_io_config.data_bits = 8;
578 parser_p->dce_io_config.parity_bits = 0; /* no parity */
579 parser_p->dce_io_config.stop_bits = 1;
580 parser_p->dce_io_config.parity = utlDATA_PARITY_SPACE;
581 parser_p->dce_io_config.flow_control.dce_by_dte = 2;
582 parser_p->dce_io_config.flow_control.dte_by_dce = 2;
583 parser_p->dce_io_config.flow_control.xon_char = parser_p->parameters.S[utlAT_XON_CHAR];
584 parser_p->dce_io_config.flow_control.xoff_char = parser_p->parameters.S[utlAT_XOFF_CHAR];
585 parser_p->dce_io_config.modes.dcd_always_on = false;
586 parser_p->dce_io_config.modes.ignore_dtr = false;
587 parser_p->dce_io_config.modes.drop_call_on_dtr_loss = false;
588 parser_p->dce_io_config.modes.dsr_mode = 0;
589
590 parser_p->states.dce_io_config_pending_mask = ~0u; /* all config-changes are pending */
591 }
592
593 /*--- sound config ---*/
594 {
595 parser_p->sound_config.monitor_speaker.mode = 1;
596 parser_p->sound_config.monitor_speaker.level = 0;
597
598 parser_p->states.sound_config_pending_mask = ~0u; /* all config-changes are pending */
599 }
600
601 /*--- peg counts ---*/
602 {
603 parser_p->peg_counts.basic_commands = 0;
604 parser_p->peg_counts.extended_commands = 0;
605 parser_p->peg_counts.undefined_commands = 0;
606 parser_p->peg_counts.bad_commands = 0;
607 }
608
609 /*--- parser states ---*/
610 {
611
612 parser_p->states.go_on_line = false;
613 parser_p->states.discard_current_line = false;
614 parser_p->states.bypass_mode = false;
615
616 {
617 utlAtAsyncResponse_P async_response_p;
618
619 if (parser_p->queue_semaphore.initialized && utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
620 {
621 utlError(utlAtReset, "Cannot exclusively acquire semaphore!\n");
622 return utlFAILED;
623 }
624
625 /*--- discard any pending async responses ---*/
626 while ((async_response_p = utlGetHeadNode(&(parser_p->states.async_responses.pending), utlAtAsyncResponse_T)) != NULL)
627 {
628
629 if (parser_p->queue_semaphore.initialized) utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
630
631 /*--- stop timer ---*/
632 if ( async_response_p->timer_id != (utlTimerId_T)utlFAILED)
633 {
634 if (utlStopTimer(async_response_p->timer_id) != utlSUCCESS)
635 return utlFAILED;
636
637 async_response_p->timer_id = utlFAILED;
638 }
639
640 if (parser_p->queue_semaphore.initialized && utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
641 {
642 utlError(utlAtReset1, "Cannot exclusively acquire semaphore!\n");
643 return utlFAILED;
644 }
645
646 utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
647 }
648
649 /*--- re-initialize nodes ---*/
650 for (async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.unused.head_p; async_response_p != NULL; async_response_p = async_response_p->next_p)
651 {
652 async_response_p->parser_p = parser_p;
653 async_response_p->xid = utlFAILED;
654 async_response_p->op = utlAT_ASYNC_OP_UNKNOWN;
655 async_response_p->command_p = NULL;
656
657 }
658
659 if (parser_p->queue_semaphore.initialized) utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
660 }
661
662 parser_p->states.sync_response.complete_reported = false;
663 parser_p->states.sync_response.abort_reported = false;
664 parser_p->states.sync_response.error_reported = false;
665 parser_p->states.sync_response.parameter_values_p = NULL;
666 parser_p->states.sync_response.custom_p = NULL;
667 parser_p->states.sync_response.info_text_p = NULL;
668 parser_p->states.sync_response.abort_response_p = NULL;
669 parser_p->states.sync_response.command_syntax_p = NULL;
670
671 parser_p->states.dce_io_config_pending_mask = ~0;
672 parser_p->states.sound_config_pending_mask = ~0;
673 parser_p->states.line_off = 0;
674
675 parser_p->states.escape.last_tx_time.seconds = 0;
676 parser_p->states.escape.last_tx_time.nanoseconds = 0;
677 parser_p->states.escape.state = utlAT_PARSER_ESCAPE_STATE_BEGIN;
678
679 parser_p->states.dial_string.active = false;
680 parser_p->states.dial_string.dial_string_delay = 0; /* no delay */
681 (void)memset(parser_p->states.dial_string.last, 0, sizeof(parser_p->states.dial_string.last));
682 (void)memset(parser_p->states.dial_string.buf, 0, sizeof(parser_p->states.dial_string.buf));
683 parser_p->states.dial_string.c_p = parser_p->states.dial_string.buf; /* reset */
684 parser_p->states.dial_string.options.international = false;
685 parser_p->states.dial_string.options.do_call_origination = true;
686 parser_p->states.dial_string.options.use_CCUG_SS_info = false;
687 parser_p->states.dial_string.options.CLI_presentation = '\0';
688
689 parser_p->states.delay_dialing_time.seconds = 0;
690 parser_p->states.delay_dialing_time.nanoseconds = 125000000;
691 parser_p->states.min_silence_time.seconds = 5;
692 parser_p->states.min_silence_time.nanoseconds = 0;
693 }
694
695 /*--- set values slaved from s-parameter settings ---*/
696 if ((utlProcessSParameter(parser_p, utlAT_BLIND_DIAL_PAUSE_TIME, parser_p->parameters.S[utlAT_BLIND_DIAL_PAUSE_TIME]) != utlSUCCESS) ||
697 (utlProcessSParameter(parser_p, utlAT_CONN_COMPLETE_TIMEOUT, parser_p->parameters.S[utlAT_CONN_COMPLETE_TIMEOUT]) != utlSUCCESS) ||
698 (utlProcessSParameter(parser_p, utlAT_DIALING_PAUSE_TIME, parser_p->parameters.S[utlAT_DIALING_PAUSE_TIME]) != utlSUCCESS) ||
699 (utlProcessSParameter(parser_p, utlAT_CARRIER_DETECT_TIME, parser_p->parameters.S[utlAT_CARRIER_DETECT_TIME]) != utlSUCCESS) ||
700 (utlProcessSParameter(parser_p, utlAT_CARRIER_LOSS_TIME, parser_p->parameters.S[utlAT_CARRIER_LOSS_TIME]) != utlSUCCESS) ||
701 (utlProcessSParameter(parser_p, utlAT_XON_CHAR, parser_p->parameters.S[utlAT_XON_CHAR]) != utlSUCCESS) ||
702 (utlProcessSParameter(parser_p, utlAT_XOFF_CHAR, parser_p->parameters.S[utlAT_XOFF_CHAR]) != utlSUCCESS) ||
703 (utlProcessSParameter(parser_p, utlAT_DTR_DELAY_TIME, parser_p->parameters.S[utlAT_DTR_DELAY_TIME]) != utlSUCCESS) ||
704 (utlProcessSParameter(parser_p, utlAT_HOOK_FLASH_TIME, parser_p->parameters.S[utlAT_HOOK_FLASH_TIME]) != utlSUCCESS) ||
705 (utlProcessSParameter(parser_p, utlAT_INACTIVITY_TIME, parser_p->parameters.S[utlAT_INACTIVITY_TIME]) != utlSUCCESS) ||
706 (utlProcessSParameter(parser_p, utlAT_DISCONNECT_WAIT_TIME, parser_p->parameters.S[utlAT_DISCONNECT_WAIT_TIME]) != utlSUCCESS))
707 return utlFAILED;
708
709 if (parser_p->cmd_cnt_semaphore.initialized && utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
710 {
711 utlError(utlAtReset2, "Cannot exclusively acquire semaphore!\n");
712 return utlFAILED;
713 }
714
715 parser_p->commands_in_line = 0;
716
717 if (parser_p->cmd_cnt_semaphore.initialized) utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
718
719 if( utlInitSemaphore(&parser_p->queue_semaphore, utlSEMAPHORE_ATTR_SHARING_ENABLE |
720 utlSEMAPHORE_ATTR_NESTING_ENABLE) != utlSUCCESS )
721 return utlFAILED;
722
723 if( utlInitSemaphore(&parser_p->cmd_cnt_semaphore, utlSEMAPHORE_ATTR_SHARING_ENABLE |
724 utlSEMAPHORE_ATTR_NESTING_ENABLE) != utlSUCCESS )
725 return utlFAILED;
726
727 //reset proxy configuration
728 parser_p->isProxy = false;
729
730 return utlSUCCESS;
731}
732
733/*------------------------------------------------------------------------------
734 * Function that check parameters for utlOpenAtParser
735 *------------------------------------------------------------------------------*/
736static int CheckParamForOpenAtParser(const utlAtCommand_P2c commands_p,
737 const size_t num_commands,
738 void *arg_p)
739{
740#ifdef utlDEBUG
741 utlAtCommand_P2c command_p;
742 utlAtCommand_P2c term_command_p;
743
744 /*--- for each command... ---*/
745 term_command_p = commands_p + num_commands;
746 for (command_p = commands_p; command_p < term_command_p; command_p++)
747 {
748 /*--- name missing? ---*/
749 if (command_p->name_p == NULL)
750 {
751 utlError(CheckParamForOpenAtParser, "Command at %d has no name.", command_p - commands_p);
752 return -1;
753 }
754
755 if (command_p->type == utlAT_COMMAND_TYPE_BASIC)
756 {
757
758 /*--- check command name syntax (must be a single character,
759 or a single character preceded by one of the pre-defined
760 basic-AT-command prefixes) */
761 {
762 const char *c_p;
763 c_p = command_p->name_p;
764 if (strchr(utlAT_BASIC_COMMAND_PREFIXES, *c_p) != NULL)
765 c_p++;
766 if (((*c_p < 'A') || (*c_p > 'Z')) &&
767 ((*c_p < 'a') || (*c_p > 'z')))
768 {
769 utlError(CheckParamForOpenAtParser1, "Invalid basic AT-command-name character '%c'.", *c_p);
770 return -1;
771 }
772 c_p++;
773 if (*c_p != '\0')
774 {
775 utlError(CheckParamForOpenAtParser2, "Basic AT-command name '%s' too long.",
776 command_p->name_p);
777 return -1;
778 }
779 }
780
781 /*--- check command parameter info (can either be zero or one parameter) ---*/
782 {
783 /*--- no parameters? ---*/
784 if (command_p->parameters_p == NULL)
785 {
786 if (command_p->num_parameters != (size_t)0)
787 {
788 utlError(CheckParamForOpenAtParser3, "Command '%s' has an invalid number of parameters (%d).", command_p->name_p, command_p->num_parameters);
789 return -1;
790 }
791 }
792 else
793 {
794 utlAtParameter_P2c parameter_p;
795 if (command_p->num_parameters != (size_t)1)
796 {
797 utlError(CheckParamForOpenAtParser4, "Command '%s' has an invalid number of parameters (%d).", command_p->name_p, command_p->num_parameters);
798 return -1;
799 }
800 parameter_p = command_p->parameters_p;
801 /*--- parameter (if present) must be decimal, except for the D and &Z commands ---*/
802 if ((((strcasecmp(command_p->name_p, "D") == 0) || (strcasecmp(command_p->name_p, "&Z") == 0)) && (parameter_p->type != utlAT_DATA_TYPE_DIAL_STRING)) ||
803 (((strcasecmp(command_p->name_p, "D") != 0) && (strcasecmp(command_p->name_p, "&Z") != 0)) && (parameter_p->type != utlAT_DATA_TYPE_DECIMAL)))
804 {
805 utlError(CheckParamForOpenAtParser5, "Command '%s' has an invalid parameter type.", command_p->name_p);
806 return -1;
807 }
808 if (parameter_p->access != utlAT_PARAMETER_ACCESS_READ_WRITE)
809 {
810 utlError(CheckParamForOpenAtParser6, "Command '%s' specifies an invalid parameter access.", command_p->name_p);
811 return -1;
812 }
813 }
814 }
815
816 }
817 else if ((command_p->type == utlAT_COMMAND_TYPE_EXTENDED) ||
818 (command_p->type == utlAT_COMMAND_TYPE_EXACTION)) ||
819 (command_p->type == utlAT_COMMAND_TYPE_EXTENDED_EXACTION))
820 {
821 /*--- check command name syntax ---*/
822 {
823 const char *c_p;
824
825 if (strlen(command_p->name_p) > 17)
826 {
827 utlError(CheckParamForOpenAtParser7, "Command name %s too long.", command_p->name_p);
828 return -1;
829 }
830 c_p = command_p->name_p;
831
832 /*--- first character must be a valid extended command prefix, second must
833 be alphabetic, rest must belong to a specific set of characters */
834 if (strchr(utlAT_EXTENDED_COMMAND_PREFIXES, *c_p) == NULL)
835 {
836 utlError(CheckParamForOpenAtParser8, "Invalid extended AT-command-name character '%c' in command '%s'.", *c_p, command_p->name_p);
837 return -1;
838 }
839 c_p++;
840 if (((*c_p < 'A') || (*c_p > 'Z')) &&
841 ((*c_p < 'a') || (*c_p > 'z')) && (*c_p != ' '))
842 {
843 utlError(CheckParamForOpenAtParser9, "Invalid extended AT-command-name character '%c' in command '%s'.", *c_p, command_p->name_p);
844 return -1;
845 }
846 c_p++;
847 for (; *c_p != '\0'; c_p++)
848 if (((*c_p < 'A') || (*c_p > 'Z')) &&
849 ((*c_p < 'a') || (*c_p > 'z')) &&
850 ((*c_p < '0') || (*c_p > '9')) &&
851 (*c_p != '!') && (*c_p != '%') &&
852 (*c_p != '-') && (*c_p != '.') &&
853 (*c_p != '/') && (*c_p != ':') && (*c_p != '_'))
854 {
855 utlError(CheckParamForOpenAtParser10, "Invalid extended AT-command-name character '%c' in command '%s'.", *c_p, command_p->name_p);
856 return -1;
857 }
858 }
859
860 /*--- check command parameter(s) info ---*/
861 {
862 /*--- no parameters? ---*/
863 if (command_p->parameters_p == NULL)
864 {
865 /* FIXME: The definition of utlDEFINE_EXACTION_AT_COMMAND has problem and will result in wrong parameter; "telcontroller.c" cannot initialize AT parser because of this error.
866 if (command_p->num_parameters != (size_t) 0) {
867 utlError("Command '%s' has an invalid number of parameters (%d).", command_p->name_p, command_p->num_parameters);
868 return -1;
869 }
870 */
871
872 }
873 else
874 {
875 utlAtParameter_P2c parameter_p;
876 utlAtParameter_P2c term_parameter_p;
877 if (command_p->num_parameters > utlAT_MAX_PARAMETERS)
878 {
879 utlError(CheckParamForOpenAtParser11, "Command '%s' has too many parameters (%d).", command_p->name_p, command_p->num_parameters);
880 return -1;
881 }
882 /*--- for each parameter... ---*/
883 term_parameter_p = command_p->parameters_p + command_p->num_parameters;
884 for ( parameter_p = command_p->parameters_p; parameter_p < term_parameter_p; parameter_p++)
885 {
886 if ((parameter_p->type != utlAT_DATA_TYPE_DECIMAL) &&
887 (parameter_p->type != utlAT_DATA_TYPE_HEXADECIMAL) &&
888 (parameter_p->type != utlAT_DATA_TYPE_BINARY) &&
889 (parameter_p->type != utlAT_DATA_TYPE_STRING) &&
890 (parameter_p->type != utlAT_DATA_TYPE_QSTRING) &&
891 (parameter_p->type != utlAT_DATA_TYPE_DIAL_STRING))
892 {
893 utlError(CheckParamForOpenAtParser12, "Command '%s' has an invalid parameter type.", command_p->name_p);
894 return -1;
895 }
896 if ((parameter_p->access != utlAT_PARAMETER_ACCESS_READ_WRITE) &&
897 (parameter_p->access != utlAT_PARAMETER_ACCESS_READ) &&
898 (parameter_p->access != utlAT_PARAMETER_ACCESS_READ_ONLY) &&
899 (parameter_p->access != utlAT_PARAMETER_ACCESS_WRITE_ONLY))
900 {
901 utlError(CheckParamForOpenAtParser13, "Command '%s' specifies an invalid parameter access.", command_p->name_p);
902 return -1;
903 }
904
905 /*--- check that dial-string parameter is the very last parameter ---*/
906 if (( parameter_p->type == utlAT_DATA_TYPE_DIAL_STRING) &&
907 ((parameter_p + 1) != term_parameter_p))
908 {
909 utlError(CheckParamForOpenAtParser14, "Dial-string parameter is not the last parameter in command '%s'.", command_p->name_p);
910 return -1;
911 }
912 }
913 }
914 }
915 }
916 }
917#endif
918 UNUSEDPARAM(commands_p)
919 UNUSEDPARAM(num_commands)
920 UNUSEDPARAM(arg_p)
921 return 0;
922
923}
924
925/*---------------------------------------------------------------------------*
926* FUNCTION
927* utOpenAtParser(commands_p, num_commands, arg_p)
928* INPUT
929* commands_p == pointer to an array of utlAtCommand_T structures
930* num_commands == number of commands pointed to by `commands_p'
931* arg_p == user-defined argument for call-backs
932* OUTPUT
933* none
934* RETURNS
935* pointer to an initialized utlAtParser_T structure.
936* DESCRIPTION
937* Opens a new AT command parser.
938*---------------------------------------------------------------------------*/
939utlAtParser_P utlOpenAtParser(const utlAtCommand_P2c commands_p,
940 const size_t num_commands,
941 void *arg_p)
942{
943 utlAtParser_P parser_p;
944
945 utlAssert(commands_p != NULL);
946 utlAssert(num_commands > (size_t)0);
947
948 atcmd_mult_init();
949
950 if (CheckParamForOpenAtParser(commands_p, num_commands, arg_p) < 0)
951 return NULL;
952
953 /*--- allocate and initialize a new AT command parser ---*/
954 {
955 size_t parser_size;
956
957 parser_size = sizeof(utlAtParser_T);
958
959 if ((parser_p = (utlAtParser_P)utlMalloc(parser_size)) == NULL)
960 return NULL;
961
962 (void)memset(parser_p, 0, sizeof(*parser_p));
963
964 parser_p->next_p = NULL;
965
966 /*--- info ---*/
967 {
968 parser_p->info.id_p = "ASR";
969 parser_p->info.manufacturer_p = "ASR";
970 parser_p->info.model_p = "Linux";
971 parser_p->info.revision_p = "1.0";
972 parser_p->info.serial_number_p = NULL;
973 parser_p->info.object_id_p = NULL;
974 parser_p->info.country_code_p = NULL;
975 parser_p->info.connect_text_p = NULL;
976 parser_p->info.mt_capabilities_p = "+GCAP: +CGSM";
977 }
978
979 /*--- options ---*/
980 {
981 parser_p->options.allow_default_S_parameter_values = true;
982 parser_p->options.allow_string_escapes = true;
983 parser_p->options.use_carrier_result_code = false;
984 parser_p->options.report_each_ring = false;
985 }
986
987 /*--- call backs ---*/
988 {
989 parser_p->call_backs.dce_io_config_function_p = NULL;
990 parser_p->call_backs.sound_config_function_p = NULL;
991 parser_p->call_backs.s_parameter_function_p = NULL;
992 parser_p->call_backs.save_dial_string_function_p = utlAtParserStoreSaveDialString;
993 parser_p->call_backs.retrieve_dial_string_function_p = utlAtParserStoreRetrieveDialString;
994 parser_p->call_backs.reply_function_p = NULL;
995 parser_p->call_backs.tx_line_data_function_p = NULL;
996 parser_p->call_backs.driver_request_function_p = NULL;
997 parser_p->call_backs.arg_p = arg_p;
998 }
999
1000 parser_p->commands_p = commands_p;
1001 parser_p->num_commands = num_commands;
1002
1003 /*--- parser states ---*/
1004 {
1005 utlAtAsyncResponse_P async_response_p;
1006 utlAtAsyncResponse_P term_async_response_p;
1007
1008 utlInitLinkedList(&(parser_p->states.async_responses.unused));
1009 utlInitLinkedList(&(parser_p->states.async_responses.pending));
1010
1011 term_async_response_p = parser_p->states.async_responses.nodes +
1012 utlNumberOf(parser_p->states.async_responses.nodes);
1013
1014 for (async_response_p = parser_p->states.async_responses.nodes;
1015 async_response_p < term_async_response_p; async_response_p++)
1016 {
1017 async_response_p->parser_p = parser_p;
1018 async_response_p->timer_id = utlFAILED;
1019
1020 utlPutTailNode(&(parser_p->states.async_responses.unused),
1021 utlAtAsyncResponse_T, async_response_p);
1022 }
1023 }
1024
1025 if (utlAtReset(parser_p) != utlSUCCESS)
1026 {
1027 /*--- clean ---*/
1028 utlFree(parser_p);
1029 return NULL;
1030 }
1031
1032 }
1033
1034 /*--- apply any pending configuration changes ---*/
1035 if ((utlAtDceIoConfigEvent(parser_p) != utlSUCCESS) ||
1036 (utlAtSoundConfigEvent(parser_p) != utlSUCCESS))
1037 {
1038 /*--- clean ---*/
1039 utlFree(parser_p);
1040
1041 return NULL;
1042 }
1043
1044 /*--- add to list of known AT parsers ---*/
1045 utlPutTailNode(&parsers, utlAtParser_T, parser_p);
1046
1047 return parser_p;
1048}
1049
1050/*---------------------------------------------------------------------------*
1051* FUNCTION
1052* utlCloseAtParser(parser_p)
1053* INPUT
1054* parser_p == an open AT-command parser
1055* OUTPUT
1056* none
1057* RETURNS
1058* utlSUCCESS
1059* DESCRIPTION
1060* Closes an open AT command parser.
1061*---------------------------------------------------------------------------*/
1062utlReturnCode_T utlCloseAtParser(const utlAtParser_P parser_p)
1063{
1064 utlAssert(parser_p != NULL);
1065
1066#ifdef LPP_DEBUG
1067 ERRMSG(utlCloseAtParser1059, "%s: enter\n", __FUNCTION__);
1068#endif
1069
1070 /*--- parser states ---*/
1071 {
1072 utlAtAsyncResponse_P async_response_p;
1073
1074 /*--- discard any pending responsess ---*/
1075 while ((async_response_p = utlGetHeadNode(&(parser_p->states.async_responses.pending), utlAtAsyncResponse_T)) != NULL)
1076 if ( async_response_p->timer_id != (utlTimerId_T) utlFAILED)
1077 {
1078 if (utlStopTimer(async_response_p->timer_id) != utlSUCCESS)
1079 return utlFAILED;
1080
1081 async_response_p->timer_id = utlFAILED;
1082 }
1083 }
1084
1085 /*--- remove AT parser from list of known parsers ---*/
1086 if (utlGetNode(&parsers, utlAtParser_T, NULL, parser_p) != parser_p)
1087 return utlFAILED;
1088
1089 /*--- destroy parser ---*/
1090 utlFreeConst(parser_p);
1091
1092 return utlSUCCESS;
1093}
1094
1095/*---------------------------------------------------------------------------*
1096* FUNCTION
1097* utlAtParserOp(parser_p, op, ...)
1098*
1099* utlAtParserOp(parser_p, utlAT_PARSER_OP_HANG_UP)
1100* utlAtParserOp(parser_p, utlAT_PARSER_OP_RESET)
1101* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_DCE_IO_CONFIG_HANDLER, dce_io_config_function_p)
1102* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_SOUND_CONFIG_HANDLER, sound_config_function_p)
1103* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_S_PARAMETER_HANDLER, s_parameter_function_p)
1104* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_SAVE_DIAL_STRING_HANLDER, save_dial_string_function_p)
1105* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_RETRIEVE_DIAL_STRING_HANLDER, retrieve_dial_string_function_p)
1106* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_REPLY_HANDLER, reply_function_p)
1107* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_TX_LINE_DATA_HANDLER, tx_line_data_function_p)
1108* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_DRIVER_REQUEST_HANDLER, driver_request_function_p)
1109* utlAtParserOp(parser_p, utlAT_PARSER_OP_ECHO_ON)
1110* utlAtParserOp(parser_p, utlAT_PARSER_OP_ECHO_OFF)
1111* utlAtParserOp(parser_p, utlAT_PARSER_OP_SELECT_CARRIER_RESULT_CODE)
1112* utlAtParserOp(parser_p, utlAT_PARSER_OP_SELECT_CONNECT_RESULT_CODE)
1113* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_S_PARAMETER_VALUE, parameter_num, parameter_value)
1114* utlAtParserOp(parser_p, utlAT_PARSER_OP_GET_S_PARAMETER_VALUE, parameter_num, parameter_value_p)
1115* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_ID, id_p)
1116* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_MANUFACTURER, manufacturer_p)
1117* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_MODEL, model_p)
1118* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_REVISION, revision_p)
1119* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_SERIAL_NUMBER, serial_number_p)
1120* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_OBJECT_ID, object_id_p)
1121* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_COUNTRY_CODE, country_code_p)
1122* utlAtParserOp(parser_p, utlAT_PARSER_OP_SET_CONNECT_TEXT, connect_text_p)
1123* utlAtParserOp(parser_p, utlAT_PARSER_OP_ENABLE_BYPASS_MODE)
1124* utlAtParserOp(parser_p, utlAT_PARSER_OP_DISABLE_BYPASS_MODE)
1125* INPUT
1126* parser_p == an open AT-command parser
1127* op == the operation to perform
1128* ... == zero or more operation-specific parameters
1129* OUTPUT
1130* none
1131* RETURNS
1132* utlSUCCESS for success, otherwise utlFAILED
1133* DESCRIPTION
1134* Performs the requested operation on an open At-command parser.
1135*---------------------------------------------------------------------------*/
1136utlReturnCode_T utlAtParserOp(const utlAtParser_P parser_p,
1137 const utlAtParserOp_T op,
1138 ...)
1139{
1140 va_list va_arg_p;
1141 const char *s_p = NULL;
1142 unsigned int parameter_num = 0;
1143 unsigned int parameter_value = 0;
1144 unsigned int *parameter_value_p = NULL;
1145
1146 utlAssert(parser_p != NULL);
1147
1148 va_start(va_arg_p, op);
1149
1150 /*--- check parameter(s) (where possible) ---*/
1151 switch (op)
1152 {
1153 case utlAT_PARSER_OP_SET_S_PARAMETER_VALUE:
1154 parameter_num = va_arg(va_arg_p, unsigned int);
1155 parameter_value = va_arg(va_arg_p, unsigned int);
1156
1157 /*--- parameter-number too large? ---*/
1158 if (parameter_num >= utlNumberOf(parser_p->parameters.S))
1159 {
1160 utlError(utlAtParserOp, "Invalid S-parameter number %d", parameter_num);
1161 va_end(va_arg_p);
1162 return utlFAILED;
1163 }
1164 break;
1165
1166 case utlAT_PARSER_OP_GET_S_PARAMETER_VALUE:
1167 parameter_num = va_arg(va_arg_p, unsigned int);
1168 parameter_value_p = va_arg(va_arg_p, unsigned int *);
1169
1170 /*--- parameter-number too large? ---*/
1171 if (parameter_num >= utlNumberOf(parser_p->parameters.S))
1172 {
1173 utlError(utlAtParserOp1, "Invalid S-parameter number %d", parameter_num);
1174 va_end(va_arg_p);
1175 return utlFAILED;
1176 }
1177
1178 /*--- bad pointer ---*/
1179 if (parameter_value_p == NULL)
1180 {
1181 utlError(utlAtParserOp2, "Invalid S-parameter value pointer");
1182 va_end(va_arg_p);
1183 return utlFAILED;
1184 }
1185 break;
1186
1187 case utlAT_PARSER_OP_SET_ID:
1188 case utlAT_PARSER_OP_SET_MANUFACTURER:
1189 case utlAT_PARSER_OP_SET_MODEL:
1190 case utlAT_PARSER_OP_SET_REVISION:
1191 case utlAT_PARSER_OP_SET_SERIAL_NUMBER:
1192 case utlAT_PARSER_OP_SET_OBJECT_ID:
1193 case utlAT_PARSER_OP_SET_CAPABILITIES:
1194 s_p = va_arg(va_arg_p, const char *);
1195
1196 /*--- is string parameter too long? ---*/
1197 if (strlen(s_p) > (size_t)2048)
1198 {
1199 utlError(utlAtParserOp3, "Character string parameter is too long (> 2048 characters).");
1200
1201 /*--- clean ---*/
1202 va_end(va_arg_p);
1203
1204 return utlFAILED;
1205 }
1206
1207 /*--- does string parameter contain reserved character sequences? ---*/
1208 if (( strstr(s_p, "0\r")) || (strcasestr(s_p, "OK\r")))
1209 {
1210 utlError(utlAtParserOp4, "Character string contains reserved character sequences (0<cr> or OK<cr>).");
1211
1212 /*--- clean ---*/
1213 va_end(va_arg_p);
1214
1215 return utlFAILED;
1216 }
1217 break;
1218
1219 case utlAT_PARSER_OP_SET_COUNTRY_CODE:
1220 s_p = va_arg(va_arg_p, const char *);
1221
1222 /*--- Country codes are encoded using T.35 8-bit country codes, and
1223 consist of a single 2-digit hexadecimal value, or multple comma-
1224 separated 2-digit hexadecimal values all enclosed in parenthesis.
1225 Some sample country code strings are shown below:
1226 "20"
1227 "(20,B5,00)"
1228
1229 Some T.35 country codes:
1230 20 == Canada
1231 3C == Finland
1232 3D == France
1233 42 == Germany
1234 50 == Hongkong
1235 58 == Israel
1236 00 == Japan
1237 61 == Korea
1238 FE == Taiwan
1239 A9 == Thailand
1240 B4 == UK
1241 B5 == USA */
1242
1243 /*--- is string parameter too long? ---*/
1244 if (strlen(s_p) > (size_t)2048)
1245 {
1246 utlError(utlAtParserOp5, "Character string parameter is too long (> 2048 characters).");
1247
1248 /*--- clean ---*/
1249 va_end(va_arg_p);
1250
1251 return utlFAILED;
1252 }
1253
1254 /*--- check that syntax is of the form: (hh,hh,hh,..,hh) ---*/
1255 if (s_p[0] == '(')
1256 {
1257 const char *c_p;
1258
1259 c_p = s_p;
1260
1261 /*--- ensure there's an opening parenthesis ---*/
1262 if (*c_p != '(')
1263 {
1264 utlError(utlAtParserOp6, "Invalid country-code syntax.");
1265
1266 /*--- clean ---*/
1267 va_end(va_arg_p);
1268
1269 return utlFAILED;
1270 }
1271
1272 for (c_p++; *c_p != '\0'; c_p++)
1273 {
1274 /*--- check 2-digit hexadecimal value ---*/
1275 if ((((c_p[0] < '0') || (c_p[0] > '9')) &&
1276 ((c_p[0] < 'A') || (c_p[0] > 'F')) &&
1277 ((c_p[0] < 'a') || (c_p[0] > 'f'))) ||
1278 (((c_p[1] < '0') || (c_p[1] > '9')) &&
1279 ((c_p[1] < 'A') || (c_p[1] > 'F')) &&
1280 ((c_p[1] < 'a') || (c_p[1] > 'f'))))
1281 {
1282 utlError(utlAtParserOp7, "Invalid country-code syntax.");
1283
1284 /*--- clean ---*/
1285 va_end(va_arg_p);
1286
1287 return utlFAILED;
1288 }
1289
1290 c_p += 2;
1291
1292 if (*c_p == ')')
1293 break;
1294 else if (*c_p != ',')
1295 {
1296 utlError(utlAtParserOp8, "Invalid country-code syntax.");
1297
1298 /*--- clean ---*/
1299 va_end(va_arg_p);
1300
1301 return utlFAILED;
1302 }
1303 }
1304
1305 /*--- ensure there's a closing parenthesis ---*/
1306 if (*c_p != ')')
1307 {
1308 utlError(utlAtParserOp9, "Invalid country-code syntax.");
1309
1310 /*--- clean ---*/
1311 va_end(va_arg_p);
1312
1313 return utlFAILED;
1314 }
1315
1316 /*--- check that syntax of single values have the form: hh ---*/
1317 }
1318 else
1319 {
1320 /*--- check 2-digit hexadecimal value ---*/
1321 if ((((s_p[0] < '0') || (s_p[0] > '9')) &&
1322 ((s_p[0] < 'A') || (s_p[0] > 'F')) &&
1323 ((s_p[0] < 'a') || (s_p[0] > 'f'))) ||
1324 (((s_p[1] < '0') || (s_p[1] > '9')) &&
1325 ((s_p[1] < 'A') || (s_p[1] > 'F')) &&
1326 ((s_p[1] < 'a') || (s_p[1] > 'f'))) ||
1327 ( s_p[2] != '\0'))
1328 {
1329 utlError(utlAtParserOp10, "Invalid country-code syntax.");
1330
1331 /*--- clean ---*/
1332 va_end(va_arg_p);
1333
1334 return utlFAILED;
1335 }
1336 }
1337 break;
1338
1339 case utlAT_PARSER_OP_SET_CONNECT_TEXT:
1340 s_p = va_arg(va_arg_p, const char *);
1341
1342 /*--- is string parameter too long? ---*/
1343 if (strlen(s_p) > (size_t)utlAT_MAX_CONNECT_TEXT_LENGTH)
1344 {
1345 utlError(utlAtParserOp11, "Character string parameter is too long (> %d characters).", utlAT_MAX_CONNECT_TEXT_LENGTH);
1346
1347 /*--- clean ---*/
1348 va_end(va_arg_p);
1349
1350 return utlFAILED;
1351 }
1352 break;
1353
1354 default:
1355 break;
1356 }
1357
1358 /*--- execute operation ---*/
1359 switch (op)
1360 {
1361 case utlAT_PARSER_OP_HANG_UP:
1362
1363 break;
1364
1365 case utlAT_PARSER_OP_RESET:
1366
1367 break;
1368
1369 case utlAT_PARSER_OP_SET_DCE_IO_CONFIG_HANDLER:
1370 parser_p->call_backs.dce_io_config_function_p = va_arg(va_arg_p, utlAtDceIoConfigFunction_P);
1371
1372 /*--- notify application of current I/O config settings ---*/
1373 if (parser_p->call_backs.dce_io_config_function_p != NULL)
1374 {
1375 if (utlAtDceIoConfigEvent(parser_p) != utlSUCCESS)
1376 {
1377 /*--- clean ---*/
1378 va_end(va_arg_p);
1379
1380 return utlAT_RESULT_CODE_ERROR;
1381 }
1382 }
1383 break;
1384
1385 case utlAT_PARSER_OP_SET_SOUND_CONFIG_HANDLER:
1386 parser_p->call_backs.sound_config_function_p = va_arg(va_arg_p, utlAtSoundConfigFunction_P);
1387
1388 /*--- notify application of current sound config settings ---*/
1389 if (parser_p->call_backs.sound_config_function_p != NULL)
1390 {
1391 if (utlAtSoundConfigEvent(parser_p) != utlSUCCESS)
1392 {
1393 /*--- clean ---*/
1394 va_end(va_arg_p);
1395
1396 return utlAT_RESULT_CODE_ERROR;
1397 }
1398 }
1399 break;
1400
1401 case utlAT_PARSER_OP_SET_S_PARAMETER_HANDLER:
1402 parser_p->call_backs.s_parameter_function_p = va_arg(va_arg_p, utlAtSParameterFunction_P);
1403
1404 /*--- notify application of current S-parameter settings ---*/
1405 if (parser_p->call_backs.s_parameter_function_p != NULL)
1406 {
1407 size_t i;
1408
1409 for (i = 0; i < utlAT_NUM_S_PARAMETERS; i++)
1410 if ((parser_p->call_backs.s_parameter_function_p)(i, parser_p->parameters.S[i], parser_p->call_backs.arg_p) != utlSUCCESS)
1411 {
1412
1413 /*--- clean ---*/
1414 va_end(va_arg_p);
1415
1416 return utlFAILED;
1417 }
1418 }
1419 break;
1420
1421 case utlAT_PARSER_OP_SET_REPLY_HANDLER:
1422 {
1423 utlAtReplyFunction_P reply_function_p;
1424
1425 reply_function_p = va_arg(va_arg_p, utlAtReplyFunction_P);
1426
1427 /*--- when the first handler is set, emit an "OK" message ---*/
1428 if ((parser_p->call_backs.reply_function_p == NULL) && (reply_function_p != NULL))
1429 {
1430 parser_p->call_backs.reply_function_p = reply_function_p;
1431
1432 /* Fix me: We don't need to emit "OK" here */
1433 //if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_OK, false) != utlSUCCESS)
1434 // return utlFAILED;
1435
1436 }
1437 else
1438 parser_p->call_backs.reply_function_p = reply_function_p;
1439 }
1440 break;
1441
1442 case utlAT_PARSER_OP_SET_GET_ATCMD_TIMEOUT_VALUE_HANDLER:
1443 {
1444 utlAtGetAtcmdTimeoutValueFunction_P getAtcmdTimeoutValue_function_p;
1445
1446 getAtcmdTimeoutValue_function_p = va_arg(va_arg_p, utlAtGetAtcmdTimeoutValueFunction_P);
1447
1448 parser_p->call_backs.getAtcmdTimeoutValue_function_p = getAtcmdTimeoutValue_function_p;
1449 }
1450 break;
1451
1452 case utlAT_PARSER_OP_SET_ATCMD_TIMEOUT_ERROR_HANDLER:
1453 {
1454 utlAtcmdTimeoutErrorFunction_P atcmdTimeoutError_function_P;
1455
1456 atcmdTimeoutError_function_P = va_arg(va_arg_p, utlAtcmdTimeoutErrorFunction_P);
1457
1458 parser_p->call_backs.atcmdTimeoutError_function_P = atcmdTimeoutError_function_P;
1459 }
1460 break;
1461
1462 case utlAT_PARSER_OP_SET_ATCMD_CONTINUOUS_TIMEOUT_HANDLER:
1463 {
1464 utlAtcmdContinuousTimeoutFunction_P atcmdContinuousTimeout_function_p;
1465
1466 atcmdContinuousTimeout_function_p = va_arg(va_arg_p, utlAtcmdContinuousTimeoutFunction_P);
1467
1468 parser_p->call_backs.atcmdContinuousTimeout_function_p = atcmdContinuousTimeout_function_p;
1469 }
1470 break;
1471
1472 case utlAT_PARSER_OP_SET_AT_PARSER_TRIGGER_HANDLER:
1473 {
1474 utlAtParserTriggerFunction_P atParserTrigger_function_p;
1475
1476 atParserTrigger_function_p = va_arg(va_arg_p, utlAtParserTriggerFunction_P);
1477
1478 parser_p->call_backs.atParserTrigger_function_p = atParserTrigger_function_p;
1479 }
1480 break;
1481
1482 case utlAT_PARSER_OP_SET_SAVE_DIAL_STRING_HANDLER: parser_p->call_backs.save_dial_string_function_p = va_arg(va_arg_p, utlAtSaveDialStringFunction_P); break;
1483 case utlAT_PARSER_OP_SET_RETRIEVE_DIAL_STRING_HANDLER: parser_p->call_backs.retrieve_dial_string_function_p = va_arg(va_arg_p, utlAtRetrieveDialStringFunction_P); break;
1484 case utlAT_PARSER_OP_SET_TX_LINE_DATA_HANDLER: parser_p->call_backs.tx_line_data_function_p = va_arg(va_arg_p, utlAtTxLineDataFunction_P); break;
1485 case utlAT_PARSER_OP_SET_DRIVER_REQUEST_HANDLER: parser_p->call_backs.driver_request_function_p = va_arg(va_arg_p, utlAtDriverRequestFunction_P); break;
1486
1487 case utlAT_PARSER_OP_ECHO_ON: parser_p->parameters.echo_text = true; break;
1488 case utlAT_PARSER_OP_ECHO_OFF: parser_p->parameters.echo_text = false; break;
1489
1490 case utlAT_PARSER_OP_SELECT_CARRIER_RESULT_CODE: parser_p->options.use_carrier_result_code = true; break;
1491 case utlAT_PARSER_OP_SELECT_CONNECT_RESULT_CODE: parser_p->options.use_carrier_result_code = false; break;
1492
1493 case utlAT_PARSER_OP_SET_S_PARAMETER_VALUE:
1494 /*--- apply S-parameter value change ---*/
1495 if (utlProcessSParameter(parser_p, parameter_num, parameter_value) != utlSUCCESS)
1496 {
1497 va_end(va_arg_p);
1498 return utlAT_RESULT_CODE_ERROR;
1499 }
1500
1501 /*--- notify application of S-parameter value change ---*/
1502 if ( parser_p->call_backs.s_parameter_function_p != NULL)
1503 if ((parser_p->call_backs.s_parameter_function_p)(parameter_num,
1504 parameter_value,
1505 parser_p->call_backs.arg_p) != utlSUCCESS)
1506 {
1507 va_end(va_arg_p);
1508 return utlAT_RESULT_CODE_ERROR;
1509 }
1510
1511 /*--- save new S-parameter value ---*/
1512 parser_p->parameters.S[parameter_num] = parameter_value;
1513 break;
1514
1515 case utlAT_PARSER_OP_GET_S_PARAMETER_VALUE:
1516 /*--- fetch value ---*/
1517 *parameter_value_p = parser_p->parameters.S[parameter_num];
1518 break;
1519
1520 case utlAT_PARSER_OP_REPORT_EACH_RING: parser_p->options.report_each_ring = true; break;
1521 case utlAT_PARSER_OP_ONLY_REPORT_FIRST_RING: parser_p->options.report_each_ring = false; break;
1522
1523 case utlAT_PARSER_OP_SET_ID: parser_p->info.id_p = s_p; break;
1524 case utlAT_PARSER_OP_SET_MANUFACTURER: parser_p->info.manufacturer_p = s_p; break;
1525 case utlAT_PARSER_OP_SET_MODEL: parser_p->info.model_p = s_p; break;
1526 case utlAT_PARSER_OP_SET_REVISION: parser_p->info.revision_p = s_p; break;
1527 case utlAT_PARSER_OP_SET_SERIAL_NUMBER: parser_p->info.serial_number_p = s_p; break;
1528 case utlAT_PARSER_OP_SET_OBJECT_ID: parser_p->info.object_id_p = s_p; break;
1529 case utlAT_PARSER_OP_SET_COUNTRY_CODE: parser_p->info.country_code_p = s_p; break;
1530 case utlAT_PARSER_OP_SET_CONNECT_TEXT: parser_p->info.connect_text_p = s_p; break;
1531 case utlAT_PARSER_OP_SET_CAPABILITIES: parser_p->info.mt_capabilities_p= s_p; break;
1532 case utlAT_PARSER_OP_ENABLE_BYPASS_MODE: parser_p->states.bypass_mode = true; break;
1533 case utlAT_PARSER_OP_DISABLE_BYPASS_MODE: parser_p->states.bypass_mode = false; break;
1534
1535 case utlAT_PARSER_OP_SET_AUTO_ANSWER_DELAY:
1536 {
1537 utlSetAutoAnswerDelay_P setAutoAnswerDelay_function_p;
1538
1539 setAutoAnswerDelay_function_p = va_arg(va_arg_p, utlSetAutoAnswerDelay_P);
1540
1541 parser_p->call_backs.setAutoAnswerDelay_function_p = setAutoAnswerDelay_function_p;
1542 break;
1543 }
1544
1545 case utlAT_PARSER_OP_GET_AUTO_ANSWER_DELAY:
1546 {
1547 utlGetAutoAnswerDelay_P getAutoAnswerDelay_function_p;
1548 getAutoAnswerDelay_function_p = va_arg(va_arg_p, utlGetAutoAnswerDelay_P);
1549 parser_p->call_backs.getAutoAnswerDelay_function_p = getAutoAnswerDelay_function_p;
1550 break;
1551 }
1552 case utlAT_PARSER_OP_SET_AT_PARSER_PROXY_CB:
1553 {
1554 utlSendToProxy_P sendToProxy_function_p;
1555 sendToProxy_function_p = va_arg(va_arg_p, utlSendToProxy_P);
1556 parser_p->call_backs.sendToProxy_function_p = sendToProxy_function_p;
1557 break;
1558 }
1559 case utlAT_PARSER_OP_SET_IS_PROXY_REQ_CB:
1560 {
1561 utlIsProxyReq_P isProxyReq_function_p;
1562 isProxyReq_function_p = va_arg(va_arg_p, utlIsProxyReq_P);
1563 parser_p->call_backs.isProxyReq_function_p = isProxyReq_function_p;
1564 break;
1565 }
1566 case utlAT_PARSER_OP_SET_INC_PROXY_TO_COUNTER_CB:
1567 {
1568 utlIncProxyTOCounter_P incProxyTOCounter_function_p;
1569 incProxyTOCounter_function_p = va_arg(va_arg_p, utlIncProxyTOCounter_P);
1570 parser_p->call_backs.incProxyTOCounter_p = incProxyTOCounter_function_p;
1571 break;
1572 }
1573 case utlAT_PARSER_OP_SET_PRXY_ONLY_CMD_PTR:
1574 {
1575 utlAtCommand_P pProxyOnlyCmd;
1576 pProxyOnlyCmd = va_arg(va_arg_p, utlAtCommand_P);
1577 parser_p->pProxyOnlyCmd = pProxyOnlyCmd;
1578 break;
1579 }
1580 case utlAT_PARSER_OP_SET_PRXY_ESC_CB:
1581 {
1582 utlProxyEsc_P pProxyEsc;
1583 pProxyEsc = va_arg(va_arg_p, utlProxyEsc_P);
1584 parser_p->call_backs.proxyEsc_p = pProxyEsc;
1585 break;
1586 }
1587 case utlAT_PARSER_OP_CLEAR_SMS_DATDAMODE_CB:
1588 {
1589 utlClearSmsDataMode_P pClearSmsDataMode;
1590 pClearSmsDataMode = va_arg(va_arg_p, utlClearSmsDataMode_P);
1591 parser_p->call_backs.clearSmsDataMode_p = pClearSmsDataMode;
1592 break;
1593 }
1594 case utlAT_PARSER_OP_CLEAR_SMS_OVER_NAS_CB:
1595 {
1596 utlClearSmsoverNas_P pClearSmsoverNas;
1597 pClearSmsoverNas = va_arg(va_arg_p, utlClearSmsoverNas_P);
1598 parser_p->call_backs.clearSmsoverNas_P = pClearSmsoverNas;
1599 break;
1600 }
1601 case utlAT_PARSER_OP_SET_CHECK_SMS_PARA_CB:
1602 {
1603 utlCheckSmsPara_P checkSmsPara_function_p;
1604 checkSmsPara_function_p = va_arg(va_arg_p, utlCheckSmsPara_P);
1605 parser_p->call_backs.checkSmsPara_function_p = checkSmsPara_function_p;
1606 break;
1607 }
1608 case utlAT_PARSER_OP_CONVERT_ATCMD_STR_CB:
1609 {
1610 utlConvertAtcmdStr_P convert_atcmd_str_p;
1611 convert_atcmd_str_p = va_arg(va_arg_p, utlConvertAtcmdStr_P);
1612 parser_p->call_backs.convert_atcmd_str_p = convert_atcmd_str_p;
1613 break;
1614 }
1615
1616 default:
1617 utlError(utlAtParserOp12, "Invalid op-code %d.", op);
1618
1619 /*--- clean ---*/
1620 va_end(va_arg_p);
1621
1622 return utlFAILED;
1623 }
1624
1625 va_end(va_arg_p);
1626
1627 return utlSUCCESS;
1628}
1629
1630/*---------------------------------------------------------------------------*
1631* FUNCTION
1632* utlSendString(parser_p, string_p)
1633* INPUT
1634* parser_p == an open AT-command parser
1635* string_p == pointer to the string to send expressed as a null-
1636* terminated character string
1637* OUTPUT
1638* none
1639* RETURNS
1640* utlSUCCESS for success, otherwise utlFAILED
1641* DESCRIPTION
1642* Sends the specified null-terminated reply string to the DTE.
1643*---------------------------------------------------------------------------*/
1644static utlReturnCode_T utlSendString(const utlAtParser_P2c parser_p,
1645 const char *string_p)
1646{
1647 utlAssert(parser_p != NULL);
1648 utlAssert(string_p != NULL);
1649
1650 /*--- is bypass mode enabled? ---*/
1651 if (parser_p->states.bypass_mode)
1652 return utlSUCCESS;
1653
1654 /*--- nothing to send? ---*/
1655 if (*string_p == '\0')
1656 return utlSUCCESS;
1657
1658 /*--- invoke reply call-back (if any) ---*/
1659 if ( parser_p->call_backs.reply_function_p != NULL)
1660 return (parser_p->call_backs.reply_function_p)(string_p, parser_p->call_backs.arg_p);
1661
1662 return utlSUCCESS;
1663}
1664
1665/*---------------------------------------------------------------------------*
1666* FUNCTION
1667* utlSendSubstring(parser_p, string_p, len)
1668* INPUT
1669* parser_p == an open AT-command parser
1670* string_p == pointer to the string to send
1671* len == number of characters to send, starting from the character
1672* pointed to by `string_p'
1673* OUTPUT
1674* none
1675* RETURNS
1676* utlSUCCESS for success, otherwise utlFAILED
1677* DESCRIPTION
1678* Sends the specified reply sub-string to the DTE.
1679*---------------------------------------------------------------------------*/
1680static utlReturnCode_T utlSendSubstring(const utlAtParser_P2c parser_p,
1681 const char *string_p,
1682 size_t len)
1683{
1684 char buf[utlAT_MAX_RESPONSE_LENGTH];
1685 const char *c_p;
1686
1687 utlAssert(parser_p != NULL);
1688 utlAssert(string_p != NULL);
1689
1690 /*--- is bypass mode enabled? ---*/
1691 if (parser_p->states.bypass_mode)
1692 return utlSUCCESS;
1693
1694 /*--- no reply call-back defined? ---*/
1695 if (parser_p->call_backs.reply_function_p == NULL)
1696 return utlSUCCESS;
1697
1698 c_p = string_p;
1699
1700 /*--- while there's more data to send... ---*/
1701 while (len > (size_t)0)
1702 {
1703 size_t n;
1704
1705 if (len >= utlNumberOf(buf)) n = utlNumberOf(buf) - 1;
1706 else n = len;
1707
1708 /*--- copy data into buffer, filtering out illegal characters ---*/
1709 {
1710 const char *src_p;
1711 const char *term_src_p;
1712 char *dest_p;
1713
1714 src_p = c_p;
1715 term_src_p = c_p + n;
1716 for (dest_p = buf; src_p < term_src_p; src_p++)
1717 /*--- only process characters that are valid in AT-commands... ---*/
1718 if ((*src_p >= '\00') ||
1719 (*src_p == parser_p->parameters.S[utlAT_ESCAPE_CHAR]) ||
1720 (*src_p == parser_p->parameters.S[utlAT_LINE_TERM_CHAR]) ||
1721 (*src_p == parser_p->parameters.S[utlAT_FORMATTING_CHAR]) ||
1722 (*src_p == parser_p->parameters.S[utlAT_LINE_EDIT_CHAR]) ||
1723 (*src_p == parser_p->parameters.S[utlAT_SEPARATER_CHAR]) ||
1724 (*src_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]))
1725 *dest_p++ = *src_p;
1726 *dest_p = '\0';
1727 }
1728
1729 /*--- invoke reply call-back ---*/
1730 if ((parser_p->call_backs.reply_function_p)(buf, parser_p->call_backs.arg_p) != utlSUCCESS)
1731 return utlFAILED;
1732
1733 len -= n;
1734 c_p += n;
1735 }
1736
1737 return utlSUCCESS;
1738}
1739
1740/*---------------------------------------------------------------------------*
1741* FUNCTION
1742* utlSendInfoResponse(parser_p, string_p)
1743* INPUT
1744* parser_p == an open AT-command parser
1745* string_p == pointer to the info-text response expressed as a null-
1746* terminated character string
1747* OUTPUT
1748* none
1749* RETURNS
1750* utlSUCCESS for success, otherwise utlFAILED
1751* DESCRIPTION
1752* Sends the specified info-response string to the DTE.
1753*---------------------------------------------------------------------------*/
1754static utlReturnCode_T utlSendInfoResponse(const utlAtParser_P2c parser_p,
1755 const char *string_p)
1756{
1757 char buf[utlAT_MAX_RESPONSE_LENGTH];
1758 size_t len;
1759 size_t i;
1760
1761 utlAssert(parser_p != NULL);
1762 utlAssert(string_p != NULL);
1763
1764 len = strlen(string_p);
1765
1766 /*--- nothing to send? ---*/
1767 if (len == (size_t)0)
1768 return utlSUCCESS;
1769
1770 /*--- no room? ---*/
1771 if (len >= (utlNumberOf(buf) - 5))
1772 {
1773 utlError(utlSendInfoResponse, "Response-buffer overflow.");
1774 return utlFAILED;
1775 }
1776
1777 i = 0;
1778
1779 /*--- prefix ---*/
1780 if (parser_p->parameters.verbose_results == true)
1781 {
1782 buf[i++] = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
1783 buf[i++] = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
1784 }
1785
1786 /*--- text ---*/
1787 (void)strcpy(buf + i, string_p);
1788 i += len;
1789
1790 /*--- suffix ---*/
1791 buf[i++] = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
1792 buf[i++] = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
1793
1794 buf[i] = '\0';
1795
1796 return utlSendString(parser_p, buf);
1797}
1798
1799/*---------------------------------------------------------------------------*
1800* FUNCTION
1801* utlSendBasicSyntaxResultCode(parser_p, code, ignore_state)
1802* INPUT
1803* parser_p == an open AT-command parser
1804* code == a result code
1805* ignore_state == ignore current state?
1806* OUTPUT
1807* none
1808* RETURNS
1809* utlSUCCESS for success, otherwise utlFAILED
1810* DESCRIPTION
1811* Sends the specified basic-AT-Command result code to the DTE.
1812*---------------------------------------------------------------------------*/
1813static utlReturnCode_T utlSendBasicSyntaxResultCode(const utlAtParser_P2c parser_p,
1814 const utlAtResultCode_T code,
1815 const bool ignore_state)
1816{
1817 UNUSEDPARAM(ignore_state)
1818
1819 char buf[40];
1820 size_t i;
1821
1822 utlAssert(parser_p != NULL);
1823
1824 /*--- suppress result code? ---*/
1825 if ((parser_p->parameters.suppress_results == true) ||
1826 (code == utlAT_RESULT_CODE_SUPPRESS))
1827 return utlSUCCESS;
1828
1829 if (utlAcquireExclusiveAccess(&((utlAtParser_P)parser_p)->cmd_cnt_semaphore) != utlSUCCESS)
1830 {
1831 utlError(utlSendBasicSyntaxResultCode, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
1832 return utlFAILED;
1833 }
1834
1835 /* For multiple AT commands in one line, only for the last AT command, we can return OK */
1836 if (code == utlAT_RESULT_CODE_OK && parser_p->commands_in_line != 0)
1837 {
1838 utlReleaseExclusiveAccess(&((utlAtParser_P)parser_p)->cmd_cnt_semaphore);
1839 return utlSUCCESS;
1840 }
1841
1842 utlReleaseExclusiveAccess(&((utlAtParser_P)parser_p)->cmd_cnt_semaphore);
1843
1844 if (parser_p->parameters.verbose_results == true)
1845 {
1846 const char *s_p;
1847 switch (code)
1848 {
1849 case utlAT_RESULT_CODE_CONNECT:
1850 if (parser_p->options.use_carrier_result_code == true) s_p = "CARRIER";
1851 else s_p = "CONNECT";
1852 break;
1853
1854 case utlAT_RESULT_CODE_OK: s_p = "OK"; break;
1855 case utlAT_RESULT_CODE_RING: s_p = "RING"; break;
1856 case utlAT_RESULT_CODE_NO_CARRIER: s_p = "NO CARRIER"; break;
1857 case utlAT_RESULT_CODE_ERROR: s_p = "ERROR"; break;
1858 case utlAT_RESULT_CODE_NO_DIAL_TONE: s_p = "NO DIAL TONE"; break;
1859 case utlAT_RESULT_CODE_BUSY: s_p = "BUSY"; break;
1860 case utlAT_RESULT_CODE_NO_ANSWER: s_p = "NO ANSWER"; break;
1861 default:
1862 utlError(utlSendBasicSyntaxResultCode1, "Invalid result code %d.", code);
1863 return utlFAILED;
1864 }
1865
1866 i = 0;
1867
1868 /*--- prefix ---*/
1869 buf[i++] = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
1870 buf[i++] = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
1871
1872 /*--- text ---*/
1873 {
1874 (void)strcpy(buf + i, s_p);
1875 i = strlen(buf);
1876
1877 /*--- if we're connecting, insert connect text (if configured) ---*/
1878 if ((parser_p->parameters.include_connect_text == true) &&
1879 (code == utlAT_RESULT_CODE_CONNECT) &&
1880 (parser_p->info.connect_text_p != NULL))
1881 {
1882 buf[i++] = ' ';
1883 buf[i++] = '(';
1884
1885 (void)strncpy(buf + i, parser_p->info.connect_text_p, utlNumberOf(buf) - 8);
1886 i += strlen(parser_p->info.connect_text_p);
1887
1888 buf[i++] = ')';
1889 }
1890 }
1891
1892 /*--- suffix ---*/
1893 buf[i++] = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
1894 buf[i++] = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
1895 buf[i] = '\0';
1896
1897 }
1898 else
1899 {
1900 i = utlDecimalToString(buf, code, utlNumberOf(buf) - 3);
1901
1902 buf[i++] = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
1903 buf[i++] = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
1904 buf[i] = '\0';
1905 }
1906
1907 return utlSendString(parser_p, buf);
1908}
1909
1910static utlReturnCode_T __utlAtCommandResponse(utlAtParser_P parser_p,
1911 utlAtCommand_P2c command_p,
1912 const utlAtCommandResponseType_T response_type,
1913 va_list va_arg_p)
1914{
1915 utlAtParameterValue_P2c parameter_values_p = NULL;
1916 size_t num_parameters = 0;
1917 const char *custom_p = NULL;
1918 const char *info_text_p = NULL;
1919 const char *abort_response_p = NULL;
1920 const char *command_syntax_p = NULL;
1921
1922 /*--- fetch remaining parameters... ---*/
1923 switch (response_type)
1924 {
1925 case utlAT_COMMAND_RESPONSE_TYPE_PARAMETERS:
1926 parameter_values_p = va_arg(va_arg_p, utlAtParameterValue_P2c);
1927 num_parameters = va_arg(va_arg_p, size_t);
1928
1929 /*--- verify parameter count ---*/
1930 if ((num_parameters != command_p->num_parameters) ||
1931 (num_parameters > utlAT_MAX_PARAMETERS))
1932 {
1933 utlError(__utlAtCommandResponse, "Invalid number of AT command parameters: %d", num_parameters);
1934
1935 return utlFAILED;
1936 }
1937
1938 /*--- verify parameter types ---*/
1939 {
1940 utlAtParameter_P parameter_p;
1941 utlAtParameterValue_P2c parameter_value_p;
1942
1943 parameter_p = command_p->parameters_p;
1944 parameter_value_p = parameter_values_p;
1945
1946 /*--- for each of this AT-Command's known parameters... ---*/
1947 while (parameter_p < (command_p->parameters_p + command_p->num_parameters))
1948 {
1949 if (parameter_p->type != parameter_value_p->type)
1950 {
1951 utlError(__utlAtCommandResponse1, "Invalid data type for parameter %d", parameter_p - command_p->parameters_p);
1952
1953 return utlFAILED;
1954 }
1955
1956 parameter_p++;
1957 parameter_value_p++;
1958 }
1959 }
1960 break;
1961
1962 case utlAT_COMMAND_RESPONSE_TYPE_CUSTOM:
1963 custom_p = va_arg(va_arg_p, const char *);
1964 break;
1965
1966 case utlAT_COMMAND_RESPONSE_TYPE_INFO_TEXT:
1967 info_text_p = va_arg(va_arg_p, const char *);
1968 break;
1969
1970 case utlAT_COMMAND_RESPONSE_TYPE_COMMAND_SYNTAX:
1971 command_syntax_p = va_arg(va_arg_p, char *);
1972 break;
1973
1974 case utlAT_COMMAND_RESPONSE_TYPE_REQUEST_COMPLETED:
1975 break;
1976
1977 case utlAT_COMMAND_RESPONSE_TYPE_ABORT:
1978 abort_response_p = va_arg(va_arg_p, const char *);
1979 break;
1980
1981 case utlAT_COMMAND_RESPONSE_TYPE_ERROR:
1982 /* do nothing */
1983 break;
1984
1985 default:
1986 utlError(__utlAtCommandResponse2, "Invalid response-type %d.", response_type);
1987
1988 return utlFAILED;
1989 }
1990
1991 /*--- generate reply ---*/
1992 switch (response_type)
1993 {
1994 case utlAT_COMMAND_RESPONSE_TYPE_PARAMETERS:
1995 if (utlGenerateFormattedGetResponse(parser_p, command_p->name_p, parameter_values_p, num_parameters) != utlSUCCESS)
1996 {
1997 return utlFAILED;
1998 }
1999
2000 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_OK, false) != utlSUCCESS)
2001 return utlFAILED;
2002 break;
2003
2004 case utlAT_COMMAND_RESPONSE_TYPE_CUSTOM:
2005 if (utlSendInfoResponse(parser_p, custom_p) != utlSUCCESS)
2006 {
2007 return utlFAILED;
2008 }
2009
2010 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_SUPPRESS, false) != utlSUCCESS)
2011 return utlFAILED;
2012
2013 break;
2014
2015 case utlAT_COMMAND_RESPONSE_TYPE_INFO_TEXT:
2016 if (utlSendInfoResponse(parser_p, info_text_p) != utlSUCCESS)
2017 {
2018 return utlFAILED;
2019 }
2020
2021 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_OK, false) != utlSUCCESS)
2022 return utlFAILED;
2023 break;
2024
2025 case utlAT_COMMAND_RESPONSE_TYPE_COMMAND_SYNTAX:
2026 if (utlSendInfoResponse(parser_p, command_syntax_p) != utlSUCCESS)
2027 {
2028 return utlAT_RESULT_CODE_ERROR;
2029 }
2030
2031 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_OK, false) != utlSUCCESS)
2032 return utlFAILED;
2033 break;
2034
2035 case utlAT_COMMAND_RESPONSE_TYPE_REQUEST_COMPLETED:
2036
2037 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_OK, false) != utlSUCCESS)
2038 return utlFAILED;
2039 break;
2040
2041 case utlAT_COMMAND_RESPONSE_TYPE_ABORT:
2042 case utlAT_COMMAND_RESPONSE_TYPE_ERROR:
2043 /*--- if we are in a state that requires state-machine intervention ---*/
2044
2045 /*--- just echo failure string ---*/
2046 if (response_type == utlAT_COMMAND_RESPONSE_TYPE_ABORT)
2047 {
2048 if (utlSendInfoResponse(parser_p, abort_response_p) != utlSUCCESS)
2049 {
2050 return utlFAILED;
2051 }
2052
2053 }
2054 else
2055 {
2056 if (utlSendBasicSyntaxResultCode(parser_p, utlAT_RESULT_CODE_ERROR, false) != utlSUCCESS)
2057 {
2058 return utlFAILED;
2059 }
2060
2061 }
2062 break;
2063/* dead code detected here. comment here
2064 default:
2065 utlError("Invalid response-type %d.", response_type);
2066 return utlFAILED;
2067 */
2068 }
2069
2070 return utlSUCCESS;
2071}
2072
2073/*---------------------------------------------------------------------------*
2074* FUNCTION
2075* utlAtCommandResponse(xid, response_type, ...)
2076*
2077* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_PARAMETERS, parameter_values_p, num_parameters)
2078* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_CUSTOM, custom_p)
2079* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_INFO_TEXT, info_text_p)
2080* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_COMMAND_SYNTAX, command_syntax_p)
2081* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_REQUEST_COMPLETED)
2082* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_ABORT, abort_response_p)
2083* utlAtCommandResponse(xid, utlAT_COMMAND_RESPONSE_TYPE_SYNC_ERROR)
2084* INPUT
2085* xid == transaction ID
2086* response_type == the type of response being reported
2087* ... == type-specific parameters
2088* OUTPUT
2089* none
2090* RETURNS
2091* utlSUCCESS for success, otherwise utlFAILED
2092* DESCRIPTION
2093* Forwards an AT-command response to the At-command parser waiting for
2094* `xid'.
2095*---------------------------------------------------------------------------*/
2096utlReturnCode_T utlAtCommandResponse(const unsigned int xid,
2097 const utlAtCommandResponseType_T response_type,
2098 ...)
2099{
2100 va_list va_arg_p;
2101 utlAtParser_P parser_p;
2102 utlAtAsyncResponse_P async_response_p;
2103 utlAtCommand_P2c command_p;
2104 utlReturnCode_T ret = utlFAILED;
2105
2106#ifdef LPP_DEBUG
2107 ERRMSG(utlAtCommandResponse2086, "%s: xid %u, response_type %d\n", __FUNCTION__,xid, response_type);
2108#endif
2109
2110 /*--- ignore command response if transaction ID is 0 or 1 (both are reserved) ---*/
2111 if ((xid == (unsigned int)0) ||
2112 (xid == (unsigned int)1))
2113 return utlSUCCESS;
2114
2115
2116 /*FUTURE
2117 oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo
2118 Interleaving requests...
2119
2120 Currently:
2121 - We get characters and place them into a circular queue (line accumulation).
2122 Once the circular queue contains a complete AT-command, we echo it, and then invoke the call-back
2123 function for that command (if any). If call-back is synchronous, we immediately emit the response.
2124 if call-back is asynchronous, we wait until we get the response, at which time we emit the response.
2125 if another AT-command arrives, we place the characters into the circular queue and wait until we've
2126 echoed the asynchronous response from the current command.
2127
2128 Want:
2129 - The ability to have multiple asynchronous AT command call-backs outstanding at any given time.
2130
2131 Thoughts:
2132 - We already have the technology to queue AT-commands, I would like to keep that feature in order to
2133 limit the max number of active AT commands.
2134 - AT-command echoing is done very early. I some how need to defer this.
2135 - Typical sequence:
2136 AT-command 1
2137 echo "AT-command 1"
2138 AT-command 2
2139 queue "AT-command 2
2140 AT-command 1 response"
2141 echo "AT-command 1 response"
2142 echo "AT-command 2
2143 AT-command 2 response"
2144 echo "AT-command 2 response"
2145 AT-command 3
2146 echo "AT-command 3"
2147 - "parser_p->states.async_response" must be converted into an array AT-commands awaiting an async response.
2148 There is no longer a single await-async timer. Instead there is one for each outstanding async command.
2149 I need to keep track of what is pending an echo. DONE
2150 - Need to keep track of echoed back-space chars too.
2151 - Right now echoing and processing are done at the same time. I need to separate these. Instead of echoing
2152 via "utlSendSubstring()", I could queue it for future echoing. But how to demark what gets echoed from what
2153 gets emitted due to replies?
2154 What if each "await" node had a pointer to where to echo up to (where that command ends). There would then
2155 be two head pointers, one indicating how far we've processed, and another indicating where we should stop
2156 echoing.
2157 - when issuing new commands while existing ones are not done, don't allow new ones with the same OP to
2158 be issued (to prevent abiguity)
2159
2160 ----------------------------------
2161
2162 Solution 1: Receive AT command and issue call-back
2163 immediately, queue echos and responses.
2164
2165 Synchronous: Call-back function returns and specifies the contents of
2166 the response, we just format the response and then echo it.
2167 We need to hold-back the echo'ed text too.
2168
2169 Asynchronous: Call-back function starts the command rolling. We then
2170 wait for the driver event containing the contents of the
2171 response, wich we format and echo.
2172 We need to hold-back the echo'ed text too.
2173
2174 Solution 2:
2175 Receive AT command and issue call-back immediately. Only echo command
2176 once we've received the response. We'll need to preserve command ordering somehow.
2177
2178 Solution 3:
2179 Every time we issue a command, create a node and add to pending-commands list.
2180 Every time we receive a response, match the response to a pending command in the
2181 pending commands list. Every time we receive a response, check the pending-commands
2182 list for finished commands--echo any that are found. Note that the pending-commands
2183 list must also contain the command-string to be echo'ed.
2184
2185 Could have two types of command nodes: waiting for an AT-command reply, strings
2186 that need to be echoed. Nodes must be ordered. Can echo strings at the head
2187 of the list immediately. Can only echo AT-command reply nodes once the AT command
2188 reply has been received.
2189
2190 Notes:
2191 - We want a command like ATH to be able to abort a pending ATD command.
2192 - Can all commands be issued while a current one is pending?
2193 - How many commands will we allow to be pending at the same time?
2194 - I will need a separate async_response structure for each pending command.
2195 - Timeout function needs to know which async_response structure has timed out.
2196 "arg_p" structure should point to async_response function, not parser structure.
2197 -
2198 oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo
2199
2200 Notes:
2201 - Echoed text will always be in the correct order, we just need to insert the responses into the right places
2202 - Responses are a problem. They can arrive in any order.
2203 - I need to match up the responses to the associated requests. When the xid is assigned (first by this library,
2204 then later optionally by the call-back), I need to save it with the text that needs to be echoed
2205 - Sequence:
2206 receive text, echo into a text-fragment node
2207 assign xid, invoke call-back (which may modify the xid)
2208 save xid to text-fragment node
2209 receive reply text, place into a new text-fragment node
2210 insertion sort new text-fragment node into list of waiting text fragments
2211
2212
2213 typedef struct utlTextFragment_S *utlTextFragment_P;
2214 typedef struct utlTextFragment_S {
2215 utlTextFragment_P next_p;
2216 unsigned int xid;
2217 char text[100];
2218 } utlTextFragment_T;
2219
2220 struct {
2221 utlLinkedList_T text_fragments;
2222 } pending_text;
2223
2224 oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo
2225 */
2226
2227 /*--- determine the parser and async_response node associated with the given transaction ID ---*/
2228 {
2229
2230#ifdef LPP_DEBUG
2231 ERRMSG(utlAtCommandResponse2203,"%s: input xid %u\n", __FUNCTION__,xid);
2232#endif
2233 /*--- for each parser... ---*/
2234
2235 for (parser_p = (utlAtParser_P)parsers.head_p; parser_p != NULL; parser_p = parser_p->next_p)
2236 {
2237#ifdef LPP_DEBUG
2238 ERRMSG(utlAtCommandResponse2207,"%s: parser_p 0x%X\n", __FUNCTION__, parser_p);
2239#endif
2240
2241 /*--- for each async response this parser is waiting for... ---*/
2242 for (async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p; async_response_p != NULL; async_response_p = async_response_p->next_p)
2243 {
2244#ifdef LPP_DEBUG
2245 ERRMSG(utlAtCommandResponse2212,"%s: async_response_p->xid %u\n", __FUNCTION__, async_response_p->xid);
2246#endif
2247 if (async_response_p->xid == xid)
2248 break;
2249 }
2250
2251 /*--- found it? ---*/
2252 if (async_response_p != NULL)
2253 break;
2254 }
2255
2256 /*--- is XID invalid/unknown? ---*/
2257 if (parser_p == NULL)
2258 {
2259 utlError(utlAtCommandResponse0,"Invalid/unknown transaction ID %d\n", xid);
2260 return utlFAILED;
2261 }
2262 }
2263
2264 utlAssert(async_response_p != NULL);
2265
2266 /*--- if we're not expecting this response, we'll ignore it ---*/
2267 switch (response_type)
2268 {
2269 case utlAT_COMMAND_RESPONSE_TYPE_PARAMETERS:
2270 if (async_response_p->op != utlAT_ASYNC_OP_GET)
2271 return utlSUCCESS;
2272 break;
2273
2274 case utlAT_COMMAND_RESPONSE_TYPE_CUSTOM:
2275 case utlAT_COMMAND_RESPONSE_TYPE_INFO_TEXT:
2276 if ((async_response_p->op != utlAT_ASYNC_OP_EXEC) &&
2277 (async_response_p->op != utlAT_ASYNC_OP_GET) &&
2278 (async_response_p->op != utlAT_ASYNC_OP_SET) &&
2279 (async_response_p->op != utlAT_ASYNC_OP_ACTION) &&
2280 (async_response_p->op != utlAT_ASYNC_OP_SYNTAX))
2281 return utlSUCCESS;
2282 break;
2283
2284 case utlAT_COMMAND_RESPONSE_TYPE_COMMAND_SYNTAX:
2285 if (async_response_p->op != utlAT_ASYNC_OP_SYNTAX)
2286 return utlSUCCESS;
2287 break;
2288
2289 case utlAT_COMMAND_RESPONSE_TYPE_REQUEST_COMPLETED:
2290 if ((async_response_p->op != utlAT_ASYNC_OP_EXEC) &&
2291 (async_response_p->op != utlAT_ASYNC_OP_SET) &&
2292 (async_response_p->op != utlAT_ASYNC_OP_ACTION))
2293 return utlSUCCESS;
2294 break;
2295
2296 case utlAT_COMMAND_RESPONSE_TYPE_ABORT:
2297 case utlAT_COMMAND_RESPONSE_TYPE_ERROR:
2298 if (async_response_p->op == utlAT_ASYNC_OP_UNKNOWN)
2299 return utlSUCCESS;
2300 break;
2301
2302 default:
2303 utlError(utlAtCommandResponse, "Invalid response type %d.", response_type);
2304 return utlFAILED;
2305 }
2306
2307 /*--- now that we've received an expected asynchronous response, stop timer first ---*/
2308 {
2309 /*--- stop timer ---*/
2310 if (async_response_p->timer_id != (utlTimerId_T)utlFAILED)
2311 {
2312 if (utlStopTimer(async_response_p->timer_id) != utlSUCCESS)
2313 return utlFAILED;
2314
2315 async_response_p->timer_id = utlFAILED;
2316 }
2317 }
2318
2319 //clear SMS datamode
2320 parser_p->call_backs.clearSmsDataMode_p(async_response_p);
2321
2322 /*--- release multiple at commands mutex ---*/
2323 atmcd_mult_unlock(async_response_p->parser_p, async_response_p->command_p, op2type(async_response_p->op));
2324
2325 /*--- update commands_in_line ---*/
2326 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
2327 {
2328 utlError(utlAtCommandResponse1, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
2329 ret = utlFAILED;
2330 goto exit;
2331 }
2332
2333 if (parser_p->commands_in_line == 0)
2334 {
2335 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2336 ret = utlSUCCESS;
2337 goto exit;
2338 }
2339#ifndef AT_CMD_ASYNC_MODE
2340 if(response_type == utlAT_COMMAND_RESPONSE_TYPE_ABORT
2341 || response_type == utlAT_COMMAND_RESPONSE_TYPE_ERROR)
2342 parser_p->commands_in_line = 0;
2343 else
2344 parser_p->commands_in_line--;
2345#else
2346 parser_p->commands_in_line--;
2347#endif
2348 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2349
2350 /*--- ensure we actually reference a command ---*/
2351 if(async_response_p->command_p == NULL)
2352 {
2353 utlError(utlAtCommandResponse3, "%s: command already timeout and has been handled, return directly\n", __FUNCTION__);
2354 return utlFAILED;
2355 }
2356
2357 //check if the command was proxied, and reset the TO counter if it was proxied.
2358 if(async_response_p->isProxy) {
2359 DBGMSG(utlAtCommandResponse4, "PROXY_DEBUG -%s,%d - cmd %s is proxy , and was answered, reset counter\n ",
2360 __FUNCTION__, __LINE__, async_response_p->command_p->name_p);
2361#ifdef OPT_DSDS
2362 parser_p->call_backs.incProxyTOCounter_p(async_response_p->xid, 0);
2363#else
2364 parser_p->call_backs.incProxyTOCounter_p(0);
2365#endif
2366 }
2367
2368 command_p = async_response_p->command_p;
2369 async_response_p->command_p = NULL;
2370
2371 /*--- fetch parameter and send reply ---*/
2372 va_start(va_arg_p, response_type);
2373 ret = __utlAtCommandResponse(parser_p, command_p, response_type, va_arg_p);
2374 va_end(va_arg_p);
2375
2376exit:
2377 /*--- update pending list ---*/
2378#ifndef AT_CMD_ASYNC_MODE
2379 if(response_type == utlAT_COMMAND_RESPONSE_TYPE_ABORT
2380 || response_type == utlAT_COMMAND_RESPONSE_TYPE_ERROR)
2381 {
2382 utlAbandonAllPendingAsyncResponse(parser_p);
2383 }
2384 else
2385#endif
2386 {
2387 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
2388 {
2389 utlError(utlAtCommandResponse5, "Cannot exclusively acquire semaphore!\n");
2390 return utlFAILED;
2391 }
2392
2393 if (utlGetNode( &(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, NULL, async_response_p) != NULL)
2394 {
2395 utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
2396 }
2397 else
2398 {
2399 utlError(utlAtCommandResponse6, "%s:!!!!!!!!!!!!!!!!!!!!!get node error\n", __FUNCTION__);
2400 }
2401
2402#ifdef LPP_DEBUG
2403 ERRMSG(utlAtCommandResponse2374, "%s: remove xid, parser_p 0x%X, counter %d\n", __FUNCTION__,parser_p, parser_p->states.async_responses.pending.node_count);
2404#endif
2405 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
2406 }
2407
2408 async_response_p->xid = utlFAILED;
2409
2410 /*--- trigger AT parser again ---*/
2411 {
2412 if(parser_p->call_backs.atParserTrigger_function_p == NULL)
2413 {
2414 utlError(utlAtCommandResponse7, "Not have AT parser trigger handler\n");
2415 return utlFAILED;
2416 }
2417 if (parser_p->call_backs.atParserTrigger_function_p(parser_p) < 0)
2418 return utlFAILED;
2419 }
2420
2421 return ret;
2422}
2423
2424/*---------------------------------------------------------------------------*
2425* FUNCTION
2426* utlAtDceIoConfigEvent(parser_p)
2427* INPUT
2428* parser_p == an open AT-command parser
2429* OUTPUT
2430* none
2431* RETURNS
2432* utlSUCCESS for success, otherwise utlFAILED
2433* DESCRIPTION
2434* Generates notifications of DCE I/O configuration-changes.
2435*---------------------------------------------------------------------------*/
2436static utlReturnCode_T utlAtDceIoConfigEvent(const utlAtParser_P parser_p)
2437{
2438 utlAssert(parser_p != NULL);
2439
2440 /*--- nothing to report? ---*/
2441 if (parser_p->states.dce_io_config_pending_mask == (unsigned int)0)
2442 return utlSUCCESS;
2443
2444 /*--- update dependent fields ---*/
2445 switch (parser_p->parameters.raw_framing)
2446 {
2447 case 0: parser_p->dce_io_config.data_bits = 0;
2448 parser_p->dce_io_config.parity_bits = 0;
2449 parser_p->dce_io_config.stop_bits = 0; break;
2450 case 1: parser_p->dce_io_config.data_bits = 8;
2451 parser_p->dce_io_config.parity_bits = 0;
2452 parser_p->dce_io_config.stop_bits = 2; break;
2453 case 2: parser_p->dce_io_config.data_bits = 8;
2454 parser_p->dce_io_config.parity_bits = 1;
2455 parser_p->dce_io_config.stop_bits = 1; break;
2456 case 3: parser_p->dce_io_config.data_bits = 8;
2457 parser_p->dce_io_config.parity_bits = 0;
2458 parser_p->dce_io_config.stop_bits = 1; break;
2459 case 4: parser_p->dce_io_config.data_bits = 7;
2460 parser_p->dce_io_config.parity_bits = 0;
2461 parser_p->dce_io_config.stop_bits = 2; break;
2462 case 5: parser_p->dce_io_config.data_bits = 7;
2463 parser_p->dce_io_config.parity_bits = 1;
2464 parser_p->dce_io_config.stop_bits = 1; break;
2465 case 6: parser_p->dce_io_config.data_bits = 7;
2466 parser_p->dce_io_config.parity_bits = 0;
2467 parser_p->dce_io_config.stop_bits = 1; break;
2468
2469 default:
2470 return utlFAILED;
2471 }
2472 switch (parser_p->parameters.raw_parity)
2473 {
2474 case 0: parser_p->dce_io_config.parity = utlDATA_PARITY_ODD; break;
2475 case 1: parser_p->dce_io_config.parity = utlDATA_PARITY_EVEN; break;
2476 case 2: parser_p->dce_io_config.parity = utlDATA_PARITY_MARK; break;
2477 case 3: parser_p->dce_io_config.parity = utlDATA_PARITY_SPACE;
2478 break;
2479
2480 default:
2481 return utlFAILED;
2482 }
2483
2484 /*--- notify I/O subsystem of DCE I/O configuration change ---*/
2485 if ( parser_p->call_backs.dce_io_config_function_p != NULL)
2486 {
2487 if ((parser_p->call_backs.dce_io_config_function_p)(&(parser_p->dce_io_config), parser_p->call_backs.arg_p) != utlSUCCESS)
2488 return utlFAILED;
2489
2490 parser_p->states.dce_io_config_pending_mask = 0;
2491 }
2492
2493 return utlSUCCESS;
2494}
2495
2496/*---------------------------------------------------------------------------*
2497* FUNCTION
2498* utlAtSoundConfigEvent(parser_p)
2499* INPUT
2500* parser_p == an open AT-command parser
2501* OUTPUT
2502* none
2503* RETURNS
2504* utlSUCCESS for success, otherwise utlFAILED
2505* DESCRIPTION
2506* Generates notifications of sound configuration-changes.
2507*---------------------------------------------------------------------------*/
2508static utlReturnCode_T utlAtSoundConfigEvent(const utlAtParser_P parser_p)
2509{
2510 utlAssert(parser_p != NULL);
2511
2512 /*--- nothing to report? ---*/
2513 if (parser_p->states.sound_config_pending_mask == (unsigned int)0)
2514 return utlSUCCESS;
2515
2516 /*--- notify sound subsystem of DCE sound configuration change ---*/
2517 if ( parser_p->call_backs.sound_config_function_p != NULL)
2518 {
2519 if ((parser_p->call_backs.sound_config_function_p)(&(parser_p->sound_config), parser_p->call_backs.arg_p) != utlSUCCESS)
2520 return utlFAILED;
2521
2522 parser_p->states.sound_config_pending_mask = 0;
2523 }
2524
2525 return utlSUCCESS;
2526}
2527
2528/*---------------------------------------------------------------------------*
2529* FUNCTION
2530* utlProcessSParameter(parser_p, parameter_num, parameter_value)
2531* INPUT
2532* parser_p == an open AT-command parser
2533* parameter_num == Number of S-parameter to process
2534* parameter_value == S-parameter's value
2535* OUTPUT
2536* none
2537* RETURNS
2538* returns utlSUCCESS for success, otherwise utlFAILED
2539* DESCRIPTION
2540* Processes the specified S-parameter: update dependent fields.
2541*---------------------------------------------------------------------------*/
2542static utlAtResultCode_T utlProcessSParameter(const utlAtParser_P parser_p,
2543 const unsigned int parameter_num,
2544 const unsigned int parameter_value)
2545{
2546 utlAssert(parser_p != NULL);
2547
2548 /*--- check value ---*/
2549 {
2550 bool bad_value;
2551
2552 bad_value = false;
2553
2554 switch (parameter_num)
2555 {
2556 case utlAT_ESCAPE_CHAR:
2557 case utlAT_SEPARATER_CHAR:
2558 case utlAT_TERMINATER_CHAR:
2559 case utlAT_XON_CHAR:
2560 case utlAT_XOFF_CHAR:
2561 if (parameter_value > (unsigned int)127)
2562 bad_value = true;
2563 break;
2564
2565 /* for S3, only 13 is valid */
2566 case utlAT_LINE_TERM_CHAR:
2567 if (parameter_value != (unsigned int)13)
2568 bad_value = true;
2569 break;
2570
2571 /* for S4, only 10 is valid */
2572 case utlAT_FORMATTING_CHAR:
2573 if (parameter_value != (unsigned int)10)
2574 bad_value = true;
2575 break;
2576
2577 /* for S5, only 8 is valid */
2578 case utlAT_LINE_EDIT_CHAR:
2579 if (parameter_value != (unsigned int)8)
2580 bad_value = true;
2581 break;
2582
2583 case utlAT_AUTO_ANSWER:
2584 case utlAT_RING_COUNTER:
2585 case utlAT_DIALING_PAUSE_TIME:
2586 case utlAT_ESCAPE_GUARD_TIME:
2587 case utlAT_DTR_DELAY_TIME:
2588 case utlAT_HOOK_FLASH_TIME:
2589 case utlAT_INACTIVITY_TIME:
2590 case utlAT_DISCONNECT_WAIT_TIME:
2591 if (parameter_value > (unsigned int)255)
2592 bad_value = true;
2593 break;
2594
2595 case utlAT_BLIND_DIAL_PAUSE_TIME:
2596 if ((parameter_value < (unsigned int)2) ||
2597 (parameter_value > (unsigned int)10))
2598 bad_value = true;
2599 break;
2600
2601 case utlAT_CONN_COMPLETE_TIMEOUT:
2602 case utlAT_CARRIER_DETECT_TIME:
2603 if ((parameter_value < (unsigned int)1) ||
2604 (parameter_value > (unsigned int)255))
2605 bad_value = true;
2606 break;
2607
2608 /* the range of S11 is 50 - 255 */
2609 case utlAT_DTMF_TONE_DURATION:
2610 if ((parameter_value < (unsigned int)50) ||
2611 (parameter_value > (unsigned int)255))
2612 bad_value = true;
2613 break;
2614
2615 case utlAT_CARRIER_LOSS_TIME:
2616 if ((parameter_value < (unsigned int)1) ||
2617 (parameter_value > (unsigned int)254))
2618 bad_value = true;
2619 break;
2620
2621 default:
2622 /*--- will S-parameter value not fit into S-parameter data type? ---*/
2623 if (parameter_value > ( 1u << ((sizeof(parser_p->parameters.S[0]) * 8u) - 1u)) +
2624 ((1u << ((sizeof(parser_p->parameters.S[0]) * 8u) - 1u)) - 1u))
2625 bad_value = true;
2626 break;
2627 }
2628
2629 if (bad_value == true)
2630 {
2631 utlError(utlProcessSParameter, "Invalid S-parameter value (%d) for S-parameter %d.", parameter_value, parameter_num);
2632 return utlAT_RESULT_CODE_ERROR;
2633 }
2634 }
2635
2636 /*--- update dependencies (if any) ---*/
2637 switch (parameter_num)
2638 {
2639 case utlAT_AUTO_ANSWER:
2640 if(parser_p->call_backs.setAutoAnswerDelay_function_p == NULL)
2641 {
2642 utlError(utlProcessSParameter1, "No auto answer delay set call back function!");
2643 return utlAT_RESULT_CODE_ERROR;
2644 }
2645 parser_p->call_backs.setAutoAnswerDelay_function_p(parser_p->call_backs.arg_p, parameter_value);
2646 break;
2647 case utlAT_BLIND_DIAL_PAUSE_TIME: parser_p->states.blind_dial_pause_time.seconds = parameter_value;
2648 parser_p->states.blind_dial_pause_time.nanoseconds = 0; break;
2649 case utlAT_CONN_COMPLETE_TIMEOUT: parser_p->states.conn_complete_timeout.seconds = parameter_value;
2650 parser_p->states.conn_complete_timeout.nanoseconds = 0; break;
2651 case utlAT_DIALING_PAUSE_TIME: parser_p->states.dialing_pause_time.seconds = parameter_value;
2652 parser_p->states.dialing_pause_time.nanoseconds = 0; break;
2653 case utlAT_CARRIER_DETECT_TIME: parser_p->states.carrier_detect_time.seconds = parameter_value / 10;
2654 parser_p->states.carrier_detect_time.nanoseconds = (parameter_value % 10) * (1000000000 / 10); break;
2655 case utlAT_CARRIER_LOSS_TIME: parser_p->states.carrier_loss_time.seconds = parameter_value / 10;
2656 parser_p->states.carrier_loss_time.nanoseconds = (parameter_value % 10) * (1000000000 / 10); break;
2657 case utlAT_XON_CHAR: parser_p->dce_io_config.flow_control.xon_char = parameter_value;
2658 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_FLOW_CONTROL; break;
2659 case utlAT_XOFF_CHAR: parser_p->dce_io_config.flow_control.xoff_char = parameter_value;
2660 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_FLOW_CONTROL; break;
2661 case utlAT_DTR_DELAY_TIME: parser_p->dce_io_config.dtr_delay_time.seconds = parameter_value / 100;
2662 parser_p->dce_io_config.dtr_delay_time.nanoseconds = parameter_value % 100 * (1000000000 / 100);
2663 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DTR_DELAY; break;
2664 case utlAT_HOOK_FLASH_TIME: parser_p->states.hook_flash_time.seconds = parameter_value / 10;
2665 parser_p->states.hook_flash_time.nanoseconds = (parameter_value % 10) * (1000000000 / 10); break;
2666 case utlAT_INACTIVITY_TIME: parser_p->states.inactivity_time.seconds = parameter_value * 10;
2667 parser_p->states.inactivity_time.nanoseconds = 0; break;
2668 case utlAT_DISCONNECT_WAIT_TIME: parser_p->states.disconnect_wait_time.seconds = parameter_value;
2669 parser_p->states.disconnect_wait_time.nanoseconds = 0; break;
2670 default:
2671 break;
2672 }
2673
2674 return utlSUCCESS;
2675}
2676
2677/*---------------------------------------------------------------------------*
2678* FUNCTION
2679* utlProcessBasicAtCommand(parser_p, command_p, parameter_value_p,
2680* response_p, response_siz, syntax_off)
2681* INPUT
2682* parser_p == an open AT-command parser
2683* command_p == the AT command to process
2684* parameter_value_p == the found parameter value (there's only ever one)
2685* response_p == pointer to where the response (if any) should be placed
2686* response_siz == length of array pointed to by `response_p'
2687* syntax_off == offset from start of line to the AT-command (for
2688* error reporting)
2689* OUTPUT
2690* *response_p == the response (if any)
2691* RETURNS
2692* utlAT_RESULT_CODE_ERROR for failure, other values for success
2693* DESCRIPTION
2694* Processes a basic AT-command.
2695*---------------------------------------------------------------------------*/
2696static utlAtResultCode_T utlProcessBasicAtCommand(const utlAtParser_P parser_p,
2697 const utlAtCommand_P2c command_p,
2698 const utlAtParameterValue_P2c parameter_value_p,
2699 char *response_p,
2700 const size_t response_siz,
2701 const size_t syntax_off)
2702{
2703 utlAtResultCode_T rc;
2704
2705 utlAssert(parser_p != NULL);
2706 utlAssert(command_p != NULL);
2707 utlAssert(parameter_value_p != NULL);
2708 utlAssert(response_p != NULL);
2709
2710 utlError(utlProcessBasicAtCommand100, "utlProcessBasicAtCommand\n");
2711
2712 rc = utlAT_RESULT_CODE_OK;
2713
2714 switch (command_p->name_p[0])
2715 {
2716 case 'e': /*--- command echo ---*/
2717 case 'E': if (parameter_value_p->value.decimal == (unsigned int)0) parser_p->parameters.echo_text = false;
2718 else if (parameter_value_p->value.decimal == (unsigned int)1) parser_p->parameters.echo_text = true;
2719 else
2720 rc = utlAT_RESULT_CODE_ERROR;
2721 break;
2722
2723 case 'i': /*--- request identification information ---*/
2724 case 'I': if (parameter_value_p->value.decimal != (unsigned int)0)
2725 {
2726 rc = utlAT_RESULT_CODE_ERROR;
2727 break;
2728 }
2729
2730 (void)strncpy(response_p, parser_p->info.id_p, response_siz);
2731 break;
2732
2733 case 'l': /*--- set monitor-speaker level ---*/
2734 case 'L': switch (parameter_value_p->value.decimal)
2735 {
2736 case 0:
2737 case 1:
2738 case 2:
2739 case 3: parser_p->sound_config.monitor_speaker.level = parameter_value_p->value.decimal;
2740 parser_p->states.sound_config_pending_mask |= utlAT_SOUND_CONFIG_PENDING_LEVEL;
2741 break;
2742 default:
2743 rc = utlAT_RESULT_CODE_ERROR;
2744 break;
2745 }
2746 break;
2747
2748 case 'm': /*--- set monitor-speaker mode ---*/
2749 case 'M': switch (parameter_value_p->value.decimal)
2750 {
2751 case 0:
2752 case 1:
2753 case 2: parser_p->sound_config.monitor_speaker.mode = parameter_value_p->value.decimal;
2754 parser_p->states.sound_config_pending_mask |= utlAT_SOUND_CONFIG_PENDING_MODE;
2755 break;
2756 default:
2757 rc = utlAT_RESULT_CODE_ERROR;
2758 break;
2759 }
2760 break;
2761
2762 case 'o': /*--- enter on-line mode ---*/
2763 case 'O': if ((parameter_value_p->value.decimal == (unsigned int)0) ||
2764 (parameter_value_p->value.decimal == (unsigned int)1))
2765 {
2766
2767 parser_p->states.go_on_line = true;
2768 rc = utlAT_RESULT_CODE_CONNECT;
2769
2770 }
2771 else
2772 {
2773 rc = utlAT_RESULT_CODE_ERROR;
2774 break;
2775 }
2776 break;
2777
2778 case 'p': /*--- select pulse dialing ---*/
2779 case 'P': if (parameter_value_p->value.decimal != (unsigned int)0)
2780 {
2781 rc = utlAT_RESULT_CODE_ERROR;
2782 break;
2783 }
2784
2785 parser_p->parameters.dialing_mode = utlAT_DIALING_MODE_PULSE;
2786 break;
2787
2788 case 'q': /*--- result-code suppression ---*/
2789 case 'Q': if (parameter_value_p->value.decimal == (unsigned int)0) parser_p->parameters.suppress_results = false;
2790 else if (parameter_value_p->value.decimal == (unsigned int)1) parser_p->parameters.suppress_results = true;
2791 else
2792 {
2793 rc = utlAT_RESULT_CODE_ERROR;
2794 break;
2795 }
2796 break;
2797
2798 case 't': /*--- select DTMF tone dialing ---*/
2799 case 'T': if (parameter_value_p->value.decimal != (unsigned int)0)
2800 {
2801 rc = utlAT_RESULT_CODE_ERROR;
2802 break;
2803 }
2804
2805 parser_p->parameters.dialing_mode = utlAT_DIALING_MODE_TONE;
2806 break;
2807
2808 case 'v': /*--- DCE response format ---*/
2809 case 'V': if (parameter_value_p->value.decimal == (unsigned int)0) parser_p->parameters.verbose_results = false;
2810 else if (parameter_value_p->value.decimal == (unsigned int)1) parser_p->parameters.verbose_results = true;
2811 else
2812 {
2813 rc = utlAT_RESULT_CODE_ERROR;
2814 break;
2815 }
2816 break;
2817
2818 case 'x': /*--- result code selection and call progress monitoring control ---*/
2819 case 'X': switch (parameter_value_p->value.decimal)
2820 {
2821 case 0: parser_p->parameters.include_connect_text = false;
2822 parser_p->parameters.detect_dial_tone = false;
2823 parser_p->parameters.detect_busy_signal = false;
2824 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DIAL_TONE |
2825 utlAT_DCE_IO_CONFIG_PENDING_BUSY_SIGNAL; break;
2826 case 1: parser_p->parameters.include_connect_text = true;
2827 parser_p->parameters.detect_dial_tone = false;
2828 parser_p->parameters.detect_busy_signal = false;
2829 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DIAL_TONE |
2830 utlAT_DCE_IO_CONFIG_PENDING_BUSY_SIGNAL; break;
2831 case 2: parser_p->parameters.include_connect_text = true;
2832 parser_p->parameters.detect_dial_tone = true;
2833 parser_p->parameters.detect_busy_signal = false;
2834 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DIAL_TONE |
2835 utlAT_DCE_IO_CONFIG_PENDING_BUSY_SIGNAL; break;
2836 case 3: parser_p->parameters.include_connect_text = true;
2837 parser_p->parameters.detect_dial_tone = false;
2838 parser_p->parameters.detect_busy_signal = true;
2839 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DIAL_TONE |
2840 utlAT_DCE_IO_CONFIG_PENDING_BUSY_SIGNAL; break;
2841 case 4: parser_p->parameters.include_connect_text = true;
2842 parser_p->parameters.detect_dial_tone = true;
2843 parser_p->parameters.detect_busy_signal = true;
2844 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DIAL_TONE |
2845 utlAT_DCE_IO_CONFIG_PENDING_BUSY_SIGNAL; break;
2846 default:
2847 rc = utlAT_RESULT_CODE_ERROR;
2848 break;
2849 }
2850 break;
2851
2852 case 'z': /*--- Reset to default configuration ---*/
2853 case 'Z': if (parameter_value_p->value.decimal != (unsigned int)0)
2854 {
2855 rc = utlAT_RESULT_CODE_ERROR;
2856 break;
2857 }
2858 {
2859 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
2860 {
2861 utlError(utlProcessBasicAtCommand, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
2862 return utlAT_RESULT_CODE_ERROR;
2863 }
2864
2865 size_t commands_in_line = parser_p->commands_in_line;
2866
2867 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2868
2869 if (utlAtReset(parser_p) != utlSUCCESS)
2870 rc = utlAT_RESULT_CODE_ERROR;
2871
2872 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
2873 {
2874 utlError(utlProcessBasicAtCommand1, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
2875 return utlAT_RESULT_CODE_ERROR;
2876 }
2877
2878 parser_p->commands_in_line = commands_in_line;
2879
2880 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2881 }
2882 break;
2883
2884 case '&': /*--- basic-command prefix character ---*/
2885 switch (command_p->name_p[1])
2886 {
2887 case 'c': /*--- DCD (output) control ---*/
2888 case 'C': switch (parameter_value_p->value.decimal)
2889 {
2890 case 0: parser_p->dce_io_config.modes.dcd_always_on = true;
2891 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DCD; break;
2892 case 1: parser_p->dce_io_config.modes.dcd_always_on = false;
2893 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DCD; break;
2894 default:
2895 rc = utlAT_RESULT_CODE_ERROR;
2896 break;
2897 }
2898 break;
2899
2900 case 'd': /*--- DTR (input) monitoring ---*/
2901 case 'D': switch (parameter_value_p->value.decimal)
2902 {
2903 case 0: parser_p->dce_io_config.modes.ignore_dtr = true;
2904 parser_p->dce_io_config.modes.drop_call_on_dtr_loss = false;
2905 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DTR; break;
2906 case 1: parser_p->dce_io_config.modes.ignore_dtr = false;
2907 parser_p->dce_io_config.modes.drop_call_on_dtr_loss = false;
2908 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DTR; break;
2909 case 2: parser_p->dce_io_config.modes.ignore_dtr = false;
2910 parser_p->dce_io_config.modes.drop_call_on_dtr_loss = true;
2911 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DTR; break;
2912 default:
2913 rc = utlAT_RESULT_CODE_ERROR;
2914 break;
2915 }
2916 break;
2917
2918 case 'f': /*--- set to factory configuration ---*/
2919 case 'F': if (parameter_value_p->value.decimal != (unsigned int)0)
2920 {
2921 rc = utlAT_RESULT_CODE_ERROR;
2922 break;
2923 }
2924 {
2925 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
2926 {
2927 utlError(utlProcessBasicAtCommand2, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
2928 return utlAT_RESULT_CODE_ERROR;
2929 }
2930
2931 size_t commands_in_line = parser_p->commands_in_line;
2932
2933 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2934
2935 if (utlAtReset(parser_p) != utlSUCCESS)
2936 rc = utlAT_RESULT_CODE_ERROR;
2937
2938 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
2939 {
2940 utlError(utlProcessBasicAtCommand3, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
2941 return utlAT_RESULT_CODE_ERROR;
2942 }
2943
2944 parser_p->commands_in_line = commands_in_line;
2945
2946 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
2947 }
2948
2949 break;
2950
2951 case 's': /*--- DSR (output) control ---*/
2952 case 'S': switch (parameter_value_p->value.decimal)
2953 {
2954 case 0: parser_p->dce_io_config.modes.dsr_mode = 0;
2955 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DSR; break;
2956 case 1: parser_p->dce_io_config.modes.dsr_mode = 0;
2957 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DSR; break;
2958 default:
2959 rc = utlAT_RESULT_CODE_ERROR;
2960 break;
2961 }
2962 break;
2963
2964 default: break;
2965 }
2966
2967 default: break;
2968 }
2969
2970 /*--- if execution of the basic build-in AT-command failed ---*/
2971 if (rc == utlAT_RESULT_CODE_ERROR)
2972 {
2973 switch (parameter_value_p->type)
2974 {
2975 case utlAT_DATA_TYPE_DECIMAL: utlError(utlProcessBasicAtCommand4, "Invalid parameter value (%d) for `%s' AT command at col=%d.", parameter_value_p->value.decimal, command_p->name_p, syntax_off); break;
2976 case utlAT_DATA_TYPE_DIAL_STRING: utlError(utlProcessBasicAtCommand5, "Invalid parameter value (%s) for `%s' AT command at col=%d.", parameter_value_p->value.dial_string_p, command_p->name_p, syntax_off); break;
2977 default: utlError(utlProcessBasicAtCommand6, "Invalid parameter value for `%s' AT command at col=%d.", command_p->name_p, syntax_off); break;
2978 }
2979 }
2980
2981 return rc;
2982}
2983
2984/*---------------------------------------------------------------------------*
2985* FUNCTION
2986* utlAsyncResponseTimeoutHandler(id, timeout_count, arg_p, curr_time_p)
2987* INPUT
2988* id == timer ID
2989* timeout_count == the time-out count
2990* arg_p == pointer to the response we timed-out on
2991* curr_time_p == current time since the epoch
2992* OUTPUT
2993* modifies the data pointed to by `arg_p'
2994* RETURNS
2995* utlSUCCESS for success, utlFAILED for failure.
2996* DESCRIPTION
2997* Handles async response time-out events: terminates the wait by
2998* generating an error.
2999*---------------------------------------------------------------------------*/
3000static utlReturnCode_T utlAsyncResponseTimeoutHandler(const utlTimerId_T id,
3001 const unsigned long timeout_count,
3002 void *arg_p,
3003 const utlAbsoluteTime_P2c curr_time_p)
3004{
3005 UNUSEDPARAM(id)
3006 UNUSEDPARAM(timeout_count)
3007 UNUSEDPARAM(curr_time_p)
3008
3009 utlAtAsyncResponse_P async_response_p;
3010 utlReturnCode_T rc;
3011 utlAtParser_P parser_p;
3012
3013 utlAssert(arg_p != NULL);
3014
3015 async_response_p = (utlAtAsyncResponse_P)arg_p;
3016 parser_p = async_response_p->parser_p;
3017 utlAssert(parser_p != NULL);
3018
3019
3020 if(async_response_p->command_p != NULL)
3021 {
3022 utlError(utlAsyncResponseTimeoutHandler, "AT Command %s timeout\n", async_response_p->command_p->name_p);
3023 }
3024
3025 //clear SMS_over_nas
3026 parser_p->call_backs.clearSmsoverNas_P(async_response_p);
3027
3028 //check if this command was proxied
3029 if(async_response_p->isProxy) {
3030 //clear the proxy flag for the command, to avoid double handling
3031 async_response_p->isProxy = 0;
3032
3033 utlError(utlAsyncResponseTimeoutHandler3, "ready to proxyEsc\n");
3034
3035 //proxy esc to ims
3036 parser_p->call_backs.proxyEsc_p(arg_p);
3037
3038 //increment the command counter
3039 if(async_response_p->command_p) {
3040 DBGMSG(utlAsyncResponseTimeoutHandler1, "PROXY_DEBUG -%s,%d - cmd %s is proxy , and failed, inc counter\n ",
3041 __FUNCTION__, __LINE__, async_response_p->command_p->name_p);
3042 }
3043#ifdef OPT_DSDS
3044 parser_p->call_backs.incProxyTOCounter_p(async_response_p->xid,1);
3045#else
3046 parser_p->call_backs.incProxyTOCounter_p(1);
3047#endif
3048 }
3049
3050 if(parser_p->call_backs.atcmdTimeoutError_function_P == NULL)
3051 {
3052 utlError(utlAsyncResponseTimeoutHandler2, "Not have AT command timeout error handler\n");
3053 return utlFAILED;
3054 }
3055 rc = parser_p->call_backs.atcmdTimeoutError_function_P(async_response_p->xid);
3056
3057 async_response_p->op = utlAT_ASYNC_OP_UNKNOWN;
3058 async_response_p->command_p = NULL;
3059 async_response_p->timer_id = utlFAILED;
3060
3061 parser_p->states.sync_response.complete_reported = false;
3062 parser_p->states.sync_response.abort_reported = false;
3063 parser_p->states.sync_response.error_reported = false;
3064 parser_p->states.sync_response.parameter_values_p = NULL;
3065 parser_p->states.sync_response.custom_p = NULL;
3066 parser_p->states.sync_response.info_text_p = NULL;
3067 parser_p->states.sync_response.abort_response_p = NULL;
3068 parser_p->states.sync_response.command_syntax_p = NULL;
3069
3070 if(parser_p->call_backs.atcmdContinuousTimeout_function_p != NULL)
3071 {
3072#ifdef OPT_DSDS
3073 parser_p->call_backs.atcmdContinuousTimeout_function_p(arg_p);
3074#else
3075 parser_p->call_backs.atcmdContinuousTimeout_function_p();
3076#endif
3077 }
3078
3079 return rc;
3080}
3081
3082/*---------------------------------------------------------------------------*
3083* FUNCTION
3084* utlSetupPendingAsyncResponse(parser_p, op, command_p)
3085* INPUT
3086* parser_p == an open AT-command parser
3087* op == a pending asyncchronous operation
3088* command_p == pointer to the AT-command about to be executed
3089* OUTPUT
3090* none
3091* RETURNS
3092* a pointer to a new async-response node success, NULL for failure.
3093* DESCRIPTION
3094* Sets up for an async response.
3095*---------------------------------------------------------------------------*/
3096static utlAtAsyncResponse_P utlSetupPendingAsyncResponse(const utlAtParser_P parser_p,
3097 const utlAtAsyncOp_T op,
3098 const utlAtCommand_P2c command_p,
3099 unsigned int proxyFlag)
3100{
3101 utlAtAsyncResponse_P async_response_p;
3102
3103 utlAssert(parser_p != NULL);
3104
3105 utlError(utlSetupPendingAsyncResponse100, "utlSetupPendingAsyncResponse\n");
3106
3107 {
3108 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3109 {
3110 utlError(utlSetupPendingAsyncResponse, "Cannot exclusively acquire semaphore!\n");
3111 return NULL;
3112 }
3113
3114 if ((async_response_p = utlGetHeadNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T)) == NULL)
3115 {
3116 utlError(utlSetupPendingAsyncResponse1, "There is no unused response node!\n");
3117 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3118 return NULL;
3119 }
3120
3121 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3122
3123 async_response_p->parser_p = parser_p;
3124 async_response_p->xid = utlNextAvailableXID();
3125 async_response_p->op = op;
3126 async_response_p->command_p = command_p;
3127 async_response_p->text_response_p = NULL;
3128 async_response_p->isProxy = proxyFlag; //if 1 - command send to proxy
3129
3130 /*--- start timer ---*/
3131 {
3132 utlRelativeTime_T period;
3133
3134 if(parser_p->call_backs.getAtcmdTimeoutValue_function_p == NULL)
3135 {
3136 utlError(utlSetupPendingAsyncResponse2, "Not have the at command timeout value getting handler\n");
3137 return NULL;
3138 }
3139
3140 if(strcasecmp(command_p->name_p, "*PRXYUNKOWN") != 0)
3141 period.seconds = parser_p->call_backs.getAtcmdTimeoutValue_function_p(command_p->name_p, op);
3142 else
3143 period.seconds = parser_p->call_backs.getAtcmdTimeoutValue_function_p(prxy_command_name, op);
3144
3145 if(proxyFlag)
3146 period.seconds += 180; //to avoid AT with long timeout blocks following AT
3147
3148 ERRMSG(utlSetupPendingAsyncResponse101, "[%s] name_p %s, period.seconds %d\n", __FUNCTION__, command_p->name_p, period.seconds);
3149
3150 period.nanoseconds = 0;
3151 if ((async_response_p->timer_id = utlStartTimer(&period, 1, &utlAsyncResponseTimeoutHandler, async_response_p)) == (utlTimerId_T)utlFAILED)
3152 {
3153
3154 utlError(utlSetupPendingAsyncResponse3, "Fail to start the timer!\n");
3155 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3156 {
3157 utlError(utlSetupPendingAsyncResponse4, "Cannot exclusively acquire semaphore!\n");
3158 return NULL;
3159 }
3160
3161 /*--- clean ---*/
3162 (void)utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
3163
3164 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3165 return NULL;
3166 }
3167 }
3168
3169 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3170 {
3171 utlError(utlSetupPendingAsyncResponse5, "Cannot exclusively acquire semaphore!\n");
3172 return NULL;
3173 }
3174
3175 utlPutTailNode(&(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, async_response_p);
3176
3177 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3178 }
3179
3180 parser_p->states.sync_response.complete_reported = false;
3181 parser_p->states.sync_response.abort_reported = false;
3182 parser_p->states.sync_response.error_reported = false;
3183 parser_p->states.sync_response.parameter_values_p = NULL;
3184 parser_p->states.sync_response.custom_p = NULL;
3185 parser_p->states.sync_response.info_text_p = NULL;
3186 parser_p->states.sync_response.abort_response_p = NULL;
3187 parser_p->states.sync_response.command_syntax_p = NULL;
3188
3189#ifdef LPP_DEBUG
3190 utlAtAsyncResponse_P async_response_p_bak;
3191 utlAtParser_P parser_p_bak;
3192
3193 for (parser_p_bak = (utlAtParser_P)parsers.head_p; parser_p_bak != NULL; parser_p_bak = parser_p_bak->next_p)
3194 {
3195 ERRMSG(utlSetupPendingAsyncResponse3157,"%s: parser_p 0x%X\n", __FUNCTION__, parser_p_bak);
3196
3197 /*--- for each async response this parser is waiting for... ---*/
3198 for (async_response_p_bak = (utlAtAsyncResponse_P)parser_p_bak->states.async_responses.pending.head_p; async_response_p_bak != NULL; async_response_p_bak = async_response_p_bak->next_p)
3199 {
3200 ERRMSG(utlSetupPendingAsyncResponse3162,"%s: async_response_p->xid %u\n", __FUNCTION__, async_response_p_bak->xid);
3201 }
3202 }
3203#endif
3204
3205 return async_response_p;
3206}
3207/*---------------------------------------------------------------------------*
3208* FUNCTION
3209* utlModifyPendingAsyncResponse(period_p, xid)
3210* INPUT
3211* period_p == pointer to the timeout time you want to set
3212* xid == transaction ID
3213* OUTPUT
3214* none
3215* RETURNS
3216* utlFAILED for failure, utlSUCCESS for success
3217* DESCRIPTION
3218* Modify the Pending time for an async response.
3219*---------------------------------------------------------------------------*/
3220utlReturnCode_T utlModifyPendingAsyncResponse( const utlRelativeTime_P period_p,
3221 const unsigned int xid)
3222{
3223 utlAtParser_P parser_p = NULL;
3224 utlAtAsyncResponse_P async_response_p = NULL;
3225 utlAssert(period_p != NULL);
3226 for (parser_p = (utlAtParser_P)parsers.head_p; parser_p != NULL; parser_p = parser_p->next_p)
3227 {
3228 async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p;
3229 for (; async_response_p != NULL; async_response_p = async_response_p->next_p)
3230 {
3231 if (async_response_p->xid == xid)
3232 {
3233 break;
3234 }
3235 }
3236 if (async_response_p != NULL)
3237 break;
3238 }
3239 if(parser_p == NULL)
3240 {
3241 utlError(utlModifyPendingAsyncResponse, "Invalid/unknown transaction ID %d\n", xid);
3242 return utlFAILED;
3243 }
3244 utlAssert(async_response_p != NULL);
3245 if (async_response_p->timer_id != (utlTimerId_T)utlFAILED)
3246 {
3247 if (utlStopTimer(async_response_p->timer_id) != utlSUCCESS)
3248 return utlFAILED;
3249 async_response_p->timer_id = utlFAILED;
3250 }
3251 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3252 {
3253 utlError(utlModifyPendingAsyncResponse1, "Cannot exclusively acquire semaphore!\n");
3254 return utlFAILED;
3255 }
3256 if (utlGetNode(&(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, NULL, async_response_p) == NULL)
3257 {
3258 utlError(utlModifyPendingAsyncResponse2, "There is no such pending response node!\n");
3259 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3260 return utlFAILED;
3261 }
3262 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3263 if ((async_response_p->timer_id = utlStartTimer(period_p, 1, &utlAsyncResponseTimeoutHandler, async_response_p)) == (utlTimerId_T)utlFAILED)
3264 {
3265 utlError(utlModifyPendingAsyncResponse3, "Fail to start the timer!\n");
3266 /*--- clean ---*/
3267 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3268 {
3269 utlError(utlModifyPendingAsyncResponse4, "Cannot exclusively acquire semaphore!\n");
3270 return utlFAILED;
3271 }
3272 utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
3273 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3274 return utlFAILED;
3275 }
3276
3277 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3278 {
3279 utlError(utlModifyPendingAsyncResponse5, "Cannot exclusively acquire semaphore!\n");
3280 return utlFAILED;
3281 }
3282
3283 utlPutTailNode(&(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, async_response_p);
3284
3285 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3286 return utlSUCCESS;
3287}
3288
3289/*---------------------------------------------------------------------------*
3290* FUNCTION
3291* utlAbandonPendingAsyncResponse(async_response_p)
3292* INPUT
3293* async_response_p == the response to abandon
3294* OUTPUT
3295* none
3296* RETURNS
3297* nothing
3298* DESCRIPTION
3299* Abandons the setup for a pending async response.
3300*---------------------------------------------------------------------------*/
3301static void utlAbandonPendingAsyncResponse(const utlAtAsyncResponse_P async_response_p)
3302{
3303 utlAtParser_P parser_p;
3304
3305 utlAssert(async_response_p != NULL);
3306
3307 parser_p = async_response_p->parser_p;
3308 utlAssert(parser_p != NULL);
3309
3310 /*--- release ---*/
3311 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3312 {
3313 utlError(utlAbandonPendingAsyncResponse, "Cannot exclusively acquire semaphore!\n");
3314 return;
3315 }
3316
3317 if (utlGetNode( &(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, NULL, async_response_p) != NULL)
3318 {
3319 utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
3320
3321 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3322
3323 /*--- stop timer (as necessary) ---*/
3324 if ( async_response_p->timer_id != (utlTimerId_T)utlFAILED)
3325 {
3326 (void)utlStopTimer(async_response_p->timer_id);
3327
3328 async_response_p->timer_id = utlFAILED;
3329 }
3330 }
3331 else
3332 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3333
3334#ifdef LPP_DEBUG
3335 ERRMSG(utlAbandonPendingAsyncResponse3307, "%s: remove xid, parser_p 0x%X, counter %d\n", __FUNCTION__,parser_p, parser_p->states.async_responses.pending.node_count);
3336#endif
3337}
3338
3339/*---------------------------------------------------------------------------*
3340* FUNCTION
3341* utlAbandonAllPendingAsyncResponse(parser_p)
3342* INPUT
3343* parser_p
3344* OUTPUT
3345* none
3346* RETURNS
3347* nothing
3348* DESCRIPTION
3349* Abandons all the pending async responses for one parser.
3350*---------------------------------------------------------------------------*/
3351static void utlAbandonAllPendingAsyncResponse(utlAtParser_P parser_p)
3352{
3353 utlAtAsyncResponse_P async_response_p;
3354
3355 utlAssert(parser_p != NULL);
3356
3357 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3358 {
3359 utlError(utlAbandonAllPendingAsyncResponse, "Cannot exclusively acquire semaphore!\n");
3360 return;
3361 }
3362
3363 /* just fetch the head node without removing it from pending list */
3364 async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p;
3365
3366 if (async_response_p != NULL)
3367 {
3368 while (async_response_p != NULL)
3369 {
3370 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3371
3372 /*--- stop timer (as necessary) ---*/
3373 if (async_response_p->timer_id != (utlTimerId_T)utlFAILED)
3374 {
3375 (void)utlStopTimer(async_response_p->timer_id);
3376 async_response_p->timer_id = utlFAILED;
3377 }
3378
3379 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
3380 {
3381 utlError(utlAbandonAllPendingAsyncResponse1, "Cannot exclusively acquire semaphore!\n");
3382 return;
3383 }
3384 /* remove node from pending list, and append it to unused list */
3385 if (utlGetNode( &(parser_p->states.async_responses.pending), utlAtAsyncResponse_T, NULL, async_response_p) != NULL)
3386 utlPutTailNode(&(parser_p->states.async_responses.unused), utlAtAsyncResponse_T, async_response_p);
3387
3388#ifdef LPP_DEBUG
3389 ERRMSG(utlAbandonAllPendingAsyncResponse3360, "%s: remove xid, parser_p 0x%X,counter %d\n", __FUNCTION__,parser_p, parser_p->states.async_responses.pending.node_count);
3390#endif
3391 /* fetch next head node from pending list */
3392 async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p;
3393 }
3394 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3395
3396 }
3397 else
3398 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
3399}
3400/*---------------------------------------------------------------------------*
3401* FUNCTION
3402* utlClearPendingAsyncResponse()
3403* INPUT
3404* parser_p
3405* OUTPUT
3406* none
3407* RETURNS
3408* nothing
3409* DESCRIPTION
3410* Clear all the pending async responses for all parsers
3411*---------------------------------------------------------------------------*/
3412void utlClearPendingAsyncResponse(void)
3413{
3414 utlAtParser_P parser_p;
3415 utlAtAsyncResponse_P async_response_p;
3416
3417#ifdef LPP_DEBUG
3418 ERRMSG(utlClearPendingAsyncResponse3367,"%s: clear xid\n", __FUNCTION__);
3419#endif
3420
3421 /*--- iterate all parsers and send ERROR for pending async response ---*/
3422 {
3423 /*--- for each parser... ---*/
3424 for (parser_p = (utlAtParser_P)parsers.head_p; parser_p != NULL; parser_p = parser_p->next_p)
3425 {
3426
3427 /*--- fetch the first pending async response for this parser,
3428 other pending async response will be cleared in utlAtCommandResponse */
3429 async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p;
3430 if (async_response_p != NULL)
3431 utlAtCommandResponse(async_response_p->xid, utlAT_COMMAND_RESPONSE_TYPE_ERROR, "");
3432
3433 parser_p->states.sync_response.complete_reported = false;
3434 parser_p->states.sync_response.abort_reported = false;
3435 parser_p->states.sync_response.error_reported = false;
3436 parser_p->states.sync_response.parameter_values_p = NULL;
3437 parser_p->states.sync_response.custom_p = NULL;
3438 parser_p->states.sync_response.info_text_p = NULL;
3439 parser_p->states.sync_response.abort_response_p = NULL;
3440 parser_p->states.sync_response.command_syntax_p = NULL;
3441 }
3442 }
3443}
3444
3445#if 0
3446/*---------------------------------------------------------------------------*
3447* FUNCTION
3448* utlAtResultCode_T utlHandleLateEvent(const utlAtParser_P parser_p,
3449* utlAtAsyncResponse_P async_response_p)
3450* INPUT
3451* parser_p == an open AT-command parser
3452* async_response_p == name of the AT command to execute
3453*
3454* OUTPUT
3455* none
3456* RETURNS
3457* utlAT_RESULT_CODE_ERROR for failure, other values for success
3458* DESCRIPTION
3459* Handle driver events that occur during the invocation of an application-supplied call-back function
3460*---------------------------------------------------------------------------*/
3461static utlAtResultCode_T utlHandleLateEvent(const utlAtParser_P parser_p,
3462 utlAtAsyncResponse_P async_response_p)
3463{
3464 utlAtResultCode_T rc = utlAT_RESULT_CODE_NULL;
3465
3466 /*--- utlAT_COMMAND_RESPONSE_TYPE_ERROR response ---*/
3467 if (parser_p->states.sync_response.error_reported)
3468 {
3469 parser_p->states.sync_response.error_reported = false;
3470 utlAbandonPendingAsyncResponse(async_response_p);
3471
3472 parser_p->peg_counts.bad_commands++;
3473 return utlAT_RESULT_CODE_ERROR;
3474 }
3475
3476 /*--- utlAT_COMMAND_RESPONSE_TYPE_ABORT response ---*/
3477 if (parser_p->states.sync_response.abort_reported)
3478 {
3479 parser_p->states.sync_response.abort_reported = false;
3480 utlAbandonPendingAsyncResponse(async_response_p);
3481
3482 if (utlSendInfoResponse(parser_p, parser_p->states.sync_response.abort_response_p) != utlSUCCESS)
3483 return utlAT_RESULT_CODE_ERROR;
3484 parser_p->states.sync_response.abort_response_p = NULL;
3485
3486 parser_p->peg_counts.bad_commands++;
3487 return utlAT_RESULT_CODE_SUPPRESS;
3488 }
3489
3490 /*--- utlAT_COMMAND_RESPONSE_TYPE_REQUEST_COMPLETED response ---*/
3491 if (parser_p->states.sync_response.complete_reported)
3492 {
3493 utlAbandonPendingAsyncResponse(async_response_p);
3494
3495 parser_p->peg_counts.basic_commands++;
3496 return utlAT_RESULT_CODE_OK;
3497 }
3498
3499 /*--- utlAT_COMMAND_RESPONSE_TYPE_CUSTOM response ---*/
3500 if (parser_p->states.sync_response.custom_p != NULL)
3501 {
3502 utlAbandonPendingAsyncResponse(async_response_p);
3503
3504 if (utlSendInfoResponse(parser_p, parser_p->states.sync_response.custom_p) != utlSUCCESS)
3505 return utlAT_RESULT_CODE_ERROR;
3506 parser_p->states.sync_response.custom_p = NULL;
3507
3508 parser_p->peg_counts.basic_commands++;
3509 return utlAT_RESULT_CODE_SUPPRESS;
3510 }
3511
3512 /*--- utlAT_COMMAND_RESPONSE_TYPE_INFO_TEXT response ---*/
3513 if (parser_p->states.sync_response.info_text_p != NULL)
3514 {
3515 utlAbandonPendingAsyncResponse(async_response_p);
3516
3517 if (utlSendInfoResponse(parser_p, parser_p->states.sync_response.info_text_p) != utlSUCCESS)
3518 return utlAT_RESULT_CODE_ERROR;
3519 parser_p->states.sync_response.info_text_p = NULL;
3520
3521 parser_p->peg_counts.basic_commands++;
3522 return utlAT_RESULT_CODE_OK;
3523 }
3524
3525 /*--- utlAT_COMMAND_RESPONSE_TYPE_COMMAND_SYNTAX events ---*/
3526 if (parser_p->states.sync_response.command_syntax_p != NULL)
3527 {
3528 utlAbandonPendingAsyncResponse(async_response_p);
3529
3530 if (utlSendInfoResponse(parser_p, parser_p->states.sync_response.command_syntax_p) != utlSUCCESS)
3531 return utlAT_RESULT_CODE_ERROR;
3532 parser_p->states.sync_response.command_syntax_p = NULL;
3533
3534 parser_p->peg_counts.extended_commands++;
3535 return utlAT_RESULT_CODE_OK;
3536 }
3537
3538 return rc;
3539}
3540#endif
3541
3542unsigned int utlCheckIfSendToProxy(const char * cmdName,utlAtRequestType_T reqType ,const utlAtParser_P parser_p, const char* parameters_string_p)
3543{
3544 utlAtParameterOp_T cmdOp = utlAT_PARAMETER_OP_SYNTAX;
3545 unsigned int parserIdForProxy;
3546 unsigned int proxyFlag = 0;
3547
3548 VDBGMSG(utlCheckIfSendToProxy, "PROXY_DEBUG -%s,%d - check if comand %s with op %d is proxy\n",
3549 __FUNCTION__, __LINE__, cmdName, (int)reqType);
3550
3551 //TODO the two special case used to trigger cp assert , should not foward to proxy channel
3552 if(strcasecmp(cmdName,"D")==0 && strcasecmp(parser_p->states.dial_string.buf,"##3424*9#")==0){
3553 return proxyFlag;
3554 }
3555 if(strcasecmp(cmdName,"D")==0 && parser_p->states.dial_string.buf[strlen(parser_p->states.dial_string.buf)-1]!=';'){
3556 return proxyFlag;
3557 }
3558 if(strcasecmp(cmdName,"+CUSD")==0 && strcasecmp(parser_p->basic_command_param,"1,##3424*9#")==0){
3559 return proxyFlag;
3560 }
3561#if 0
3562 if(strcasecmp(cmdName,"+CFUN")==0){
3563 return proxyFlag;
3564 }
3565#endif
3566 if(strcasecmp(cmdName,"+CLCK")==0){
3567
3568 if(parameters_string_p != NULL) {
3569 char* pos0 = NULL;
3570 char* pos1 = NULL;
3571 char fac[16]={'\0'};
3572 pos0 = strstr(parameters_string_p, "\"");
3573 if (pos0 != NULL) {
3574 pos1 = strstr(pos0 + 1, "\"");
3575 if (pos1 != NULL)
3576 strncpy(fac, pos0 + 1, pos1 - pos0 -1);
3577 }
3578
3579 if (strcasecmp(fac, "AO") != 0 && strcasecmp(fac, "OI") != 0 && strcasecmp(fac, "OX") != 0 && strcasecmp(fac, "AI") != 0 &&
3580 strcasecmp(fac, "IR") != 0 && strcasecmp(fac, "AB") != 0 && strcasecmp(fac, "AG") != 0 && strcasecmp(fac, "AC") != 0) {
3581 VDBGMSG(utlCheckIfSendToProxy_3438, "PROXY_DEBUG -%s,%d - comand %s will not proxy\n",
3582 __FUNCTION__, __LINE__, cmdName);
3583 return proxyFlag;
3584 }
3585 } else
3586 return proxyFlag;
3587 }
3588 //translate command req to operation
3589 switch(reqType) {
3590 case utlAT_REQUEST_TYPE_SYNTAX:
3591 cmdOp = utlAT_PARAMETER_OP_SYNTAX;
3592 break;
3593 case utlAT_REQUEST_TYPE_SET:
3594 cmdOp = utlAT_PARAMETER_OP_SET;
3595 break;
3596 case utlAT_REQUEST_TYPE_GET:
3597 cmdOp = utlAT_PARAMETER_OP_GET;
3598 break;
3599 }
3600
3601 //check if the command appears in the proxy list
3602 if(parser_p->call_backs.isProxyReq_function_p != NULL) {
3603 parserIdForProxy = *(unsigned int*)(parser_p->call_backs.arg_p);
3604
3605 proxyFlag = (parser_p->call_backs.isProxyReq_function_p)(cmdName,cmdOp, parserIdForProxy);
3606 }
3607
3608 return proxyFlag;
3609}
3610
3611/*---------------------------------------------------------------------------*
3612* FUNCTION
3613* utlExecuteBasicAtCommand(parser_p, command_name_p, parameter_found,
3614* parameter_value_p, syntax_off)
3615* INPUT
3616* parser_p == an open AT-command parser
3617* command_name_p == name of the AT command to execute
3618* parameter_found == was the parameter found?
3619* parameter_value_p == a pointer to the parameter value
3620* syntax_off == offset from start of line to the AT-command (for
3621* error reporting)
3622* OUTPUT
3623* none
3624* RETURNS
3625* utlAT_RESULT_CODE_ERROR for failure, other values for success
3626* DESCRIPTION
3627* Executes the basic AT-command specified by `command_name_p'.
3628*---------------------------------------------------------------------------*/
3629static utlAtResultCode_T utlExecuteBasicAtCommand(const utlAtParser_P parser_p,
3630 const char *command_name_p,
3631 const bool parameter_found,
3632 const utlAtParameterValue_P2c parameter_value_p,
3633 const size_t syntax_off)
3634{
3635 utlAtCommand_P2c command_p;
3636 char text_response[utlAT_MAX_RESPONSE_LENGTH];
3637 utlAtResultCode_T rc;
3638 unsigned int proxyFlag = 0;
3639
3640 utlAssert(parser_p != NULL);
3641 utlAssert(parameter_value_p != NULL);
3642 utlAssert(command_name_p != NULL);
3643
3644 utlError(utlExecuteBasicAtCommand100, "utlExecuteBasicAtCommand\n");
3645
3646 /*--- search for AT-command info ---*/
3647 {
3648 utlAtCommand_P2c term_command_p;
3649
3650 term_command_p = parser_p->commands_p + parser_p->num_commands;
3651 for (command_p = parser_p->commands_p; command_p < term_command_p; command_p++)
3652 if ((command_p->type == utlAT_COMMAND_TYPE_BASIC) &&
3653 (tolower( command_p->name_p[0]) == tolower(command_name_p[0])) &&
3654 (strcasecmp(command_p->name_p, command_name_p) == 0))
3655 break;
3656
3657 if (command_p >= term_command_p)
3658 {
3659 parser_p->peg_counts.undefined_commands++;
3660 return utlAT_RESULT_CODE_ERROR;
3661 }
3662 }
3663
3664 /*-- complain if command should not have a parameter, yet a parameter was found ---*/
3665 if ((parameter_found == true) && (command_p->parameters_p == NULL))
3666 {
3667 utlError(utlExecuteBasicAtCommand, "Unexpected parameter supplied to AT command at col=%d.", syntax_off);
3668 parser_p->peg_counts.bad_commands++;
3669 return utlAT_RESULT_CODE_ERROR;
3670 }
3671
3672 //check if the command is proxy
3673 proxyFlag = utlCheckIfSendToProxy(command_name_p, utlAT_REQUEST_TYPE_SET, parser_p, NULL);//the handled basic commands are considered as SET
3674 utlError(utlExecuteBasicAtCommand2, "PRXY_DEBUG -%s,%d- proxy flag for comand %s with op %d is %d\n",
3675 __FUNCTION__, __LINE__, command_name_p, (int)utlAT_REQUEST_TYPE_SET,proxyFlag);
3676
3677 utlTrace(utlTRACE_AT_PARSER,
3678 switch (parameter_value_p->type)
3679 {
3680 case utlAT_DATA_TYPE_DECIMAL: utlPrintTrace("AT%s (set: %d)\n", command_name_p, parameter_value_p->value.decimal); break;
3681 case utlAT_DATA_TYPE_HEXADECIMAL: utlPrintTrace("AT%s (set: 0x%x)\n", command_name_p, parameter_value_p->value.hexadecimal); break;
3682 case utlAT_DATA_TYPE_BINARY: utlPrintTrace("AT%s (set: 0x%x)\n", command_name_p, parameter_value_p->value.binary); break;
3683 case utlAT_DATA_TYPE_STRING: utlPrintTrace("AT%s (set: \"%s\")\n", command_name_p, parameter_value_p->value.string_p); break;
3684 case utlAT_DATA_TYPE_QSTRING: utlPrintTrace("AT%s (set: \"%s\")\n", command_name_p, parameter_value_p->value.qstring_p); break;
3685 case utlAT_DATA_TYPE_DIAL_STRING: utlPrintTrace("AT%s (set: %s)\n", command_name_p, parameter_value_p->value.dial_string_p); break;
3686 }
3687 );
3688
3689 atmcd_mult_lock(parser_p, command_p, 0);
3690
3691 /*--- process built-in AT commands (as necessary) ---*/
3692 {
3693 /*--- initially assume no text response is required ---*/
3694 text_response[0] = '\0';
3695
3696 if ((rc = utlProcessBasicAtCommand(parser_p,
3697 command_p,
3698 parameter_value_p,
3699 text_response,
3700 utlNumberOf(text_response),
3701 syntax_off)) == utlAT_RESULT_CODE_ERROR)
3702 {
3703 parser_p->peg_counts.bad_commands++;
3704 rc = utlAT_RESULT_CODE_ERROR;
3705 utlError(utlExecuteBasicAtCommand11, "utlExecuteBasicAtCommand: utlProcessBasicAtCommand fail\n");
3706
3707 goto out_err;
3708 }
3709 }
3710
3711 /*--- invoke AT-command call-back (as appropriate) ---*/
3712 if ((command_p->call_backs.set_parameter_function_p != NULL)||(proxyFlag))
3713 {
3714 utlAtAsyncResponse_P async_response_p;
3715
3716 /*--- setup for pending asynchronous response ---*/
3717 if ((async_response_p = utlSetupPendingAsyncResponse(parser_p, utlAT_ASYNC_OP_EXEC, command_p,proxyFlag)) == NULL) {
3718 rc = utlAT_RESULT_CODE_ERROR;
3719 utlError(utlExecuteBasicAtCommand12, "utlExecuteBasicAtCommand: utlSetupPendingAsyncResponse fail\n");
3720 goto out_err;
3721 }
3722
3723 if(proxyFlag) {
3724 //handle ATD specificly
3725 if(!strcasecmp(command_name_p,"d")) {
3726 //handle D specificly
3727 utlError(utlExecuteBasicAtCommand3, "PROXY_DEBUG -%s,%d- for ATD - proxy flag is on, sent string is %s\n",
3728 __FUNCTION__, __LINE__, parser_p->states.dial_string.buf);
3729
3730 if( (parser_p->call_backs.sendToProxy_function_p)(command_name_p,
3731 utlAT_PARAMETER_OP_EXEC, //need to send the command with =
3732 parser_p->states.dial_string.buf,
3733 &(async_response_p->xid),
3734 parser_p->call_backs.arg_p)!= utlSUCCESS)
3735 {
3736 /*--- clean ---*/
3737 utlAbandonPendingAsyncResponse(async_response_p);
3738 utlError(utlExecuteBasicAtCommand13, "utlExecuteBasicAtCommand: sendToProxy ATD fail\n");
3739
3740 parser_p->peg_counts.bad_commands++;
3741 rc = utlAT_RESULT_CODE_ERROR;
3742 goto out_err;
3743 }
3744 }
3745 else {
3746 //send the command with the proxy string that was created before
3747 utlError(utlExecuteBasicAtCommand4, "PROXY_DEBUG -%s,%d- for cmd %s- with param %s\n",
3748 __FUNCTION__, __LINE__, command_name_p,parser_p->basic_command_param);
3749 if( (parser_p->call_backs.sendToProxy_function_p)(command_name_p,
3750 utlAT_PARAMETER_OP_EXEC,
3751 parser_p->basic_command_param,
3752 &(async_response_p->xid),
3753 parser_p->call_backs.arg_p)!= utlSUCCESS)
3754 {
3755 /*--- clean ---*/
3756 utlAbandonPendingAsyncResponse(async_response_p);
3757
3758 parser_p->peg_counts.bad_commands++;
3759 rc = utlAT_RESULT_CODE_ERROR;
3760
3761 utlError(utlExecuteBasicAtCommand14, "utlExecuteBasicAtCommand: sendToProxy fail\n");
3762
3763 goto out_err;
3764 }
3765 }
3766 }
3767
3768 else{
3769 if ((command_p->call_backs.set_parameter_function_p)(utlAT_PARAMETER_OP_EXEC,
3770 command_name_p,
3771 (command_p->num_parameters == (size_t)0) ? NULL : parameter_value_p,
3772 command_p->num_parameters,
3773 text_response,
3774 &(async_response_p->xid),
3775 parser_p->call_backs.arg_p) != utlSUCCESS)
3776 {
3777 /*--- clean ---*/
3778 utlAbandonPendingAsyncResponse(async_response_p);
3779
3780 parser_p->peg_counts.bad_commands++;
3781 rc = utlAT_RESULT_CODE_ERROR;
3782 utlError(utlExecuteBasicAtCommand15, "utlExecuteBasicAtCommand: set_parameter_function fail\n");
3783
3784 goto out_err;
3785 }
3786 }
3787 rc = utlAT_RESULT_CODE_SUPPRESS;
3788 }
3789 else
3790 {
3791 parser_p->peg_counts.bad_commands++;
3792 rc = utlAT_RESULT_CODE_ERROR;
3793 utlError(utlExecuteBasicAtCommand16, "utlExecuteBasicAtCommand: bad_commands\n");
3794 goto out_err;
3795 }
3796 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
3797 {
3798 utlError(utlExecuteBasicAtCommand5, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
3799 rc = utlAT_RESULT_CODE_ERROR;
3800 goto out_err;
3801 }
3802
3803 /* dead code detected by converty comment here
3804 if (rc == utlAT_RESULT_CODE_OK)
3805 parser_p->commands_in_line--;
3806 */
3807
3808 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
3809
3810 parser_p->peg_counts.basic_commands++;
3811
3812 return rc;
3813out_err:
3814 utlError(utlExecuteBasicAtCommand6, "TOMER @%s:%d\n", __FUNCTION__, __LINE__);
3815 atmcd_mult_unlock(parser_p, command_p, 0);
3816 return rc;
3817}
3818
3819/*---------------------------------------------------------------------------*
3820* FUNCTION
3821* utlFormatExtendedResultString(parser_p, result_p, result_siz, name_p, string_p)
3822* INPUT
3823* parser_p == an open AT-command parser
3824* result_p == pointer to where to place the formated result
3825* result_siz == length of array pointed to by `result_p'
3826* name_p == pointer to an AT-Command name expressed as a null-terminated
3827* character string
3828* string_p == pointer to a null-terminated character string
3829* OUTPUT
3830* *result_p == the formated result
3831* RETURNS
3832* the number of characters written to `string_p'
3833* DESCRIPTION
3834* Formats the specified extended-AT-Command result string.
3835*---------------------------------------------------------------------------*/
3836static size_t utlFormatExtendedResultString(const utlAtParser_P parser_p,
3837 char *result_p,
3838 const size_t result_siz,
3839 const char *name_p,
3840 const char *string_p)
3841{
3842 size_t name_len;
3843 size_t string_len;
3844 size_t i;
3845
3846 utlAssert(parser_p != NULL);
3847 utlAssert(result_p != NULL);
3848 utlAssert(name_p != NULL);
3849 utlAssert(string_p != NULL);
3850
3851 /*--- are results being suppressed? ---*/
3852 if (parser_p->parameters.suppress_results == true)
3853 return 0;
3854
3855 name_len = strlen( name_p);
3856 string_len = strlen(string_p);
3857
3858 /*--- no room for result? ---*/
3859 if ((name_len + string_len) >= (result_siz - 3))
3860 {
3861 utlError(utlFormatExtendedResultString, "Buffer overflow.");
3862 return 0;
3863 }
3864
3865 /*--- format for result is: "<name_p>: <string_p>" ---*/
3866 (void)strcpy(result_p, name_p);
3867 i = name_len;
3868
3869 result_p[i++] = ':';
3870 result_p[i++] = ' ';
3871
3872 (void)strcpy(result_p + i, string_p);
3873 i += string_len;
3874
3875 result_p[i] = '\0';
3876
3877 return i;
3878}
3879
3880/*---------------------------------------------------------------------------*
3881* FUNCTION
3882* utlProcessExtendedAtCommand(parser_p, request_type, command_p,
3883* parameter_values_p, response_p,
3884* response_siz, syntax_off)
3885* INPUT
3886* parser_p == an open AT-command parser
3887* request_type == type of request
3888* command_p == pointer to the AT command to process
3889* parameter_values_p == command's associated parameter values
3890* response_p == where to place the response (if any)
3891* response_siz == length of array pointed to by `response_p'
3892* syntax_off == offset from start of line to AT-command (only
3893* used for error reporting)
3894* OUTPUT
3895* response_p == where the response was placed (if any)
3896* RETURNS
3897* utlAT_RESULT_CODE_ERROR for failure, other values for success
3898* DESCRIPTION
3899* Processes the extended built-in AT command specified by `command_p'.
3900*---------------------------------------------------------------------------*/
3901static utlAtResultCode_T utlProcessExtendedAtCommand(const utlAtParser_P parser_p,
3902 const utlAtRequestType_T request_type,
3903 const utlAtCommand_P2c command_p,
3904 utlAtParameterValue_P parameter_values_p,
3905 char *response_p,
3906 const size_t response_siz,
3907 const size_t syntax_off)
3908{
3909 utlAtResultCode_T rc;
3910
3911 utlAssert(parser_p != NULL);
3912 utlAssert(command_p != NULL);
3913 utlAssert(response_p != NULL);
3914 utlAssert(response_siz > (size_t)2);
3915
3916 utlAssert(command_p->name_p != NULL);
3917
3918 utlError(utlProcessExtendedAtCommand100, "utlProcessExtendedAtCommand\n");
3919
3920 /*--- nothing to do (we only process commands starting with "+A", "+G", "+I", or "+C")? ---*/
3921 if ((command_p->name_p[0] != '+') || ((command_p->name_p[1] != 'a') &&
3922 (command_p->name_p[1] != 'A') &&
3923 (command_p->name_p[1] != 'c') &&
3924 (command_p->name_p[1] != 'C') &&
3925 (command_p->name_p[1] != 'g') &&
3926 (command_p->name_p[1] != 'G') &&
3927 (command_p->name_p[1] != 'i') &&
3928 (command_p->name_p[1] != 'I')))
3929 return utlAT_RESULT_CODE_OK;
3930
3931 rc = utlAT_RESULT_CODE_OK;
3932
3933 /*--- save/fetch dial-string ---*/
3934 if (strcasecmp(command_p->name_p, "+ASTO") == 0)
3935 {
3936 utlAssert((parameter_values_p[0].type == utlAT_DATA_TYPE_DECIMAL) ||
3937 (parameter_values_p[0].type == utlAT_DATA_TYPE_STRING) ||
3938 (parameter_values_p[0].type == utlAT_DATA_TYPE_QSTRING));
3939 utlAssert(parameter_values_p[1].type == utlAT_DATA_TYPE_DIAL_STRING);
3940
3941 /*--- fetch? ---*/
3942 if (request_type == utlAT_REQUEST_TYPE_GET)
3943 {
3944 char *c_p;
3945 char *term_c_p;
3946 const char *next_location_name_p;
3947 bool need_cr_lf;
3948
3949 c_p = response_p;
3950 term_c_p = response_p + response_siz;
3951
3952 next_location_name_p = NULL;
3953
3954 /*--- retrieve name of first location (if any) ---*/
3955 if ( parser_p->call_backs.retrieve_dial_string_function_p != NULL)
3956 if ((parser_p->call_backs.retrieve_dial_string_function_p)(&next_location_name_p, NULL, parser_p->call_backs.arg_p) != utlSUCCESS)
3957 {
3958 rc = utlAT_RESULT_CODE_ERROR;
3959 next_location_name_p = NULL;
3960 }
3961
3962 /*--- for each stored dial-string... ---*/
3963 need_cr_lf = false;
3964 while (next_location_name_p != NULL)
3965 {
3966 const char *location_name_p;
3967 const char *dial_string_p;
3968
3969 /*--- save location name reference ---*/
3970 location_name_p = next_location_name_p;
3971
3972 dial_string_p = NULL;
3973
3974 /*--- retrieve previously saved dial string (if any) ---*/
3975 if ( parser_p->call_backs.retrieve_dial_string_function_p != NULL)
3976 if ((parser_p->call_backs.retrieve_dial_string_function_p)(&next_location_name_p, &dial_string_p, parser_p->call_backs.arg_p) != utlSUCCESS)
3977 {
3978 rc = utlAT_RESULT_CODE_ERROR;
3979 break;
3980 }
3981
3982 /*--- found a previously-saved dial string? ---*/
3983 if ((dial_string_p != NULL) && (strlen(dial_string_p) > (size_t)0))
3984 {
3985 char buf[utlAT_MAX_RESPONSE_LENGTH];
3986
3987 /*--- generate dial-string info: <location>,<dial-string><cr><lf> ---*/
3988 {
3989 size_t i;
3990
3991 (void)strncpy(buf, location_name_p, utlNumberOf(buf));
3992 i = strlen(location_name_p);
3993
3994 buf[i++] = parser_p->parameters.S[utlAT_SEPARATER_CHAR];
3995
3996 (void)strncpy(buf + i, dial_string_p, utlNumberOf(buf) - i - 4);
3997 i += strlen(dial_string_p);
3998
3999 buf[i] = '\0';
4000
4001 }
4002
4003 /*--- append dial-string info ---*/
4004 {
4005 size_t rv;
4006
4007 /*--- separate multiple entries with line-termination sequences (if there's room) ---*/
4008 if (need_cr_lf == true)
4009 {
4010 if (response_siz > (size_t)(c_p - response_p + 2))
4011 {
4012 *c_p++ = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
4013 *c_p++ = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
4014 }
4015 }
4016 else
4017 need_cr_lf = true;
4018
4019 if ((rv = utlFormatExtendedResultString(parser_p, c_p,
4020 response_siz - (c_p - response_p),
4021 command_p->name_p,
4022 buf)) == (size_t)0)
4023 {
4024 rc = utlAT_RESULT_CODE_ERROR;
4025 break;
4026 }
4027
4028 c_p += rv;
4029 }
4030 }
4031 }
4032
4033 /*--- generate empty response if there's nothing to report ---*/
4034 if (c_p == response_p)
4035 {
4036 *c_p++ = parser_p->parameters.S[utlAT_LINE_TERM_CHAR];
4037 *c_p++ = parser_p->parameters.S[utlAT_FORMATTING_CHAR];
4038 }
4039
4040 *c_p = '\0';
4041
4042 /*--- else save ---*/
4043 }
4044 else if (request_type == utlAT_REQUEST_TYPE_SET)
4045 {
4046 const char *location_name_p;
4047 const char *dial_string_p;
4048 char location_name[20]; /* plenty big for a 64-bit unsigned integer */
4049 /*--- we'll accept either a decimal or string for "location". According
4050 to V.250 this parameter should be a decimal number, but our dial-string
4051 storage implementation also supports storing phone numbers under
4052 names. So allowing ASTO to also store under names is convenient for
4053 testing. */
4054 if (parameter_values_p[0].type == utlAT_DATA_TYPE_DECIMAL)
4055 {
4056 unsigned int location;
4057
4058 location = parameter_values_p[0].value.decimal;
4059
4060 if (utlDecimalToString(location_name, location, utlNumberOf(location_name)) == (size_t)0)
4061 rc = utlAT_RESULT_CODE_ERROR;
4062
4063 location_name_p = location_name;
4064
4065 }
4066 else if (parameter_values_p[0].type == utlAT_DATA_TYPE_STRING)
4067 location_name_p = parameter_values_p[0].value.string_p;
4068
4069 else if (parameter_values_p[0].type == utlAT_DATA_TYPE_STRING)
4070 location_name_p = parameter_values_p[0].value.qstring_p;
4071
4072 else
4073 location_name_p = "";
4074
4075 if (rc == utlAT_RESULT_CODE_OK)
4076 {
4077 dial_string_p = parameter_values_p[1].value.dial_string_p;
4078
4079 /*--- invoke save-dial-string call-back (if any) ---*/
4080 if ( parser_p->call_backs.save_dial_string_function_p != NULL)
4081 {
4082 if ((parser_p->call_backs.save_dial_string_function_p)(location_name_p, dial_string_p, parser_p->call_backs.arg_p) != utlSUCCESS)
4083 rc = utlAT_RESULT_CODE_ERROR;
4084 }
4085 }
4086
4087 }
4088 else
4089 rc = utlAT_RESULT_CODE_ERROR;
4090
4091 /*--- request manufacturer identification ---*/
4092 }
4093 else if ((strcasecmp(command_p->name_p, "+GMI") == 0) ||
4094 (strcasecmp(command_p->name_p, "+CGMI") == 0))
4095 {
4096
4097 if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4098 (request_type == utlAT_REQUEST_TYPE_SET))
4099// (void) strncpy(response_p, parser_p->info.manufacturer_p, response_siz);
4100 sprintf(response_p, "%s: \"%s\"", command_p->name_p, parser_p->info.manufacturer_p);
4101 else
4102 rc = utlAT_RESULT_CODE_ERROR;
4103
4104 /*--- request model identification ---*/
4105 }
4106 else if ((strcasecmp(command_p->name_p, "+GMM") == 0) ||
4107 (strcasecmp(command_p->name_p, "+CGMM") == 0))
4108 {
4109
4110 if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4111 (request_type == utlAT_REQUEST_TYPE_SET))
4112// (void) strncpy(response_p, parser_p->info.model_p, response_siz);
4113 sprintf(response_p, "%s: \"%s\"", command_p->name_p, parser_p->info.model_p);
4114 else
4115 rc = utlAT_RESULT_CODE_ERROR;
4116
4117 /*--- request revision identification ---*/
4118 }
4119 else if ((strcasecmp(command_p->name_p, "+GMR") == 0) ||
4120 (strcasecmp(command_p->name_p, "+CGMR") == 0))
4121 {
4122
4123 if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4124 (request_type == utlAT_REQUEST_TYPE_SET))
4125// (void) strncpy(response_p, parser_p->info.revision_p, response_siz);
4126 sprintf(response_p, "%s: \"%s\"", command_p->name_p, revisionId);
4127 else
4128 rc = utlAT_RESULT_CODE_ERROR;
4129
4130 /*--- request product serial number (optional command) ---*/
4131 }
4132 else if ((strcasecmp(command_p->name_p, "+GSN") == 0) ||
4133 (strcasecmp(command_p->name_p, "+CGSN") == 0))
4134 {
4135
4136 if (parser_p->info.serial_number_p == NULL)
4137 rc = utlAT_RESULT_CODE_ERROR;
4138 else if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4139 (request_type == utlAT_REQUEST_TYPE_SET))
4140 (void)strncpy(response_p, parser_p->info.serial_number_p, response_siz);
4141 else
4142 rc = utlAT_RESULT_CODE_ERROR;
4143
4144 /*--- request global object identification (optional command) ---*/
4145 }
4146 else if ((strcasecmp(command_p->name_p, "+GOI") == 0) ||
4147 (strcasecmp(command_p->name_p, "+CGOI") == 0))
4148 {
4149
4150 if (parser_p->info.object_id_p == NULL)
4151 rc = utlAT_RESULT_CODE_ERROR;
4152 else if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4153 (request_type == utlAT_REQUEST_TYPE_SET))
4154 (void)strncpy(response_p, parser_p->info.object_id_p, response_siz);
4155 else
4156 rc = utlAT_RESULT_CODE_ERROR;
4157
4158 /*--- request complete capabilities list ---*/
4159 }
4160 else if (strcasecmp(command_p->name_p, "+GCAP") == 0)
4161 {
4162
4163 if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4164 (request_type == utlAT_REQUEST_TYPE_SET))
4165 {
4166 (void)strncpy(response_p, parser_p->info.mt_capabilities_p, response_siz);//according to System Definition
4167 } else
4168 rc = utlAT_RESULT_CODE_ERROR;
4169
4170 /*--- country of installation (optional command) ---*/
4171 }
4172 else if ((strcasecmp(command_p->name_p, "+GCI") == 0) ||
4173 (strcasecmp(command_p->name_p, "+CGCI") == 0))
4174 {
4175
4176 if ((request_type == utlAT_REQUEST_TYPE_GET) ||
4177 (request_type == utlAT_REQUEST_TYPE_SET))
4178 {
4179 if (utlFormatExtendedResultString(parser_p, response_p, response_siz, command_p->name_p, parser_p->info.country_code_p) == (size_t)0)
4180 rc = utlAT_RESULT_CODE_ERROR;
4181 }
4182 else
4183 rc = utlAT_RESULT_CODE_ERROR;
4184
4185 /*--- fixed DTE rate (optional command) ---*/
4186 }
4187 else if (strcasecmp(command_p->name_p, "+IPR") == 0)
4188 {
4189
4190 if (request_type == utlAT_REQUEST_TYPE_GET)
4191 {
4192 char buf[20];
4193
4194 if (utlDecimalToString(buf, parser_p->dce_io_config.data_rate, utlNumberOf(buf)) == (size_t)0)
4195 rc = utlAT_RESULT_CODE_ERROR;
4196
4197 else if (utlFormatExtendedResultString(parser_p, response_p, response_siz, command_p->name_p, buf) == (size_t)0)
4198 rc = utlAT_RESULT_CODE_ERROR;
4199
4200 }
4201 else if (request_type == utlAT_REQUEST_TYPE_SET)
4202 {
4203
4204 /*--- check parameter value and save if OK ---*/
4205 switch (parameter_values_p[0].value.decimal)
4206 {
4207 case 0: case 134: case 600: case 4800: case 19200: case 76800:
4208 case 50: case 150: case 1200: case 7200: case 28800: case 115200:
4209 case 75: case 200: case 1800: case 9600: case 38400: case 230400:
4210 case 110: case 300: case 2400: case 14400: case 57600:
4211 parser_p->dce_io_config.data_rate = parameter_values_p[0].value.decimal;
4212 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_BIT_RATE; break;
4213 break;
4214
4215 default:
4216 rc = utlAT_RESULT_CODE_ERROR;
4217 }
4218
4219 }
4220 else
4221 rc = utlAT_RESULT_CODE_ERROR;
4222
4223 /*--- DTE-DCE character framing (optional command) ---*/
4224 }
4225 else if (strcasecmp(command_p->name_p, "+ICF") == 0)
4226 {
4227
4228 if (request_type == utlAT_REQUEST_TYPE_GET)
4229 {
4230 char buf[40];
4231 size_t i;
4232
4233 i = utlDecimalToString(buf, parser_p->parameters.raw_framing, utlNumberOf(buf) - 1);
4234
4235 buf[i++] = parser_p->parameters.S[utlAT_SEPARATER_CHAR];
4236
4237 i += utlDecimalToString(buf + i, parser_p->parameters.raw_parity, utlNumberOf(buf) - i);
4238
4239 if (utlFormatExtendedResultString(parser_p, response_p, response_siz, command_p->name_p, buf) == (size_t)0)
4240 rc = utlAT_RESULT_CODE_ERROR;
4241
4242 }
4243 else if (request_type == utlAT_REQUEST_TYPE_SET)
4244 {
4245 unsigned int raw_framing;
4246 unsigned int raw_parity;
4247
4248 raw_framing = parameter_values_p[0].value.decimal;
4249
4250 if (parameter_values_p[1].is_default == false)
4251 raw_parity = parameter_values_p[1].value.decimal;
4252 else raw_parity = parser_p->parameters.raw_parity;
4253
4254 /*--- check parameter values ---*/
4255 switch (raw_framing)
4256 {
4257 case 0:
4258 case 1:
4259 case 2:
4260 case 3:
4261 case 4:
4262 case 5:
4263 case 6:
4264 break;
4265
4266 default:
4267 rc = utlAT_RESULT_CODE_ERROR;
4268 }
4269 switch (raw_parity)
4270 {
4271 case 0:
4272 case 1:
4273 case 2:
4274 case 3:
4275 break;
4276
4277 default:
4278 rc = utlAT_RESULT_CODE_ERROR;
4279 }
4280
4281 /*--- save parameter values if OK ---*/
4282 if (rc == utlAT_RESULT_CODE_OK)
4283 {
4284 parser_p->parameters.raw_framing = raw_framing;
4285 parser_p->parameters.raw_parity = raw_parity;
4286 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_FRAMING |
4287 utlAT_DCE_IO_CONFIG_PENDING_PARITY;
4288 }
4289
4290 }
4291 else
4292 rc = utlAT_RESULT_CODE_ERROR;
4293
4294 /*--- DTE-DCE local flow control (optional command) ---*/
4295 }
4296 else if (strcasecmp(command_p->name_p, "+IFC") == 0)
4297 {
4298 utlAssert(parameter_values_p[0].type == utlAT_DATA_TYPE_DECIMAL);
4299 utlAssert(parameter_values_p[1].type == utlAT_DATA_TYPE_DECIMAL);
4300
4301 if (request_type == utlAT_REQUEST_TYPE_GET)
4302 {
4303 char buf[40];
4304 size_t i;
4305
4306 i = utlDecimalToString(buf, parser_p->dce_io_config.flow_control.dce_by_dte, utlNumberOf(buf) - 1);
4307
4308 buf[i++] = parser_p->parameters.S[utlAT_SEPARATER_CHAR];
4309
4310 i += utlDecimalToString(buf + i, parser_p->dce_io_config.flow_control.dte_by_dce, utlNumberOf(buf) - i);
4311
4312 if (utlFormatExtendedResultString(parser_p, response_p, response_siz, command_p->name_p, buf) == (size_t)0)
4313 rc = utlAT_RESULT_CODE_ERROR;
4314
4315 }
4316 else if (request_type == utlAT_REQUEST_TYPE_SET)
4317 {
4318 unsigned int dce_by_dte;
4319 unsigned int dte_by_dce;
4320
4321 dce_by_dte = parameter_values_p[0].value.decimal;
4322
4323 if (parameter_values_p[1].is_default == false)
4324 dte_by_dce = parameter_values_p[1].value.decimal;
4325 else dte_by_dce = parser_p->dce_io_config.flow_control.dte_by_dce;
4326
4327 /*--- check parameter values ---*/
4328 switch (dce_by_dte)
4329 {
4330 case 0: /* none */
4331 case 1: /* DC1/DC3 (and don't pass DC1/DC3 through) */
4332 case 2: /* RTS */
4333 case 3: /* both RTS and DC1/DC3 (and pass DC1/DC3 through) */
4334 break;
4335
4336 default:
4337 rc = utlAT_RESULT_CODE_ERROR;
4338 }
4339 switch (dte_by_dce)
4340 {
4341 case 0: /* none */
4342 case 1: /* DC1/DC3 */
4343 case 2: /* CTS */
4344 break;
4345
4346 default:
4347 rc = utlAT_RESULT_CODE_ERROR;
4348 }
4349
4350 /*--- save parameter values if OK ---*/
4351 if (rc == utlAT_RESULT_CODE_OK)
4352 {
4353 parser_p->dce_io_config.flow_control.dce_by_dte = dce_by_dte;
4354 parser_p->dce_io_config.flow_control.dte_by_dce = dte_by_dce;
4355 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_FLOW_CONTROL;
4356 }
4357
4358 }
4359 else
4360 rc = utlAT_RESULT_CODE_ERROR;
4361
4362 /*--- select DSR option (optional command) ---*/
4363 }
4364 else if (strcasecmp(command_p->name_p, "+IDSR") == 0)
4365 {
4366 utlAssert(parameter_values_p[0].type == utlAT_DATA_TYPE_DECIMAL);
4367
4368 if (request_type == utlAT_REQUEST_TYPE_GET)
4369 {
4370 char buf[20];
4371
4372 if (utlDecimalToString(buf, parser_p->dce_io_config.modes.dsr_mode, utlNumberOf(buf)) == (size_t)0)
4373 rc = utlAT_RESULT_CODE_ERROR;
4374
4375 else if (utlFormatExtendedResultString(parser_p, response_p, response_siz, command_p->name_p, buf) == (size_t)0)
4376 rc = utlAT_RESULT_CODE_ERROR;
4377
4378 }
4379 else if (request_type == utlAT_REQUEST_TYPE_SET)
4380 {
4381
4382 /*--- check parameter value and save if OK ---*/
4383 switch (parameter_values_p[0].value.decimal)
4384 {
4385 case 0: /* DSR always on */
4386 case 1: /* DSR as per V.24 */
4387 case 2: /* DSR always on except for 5 seconds after disconnect */
4388 parser_p->dce_io_config.modes.dsr_mode = parameter_values_p[0].value.decimal;
4389 parser_p->states.dce_io_config_pending_mask |= utlAT_DCE_IO_CONFIG_PENDING_DSR;
4390 break;
4391
4392 default:
4393 rc = utlAT_RESULT_CODE_ERROR;
4394 }
4395
4396 }
4397 else
4398 rc = utlAT_RESULT_CODE_ERROR;
4399 }
4400
4401 /*--- if the execution of any basic build-in commands failed ---*/
4402 if (rc != utlAT_RESULT_CODE_OK)
4403 {
4404 utlError(utlProcessExtendedAtCommand, "Invalid parameter for `%s' AT command at col=%d.", command_p->name_p, syntax_off);
4405 }
4406
4407 return rc;
4408}
4409
4410/*---------------------------------------------------------------------------*
4411* FUNCTION
4412* utlSetDefaultParameterValue(parameter_value_p, type, access)
4413* INPUT
4414* parameter_value_p == pointer to the parameter to set
4415* type == the data type of `parameter_value_p'
4416* access == the access rights associated with `parameter_value_p'
4417* OUTPUT
4418* *parameter_value_p == a modified parameter
4419* RETURNS
4420* nothing
4421* DESCRIPTION
4422* Assigns the specified parameter a default value according to it's type.
4423* Modified by Rovin Yu: other file can also use this function
4424*---------------------------------------------------------------------------*/
4425void utlSetDefaultParameterValue(const utlAtParameterValue_P parameter_value_p,
4426 const utlAtDataType_T type,
4427 const utlAtParameterAccess_T access)
4428{
4429 utlAssert(parameter_value_p != NULL);
4430
4431 parameter_value_p->type = type;
4432 parameter_value_p->access = access;
4433 parameter_value_p->is_default = true;
4434
4435 switch (type)
4436 {
4437 case utlAT_DATA_TYPE_DECIMAL: parameter_value_p->value.decimal = 0; break;
4438 case utlAT_DATA_TYPE_HEXADECIMAL: parameter_value_p->value.hexadecimal = 0; break;
4439 case utlAT_DATA_TYPE_BINARY: parameter_value_p->value.binary = 0; break;
4440 case utlAT_DATA_TYPE_STRING: parameter_value_p->value.string_p = ""; break;
4441 case utlAT_DATA_TYPE_QSTRING: parameter_value_p->value.qstring_p = ""; break;
4442 case utlAT_DATA_TYPE_DIAL_STRING: parameter_value_p->value.dial_string_p = ""; break;
4443
4444 default:
4445 (void)memset(&(parameter_value_p->value), 0, sizeof(parameter_value_p->value));
4446 break;
4447 }
4448}
4449
4450/*---------------------------------------------------------------------------*
4451* FUNCTION
4452* utlAtParserInitCommandParameters(xid, parameter_values_p, num_parameters)
4453* INPUT
4454* xid == an active transaction ID
4455* parameter_values_p == an uninitialized utlAtParameterValue_T array
4456* num_parameters == number of elements in array pointed to by `parameter_values_p'
4457* OUTPUT
4458* *parameter_values_p == the initialized utlAtParameterValue_T array
4459* RETURNS
4460* the number of parameters for success, utlFAILED for failure
4461* DESCRIPTION
4462* Initializes the parameter-values structure appropriately for the
4463* AT-command associated with `xid'.
4464*---------------------------------------------------------------------------*/
4465size_t utlAtParserInitCommandParameters(const unsigned int xid,
4466 const utlAtParameterValue_P parameter_values_p,
4467 const size_t num_parameters)
4468{
4469 utlAtParser_P parser_p;
4470 utlAtAsyncResponse_P async_response_p;
4471 utlAtCommand_P2c command_p;
4472 utlAtParameter_P parameter_p;
4473 utlAtParameterValue_P parameter_value_p;
4474
4475 utlAssert(parameter_values_p != NULL);
4476
4477 /*--- determine the parser and async_response node associated with the given transaction ID ---*/
4478 {
4479 /*--- for each parser... ---*/
4480 for (parser_p = (utlAtParser_P)parsers.head_p; parser_p != NULL; parser_p = parser_p->next_p)
4481 {
4482
4483 /*--- for each pending async response for this parser... ---*/
4484 for (async_response_p = (utlAtAsyncResponse_P)parser_p->states.async_responses.pending.head_p; async_response_p != NULL; async_response_p = async_response_p->next_p)
4485 if (async_response_p->xid == xid)
4486 break;
4487
4488 /*--- bail out? ---*/
4489 if (async_response_p != NULL)
4490 break;
4491 }
4492
4493 /*--- is XID invalid/unknown? ---*/
4494 if (parser_p == NULL)
4495 {
4496 utlError(utlAtParserInitCommandParameters, "Invalid/unknown transaction ID %d\n", xid);
4497 return utlFAILED;
4498 }
4499 }
4500
4501 utlAssert(async_response_p->command_p != NULL);
4502 command_p = async_response_p->command_p;
4503
4504 /*--- check that output array is big enough ---*/
4505 if (num_parameters < command_p->num_parameters)
4506 {
4507 utlError(utlAtParserInitCommandParameters1, "Not enough room in `parameter_values_p' for all of command `%s's parameters (got %d, need %d)",
4508 command_p->name_p, num_parameters, command_p->num_parameters);
4509 return utlFAILED;
4510 }
4511
4512 parameter_p = command_p->parameters_p;
4513 parameter_value_p = parameter_values_p;
4514
4515 /*--- for each of this AT-Command's known parameters... ---*/
4516 while (parameter_p < (command_p->parameters_p + command_p->num_parameters))
4517 {
4518
4519 /*--- assign a default parameter value, according to it's data-type... ---*/
4520 utlSetDefaultParameterValue(parameter_value_p, parameter_p->type, parameter_p->access);
4521
4522 parameter_p++;
4523 parameter_value_p++;
4524 }
4525
4526 return command_p->num_parameters;
4527}
4528
4529/*---------------------------------------------------------------------------*
4530* FUNCTION
4531* utlGenerateFormattedGetResponse(parser_p, command_name_p, parameters_p,
4532* num_parameters)
4533* INPUT
4534* parser_p == an open AT-command parser
4535* command_name_p == name of the AT command to execute
4536* parameters_p == pointer to an array of parameters
4537* num_parameters == the number of elements in the array pointed to by `parameters_p'
4538* OUTPUT
4539* none
4540* RETURNS
4541* utlFAILED for failure, otherwise utlSUCCESS
4542* DESCRIPTION
4543* Handles the generation (format and transmission) of standard responses
4544* to Extended AT command "GET" requests: converts parameter values into
4545* a properly formattted text string and issues the string.
4546*---------------------------------------------------------------------------*/
4547static utlReturnCode_T utlGenerateFormattedGetResponse(const utlAtParser_P parser_p,
4548 const char *command_name_p,
4549 const utlAtParameterValue_P2c parameter_values_p,
4550 const size_t num_parameters)
4551{
4552 char buf[utlAT_MAX_RESPONSE_LENGTH];
4553 utlAtParameterValue_P2c parameter_value_p;
4554 utlAtParameterValue_P2c term_parameter_value_p;
4555 size_t i;
4556
4557 utlAssert(parser_p != NULL);
4558 utlAssert(command_name_p != NULL);
4559 utlAssert(parameter_values_p != NULL);
4560
4561 i = 0;
4562
4563 /*--- for each known parameter value... ---*/
4564 term_parameter_value_p = parameter_values_p + num_parameters;
4565 for (parameter_value_p = parameter_values_p; parameter_value_p < term_parameter_value_p; parameter_value_p++)
4566 {
4567 size_t rv;
4568
4569 /*--- append parameter separator (as necessary) ---*/
4570 if (parameter_value_p > parameter_values_p)
4571 {
4572 if (i < utlNumberOf(buf))
4573 buf[i++] = parser_p->parameters.S[utlAT_SEPARATER_CHAR];
4574 }
4575
4576 /*--- append parameter value according to type ---*/
4577 switch (parameter_value_p->type)
4578 {
4579 case utlAT_DATA_TYPE_DECIMAL:
4580 if ((rv = utlDecimalToString(buf + i, parameter_value_p->value.decimal, sizeof(buf) - i)) == (size_t)0)
4581 {
4582 utlError(utlGenerateFormattedGetResponse, "Reply-buffer overflow.");
4583 return utlFAILED;
4584 }
4585
4586 i += rv;
4587 break;
4588
4589 case utlAT_DATA_TYPE_HEXADECIMAL:
4590 if ((rv = utlHexadecimalToString(buf + i, parameter_value_p->value.hexadecimal, sizeof(buf) - i)) == (size_t)0)
4591 {
4592 utlError(utlGenerateFormattedGetResponse1, "Reply-buffer overflow.");
4593 return utlFAILED;
4594 }
4595
4596 i += rv;
4597 break;
4598
4599 case utlAT_DATA_TYPE_BINARY:
4600 if ((rv = utlBinaryToString(buf + i, parameter_value_p->value.binary, sizeof(buf) - i)) == (size_t)0)
4601 {
4602 utlError(utlGenerateFormattedGetResponse2, "Reply-buffer overflow.");
4603 return utlFAILED;
4604 }
4605
4606 i += rv;
4607 break;
4608
4609 case utlAT_DATA_TYPE_STRING:
4610 case utlAT_DATA_TYPE_QSTRING:
4611 {
4612 const char *c_p;
4613
4614 if (i < utlNumberOf(buf))
4615 buf[i++] = '"';
4616
4617 if (parameter_value_p->type == utlAT_DATA_TYPE_STRING) c_p = parameter_value_p->value.string_p;
4618 else c_p = parameter_value_p->value.qstring_p;
4619
4620 while ((*c_p != '\0') && (i < utlNumberOf(buf)))
4621 buf[i++] = *c_p++;
4622
4623 if (i < utlNumberOf(buf))
4624 buf[i++] = '"';
4625
4626 /*--- no room? ---*/
4627 if (i >= utlNumberOf(buf))
4628 {
4629 utlError(utlGenerateFormattedGetResponse3, "Reply-buffer overflow.");
4630 return utlFAILED;
4631 }
4632 }
4633 break;
4634
4635 case utlAT_DATA_TYPE_DIAL_STRING:
4636 {
4637 const char *c_p;
4638
4639 c_p = parameter_value_p->value.dial_string_p;
4640
4641 while ((*c_p != '\0') && (i < utlNumberOf(buf)))
4642 buf[i++] = *c_p++;
4643
4644 /*--- no room? ---*/
4645 if (i >= utlNumberOf(buf))
4646 {
4647 utlError(utlGenerateFormattedGetResponse4, "Reply-buffer overflow.");
4648 return utlFAILED;
4649 }
4650 }
4651 break;
4652
4653 default:
4654 utlError(utlGenerateFormattedGetResponse5, "Invalid parameter_value_p->type!\n");
4655 break;
4656 }
4657 }
4658
4659 /*--- no room? ---*/
4660 if (i >= (utlNumberOf(buf) - 1))
4661 {
4662 utlError(utlGenerateFormattedGetResponse6, "Reply-buffer overflow.");
4663 return utlFAILED;
4664 }
4665
4666 buf[i] = '\0';
4667
4668 utlTrace(utlTRACE_AT_PARSER,
4669 utlPrintTrace(utlGenerateFormattedGetResponse7, "AT%s (get: %s)\n", command_name_p, buf);
4670 );
4671
4672 if (utlSendInfoResponse(parser_p, buf) != utlSUCCESS)
4673 return utlFAILED;
4674
4675 return utlSUCCESS;
4676}
4677
4678/*---------------------------------------------------------------------------*
4679* FUNCTION
4680* utlExecuteExtendedAtCommand(parser_p, request_type, command_name_p,
4681* parameters_string_p, syntax_off)
4682* INPUT
4683* parser_p == an open AT-command parser
4684* request_type == type of extended AT-command request
4685* command_name_p == name of the AT command to execute
4686* parameters_string_p == was a parameter value found?
4687* syntax_off == offset from start of line to AT-command (only
4688* used for error reporting)
4689* OUTPUT
4690* none
4691* RETURNS
4692* utlAT_RESULT_CODE_ERROR for failure, other values for success
4693* DESCRIPTION
4694* Executes the extended AT command specified by `command_name_p'.
4695*---------------------------------------------------------------------------*/
4696static utlAtResultCode_T utlExecuteExtendedAtCommand(const utlAtParser_P parser_p,
4697 const utlAtRequestType_T request_type,
4698 const char *command_name_p,
4699 const char *parameters_string_p,
4700 const size_t syntax_off)
4701{
4702 utlAtCommand_P2c command_p;
4703 utlAtParameterValue_T parameter_values[utlAT_MAX_PARAMETERS];
4704 char string_buf[utlAT_MAX_LINE_LENGTH + utlAT_MAX_PARAMETERS];
4705 char info_text[utlAT_MAX_RESPONSE_LENGTH];
4706 utlAtResultCode_T rc;
4707 unsigned int proxyFlag = 0;
4708 unsigned int paramCheckIgnore = 0;
4709
4710 if((parser_p == NULL) || (command_name_p == NULL))
4711 return utlAT_RESULT_CODE_ERROR;
4712
4713 memset(&parameter_values, 0, sizeof(parameter_values));
4714 utlError(utlExecuteExtendedAtCommand100, "utlExecuteExtendedAtCommand\n");
4715
4716 /*--- search for AT-command info ---*/
4717 {
4718 utlAtCommand_P2c term_command_p;
4719
4720 term_command_p = parser_p->commands_p + parser_p->num_commands;
4721 for (command_p = parser_p->commands_p; command_p < term_command_p; command_p++)
4722 if (((command_p->type == utlAT_COMMAND_TYPE_EXTENDED) ||
4723 (command_p->type == utlAT_COMMAND_TYPE_EXACTION) ||
4724 (command_p->type == utlAT_COMMAND_TYPE_EXTENDED_EXACTION)) &&
4725 (tolower( command_p->name_p[1]) == tolower(command_name_p[1])) &&
4726 (strcasecmp(command_p->name_p, command_name_p) == 0))
4727 break;
4728
4729 VDBGMSG(utlExecuteExtendedAtCommand, "PRXY_DEBUG -%s,%d - parser handles command %s, with param %s, \n",
4730 __FUNCTION__, __LINE__, command_name_p, parameters_string_p);
4731
4732 if (command_p >= term_command_p)
4733 {
4734 VDBGMSG(utlExecuteExtendedAtCommand1, "PRXY_DEBUG -%s,%d - command %s with param %s not known to parser. Look at proxy list\n",
4735 __FUNCTION__, __LINE__, command_name_p, parameters_string_p);
4736 //check first if the command is proxied
4737 proxyFlag = utlCheckIfSendToProxy(command_name_p,request_type,parser_p, parameters_string_p);
4738
4739 if(!proxyFlag) {
4740 //command not found in the list, and is not proxied
4741 parser_p->peg_counts.undefined_commands++;
4742 return utlAT_RESULT_CODE_ERROR;
4743 }
4744 else{
4745 //this is a proxy cmd, use the static defention
4746 if(parser_p->pProxyOnlyCmd != NULL)
4747 {
4748 paramCheckIgnore = 1;
4749 command_p = parser_p->pProxyOnlyCmd;
4750
4751 memset(prxy_command_name, 0, sizeof(prxy_command_name));
4752 strncpy(prxy_command_name, command_name_p, sizeof(prxy_command_name)-1);
4753 }
4754 }
4755 }
4756
4757 //check if command should be proxied
4758 if(!proxyFlag) {
4759 //doesn't checked yet at the proxy list
4760
4761 proxyFlag = utlCheckIfSendToProxy(command_name_p,request_type,parser_p, parameters_string_p);
4762 VDBGMSG(utlExecuteExtendedAtCommand2, "PRXY_DEBUG -%s,%d - proxy flag for comand %s with op %d is %d\n",
4763 __FUNCTION__, __LINE__, command_name_p, (int)request_type,proxyFlag);
4764 }
4765 }
4766
4767 utlError(utlExecuteExtendedAtCommand3, "command=%s, request_type=%d\n", command_p->name_p, request_type);
4768 atmcd_mult_lock(parser_p, command_p, request_type);
4769 /*--- if we're only fetching the command syntax ---*/
4770 if (request_type == utlAT_REQUEST_TYPE_SYNTAX)
4771 {
4772
4773 rc = utlAT_RESULT_CODE_OK;
4774
4775 /*--- if the syntax for this command is static ---*/
4776 if ((command_p->usage.command_syntax_p != NULL)&&(!proxyFlag))//if command should be handled by proxy - ignore static settings
4777 {
4778
4779 utlTrace(utlTRACE_AT_PARSER,
4780 utlPrintTrace(utlExecuteExtendedAtCommand4, "AT%s (query syntax: %s)\n", command_name_p, command_p->usage.command_syntax_p);
4781 );
4782
4783 if (utlSendInfoResponse(parser_p, command_p->usage.command_syntax_p) != utlSUCCESS) {
4784 rc = utlAT_RESULT_CODE_ERROR;
4785 goto out_error;
4786 }
4787
4788 /*--- else if the syntax for this command can be fetched ---*/
4789 }
4790 else if ((command_p->usage.call_backs.command_syntax_function_p != NULL)||(proxyFlag))
4791 {
4792 utlAtAsyncResponse_P async_response_p;
4793
4794 /*--- setup for pending asynchronous response ---*/
4795 if ((async_response_p = utlSetupPendingAsyncResponse(parser_p, utlAT_ASYNC_OP_SYNTAX, command_p,proxyFlag)) == NULL) {
4796 rc = utlAT_RESULT_CODE_ERROR;
4797 goto out_error;
4798 }
4799 // call for proxy
4800 if(proxyFlag) {
4801 if(parser_p->call_backs.sendToProxy_function_p(command_name_p,
4802 utlAT_PARAMETER_OP_SYNTAX, //action not supported for proxy
4803 NULL,
4804 &(async_response_p->xid),
4805 parser_p->call_backs.arg_p)!= utlSUCCESS) {
4806
4807 utlError(utlExecuteExtendedAtCommand5, "PROXY_DEBUG - SET - send to proxy _function_p failed for cmd %s with param %s !\n", command_name_p,parameters_string_p );
4808 /*--- clean ---*/
4809 utlAbandonPendingAsyncResponse(async_response_p);
4810
4811 parser_p->peg_counts.bad_commands++;
4812 rc = utlAT_RESULT_CODE_ERROR;
4813 goto out_error;
4814 }
4815 }
4816 else{
4817 if ((command_p->usage.call_backs.command_syntax_function_p)(utlAT_PARAMETER_OP_SYNTAX,
4818 command_name_p,
4819 NULL,
4820 0,
4821 NULL,
4822 &(async_response_p->xid),
4823 parser_p->call_backs.arg_p) != utlSUCCESS)
4824 {
4825 /*--- clean ---*/
4826 utlAbandonPendingAsyncResponse(async_response_p);
4827
4828 parser_p->peg_counts.bad_commands++;
4829 rc = utlAT_RESULT_CODE_ERROR;
4830 goto out_error;
4831 }
4832 }
4833
4834 rc = utlAT_RESULT_CODE_SUPPRESS;
4835 }
4836 parser_p->peg_counts.extended_commands++;
4837
4838 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
4839 {
4840 utlError(utlExecuteExtendedAtCommand6, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
4841 rc = utlAT_RESULT_CODE_ERROR;
4842 goto out_error;
4843 }
4844
4845 if (rc == utlAT_RESULT_CODE_OK)
4846 parser_p->commands_in_line--;
4847
4848 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
4849
4850 goto out;
4851
4852 /*--- else if this is a set-request, parse for AT-command's parameters (if any)... ---*/
4853 }
4854 else if (request_type == utlAT_REQUEST_TYPE_SET)
4855 {
4856 utlAtParameter_P parameter_p;
4857 utlAtParameterValue_P parameter_value_p;
4858 char *string_buf_p;
4859 const char *c_p;
4860
4861 parameter_p = command_p->parameters_p;
4862 parameter_value_p = parameter_values; /* we'll stuff the found parameter values here */
4863
4864 string_buf_p = string_buf; /* we'll store decoded string-parameters here */
4865
4866 /*--- if any parameter values were found... ---*/
4867 if ((parameters_string_p != NULL)&&(!paramCheckIgnore))
4868 {
4869
4870 utlTrace(utlTRACE_AT_PARSER,
4871 utlPrintTrace(utlExecuteExtendedAtCommand7, "AT%s (set: %s)\n", command_name_p, parameters_string_p);
4872 );
4873
4874 /*--- for each found parameter value... ---*/
4875 for (c_p = parameters_string_p; *c_p != '\0'; )
4876 {
4877 char value_string[utlAT_MAX_LINE_LENGTH];
4878 size_t value_string_off;
4879 bool parameter_found;
4880 char parameter_term_char;
4881 bool quote_state;
4882
4883 /*--- note offset to this parameter (for error reporting) ---*/
4884 value_string_off = c_p - parameters_string_p;
4885
4886 /*--- extract parameter value (parameters separated by ',' and terminated by null) ---*/
4887 {
4888 char *dest_p;
4889 quote_state = true;
4890 parameter_found = false;
4891 parameter_term_char = '\0';
4892 for (dest_p = value_string; *c_p != '\0'; c_p++)
4893 {
4894
4895 if(*c_p == '"')
4896 quote_state = !quote_state;
4897 if ((*c_p == parser_p->parameters.S[utlAT_SEPARATER_CHAR]) && quote_state)
4898 {
4899 parameter_term_char = *c_p++; /* skip parameter-separator character */
4900 break;
4901 }
4902
4903 *dest_p++ = *c_p;
4904
4905 parameter_found = true;
4906 }
4907 *dest_p = '\0';
4908 }
4909
4910 /*--- if this command should not actually have any parameter values ---*/
4911 if (parameter_p == NULL)
4912 {
4913
4914 /*--- complain if one or more parameter values were found ---*/
4915 if (parameter_found == true)
4916 {
4917 utlError(utlExecuteExtendedAtCommand8, "Unexpected AT command parameter at col=%d.", syntax_off);
4918 parser_p->peg_counts.bad_commands++;
4919 rc = utlAT_RESULT_CODE_ERROR;
4920 goto out_error;
4921 }
4922
4923 /*--- else this command should have one or more parameters... ---*/
4924 }
4925 else
4926 {
4927 /*--- were more parameter values supplied than we can parse? ---*/
4928 if (parameter_value_p >= (parameter_values + utlAT_MAX_PARAMETERS))
4929 {
4930 utlError(utlExecuteExtendedAtCommand9, "Too many AT-command parameters at col=%d.", syntax_off);
4931 parser_p->peg_counts.bad_commands++;
4932 rc = utlAT_RESULT_CODE_ERROR;
4933 goto out_error;
4934 }
4935
4936 /*--- if no parameter value was found ---*/
4937 if (parameter_found == false)
4938 {
4939
4940 /*-- complain if omitted parameter value is not Read, Read-only, and is required ---*/
4941 if (((parameter_p->access != utlAT_PARAMETER_ACCESS_READ) &&
4942 (parameter_p->access != utlAT_PARAMETER_ACCESS_READ_ONLY)) &&
4943 ( parameter_p->presence == utlAT_PARAMETER_PRESENCE_REQUIRED))
4944 {
4945 utlError(utlExecuteExtendedAtCommand10, "Missing AT command parameter at col=%d.", syntax_off + value_string_off + 1);
4946 parser_p->peg_counts.bad_commands++;
4947 rc = utlAT_RESULT_CODE_ERROR;
4948 goto out_error;
4949 }
4950
4951 /*--- otherwise assign optional parameter a default value, according to it's type... ---*/
4952 utlSetDefaultParameterValue(parameter_value_p, parameter_p->type, parameter_p->access);
4953
4954 /*--- else if a parameter value was found ---*/
4955 }
4956 else
4957 {
4958 unsigned int num = 0;
4959 char *d_p;
4960
4961 /*--- are we attempting to set a read-only parameter? ---*/
4962 if (parameter_p->access == utlAT_PARAMETER_ACCESS_READ_ONLY)
4963 {
4964 utlError(utlExecuteExtendedAtCommand11, "Attempt to modify read-only AT command parameter at col=%d.", syntax_off + value_string_off + 1);
4965 parser_p->peg_counts.bad_commands++;
4966 rc = utlAT_RESULT_CODE_ERROR;
4967 goto out_error;
4968 }
4969
4970 /*--- grab rest of parameter string if we are expecting a dial string ---*/
4971 if ((parameter_p->type == utlAT_DATA_TYPE_DIAL_STRING) &&
4972 (parameter_term_char == parser_p->parameters.S[utlAT_SEPARATER_CHAR]))
4973 {
4974 char *dest_p;
4975
4976 dest_p = value_string + strlen(value_string);
4977
4978 *dest_p++ = parser_p->parameters.S[utlAT_SEPARATER_CHAR];
4979
4980 while (*c_p != '\0')
4981 *dest_p++ = *c_p++;
4982
4983 *dest_p = '\0';
4984 }
4985
4986 parameter_value_p->type = parameter_p->type;
4987 parameter_value_p->access = parameter_p->access;
4988 parameter_value_p->is_default = false;
4989
4990 /*--- parse found parameter value according to it's known data-type... ---*/
4991 switch (parameter_p->type)
4992 {
4993 case utlAT_DATA_TYPE_DECIMAL:
4994 num = 0;
4995 for (d_p = value_string; *d_p != '\0'; d_p++)
4996 {
4997 if ((*d_p >= '0') && (*d_p <= '9'))
4998 num = (10 * num) + (*d_p - '0');
4999 else
5000 {
5001 utlError(utlExecuteExtendedAtCommand12, "Extended-AT command syntax error at col=%d.", syntax_off + value_string_off + 1);
5002 parser_p->peg_counts.bad_commands++;
5003 rc = utlAT_RESULT_CODE_ERROR;
5004 goto out_error;
5005 }
5006 }
5007
5008 parameter_value_p->value.decimal = num;
5009 break;
5010
5011 case utlAT_DATA_TYPE_HEXADECIMAL:
5012 num = 0;
5013 for (d_p = value_string; *d_p != '\0'; d_p++)
5014 {
5015 if ((*d_p >= '0') && (*d_p <= '9')) num = (16 * num) + (*d_p - '0');
5016 else if ((*d_p >= 'A') && (*d_p <= 'F')) num = (16 * num) + (*d_p - 'A') + 10;
5017 else if ((*d_p >= 'a') && (*d_p <= 'f')) num = (16 * num) + (*d_p - 'a') + 10;
5018 else
5019 {
5020 utlError(utlExecuteExtendedAtCommand13, "Extended-AT command syntax error at col=%d.", syntax_off + value_string_off + 1);
5021 parser_p->peg_counts.bad_commands++;
5022 rc = utlAT_RESULT_CODE_ERROR;
5023 goto out_error;
5024 }
5025 }
5026
5027 parameter_value_p->value.hexadecimal = num;
5028 break;
5029
5030 case utlAT_DATA_TYPE_BINARY:
5031 num = 0;
5032 for (d_p = value_string; *d_p != '\0'; d_p++)
5033 {
5034 if (*d_p == '0') num = (num * 2);
5035 else if (*d_p == '1') num = (num * 2) + 1;
5036 else
5037 {
5038 utlError(utlExecuteExtendedAtCommand14, "Extended-AT command syntax error at col=%d.", syntax_off + value_string_off + 1);
5039 parser_p->peg_counts.bad_commands++;
5040 rc = utlAT_RESULT_CODE_ERROR;
5041 goto out_error;
5042 }
5043 }
5044
5045 parameter_value_p->value.binary = num;
5046 break;
5047
5048 case utlAT_DATA_TYPE_STRING:
5049 case utlAT_DATA_TYPE_QSTRING:
5050 {
5051 utlAtStringState_T state;
5052 char *src_p;
5053 bool quoted;
5054
5055 if (parameter_p->type == utlAT_DATA_TYPE_STRING) parameter_value_p->value.string_p = string_buf_p;
5056 else parameter_value_p->value.qstring_p = string_buf_p;
5057
5058 src_p = value_string;
5059
5060 /*--- our regular string parsing is a little more flexible than the
5061 V.250 standard specifies: strings do not have to be enclosed in
5062 double-quotes, but if double-quotes are omitted, the end of
5063 the string will be delimited by the first parameter separator
5064 character, colon character, or end-of-line encountered. */
5065 if (*src_p == '"')
5066 {
5067 src_p++;
5068 quoted = true;
5069
5070 }
5071 else if (parameter_p->type == utlAT_DATA_TYPE_QSTRING)
5072 {
5073 utlError(utlExecuteExtendedAtCommand15, "Extended-AT command syntax error at col=%d.", syntax_off + value_string_off + 1);
5074 parser_p->peg_counts.bad_commands++;
5075 rc = utlAT_RESULT_CODE_ERROR;
5076 goto out_error;
5077
5078 }
5079 else
5080 quoted = false;
5081
5082 /*--- extract string, replacing hex escape sequences with the ASCII
5083 characters they represent */
5084 state = utlAT_STRING_STATE_PASS_THROUGH;
5085
5086 for (; *src_p != '\0'; src_p++)
5087 {
5088
5089 if (quoted)
5090 {
5091 if (*src_p == '"')
5092 break;
5093 }
5094 else
5095 {
5096 if ((*src_p == parser_p->parameters.S[utlAT_SEPARATER_CHAR]) || (*src_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]))
5097 break;
5098 }
5099
5100 /*--- this a possible embedded hex escape sequence? ---*/
5101 if ((*src_p == '\\') && (parser_p->options.allow_string_escapes == true))
5102 {
5103 state = utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1;
5104 num = 0; /* initialize hex num */
5105
5106 }
5107 else if ((state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1) ||
5108 (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2))
5109 {
5110
5111 /*--- extract hexadecimal escape sequence digit ---*/
5112 if ((*src_p >= '0') && (*src_p <= '9')) num = (16 * num) + (*src_p - '0');
5113 else if ((*src_p >= 'A') && (*src_p <= 'F')) num = (16 * num) + (*src_p - 'A') + 10;
5114 else if ((*src_p >= 'a') && (*src_p <= 'f')) num = (16 * num) + (*src_p - 'a') + 10;
5115 else
5116 {
5117 /*--- if reverse-solidus was not followed by a hex character, just
5118 interpret found characters as-is */
5119 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 2))
5120 {
5121 *string_buf_p++ = '\\';
5122 *string_buf_p++ = *src_p;
5123 }
5124
5125 state = utlAT_STRING_STATE_PASS_THROUGH;
5126 continue;
5127 }
5128
5129 if (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1)
5130 {
5131 state = utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2;
5132
5133 }
5134 else if (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2)
5135 {
5136 state = utlAT_STRING_STATE_PASS_THROUGH;
5137
5138 /*--- save hex value as a character (if there's room) ---*/
5139 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 1))
5140 *string_buf_p++ = num;
5141 }
5142 else
5143 state = utlAT_STRING_STATE_PASS_THROUGH;
5144
5145 /*--- else save character (if there's room) ---*/
5146 }
5147 else if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 1))
5148 *string_buf_p++ = *src_p;
5149 }
5150 if (string_buf_p >= (string_buf + utlNumberOf(string_buf)))
5151 string_buf_p = string_buf + utlNumberOf(string_buf) - 1;
5152
5153 *string_buf_p++ = '\0';
5154
5155 if (quoted == true)
5156 {
5157 /*--- check that string ends with a double quote ---*/
5158 if (*src_p != '"')
5159 {
5160 utlError(utlExecuteExtendedAtCommand16, "Extended-AT command syntax error at col=%d.", syntax_off + value_string_off + 1);
5161 parser_p->peg_counts.bad_commands++;
5162 rc = utlAT_RESULT_CODE_ERROR;
5163 goto out_error;
5164 }
5165 }
5166 else
5167 {
5168 char *first_p;
5169 char *last_p;
5170 int i, len;
5171
5172 if (parameter_p->type == utlAT_DATA_TYPE_STRING) first_p = parameter_value_p->value.string_p;
5173 else first_p = parameter_value_p->value.qstring_p;
5174
5175 /*--- trim trailing white space from end of unquoted string ---*/
5176 for (last_p = string_buf_p - 1; last_p > first_p; last_p--)
5177 if (*(last_p - 1) != ' ')
5178 {
5179 *last_p = '\0';
5180 break;
5181 }
5182 /*--- trim trailing white space from beginning of unquoted string ---*/
5183 for (i=0; *(first_p+i)==' ' ; i++);
5184 /* remove the num of space + add the null termination */
5185 len = strlen(first_p) - i + 1;
5186 memmove(first_p, first_p+i, len);
5187
5188 }
5189 }
5190 break;
5191
5192 case utlAT_DATA_TYPE_DIAL_STRING:
5193 {
5194 utlAtStringState_T state;
5195 bool alphabetical_digits;
5196 char *src_p;
5197
5198 parameter_value_p->value.dial_string_p = string_buf_p;
5199
5200 /*--- extract string, replacing hex escape sequences with the ASCII
5201 characters they represent */
5202 state = utlAT_STRING_STATE_PASS_THROUGH;
5203
5204 alphabetical_digits = false;
5205 for (src_p = value_string; *src_p != '\0'; src_p++)
5206 {
5207
5208 /*--- are we expecting alphabetical dial-string digits? ---*/
5209 if (alphabetical_digits == true)
5210 {
5211 if (((*src_p >= 'a') || (*src_p <= 'z')) ||
5212 ((*src_p >= 'A') || (*src_p <= 'Z')))
5213 {
5214 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 1))
5215 *string_buf_p++ = *src_p;
5216
5217 }
5218 else if (*src_p != ' ')
5219 alphabetical_digits = false;
5220 }
5221
5222 if (alphabetical_digits == false)
5223 {
5224
5225 /*--- this a possible embedded hex escape sequence? ---*/
5226 if ((*src_p == '\\') && (parser_p->options.allow_string_escapes == true))
5227 {
5228 state = utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1;
5229 num = 0; /* initialize hex num */
5230
5231 }
5232 else if ((state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1) ||
5233 (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2))
5234 {
5235
5236 /*--- extract hexadecimal escape sequence digit ---*/
5237 if ((*src_p >= '0') && (*src_p <= '9')) num = (16 * num) + (*src_p - '0');
5238 else if ((*src_p >= 'A') && (*src_p <= 'F')) num = (16 * num) + (*src_p - 'A') + 10;
5239 else if ((*src_p >= 'a') && (*src_p <= 'f')) num = (16 * num) + (*src_p - 'a') + 10;
5240 else
5241 {
5242 /*--- if reverse-solidus was not followed by a hex character, just
5243 interpret found characters as-is */
5244 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 2))
5245 {
5246 *string_buf_p++ = '\\';
5247 *string_buf_p++ = *src_p;
5248 }
5249
5250 state = utlAT_STRING_STATE_PASS_THROUGH;
5251 continue;
5252 }
5253
5254 if (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT1)
5255 {
5256 state = utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2;
5257
5258 }
5259 else if (state == utlAT_STRING_STATE_EXTRACT_HEX_DIGIT2)
5260 {
5261 state = utlAT_STRING_STATE_PASS_THROUGH;
5262
5263 /*--- process recognized dial-string characters ---*/
5264 if (strchr(utlAT_DIALING_CHARACTERS, num) != NULL)
5265 {
5266
5267 /*--- are zero or more alphabetical dial-string digits to follow? ---*/
5268 if (num == '"')
5269 alphabetical_digits = true;
5270
5271 /*--- save hex value as a character (if there's room) ---*/
5272 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 1))
5273 *string_buf_p++ = num;
5274 }
5275
5276 }
5277 else
5278 state = utlAT_STRING_STATE_PASS_THROUGH;
5279
5280 /*--- else process recognized dial-string characters ---*/
5281 }
5282 else if (strchr(utlAT_DIALING_CHARACTERS, *src_p) != NULL)
5283 {
5284
5285 /*--- are zero or more alphabetical dial-string digits to follow? ---*/
5286 if (*src_p == '"')
5287 alphabetical_digits = true;
5288
5289 /*--- save character (if there's room) ---*/
5290 if (string_buf_p < (string_buf + utlNumberOf(string_buf) - 1))
5291 *string_buf_p++ = *src_p;
5292 }
5293 }
5294
5295 /*--- ignore all characters following a terminator character ---*/
5296 if (*src_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR])
5297 break;
5298 }
5299 if (string_buf_p >= (string_buf + utlNumberOf(string_buf)))
5300 string_buf_p = string_buf + utlNumberOf(string_buf) - 1;
5301
5302 *string_buf_p++ = '\0';
5303 }
5304 break;
5305
5306 default:
5307 utlError(utlExecuteExtendedAtCommand17, "parameter_value_p->type!\n");
5308 break;
5309 }
5310 }
5311
5312 /*--- advance to next parameter ---*/
5313 if (parameter_p++ >= (command_p->parameters_p + command_p->num_parameters))
5314 {
5315 utlError(utlExecuteExtendedAtCommand18, "Extended-AT command has too many parameters at col=%d.", syntax_off + c_p - parameters_string_p);
5316 parser_p->peg_counts.bad_commands++;
5317 rc = utlAT_RESULT_CODE_ERROR;
5318 goto out_error;
5319 }
5320
5321 parameter_value_p++;
5322 }
5323 }
5324
5325 }
5326 else
5327 {
5328 if(!paramCheckIgnore) { //NULL parameters
5329 utlTrace(utlTRACE_AT_PARSER,utlPrintTrace(utlExecuteExtendedAtCommand19, "AT%s (set)\n", command_name_p););
5330 }
5331 else{
5332 utlTrace(utlTRACE_AT_PARSER,utlPrintTrace(utlExecuteExtendedAtCommand20, "AT%s (PRXY set, %s )\n", command_name_p,parameters_string_p););
5333 }
5334 }
5335
5336 if (parameter_p != NULL)
5337 {
5338 /*--- for each unspecified parameter value (if any)... ---*/
5339 while (parameter_p < (command_p->parameters_p + command_p->num_parameters))
5340 {
5341
5342 /*--- too many parameter values? ---*/
5343 if (parameter_value_p >= (parameter_values + utlAT_MAX_PARAMETERS))
5344 {
5345 utlError(utlExecuteExtendedAtCommand21, "Too many AT-command parameters at col=%d.", syntax_off);
5346 parser_p->peg_counts.bad_commands++;
5347 rc = utlAT_RESULT_CODE_ERROR;
5348 goto out_error;
5349 }
5350
5351 /*-- complain if unspecified parameter value is not Read, Read-only, and is required ---*/
5352 if (((parameter_p->access != utlAT_PARAMETER_ACCESS_READ) &&
5353 (parameter_p->access != utlAT_PARAMETER_ACCESS_READ_ONLY)) &&
5354 ( parameter_p->presence == utlAT_PARAMETER_PRESENCE_REQUIRED))
5355 {
5356 utlError(utlExecuteExtendedAtCommand22, "Missing parameter(s) in Extended-AT command at col=%d.", syntax_off);
5357 parser_p->peg_counts.bad_commands++;
5358 rc = utlAT_RESULT_CODE_ERROR;
5359 goto out_error;
5360 }
5361
5362 /*--- assign unspecified parameter a default value, according to it's data-type... ---*/
5363 utlSetDefaultParameterValue(parameter_value_p, parameter_p->type, parameter_p->access);
5364
5365 parameter_p++;
5366 parameter_value_p++;
5367 }
5368 }
5369
5370 /*--- else if this is a get-request, prepare `parameter_values' structure... ---*/
5371 }
5372 else if (request_type == utlAT_REQUEST_TYPE_GET)
5373 {
5374 utlAtParameter_P parameter_p;
5375 utlAtParameterValue_P parameter_value_p;
5376
5377 /*--- this AT-command an "action" command (which we can't fetch) ---*/
5378 if (command_p->type == utlAT_COMMAND_TYPE_EXACTION)
5379 {
5380 if(strcasecmp(command_p->name_p, "*EnVsim") != 0) {
5381 utlError(utlExecuteExtendedAtCommand23, "Attempted to perform a \"read\" for an Extended-AT \"action\" command at col=%d.", syntax_off);
5382 parser_p->peg_counts.bad_commands++;
5383 rc = utlAT_RESULT_CODE_ERROR;
5384 goto out_error;
5385 }
5386 }
5387
5388 parameter_p = command_p->parameters_p;
5389 parameter_value_p = parameter_values;
5390
5391 /*--- for each of this AT-Command's known parameters... ---*/
5392 while (parameter_p < (command_p->parameters_p + command_p->num_parameters))
5393 {
5394
5395 /*--- are we attempting to fetch a write-only parameter? ---*/
5396 if (parameter_p->access == utlAT_PARAMETER_ACCESS_WRITE_ONLY)
5397 {
5398 utlError(utlExecuteExtendedAtCommand24, "Attempt to read write-only AT command parameter at col=%d.", syntax_off);
5399 parser_p->peg_counts.bad_commands++;
5400 rc = utlAT_RESULT_CODE_ERROR;
5401 goto out_error;
5402 }
5403
5404 /*--- too many parameter values? ---*/
5405 if (parameter_value_p >= (parameter_values + utlAT_MAX_PARAMETERS))
5406 {
5407 utlError(utlExecuteExtendedAtCommand25, "Too many AT-command parameters at col=%d.", syntax_off);
5408 parser_p->peg_counts.bad_commands++;
5409 rc = utlAT_RESULT_CODE_ERROR;
5410 goto out_error;
5411 }
5412
5413 /*--- assign a default parameter value, according to it's data-type... ---*/
5414 utlSetDefaultParameterValue(parameter_value_p, parameter_p->type, parameter_p->access);
5415
5416 parameter_p++;
5417 parameter_value_p++;
5418 }
5419 }
5420
5421 /*--- process extended built-in AT-commands ---*/
5422 {
5423 /*--- initially assume no test response is required ---*/
5424 info_text[0] = '\0';
5425 if(!paramCheckIgnore) {
5426
5427 if ((rc = utlProcessExtendedAtCommand(parser_p,
5428 request_type,
5429 command_p,
5430 parameter_values,
5431 info_text,
5432 utlNumberOf(info_text),
5433 syntax_off)) == utlAT_RESULT_CODE_ERROR)
5434 {
5435 parser_p->peg_counts.bad_commands++;
5436 rc = utlAT_RESULT_CODE_ERROR;
5437 goto out_error;
5438 }
5439 }
5440 else{
5441 //command is proxy responsebility - assume parameter check is OK
5442 rc = utlAT_RESULT_CODE_OK;
5443 }
5444 }
5445
5446 /*--- invoke AT-command call-back (as appropriate) ---*/
5447 switch (request_type)
5448 {
5449 case utlAT_REQUEST_TYPE_SET:
5450 {
5451 char *info_text_p;
5452 utlAtParserOp_T at_async_op;
5453 utlAtParameterOp_T at_parameter_op;
5454
5455 if (info_text[0] == '\0') info_text_p = NULL;
5456 else info_text_p = info_text;
5457
5458 if ((command_p->call_backs.set_parameter_function_p != NULL)||(proxyFlag)) //allow support for commands that should be proxied
5459 {
5460 utlAtParameterValue_P parameter_values_p;
5461 utlAtAsyncResponse_P async_response_p;
5462
5463 if (command_p->num_parameters > (size_t)0) parameter_values_p = parameter_values;
5464 else parameter_values_p = NULL;
5465 if(command_p->type == utlAT_COMMAND_TYPE_EXTENDED_EXACTION)
5466 {
5467 if(parameters_string_p)
5468 {
5469 at_async_op = utlAT_ASYNC_OP_SET;
5470 at_parameter_op = utlAT_PARAMETER_OP_SET;
5471 }
5472 else
5473 {
5474 at_async_op = utlAT_ASYNC_OP_ACTION;
5475 at_parameter_op = utlAT_PARAMETER_OP_ACTION;
5476 }
5477 }
5478 else if(command_p->type == utlAT_COMMAND_TYPE_EXACTION)
5479 {
5480 at_async_op = utlAT_ASYNC_OP_ACTION;
5481 at_parameter_op = utlAT_PARAMETER_OP_ACTION;
5482 }
5483 else
5484 {
5485 at_async_op = utlAT_ASYNC_OP_SET;
5486 at_parameter_op = utlAT_PARAMETER_OP_SET;
5487 }
5488
5489 /*--- setup for pending asynchronous response ---*/
5490 if ((async_response_p = utlSetupPendingAsyncResponse(parser_p, at_async_op, command_p,proxyFlag)) == NULL)
5491 {
5492 utlError(utlExecuteExtendedAtCommand26, "utlSetupPendingAsyncResponse failed!\n");
5493 rc = utlAT_RESULT_CODE_ERROR;
5494 goto out_error;
5495 }
5496 //if proxy command - send to proxy
5497
5498 if (proxyFlag) {
5499 //send to proxy
5500 if(parser_p->call_backs.sendToProxy_function_p(command_name_p,
5501 at_parameter_op,
5502 parameters_string_p,
5503 &(async_response_p->xid),
5504 parser_p->call_backs.arg_p)!= utlSUCCESS) {
5505
5506 utlError(utlExecuteExtendedAtCommand27, "PROXY_DEBUG - SET - send to proxy _function_p failed for cmd %s with param %s !\n", command_name_p,parameters_string_p );
5507 /*--- clean ---*/
5508 utlAbandonPendingAsyncResponse(async_response_p);
5509
5510 parser_p->peg_counts.bad_commands++;
5511 rc = utlAT_RESULT_CODE_ERROR;
5512 goto out_error;
5513 }
5514 }
5515 else{
5516 //use command standard call back
5517 if ((command_p->call_backs.set_parameter_function_p)(at_parameter_op,
5518 command_name_p,
5519 parameter_values_p,
5520 command_p->num_parameters,
5521 info_text_p,
5522 &(async_response_p->xid),
5523 parser_p->call_backs.arg_p) != utlSUCCESS)
5524 {
5525
5526 utlError(utlExecuteExtendedAtCommand28, "set_parameter_function_p failed!\n");
5527 /*--- clean ---*/
5528 utlAbandonPendingAsyncResponse(async_response_p);
5529
5530 parser_p->peg_counts.bad_commands++;
5531 rc = utlAT_RESULT_CODE_ERROR;
5532 goto out_error;
5533 } //end send to command call back
5534 }
5535 }
5536 else
5537 {
5538 parser_p->peg_counts.bad_commands++;
5539 rc = utlAT_RESULT_CODE_ERROR;
5540 goto out_error;
5541 }
5542 rc = utlAT_RESULT_CODE_SUPPRESS;
5543 }
5544 break;
5545
5546 case utlAT_REQUEST_TYPE_GET:
5547 {
5548 char *info_text_p;
5549
5550 if (info_text[0] == '\0') info_text_p = NULL;
5551 else info_text_p = info_text;
5552
5553 if ((command_p->call_backs.get_parameter_function_p != NULL)||(proxyFlag))
5554 {
5555 utlAtParameterValue_P parameter_values_p;
5556 utlAtAsyncResponse_P async_response_p;
5557
5558 if (command_p->num_parameters > (size_t)0) parameter_values_p = parameter_values;
5559 else parameter_values_p = NULL;
5560
5561 /*--- setup for pending asynchronous response ---*/
5562 if ((async_response_p = utlSetupPendingAsyncResponse(parser_p, utlAT_ASYNC_OP_GET, command_p,proxyFlag)) == NULL)
5563 {
5564 utlError(utlExecuteExtendedAtCommand29, "utlSetupPendingAsyncResponse failed!\n");
5565 rc = utlAT_RESULT_CODE_ERROR;
5566 goto out_error;
5567 }
5568 //if proxy command call proxy
5569 if(proxyFlag) {
5570 //send command to proxy
5571 if(parser_p->call_backs.sendToProxy_function_p(command_name_p,
5572 utlAT_PARAMETER_OP_GET,
5573 parameters_string_p,
5574 &(async_response_p->xid),
5575 parser_p->call_backs.arg_p)!= utlSUCCESS) {
5576
5577 utlError(utlExecuteExtendedAtCommand30, "PROXY_DEBUG - GET - send to proxy _function_p failed for cmd %s with param %s !\n", command_name_p,parameters_string_p );
5578 /*--- clean ---*/
5579 utlAbandonPendingAsyncResponse(async_response_p);
5580
5581 parser_p->peg_counts.bad_commands++;
5582 rc = utlAT_RESULT_CODE_ERROR;
5583 goto out_error;
5584 }
5585 }
5586 else{
5587 //no need for proxy
5588 if ((command_p->call_backs.get_parameter_function_p)(utlAT_PARAMETER_OP_GET,
5589 command_name_p,
5590 parameter_values_p,
5591 command_p->num_parameters,
5592 info_text_p,
5593 &(async_response_p->xid),
5594 parser_p->call_backs.arg_p) != utlSUCCESS)
5595 {
5596 /*--- clean ---*/
5597 utlError(utlExecuteExtendedAtCommand31, "get_parameter_function_p failed!\n");
5598 utlAbandonPendingAsyncResponse(async_response_p);
5599
5600 parser_p->peg_counts.bad_commands++;
5601 rc = utlAT_RESULT_CODE_ERROR;
5602 goto out_error;
5603 }
5604 }
5605
5606 VDBGMSG(utlExecuteExtendedAtCommand32, "PROXY_DEBUG AT PARSER-%s,%d- value handle - returned xid for cmd %d \n ",
5607 __FUNCTION__, __LINE__, async_response_p->xid);
5608 }
5609 else
5610 {
5611 parser_p->peg_counts.bad_commands++;
5612 rc = utlAT_RESULT_CODE_ERROR;
5613 goto out_error;
5614 }
5615 rc = utlAT_RESULT_CODE_SUPPRESS;
5616 }
5617 break;
5618
5619 default:
5620 utlError(utlExecuteExtendedAtCommand33, "Invalid request_type: %d!\n", request_type);
5621 break;
5622 }
5623
5624 parser_p->peg_counts.extended_commands++;
5625
5626 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
5627 {
5628 utlError(utlExecuteExtendedAtCommand34, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
5629 rc = utlAT_RESULT_CODE_ERROR;
5630 goto out_error;
5631 }
5632
5633 if (rc == utlAT_RESULT_CODE_OK)
5634 parser_p->commands_in_line--;
5635
5636 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
5637
5638 return rc;
5639
5640out_error:
5641 atmcd_mult_unlock(parser_p, command_p, request_type);
5642out:
5643 return rc;
5644}
5645
5646/*---------------------------------------------------------------------------*
5647* FUNCTION
5648* utlAddDialString(parser_p, dest_p, dest_size, dial_string_p)
5649* INPUT
5650* parser_p == an open AT-command parser
5651* dest_p == where to start adding `dial_string_p'
5652* dest_size == maximum number of character to write to `dest_p'
5653* dial_string_p == the dial-string to add
5654* OUTPUT
5655* none
5656* RETURNS
5657* the number of characters appended for success, otherwise utlFAILED
5658* DESCRIPTION
5659* Add `dial_string_p' to the current dial string at position `dest_p',
5660* converting any embedded alphabetical-digits to numeric digits, and
5661* noting any embedded dial-string traits.
5662*---------------------------------------------------------------------------*/
5663static size_t utlAddDialString(const utlAtParser_P parser_p,
5664 char *dest_p,
5665 const size_t dest_size,
5666 const char *dial_string_p)
5667{
5668 bool alphabetical_digits;
5669 char *start_dest_p;
5670 char *term_dest_p;
5671
5672 utlAssert(parser_p != NULL);
5673 utlAssert(dest_p != NULL);
5674 utlAssert(dest_size > (size_t)0);
5675 utlAssert(dial_string_p != NULL);
5676
5677 start_dest_p = dest_p;
5678 term_dest_p = dest_p + dest_size;
5679
5680 alphabetical_digits = false;
5681 for (; *dial_string_p != '\0'; dial_string_p++)
5682 {
5683
5684 /*--- are we expecting alphabetical dial-string digits? ---*/
5685 if (alphabetical_digits == true)
5686 {
5687
5688 /*--- map alphabetical dial-string digit to an actual number ---*/
5689 switch (*dial_string_p)
5690 {
5691 case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': *dest_p++ = '2'; break;
5692 case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': *dest_p++ = '3'; break;
5693 case 'g': case 'G': case 'h': case 'H': case 'i': case 'I': *dest_p++ = '4'; break;
5694 case 'j': case 'J': case 'k': case 'K': case 'l': case 'L': *dest_p++ = '5'; break;
5695 case 'm': case 'M': case 'n': case 'N': case 'o': case 'O': *dest_p++ = '6'; break;
5696 case 'p': case 'P': case 'q': case 'Q': case 'r': case 'R': case 's': case 'S': *dest_p++ = '7'; break;
5697 case 't': case 'T': case 'u': case 'U': case 'v': case 'V': *dest_p++ = '8'; break;
5698 case 'w': case 'W': case 'x': case 'X': case 'y': case 'Y': case 'z': case 'Z': *dest_p++ = '9'; break;
5699
5700 case ' ':
5701 break;
5702
5703 default:
5704 alphabetical_digits = false;
5705 break;
5706 }
5707
5708 if (dest_p >= term_dest_p)
5709 {
5710 utlError(utlAddDialString, "Dial-string buffer overflow.");
5711 return utlFAILED;
5712 }
5713 }
5714
5715 if (alphabetical_digits == false)
5716 {
5717 if (*dial_string_p == '"')
5718 alphabetical_digits = true;
5719
5720 else
5721 {
5722 *dest_p++ = *dial_string_p;
5723
5724 if (dest_p >= term_dest_p)
5725 {
5726 utlError(utlAddDialString1, "Dial-string buffer overflow.");
5727 return utlFAILED;
5728 }
5729
5730 switch (*dial_string_p)
5731 {
5732 case '/': parser_p->states.dial_string.dial_string_delay++; break;
5733 case '+': parser_p->states.dial_string.options.international = true; break;
5734 case 'g': parser_p->states.dial_string.options.use_CCUG_SS_info = true; break;
5735 case 'G': parser_p->states.dial_string.options.use_CCUG_SS_info = true; break;
5736 case 'i': parser_p->states.dial_string.options.CLI_presentation = 'i'; break;
5737 case 'I': parser_p->states.dial_string.options.CLI_presentation = 'I'; break;
5738 default: break;
5739 }
5740 }
5741 }
5742 }
5743
5744 return dest_p - start_dest_p;
5745}
5746
5747/*---------------------------------------------------------------------------*
5748* FUNCTION
5749* utlParseATZ(parser_p, string_p, string_off)
5750* INPUT
5751* parser_p == an open AT-command parser
5752* string_p == the text characters to be parsed after the name "AT&Z"
5753* string_off == parmater offset (for error reporting)
5754* parse_len == length of string that has been parsed
5755* OUTPUT
5756* none
5757* RETURNS
5758* utlAT_RESULT_CODE_ERROR for failure, other values for success
5759* DESCRIPTION
5760* Parse the AT&Z command
5761*---------------------------------------------------------------------------*/
5762
5763static utlAtResultCode_T utlParseATZ(const utlAtParser_P parser_p,
5764 const char *string_p,
5765 const size_t string_off,
5766 int *parse_len)
5767
5768{
5769 utlAtParameterValue_T parameter_value;
5770 unsigned int location;
5771 size_t location_off;
5772 const char *c_p = string_p;
5773 utlAtResultCode_T rc = utlAT_RESULT_CODE_OK;
5774
5775
5776 /*--- The following forms are accepted:
5777 &Z<location>=<dial-string>
5778 &Z<location>=L (save last number dialed to <location>)
5779 &Z=<dial-string> (location defaults to 0)
5780 &Z=L (location defaults to 0)
5781 &Z<location>?
5782 &ZL? (print last number dialed)
5783 &Z? (location defaults to 0)
5784
5785 Note that due to the wide variety of characters that can legally
5786 appear in dial strings (thus making it impossible, in general, to
5787 determine where one &Z command ends and the next begins), the &Z
5788 command must be the very last AT-command on the line. */
5789
5790 location = 0;
5791 location_off = string_off;
5792
5793 /*--- extract (if present) location to save to (all digits following '&Z') ---*/
5794 while ((*c_p >= '0') &&
5795 (*c_p <= '9'))
5796 {
5797 location = (10 * location) + (*c_p - '0');
5798
5799 /*--- advance to next digit, skipping space characters ---*/
5800 do
5801 c_p++;
5802 while (*c_p == ' ');
5803
5804 if (*c_p == '\0')
5805 {
5806 utlError(utlParseATZ, "Incomplete AT-command at col=%d.", string_off + c_p - string_p + 1);
5807 parser_p->peg_counts.bad_commands++;
5808 return utlAT_RESULT_CODE_ERROR;
5809 }
5810 }
5811
5812 /*--- set default parameter value ---*/
5813 utlSetDefaultParameterValue(&parameter_value, utlAT_DATA_TYPE_DIAL_STRING, utlAT_PARAMETER_ACCESS_READ_WRITE);
5814
5815 /*--- have we possibly been asked for the last-dialed dial string? ---*/
5816 if ((*c_p == 'l') || (*c_p == 'L'))
5817 {
5818
5819 /*--- advance to character following 'L', skipping space characters ---*/
5820 do
5821 c_p++;
5822 while (*c_p == ' ');
5823
5824 /*--- if we have been asked for the last-dialed dial string ---*/
5825 if (*c_p == '?')
5826 {
5827
5828 /*--- advance to character following '?', skipping space characters ---*/
5829 do
5830 c_p++;
5831 while (*c_p == ' ');
5832
5833 /*--- reply with last-dialed dial string ---*/
5834 {
5835 if (parser_p->states.dial_string.last[0] != '\0')
5836 {
5837 parameter_value.is_default = false;
5838
5839 utlTrace(utlTRACE_AT_PARSER,
5840 utlPrintTrace(utlParseATZ1, "AT&ZL (get: %s)\n", parser_p->states.dial_string.last);
5841 );
5842 }
5843 else
5844 {
5845 utlTrace(utlTRACE_AT_PARSER,
5846 utlPrintTrace(utlParseATZ2, "AT&ZL (get)\n", location);
5847 );
5848 }
5849
5850 if (utlSendInfoResponse(parser_p, parser_p->states.dial_string.last) != utlSUCCESS)
5851 return utlAT_RESULT_CODE_ERROR;
5852
5853 parameter_value.value.dial_string_p = parser_p->states.dial_string.last;
5854 }
5855
5856 parser_p->peg_counts.basic_commands++;
5857
5858 }
5859 else
5860 {
5861 utlError(utlParseATZ3, "Incomplete AT-command at col=%d.", string_off + c_p - string_p + 1);
5862 parser_p->peg_counts.bad_commands++;
5863 return utlAT_RESULT_CODE_ERROR;
5864 }
5865
5866 /*--- have we been asked for the current value? ---*/
5867 }
5868 else if (*c_p == '?')
5869 {
5870
5871 /*--- advance to character following '?', skipping space characters ---*/
5872 do
5873 c_p++;
5874 while (*c_p == ' ');
5875
5876 /*--- reply with current value ---*/
5877 {
5878 const char *dial_string_p;
5879
5880 dial_string_p = NULL;
5881
5882 /*--- retrieve previously saved dial string ---*/
5883 if (parser_p->call_backs.retrieve_dial_string_function_p != NULL)
5884 {
5885 char location_name[20];
5886 const char *location_name_p;
5887
5888 location_name_p = location_name;
5889
5890 if ((utlDecimalToString(location_name, location, utlNumberOf(location_name)) == (size_t)0) ||
5891 ((parser_p->call_backs.retrieve_dial_string_function_p)(&location_name_p, &dial_string_p, parser_p->call_backs.arg_p) != utlSUCCESS))
5892 {
5893 parser_p->peg_counts.bad_commands++;
5894 return utlAT_RESULT_CODE_ERROR;
5895 }
5896 }
5897
5898 if (dial_string_p != NULL)
5899 {
5900 parameter_value.is_default = false;
5901
5902 utlTrace(utlTRACE_AT_PARSER,
5903 utlPrintTrace(utlParseATZ4, "AT&Z%d (get: %s)\n", location, dial_string_p);
5904 );
5905
5906 if (utlSendInfoResponse(parser_p, dial_string_p) != utlSUCCESS)
5907 return utlAT_RESULT_CODE_ERROR;
5908
5909 }
5910 else
5911 {
5912 dial_string_p = "";
5913
5914 utlTrace(utlTRACE_AT_PARSER,
5915 utlPrintTrace(utlParseATZ5, "AT&Z%d (get)\n", location);
5916 );
5917 }
5918
5919 parameter_value.value.dial_string_p = (char *)dial_string_p;
5920 }
5921
5922 parser_p->peg_counts.basic_commands++;
5923
5924 /*--- have we been asked to save a new dial-string? ---*/
5925 }
5926 else if (*c_p == '=')
5927 {
5928 char dial_string[utlAT_MAX_LINE_LENGTH];
5929 char *term_dial_string_p;
5930 char *dial_string_p;
5931 bool alphabetical_digits;
5932
5933 /*--- advance to character following '=', skipping space characters ---*/
5934 do
5935 c_p++;
5936 while (*c_p == ' ');
5937
5938 /*--- extract dial string ---*/
5939 alphabetical_digits = false;
5940 term_dial_string_p = dial_string + utlNumberOf(dial_string) - 1;
5941 for (dial_string_p = dial_string; *c_p != '\0'; c_p++)
5942 {
5943
5944 /*--- are we expecting alphabetical dial-string digits? ---*/
5945 if (alphabetical_digits == true)
5946 {
5947 if (((*c_p >= 'a') || (*c_p <= 'z')) ||
5948 ((*c_p >= 'A') || (*c_p <= 'Z')))
5949 {
5950 *dial_string_p++ = *c_p;
5951
5952 if (dial_string_p >= term_dial_string_p)
5953 {
5954 utlError(utlParseATZ6, "Dial-string buffer overflow.");
5955 return utlAT_RESULT_CODE_ERROR;
5956 }
5957
5958 }
5959 else if (*c_p != ' ')
5960 alphabetical_digits = false;
5961 }
5962
5963 if (alphabetical_digits == false)
5964 {
5965
5966 /*--- insert last dialed dial-string? ---*/
5967 if ((*c_p == 'l') || (*c_p == 'L'))
5968 {
5969 char *last_p;
5970
5971 /*--- insert last dialed dial-string ---*/
5972 for (last_p = parser_p->states.dial_string.last; *last_p != '\0'; last_p++)
5973 {
5974
5975 *dial_string_p++ = *last_p;
5976
5977 if (dial_string_p >= term_dial_string_p)
5978 {
5979 utlError(utlParseATZ7, "Dial-string buffer overflow.");
5980 return utlAT_RESULT_CODE_ERROR;
5981 }
5982 }
5983
5984 /*--- else save recognized dial-string characters ---*/
5985 }
5986 else if (strchr(utlAT_DIALING_CHARACTERS, *c_p) != NULL)
5987 {
5988
5989 /*--- are zero or more alphabetical dial-string digits to follow? ---*/
5990 if (*c_p == '"')
5991 alphabetical_digits = true;
5992
5993 *dial_string_p++ = *c_p;
5994
5995 if (dial_string_p >= term_dial_string_p)
5996 {
5997 utlError(utlParseATZ8, "Dial-string buffer overflow.");
5998 return utlAT_RESULT_CODE_ERROR;
5999 }
6000 }
6001 }
6002 }
6003 *dial_string_p = '\0';
6004
6005 utlTrace(utlTRACE_AT_PARSER,
6006 utlPrintTrace(utlParseATZ9, "AT&Z%d (set: %s)\n", location, dial_string);
6007 );
6008
6009 /*--- invoke save-dial-string call-back (if any) ---*/
6010 if (parser_p->call_backs.save_dial_string_function_p != NULL)
6011 {
6012 char location_name[20]; /* plenty big for a 64-bit unsigned integer */
6013
6014 if ((utlDecimalToString(location_name, location, utlNumberOf(location_name)) == (size_t)0) ||
6015 ((parser_p->call_backs.save_dial_string_function_p)( location_name, dial_string, parser_p->call_backs.arg_p) != utlSUCCESS))
6016 {
6017 parser_p->peg_counts.bad_commands++;
6018 return utlAT_RESULT_CODE_ERROR;
6019 }
6020 }
6021
6022 parameter_value.value.dial_string_p = dial_string;
6023 parameter_value.is_default = false;
6024 parser_p->peg_counts.basic_commands++;
6025
6026 }
6027 else
6028 {
6029 utlError(utlParseATZ10, "Syntax error at col=%d.", string_off + c_p - string_p + 1);
6030 parser_p->peg_counts.bad_commands++;
6031 return utlAT_RESULT_CODE_ERROR;
6032 }
6033
6034 *parse_len = c_p - string_p;
6035
6036 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
6037 {
6038 utlError(utlParseATZ11, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
6039 return utlAT_RESULT_CODE_ERROR;
6040 }
6041
6042 parser_p->commands_in_line--;
6043
6044 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
6045
6046 return rc;
6047
6048 /*--- extract decimal parameter (if any) ---*/
6049}
6050
6051
6052/*---------------------------------------------------------------------------*
6053* FUNCTION
6054* utlParseATD(parser_p, string_p, string_off)
6055* INPUT
6056* parser_p == an open AT-command parser
6057* string_p == the text characters to be parsed after the name "ATD"
6058* string_off == parmater offset (for error reporting)
6059* parseATD == length of string that has been parsed
6060* OUTPUT
6061* none
6062* RETURNS
6063* utlAT_RESULT_CODE_ERROR for failure, other values for success
6064* DESCRIPTION
6065* Parse the ATD command
6066*---------------------------------------------------------------------------*/
6067
6068static utlAtResultCode_T utlParseATD(const utlAtParser_P parser_p,
6069 const char *string_p,
6070 const size_t string_off,
6071 int *parse_len)
6072{
6073 char command_name[] = "D";
6074 bool parameter_found = false;
6075 char *term_dial_string_p;
6076 char *dial_string_p;
6077 bool alphabetical_digits;
6078 const char * c_p = string_p;
6079 utlAtParameterValue_T parameter_value;
6080 utlAtResultCode_T rc;
6081
6082 /*--- Notes on dial string processing:
6083 - The end of the dial-string (and thus the `D' AT-command) is
6084 demarked by either a semicolon character or by the end of the line.
6085 - If not immediately preceded by `>', `"' causes subsequent characters
6086 to be interpreted as alphabetic dial-string characters (which we
6087 translate into digits here).
6088 - If immediately preceded by `>', `"' delimits the start of a
6089 dial-string-store location-name. A second subsequenct `"' character
6090 delimits the end of the dial-string-store location-name.
6091 - 'L' is replaced by the last number dialed.
6092 - 'S' is replaced by the stored dial-string associated with location 0.
6093 - `S-<id>' is replaced by the stored dial-string associated with the specified location.
6094 - Each '/' character delays initial dialing by an additional 0.125 seconds.
6095 - A trailing ';' sets the do-call-origination flag to false.
6096 - 'G' sets the use-CCUG-SS-info option to true.
6097 - 'i' sets the CLI-presentation option to "allow".
6098 - 'I' sets the CLI-presentation option to "restrict".
6099 - '+' sets the international option to true. */
6100 parser_p->states.dial_string.active = false;
6101 parser_p->states.dial_string.dial_string_delay = 0; /* no delay */
6102 parser_p->states.dial_string.c_p = parser_p->states.dial_string.buf; /* reset */
6103 parser_p->states.dial_string.options.international = false;
6104 parser_p->states.dial_string.options.do_call_origination = true;
6105 parser_p->states.dial_string.options.use_CCUG_SS_info = false;
6106 parser_p->states.dial_string.options.CLI_presentation = '\0';
6107 alphabetical_digits = false;
6108 term_dial_string_p = parser_p->states.dial_string.buf + utlAT_MAX_DIAL_STRING_LENGTH;
6109 for (dial_string_p = parser_p->states.dial_string.buf; *c_p != '\0'; c_p++)
6110 {
6111
6112 /*--- are we expecting alphabetical dial-string digits? ---*/
6113 if (alphabetical_digits == true)
6114 {
6115
6116 /*--- map alphabetical dial-string digit to an actual number ---*/
6117 switch (*c_p)
6118 {
6119 case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': *dial_string_p++ = '2'; break;
6120 case 'd': case 'D': case 'e': case 'E': case 'f': case 'F': *dial_string_p++ = '3'; break;
6121 case 'g': case 'G': case 'h': case 'H': case 'i': case 'I': *dial_string_p++ = '4'; break;
6122 case 'j': case 'J': case 'k': case 'K': case 'l': case 'L': *dial_string_p++ = '5'; break;
6123 case 'm': case 'M': case 'n': case 'N': case 'o': case 'O': *dial_string_p++ = '6'; break;
6124 case 'p': case 'P': case 'q': case 'Q': case 'r': case 'R': case 's': case 'S': *dial_string_p++ = '7'; break;
6125 case 't': case 'T': case 'u': case 'U': case 'v': case 'V': *dial_string_p++ = '8'; break;
6126 case 'w': case 'W': case 'x': case 'X': case 'y': case 'Y': case 'z': case 'Z': *dial_string_p++ = '9'; break;
6127
6128 case ' ':
6129 break;
6130
6131 default:
6132 alphabetical_digits = false;
6133 break;
6134 }
6135
6136 if (dial_string_p >= term_dial_string_p)
6137 {
6138 utlError(utlParseATD, "Dial-string buffer overflow.");
6139 return utlAT_RESULT_CODE_ERROR;
6140 }
6141 }
6142
6143 if (alphabetical_digits == false)
6144 {
6145
6146 /*--- process recognized dial-string characters ---*/
6147 if (strchr(utlAT_DIALING_CHARACTERS, *c_p) != NULL)
6148 {
6149
6150 /*--- are zero or more alphabetical dial-string digits to follow? ---*/
6151 if (*c_p == '"')
6152 {
6153 alphabetical_digits = true;
6154
6155 /*--- else insert last dialed dial-string? ---*/
6156 }
6157 else if ((*c_p == 'l') || (*c_p == 'L'))
6158 {
6159 size_t rv;
6160
6161 /*--- insert it... ---*/
6162 if ((rv = utlAddDialString(parser_p, dial_string_p, term_dial_string_p - dial_string_p, parser_p->states.dial_string.last)) == (size_t)utlFAILED)
6163 return utlAT_RESULT_CODE_ERROR;
6164
6165 dial_string_p += rv;
6166
6167 /*--- else this a reference to a stored dial-string? (syntax: S or S-<id>) ---*/
6168 }
6169 else if ((*c_p == 's') || (*c_p == 'S'))
6170 {
6171 unsigned int location;
6172
6173 alphabetical_digits = false;
6174
6175 /*--- advance to character following 'S', skipping space characters ---*/
6176 do
6177 c_p++;
6178 while (*c_p == ' ');
6179
6180 location = 0; /* default location */
6181
6182 /*--- found a location lead-in character? ---*/
6183 if (*c_p == '-')
6184 {
6185
6186 /*--- advance to character following '-', skipping space characters ---*/
6187 do
6188 c_p++;
6189 while (*c_p == ' ');
6190
6191 /*--- extract location of stored dial-string to insert ---*/
6192 while ((*c_p >= '0') &&
6193 (*c_p <= '9'))
6194 {
6195
6196 location = (10 * location) + (*c_p - '0');
6197
6198 /*--- advance to next digit, skipping space characters ---*/
6199 do
6200 c_p++;
6201 while (*c_p == ' ');
6202 }
6203 c_p--;
6204
6205 }
6206 else
6207 c_p--;
6208
6209 /*--- retrieve and insert dial-string... ---*/
6210 {
6211 const char *retrieved_p;
6212
6213 retrieved_p = NULL;
6214
6215 /*--- retrieve previously (hopefully) saved dial string ---*/
6216 if (parser_p->call_backs.retrieve_dial_string_function_p != NULL)
6217 {
6218 char location_name[20];
6219 const char *location_name_p;
6220
6221 location_name_p = location_name;
6222
6223 if ((utlDecimalToString(location_name, location, utlNumberOf(location_name)) == (size_t)0) ||
6224 ((parser_p->call_backs.retrieve_dial_string_function_p)(&location_name_p, &retrieved_p, parser_p->call_backs.arg_p) != utlSUCCESS))
6225 {
6226 parser_p->peg_counts.bad_commands++;
6227 return utlAT_RESULT_CODE_ERROR;
6228 }
6229 }
6230
6231 /*--- insert dial string (if any)... ---*/
6232 if (retrieved_p != NULL)
6233 {
6234 size_t rv;
6235
6236 if ((rv = utlAddDialString(parser_p, dial_string_p, term_dial_string_p - dial_string_p, retrieved_p)) == (size_t)utlFAILED)
6237 return utlAT_RESULT_CODE_ERROR;
6238
6239 dial_string_p += rv;
6240 }
6241 }
6242
6243 /*--- else this a 3G phone-book dial-string reference? ---*/
6244 }
6245 else if (*c_p == '>')
6246 {
6247 char location_name[utlAT_MAX_STORED_LOCATION_NAME_LENGTH + 1];
6248 char *term_location_name_p;
6249 char *location_name_p;
6250 enum {
6251 utl3G_LOCATION_NAME_TYPE_NUMBER,
6252 utl3G_LOCATION_NAME_TYPE_MEMORY_TEXT,
6253 utl3G_LOCATION_NAME_TYPE_MEMORY_NUMBER,
6254 utl3G_LOCATION_NAME_TYPE_STRING_START,
6255 utl3G_LOCATION_NAME_TYPE_STRING_END
6256 } location_name_type;
6257
6258 /*--- The following forms of dial-string storage references are accepted:
6259
6260 ATD><number> (eg: ATD>55)
6261 ATD><mem><number> (eg: ATD>usim89)
6262 ATD>"<string>" (eg: ATD>"fred")
6263
6264 Note that dial-string storage entries are indexed by
6265 what ever text follows the "ATD>" command. This means
6266 that dial-string storage entries that are indexed by
6267 strings must include the double-quotes in the dial-string
6268 storage entry. You can store phone numbers under strings
6269 as follows (note the use of hex escapes to enter the
6270 needed double-quotes): AT+ASTO="\22fred\22",123-4567 */
6271
6272 alphabetical_digits = false;
6273
6274 /*--- advance to character following '>', skipping space characters ---*/
6275 do
6276 c_p++;
6277 while (*c_p == ' ');
6278
6279 /*--- identify type of location_name ---*/
6280 if (*c_p == '"') location_name_type = utl3G_LOCATION_NAME_TYPE_STRING_START;
6281 else if (isdigit(*c_p)) location_name_type = utl3G_LOCATION_NAME_TYPE_NUMBER;
6282 else if (isalpha(*c_p)) location_name_type = utl3G_LOCATION_NAME_TYPE_MEMORY_TEXT;
6283 else
6284 {
6285 utlError(utlParseATD1, "Dial-string syntax error.");
6286 parser_p->peg_counts.bad_commands++;
6287 return utlAT_RESULT_CODE_ERROR;
6288 }
6289
6290 /*--- extract phone-book location name ---*/
6291 term_location_name_p = location_name + utlAT_MAX_STORED_LOCATION_NAME_LENGTH;
6292 for (location_name_p = location_name; *c_p != '\0'; )
6293 {
6294 bool found_end;
6295
6296 found_end = false;
6297 switch (location_name_type)
6298 {
6299 case utl3G_LOCATION_NAME_TYPE_NUMBER:
6300 if (!isdigit(*c_p))
6301 found_end = true;
6302 break;
6303
6304 case utl3G_LOCATION_NAME_TYPE_MEMORY_TEXT:
6305 if (!isalpha(*c_p))
6306 {
6307 if (!isdigit(*c_p))
6308 found_end = true;
6309 else
6310 location_name_type = utl3G_LOCATION_NAME_TYPE_MEMORY_NUMBER;
6311 }
6312 break;
6313
6314 case utl3G_LOCATION_NAME_TYPE_MEMORY_NUMBER:
6315 if (!isdigit(*c_p))
6316 found_end = true;
6317 break;
6318
6319 case utl3G_LOCATION_NAME_TYPE_STRING_START:
6320 location_name_type = utl3G_LOCATION_NAME_TYPE_STRING_END;
6321 break;
6322
6323 case utl3G_LOCATION_NAME_TYPE_STRING_END:
6324 if (*c_p == '"')
6325 {
6326 found_end = true;
6327
6328 *location_name_p++ = *c_p++;
6329
6330 if (location_name_p >= term_location_name_p)
6331 {
6332 utlError(utlParseATD2, "Dial-string buffer overflow.");
6333 return utlAT_RESULT_CODE_ERROR;
6334 }
6335 }
6336 break;
6337
6338 default:
6339 utlError(utlParseATD3, "Invalid location_name_type: %d\n", location_name_type);
6340 break;
6341 }
6342
6343 /*--- we reach the end of the location name? ---*/
6344 if ((found_end == true) || (*c_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]))
6345 break;
6346
6347 *location_name_p++ = *c_p++;
6348
6349 if (location_name_p >= term_location_name_p)
6350 {
6351 utlError(utlParseATD4, "Dial-string buffer overflow.");
6352 return utlAT_RESULT_CODE_ERROR;
6353 }
6354 }
6355 c_p--;
6356 *location_name_p = '\0';
6357
6358 /*--- retrieve and insert dial-string... ---*/
6359 {
6360 const char *retrieved_p;
6361
6362 retrieved_p = NULL;
6363
6364 /*--- retrieve previously (hopefully) saved dial string ---*/
6365 if (parser_p->call_backs.retrieve_dial_string_function_p != NULL)
6366 {
6367 location_name_p = location_name;
6368
6369 if ((parser_p->call_backs.retrieve_dial_string_function_p)((const char **)&location_name_p, &retrieved_p, parser_p->call_backs.arg_p) != utlSUCCESS)
6370 {
6371 parser_p->peg_counts.bad_commands++;
6372 return utlAT_RESULT_CODE_ERROR;
6373 }
6374 }
6375
6376 /*--- insert dial string (if any)... ---*/
6377 if (retrieved_p != NULL)
6378 {
6379 size_t rv;
6380
6381 if ((rv = utlAddDialString(parser_p, dial_string_p, term_dial_string_p - dial_string_p, retrieved_p)) == (size_t)utlFAILED)
6382 return utlAT_RESULT_CODE_ERROR;
6383
6384 dial_string_p += rv;
6385 }
6386 }
6387
6388 /*--- insert regular dial-string digit ---*/
6389 }
6390 else
6391 {
6392 *dial_string_p++ = *c_p;
6393
6394 if (dial_string_p >= term_dial_string_p)
6395 {
6396 utlError(utlParseATD5, "Dial-string buffer overflow.");
6397 return utlAT_RESULT_CODE_ERROR;
6398 }
6399 }
6400
6401 switch (*c_p)
6402 {
6403 case '/': parser_p->states.dial_string.dial_string_delay++; break;
6404 case '+': parser_p->states.dial_string.options.international = true; break;
6405 case 'g': parser_p->states.dial_string.options.use_CCUG_SS_info = true; break;
6406 case 'G': parser_p->states.dial_string.options.use_CCUG_SS_info = true; break;
6407 case 'i': parser_p->states.dial_string.options.CLI_presentation = 'i'; break;
6408 case 'I': parser_p->states.dial_string.options.CLI_presentation = 'I'; break;
6409 default: break;
6410 }
6411
6412 }
6413 else
6414 {
6415 /*--- ignore illegal dial-string characters ---*/
6416 }
6417
6418 /*--- found end of dialing command? ---*/
6419 if (*c_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR])
6420 {
6421 *dial_string_p++ = *c_p++; /* save & skip semicolon character */
6422
6423 if (dial_string_p >= term_dial_string_p)
6424 {
6425 utlError(utlParseATD6, "Dial-string buffer overflow.");
6426 return utlAT_RESULT_CODE_ERROR;
6427 }
6428
6429 parser_p->states.dial_string.options.do_call_origination = false;
6430 break;
6431 }
6432 }
6433 }
6434 *dial_string_p = '\0';
6435
6436 /*--- is dial-string empty? ---*/
6437 if (strlen(parser_p->states.dial_string.buf) == (size_t)0)
6438 {
6439 parser_p->peg_counts.bad_commands++;
6440 return utlAT_RESULT_CODE_ERROR;
6441 }
6442
6443 parser_p->states.dial_string.active = true;
6444
6445 /*--- update "last dialed" dial string ---*/
6446 strncpy(parser_p->states.dial_string.last, parser_p->states.dial_string.buf, utlAT_MAX_DIAL_STRING_LENGTH);
6447 parser_p->states.dial_string.last[utlAT_MAX_DIAL_STRING_LENGTH] = '\0';
6448
6449 /*--- execute basic AT-command ---*/
6450 {
6451 utlSetDefaultParameterValue(&parameter_value, utlAT_DATA_TYPE_DIAL_STRING, utlAT_PARAMETER_ACCESS_READ_WRITE);
6452
6453 parameter_value.is_default = false;
6454 parameter_value.value.dial_string_p = parser_p->states.dial_string.buf;
6455
6456 if ((rc = utlExecuteBasicAtCommand(parser_p, command_name, parameter_found, &parameter_value, string_off)) == utlAT_RESULT_CODE_ERROR)
6457 return utlAT_RESULT_CODE_ERROR;
6458 }
6459
6460 /*--- for ATD, we'll defer issuing a result code until we know the status of
6461 the request, which will require traversal of the AT-parser state machine */
6462 *parse_len = c_p - string_p;
6463 return utlAT_RESULT_CODE_SUPPRESS;
6464
6465}
6466
6467/*---------------------------------------------------------------------------*
6468* FUNCTION
6469* utlGetDefaultSParameterValue(int parameter_num)
6470* INPUT
6471* parameter_num == S parameter index
6472* OUTPUT
6473* RETURNS
6474* default value of given S parameter
6475* DESCRIPTION
6476* get default value of given S parameter
6477*---------------------------------------------------------------------------*/
6478
6479static unsigned short utlGetDefaultSParameterValue(int parameter_num)
6480{
6481 unsigned short val = 0;
6482
6483 switch(parameter_num)
6484 {
6485 case utlAT_AUTO_ANSWER: val = 0; break; /* disable auto-answer */
6486 case utlAT_RING_COUNTER: val = 0; break; /* cleared */
6487 case utlAT_ESCAPE_CHAR: val = '+'; break;
6488 case utlAT_LINE_TERM_CHAR: val = '\015'; break; /* <carriage-val => */
6489 case utlAT_FORMATTING_CHAR: val = '\012'; break; /* <new-line> */
6490 case utlAT_LINE_EDIT_CHAR: val = '\010'; break; /* <back-space> */
6491 case utlAT_BLIND_DIAL_PAUSE_TIME: val = 2; break; /* 2 seconds */
6492 case utlAT_CONN_COMPLETE_TIMEOUT: val = 1; break; /* 1 second */
6493 case utlAT_DIALING_PAUSE_TIME: val = 2; break; /* 2 seconds */
6494 case utlAT_CARRIER_DETECT_TIME: val = 6; break; /* 0.6 seconds */
6495 case utlAT_CARRIER_LOSS_TIME: val = 7; break; /* 0.7 seconds */
6496 case utlAT_DTMF_TONE_DURATION: val = 63; break; /* 0.63 seconds */
6497 case utlAT_ESCAPE_GUARD_TIME: val = 50; break; /* 1 second */
6498 case utlAT_SEPARATER_CHAR: val = ','; break;
6499 case utlAT_TERMINATER_CHAR: val = ';'; break;
6500 case utlAT_XON_CHAR: val = 0x11; break; /* <DC1> */
6501 case utlAT_XOFF_CHAR: val = 0x13; break; /* <DC3> */
6502 case utlAT_SLEEP_TIME: val = 0; break; /* 0 seconds */
6503 case utlAT_DTR_DELAY_TIME: val = 10; break; /* 0.1 seconds */
6504 case utlAT_HOOK_FLASH_TIME: val = 5; break; /* 0.5 seconds */
6505 case utlAT_INACTIVITY_TIME: val = 10; break; /* 100 seconds */
6506 case utlAT_DISCONNECT_WAIT_TIME: val = 0; break; /* 0 seconds */
6507 default: val = 0; break;
6508 }
6509
6510 return val;
6511}
6512
6513/*---------------------------------------------------------------------------*
6514* FUNCTION
6515* utlParseATS(parser_p, string_p, string_off)
6516* INPUT
6517* parser_p == an open AT-command parser
6518* string_p == the text characters to be parsed after "ATS"
6519* string_off == parmater offset (for error reporting)
6520* parse_len == length of string that has been parsed
6521* OUTPUT
6522* none
6523* RETURNS
6524* utlAT_RESULT_CODE_ERROR for failure, other values for success
6525* DESCRIPTION
6526* Parse the ATS command
6527*---------------------------------------------------------------------------*/
6528static utlAtResultCode_T utlParseATS(const utlAtParser_P parser_p,
6529 const char *string_p,
6530 const size_t string_off,
6531 int *parse_len)
6532{
6533 unsigned int parameter_num;
6534 size_t parameter_num_off;
6535 const char *c_p = string_p;
6536
6537 /*--- The following forms are accepted:
6538 S<parameter-num>=<value>
6539 S=<value> (parameter-num defaults to 0)
6540 S<parameter-num>?
6541 S? (parameter-num defaults to 0)
6542
6543 Note that we support having multiple "S" AT-commands on
6544 the same line. */
6545
6546
6547 parameter_num = 0;
6548 parameter_num_off = string_off; // c_p - string_p + 1;
6549
6550 /*--- extract (if present) S-parameter number (all digits following 'S') ---*/
6551 while ((*c_p >= '0') &&
6552 (*c_p <= '9'))
6553 {
6554 parameter_num = (10 * parameter_num) + (*c_p - '0');
6555
6556 /*--- advance to next digit, skipping space characters ---*/
6557 do
6558 c_p++;
6559 while (*c_p == ' ');
6560
6561 if (*c_p == '\0')
6562 {
6563 utlError(utlParseATS, "Incomplete S-parameter at col=%d.", string_off + c_p - string_p + 1);
6564 parser_p->peg_counts.bad_commands++;
6565 return utlAT_RESULT_CODE_ERROR;
6566 }
6567 }
6568
6569 /*--- check sanity of found S-parameter number ---*/
6570 if (parameter_num >= utlNumberOf(parser_p->parameters.S))
6571 {
6572 utlError(utlParseATS1, "Invalid S-parameter number %d at col=%d.", parameter_num, string_off + parameter_num_off);
6573 parser_p->peg_counts.bad_commands++;
6574 return utlAT_RESULT_CODE_ERROR;
6575 }
6576
6577 /*--- have we been asked for the S-parameter's current value? ---*/
6578 if (*c_p == '?')
6579 {
6580
6581 /*--- advance to character following '?', skipping space characters ---*/
6582 do
6583 c_p++;
6584 while (*c_p == ' ');
6585
6586 if((parameter_num == utlAT_AUTO_ANSWER) && (parser_p->call_backs.getAutoAnswerDelay_function_p != NULL))
6587 {
6588 parser_p->call_backs.getAutoAnswerDelay_function_p(parser_p->call_backs.arg_p, &(parser_p->parameters.S[parameter_num]));
6589 }
6590 utlTrace(utlTRACE_AT_PARSER,
6591 utlPrintTrace(utlParseATS2, "ATS%d (get: %d)\n", parameter_num, parser_p->parameters.S[parameter_num]);
6592 );
6593
6594 /*--- reply with S-parameter's current value (a 3-digit decimal value) ---*/
6595 {
6596 char buf[10];
6597 size_t i;
6598 size_t rv;
6599
6600 i = 0;
6601
6602 /*--- pad value with leading zeros (as necessary) ---*/
6603 if (parser_p->parameters.S[parameter_num] < 100) buf[i++] = '0';
6604 if (parser_p->parameters.S[parameter_num] < 10) buf[i++] = '0';
6605
6606 if ((rv = utlDecimalToString(buf + i, parser_p->parameters.S[parameter_num], utlNumberOf(buf) - i)) == (size_t)0)
6607 {
6608 utlError(utlParseATS3, "Value-buffer overflow.");
6609 return utlAT_RESULT_CODE_ERROR;
6610 }
6611 i += rv;
6612
6613 buf[i] = '\0';
6614
6615 if (utlSendInfoResponse(parser_p, buf) != utlSUCCESS)
6616 return utlAT_RESULT_CODE_ERROR;
6617 }
6618
6619 parser_p->peg_counts.basic_commands++;
6620
6621 /*--- have we been asked to set S-parameter to a new value? ---*/
6622 }
6623 else if (*c_p == '=')
6624 {
6625 unsigned int parameter_value;
6626 size_t parameter_value_off;
6627
6628 /*--- advance to character following '=', skipping space characters ---*/
6629 do
6630 c_p++;
6631 while (*c_p == ' ');
6632
6633 parameter_value = 0;
6634 parameter_value_off = c_p - string_p + 1;
6635
6636 /*--- was no S-parameter value specified? ---*/
6637 if (((*c_p < '0') ||
6638 (*c_p > '9')) && ((parser_p->options.allow_default_S_parameter_values == false) ||
6639 ((*c_p != parser_p->parameters.S[utlAT_TERMINATER_CHAR]) &&
6640 (*c_p != parser_p->parameters.S[utlAT_LINE_TERM_CHAR]) && (*c_p != 0))))
6641 {
6642 utlError(utlParseATS4, "S-parameter syntax error at col=%d.", string_off + c_p - string_p + 1);
6643 parser_p->peg_counts.bad_commands++;
6644 return utlAT_RESULT_CODE_ERROR;
6645 }
6646
6647 /* if allow_default_S_parameter_values is set to true, we need to set default
6648 * value for parameter_value */
6649 if(((*c_p < '0') || (*c_p >'9')) && (parser_p->options.allow_default_S_parameter_values == true))
6650 {
6651 parameter_value = utlGetDefaultSParameterValue(parameter_num);
6652 }
6653
6654 /*--- extract S-parameter's new (numeric) value ---*/
6655 while ((*c_p >= '0') &&
6656 (*c_p <= '9'))
6657 {
6658 parameter_value = (10 * parameter_value) + (*c_p - '0');
6659
6660 if (*++c_p == '\0')
6661 break;
6662 }
6663
6664 utlTrace(utlTRACE_AT_PARSER,
6665 utlPrintTrace(utlParseATS5, "ATS%d (set: %d)\n", parameter_num, parameter_value);
6666 );
6667
6668 /*--- process new S-parameter value ---*/
6669 if (utlProcessSParameter(parser_p, parameter_num, parameter_value) != utlSUCCESS)
6670 {
6671 parser_p->peg_counts.bad_commands++;
6672 return utlAT_RESULT_CODE_ERROR;
6673 }
6674#if 0
6675 if (parameter_num == utlAT_AUTO_ANSWER)
6676 {
6677 char command_name[8]="S0";
6678 size_t command_name_off;
6679 bool parameter_found = true;
6680 utlAtParameterValue_T S0parameter_value;
6681 utlSetDefaultParameterValue(&S0parameter_value, utlAT_DATA_TYPE_DECIMAL, utlAT_PARAMETER_ACCESS_READ_WRITE);
6682 S0parameter_value.value.decimal = parameter_value;
6683
6684 S0parameter_value.is_default = !parameter_found;
6685 sprintf(parser_p->basic_command_param, "=%d\r", parameter_value);
6686
6687 /*--- execute basic AT-command ---*/
6688 utlError(utlParseATSS0, "%s: ATS0 will execute: value=%d!\n", __FUNCTION__, parameter_value);
6689 if ((utlExecuteBasicAtCommand(parser_p, command_name, parameter_found, &S0parameter_value, 0)) == utlAT_RESULT_CODE_ERROR)
6690 {
6691 utlError(utlParseATSS1, "%s: ATS0 execute failure!\n", __FUNCTION__);
6692 } else {
6693 utlError(utlParseATSS2, "%s: ATS0 execute successfully!\n", __FUNCTION__);
6694 }
6695
6696 }
6697#endif
6698 /*--- notify application of S-parameter value change ---*/
6699 if ( parser_p->call_backs.s_parameter_function_p != NULL)
6700 {
6701 if ((parser_p->call_backs.s_parameter_function_p)(parameter_num,
6702 parameter_value,
6703 parser_p->call_backs.arg_p) != utlSUCCESS)
6704 {
6705 parser_p->peg_counts.bad_commands++;
6706 return utlAT_RESULT_CODE_ERROR;
6707 }
6708 }
6709
6710 /*--- save new S-parameter value ---*/
6711 parser_p->parameters.S[parameter_num] = parameter_value;
6712 parser_p->peg_counts.basic_commands++;
6713
6714 }
6715 else
6716 {
6717 utlError(utlParseATS6, "S-parameter syntax error at col=%d.", string_off + c_p - string_p + 1);
6718 parser_p->peg_counts.bad_commands++;
6719 return utlAT_RESULT_CODE_ERROR;
6720 }
6721
6722 *parse_len = c_p - string_p;
6723
6724 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
6725 {
6726 utlError(utlParseATS7, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
6727 return utlAT_RESULT_CODE_ERROR;
6728 }
6729
6730 parser_p->commands_in_line--;
6731
6732 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
6733
6734 return utlAT_RESULT_CODE_OK;
6735
6736}
6737
6738
6739/*---------------------------------------------------------------------------*
6740* FUNCTION
6741* utlParseLine(parser_p, string_p, string_off)
6742* INPUT
6743* parser_p == an open AT-command parser
6744* string_p == the text characters to be parsed
6745* string_off == offset from start of line to `string_p' (for error
6746* reporting)
6747* OUTPUT
6748* none
6749* RETURNS
6750* utlAT_RESULT_CODE_ERROR for failure, other values for success
6751* DESCRIPTION
6752* Parses a line of text, searching for an AT command to execute, and
6753* executing it when found. Note that as-per the standard, only the first
6754* collection of AT commands on each line is parsed and executed.
6755*---------------------------------------------------------------------------*/
6756static utlAtResultCode_T utlParseLine(const utlAtParser_P parser_p,
6757 char *input_string_p,
6758 const size_t string_off)
6759{
6760 const char *c_p;
6761 utlAtResultCode_T rc;
6762 char *string_p = input_string_p;
6763
6764 utlAssert(parser_p != NULL);
6765 utlAssert(string_p != NULL);
6766
6767 ERRMSG(utlParseLine1, "[%s] %s\n", __FUNCTION__, string_p);
6768
6769 rc = utlAT_RESULT_CODE_OK;
6770 parser_p->call_backs.checkSmsPara_function_p(*(int *)(parser_p->call_backs.arg_p), input_string_p);
6771
6772 parser_p->call_backs.convert_atcmd_str_p(*(int *)(parser_p->call_backs.arg_p), input_string_p, &string_p);
6773
6774 /*--- scan for AT prefix ---*/
6775 {
6776 char last_c;
6777
6778 last_c = '\0';
6779 for (c_p = string_p; *c_p != '\0'; c_p++)
6780 {
6781
6782 /*--- ignore space characters ---*/
6783 if (*c_p == ' ')
6784 continue;
6785
6786 /*--- found an AT prefix? ---*/
6787 if (((last_c == 'A') && (*c_p == 'T')) ||
6788 ((last_c == 'a') && (*c_p == 't')))
6789 break;
6790
6791 last_c = *c_p;
6792 }
6793
6794 /*--- no AT prefix found? ---*/
6795 if (*c_p == '\0')
6796 return utlAT_RESULT_CODE_SUPPRESS;
6797 }
6798
6799 /*--- advance to character following AT prefix, skipping space characters ---*/
6800 do
6801 c_p++;
6802 while (*c_p == ' ');
6803
6804 /* Special process for the command "AT", we will delay the "OK" response until all the services have been registered */
6805 if (*c_p == '\0')
6806 {
6807 utlAtParameterValue_T parameter_value;
6808
6809 utlSetDefaultParameterValue(&parameter_value, utlAT_DATA_TYPE_DIAL_STRING, utlAT_PARAMETER_ACCESS_READ_WRITE);
6810
6811 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
6812 {
6813 utlError(utlParseLine, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
6814 return utlAT_RESULT_CODE_ERROR;
6815 }
6816
6817 parser_p->commands_in_line++;
6818
6819 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
6820
6821 if ((rc = utlExecuteBasicAtCommand(parser_p, " ", false, &parameter_value, string_off)) == utlAT_RESULT_CODE_ERROR)
6822 return utlAT_RESULT_CODE_ERROR;
6823 return rc;
6824 }
6825
6826 /* Count how many AT commands in one line*/
6827 {
6828 const char *temp = c_p;
6829
6830 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
6831 {
6832 utlError(utlParseLine1, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
6833 return utlAT_RESULT_CODE_ERROR;
6834 }
6835#ifndef AT_CMD_ASYNC_MODE
6836 parser_p->commands_in_line = 0; //async mode commands_in_line can't initialize as 0
6837#endif
6838 while (*temp != '\0')
6839 {
6840 bool quoted = false;
6841 parser_p->commands_in_line++;
6842
6843 /*--- skip to next AT command ---*/
6844 for (; *temp != '\0'; temp++)
6845 {
6846 if(*temp == '"')
6847 quoted = !quoted;
6848 if (*temp == parser_p->parameters.S[utlAT_TERMINATER_CHAR] && !quoted)
6849 {
6850 temp++; /* skip terminator char */
6851 break;
6852 }
6853 }
6854
6855 /*--- skip white space ---*/
6856 while (*temp == ' ')
6857 temp++;
6858 }
6859 utlPrintTrace(utlParseLine2, "%s: parser_p->commands_in_line:%d\n", __FUNCTION__, parser_p->commands_in_line);
6860
6861 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
6862 }
6863
6864 /*--- extract and process each AT-command following the AT prefix... ---*/
6865 while (*c_p != '\0')
6866 {
6867
6868 /*--- if this is an "extended" AT command ---*/
6869 if (strchr(utlAT_EXTENDED_COMMAND_PREFIXES, *c_p) != NULL)
6870 {
6871 char prefix_char;
6872 char command_name[utlAT_MAX_COMMAND_LENGTH_WITH_PREFIX]; /* prefix character + 16 characters + null */
6873 size_t command_name_off;
6874
6875 prefix_char = *c_p;
6876
6877 /*--- advance to character following extended command prefix, skipping space characters ---*/
6878 do
6879 c_p++;
6880 while (*c_p == ' ');
6881
6882 command_name_off = c_p - string_p + 1;
6883
6884 /*--- character immediately following command prefix must be alphabetic ---*/
6885 if (((*c_p < 'A') || (*c_p > 'Z')) &&
6886 ((*c_p < 'a') || (*c_p > 'z')))
6887 {
6888 utlError(utlParseLine3, "Invalid extended-AT command name syntax at col=%d.", string_off + command_name_off);
6889 return utlAT_RESULT_CODE_ERROR;
6890 }
6891
6892 /*--- extract extended command name (can be up to 16 characters long) ---*/
6893 {
6894 size_t i;
6895
6896 command_name[0] = prefix_char;
6897
6898 for (i = 1; *c_p != '\0'; )
6899 {
6900
6901 if (i >= (utlNumberOf(command_name) - 1))
6902 {
6903 utlError(utlParseLine4, "Extended-AT command name too long at col=%d.", string_off + command_name_off);
6904 return utlAT_RESULT_CODE_ERROR;
6905 }
6906
6907 command_name[i++] = *c_p;
6908
6909 do
6910 c_p++;
6911 while (*c_p == ' ');
6912
6913 /*--- only certain characters can appear in command names ---*/
6914 if (((*c_p < 'A') || (*c_p > 'Z')) &&
6915 ((*c_p < 'a') || (*c_p > 'z')) &&
6916 ((*c_p < '0') || (*c_p > '9')) &&
6917 (*c_p != '!') && (*c_p != '%') &&
6918 (*c_p != '-') && (*c_p != '.') &&
6919 (*c_p != '/') && (*c_p != ':') && (*c_p != '_'))
6920 break;
6921 }
6922 command_name[i++] = '\0';
6923 utlAssert(i <= utlNumberOf(command_name));
6924 }
6925
6926 /*--- process extended AT command... ---*/
6927 {
6928 /*--- have we been asked for the current parameter value(s)? ---*/
6929 if (*c_p == '?')
6930 {
6931
6932 /*--- advance to character following '?', skipping space characters ---*/
6933 do
6934 c_p++;
6935 while (*c_p == ' ');
6936
6937 /*--- get current parameter value(s) ---*/
6938 if ((rc = utlExecuteExtendedAtCommand(parser_p, utlAT_REQUEST_TYPE_GET, command_name, NULL, string_off + c_p - string_p)) == utlAT_RESULT_CODE_ERROR)
6939 return utlAT_RESULT_CODE_ERROR;
6940
6941 /*--- else have we been asked to set default parameter value(s)? ---*/
6942 }
6943 else if ((*c_p == '\0') || (*c_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]))
6944 {
6945
6946 /*--- set parameters using default parameter value(s) ---*/
6947 if ((rc = utlExecuteExtendedAtCommand(parser_p, utlAT_REQUEST_TYPE_SET, command_name, NULL, string_off + c_p - string_p)) == utlAT_RESULT_CODE_ERROR)
6948 return utlAT_RESULT_CODE_ERROR;
6949
6950 /*--- else have we been asked to set parameter values or for the command's syntax? ---*/
6951 }
6952 else if (*c_p == '=')
6953 {
6954
6955 /*--- advance to character following '=', skipping space characters ---*/
6956 do
6957 c_p++;
6958 while (*c_p == ' ');
6959
6960 /*--- have we been asked for the extended AT command's syntax? ---*/
6961 if (*c_p == '?')
6962 {
6963
6964 /*--- advance to character following '?', skipping space characters ---*/
6965 do
6966 c_p++;
6967 while (*c_p == ' ');
6968
6969 /*--- reply with command syntax ---*/
6970 if ((rc = utlExecuteExtendedAtCommand(parser_p, utlAT_REQUEST_TYPE_SYNTAX, command_name, NULL, string_off + c_p - string_p)) == utlAT_RESULT_CODE_ERROR)
6971 return utlAT_RESULT_CODE_ERROR;
6972
6973 /*--- else have we been asked to set new parameter value(s)? ---*/
6974 }
6975 else
6976 {
6977 char parameters_string[utlAT_MAX_LINE_LENGTH];
6978 size_t parameters_string_off;
6979 bool quoted = false;
6980
6981 parameters_string_off = c_p - string_p;
6982
6983 /*--- collect AT-command's parameters into a string ---*/
6984 {
6985 char *dest_p;
6986
6987 for (dest_p = parameters_string; *c_p != '\0'; c_p++)
6988 {
6989 if(*c_p == '"')
6990 quoted = !quoted;
6991
6992 if((*c_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]) && !quoted)
6993 break;
6994
6995 *dest_p++ = *c_p;
6996 }
6997 *dest_p = '\0';
6998 }
6999
7000 /*--- set current parameter value(s) ---*/
7001 if ((rc = utlExecuteExtendedAtCommand(parser_p, utlAT_REQUEST_TYPE_SET, command_name, parameters_string, string_off + parameters_string_off)) == utlAT_RESULT_CODE_ERROR)
7002 return utlAT_RESULT_CODE_ERROR;
7003 }
7004
7005 }
7006 else
7007 {
7008 utlError(utlParseLine5, "Invalid extended-AT command syntax at col=%d.", string_off + c_p - string_p + 1);
7009 parser_p->peg_counts.bad_commands++;
7010 return utlAT_RESULT_CODE_ERROR;
7011 }
7012 }
7013
7014 /*--- else assume this is a "basic" AT command ---*/
7015 }
7016 else
7017 {
7018 char command_name[3];
7019 size_t command_name_off;
7020 bool parameter_found;
7021 utlAtParameterValue_T parameter_value;
7022 int parse_len = 0;
7023
7024 /*--- extract command name ---*/
7025 {
7026 size_t i;
7027
7028 i = 0;
7029
7030 command_name_off = c_p - string_p + 1;
7031
7032 /*--- this a two-character basic AT command? ---*/
7033 if (strchr(utlAT_BASIC_COMMAND_PREFIXES, *c_p) != NULL)
7034 command_name[i++] = *c_p++;
7035
7036 /*--- skip white space ---*/
7037 while (*c_p == ' ')
7038 c_p++;
7039
7040 /*--- command character must be alphabetic ---*/
7041 if (((*c_p < 'A') || (*c_p > 'Z')) &&
7042 ((*c_p < 'a') || (*c_p > 'z')))
7043 {
7044 utlError(utlParseLine6, "AT command syntax error at col=%d.", string_off + command_name_off);
7045 parser_p->peg_counts.bad_commands++;
7046 return utlAT_RESULT_CODE_ERROR;
7047 }
7048
7049 command_name[i++] = *c_p;
7050 command_name[i++] = '\0';
7051 }
7052
7053 /*--- advance to character following command character, skipping space characters ---*/
7054 do
7055 c_p++;
7056 while (*c_p == ' ');
7057
7058 parameter_found = false;
7059
7060 /*--- this an "S-parameter" (ATS) command? ---*/
7061 if (strcasecmp(command_name, "S") == 0)
7062 {
7063 rc = utlParseATS(parser_p, c_p, (string_off + c_p - string_p), &parse_len);
7064 if (rc != utlAT_RESULT_CODE_ERROR)
7065 c_p += parse_len + 1;
7066 else
7067 return rc;
7068 /*--- else this a "dial" (ATD) command? ---*/
7069 }
7070 else if (strcasecmp(command_name, "D") == 0)
7071 {
7072
7073 rc = utlParseATD(parser_p, c_p, (string_off + c_p - string_p), &parse_len);
7074 if (rc != utlAT_RESULT_CODE_ERROR)
7075 c_p += parse_len + 1;
7076 else
7077 return rc;
7078 /*--- else this a "save dial string" (AT&Z) command? ---*/
7079 }
7080 else if (strcasecmp(command_name, "&Z") == 0)
7081 {
7082 rc = utlParseATZ(parser_p, c_p, (string_off + c_p - string_p), &parse_len);
7083 if (rc != utlAT_RESULT_CODE_ERROR)
7084 c_p += parse_len + 1;
7085 else
7086 return rc;
7087 }
7088 else
7089 {
7090 utlSetDefaultParameterValue(&parameter_value, utlAT_DATA_TYPE_DECIMAL, utlAT_PARAMETER_ACCESS_READ_WRITE);
7091
7092 /* check the parameter */
7093 if(((*c_p < '0') || (*c_p > '9')) &&
7094 (*c_p != parser_p->parameters.S[utlAT_TERMINATER_CHAR]) &&
7095 (*c_p != parser_p->parameters.S[utlAT_LINE_TERM_CHAR]) &&
7096 (*c_p != 0))
7097 return utlAT_RESULT_CODE_ERROR;
7098
7099 //copy parameter string for storage if the command needs to be proxied
7100 strncpy(parser_p->basic_command_param, c_p, sizeof(parser_p->basic_command_param)-1);
7101
7102 /*--- parameter (if present) must be composed of digits ---*/
7103 while ((*c_p >= '0') &&
7104 (*c_p <= '9'))
7105 {
7106 parameter_value.value.decimal = (10 * parameter_value.value.decimal) + (*c_p - '0');
7107 parameter_found = true;
7108
7109 /*--- advance to next digit, skipping space characters ---*/
7110 do
7111 c_p++;
7112 while (*c_p == ' ');
7113 }
7114
7115 parameter_value.is_default = !parameter_found;
7116
7117 /*--- execute basic AT-command ---*/
7118 if ((rc = utlExecuteBasicAtCommand(parser_p, command_name, parameter_found, &parameter_value, string_off + command_name_off)) == utlAT_RESULT_CODE_ERROR)
7119 return utlAT_RESULT_CODE_ERROR;
7120 }
7121 }
7122
7123 /*--- skip to end of current extended-AT command ---*/
7124 bool quoted = false;
7125 for (; *c_p != '\0'; c_p++)
7126 {
7127 if(*c_p == '"')
7128 quoted = !quoted;
7129 if (*c_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR] && !quoted)
7130 {
7131 c_p++; /* skip terminator char */
7132 break;
7133 }
7134 }
7135
7136 /*--- skip white space ---*/
7137 while (*c_p == ' ')
7138 c_p++;
7139
7140
7141 size_t commandcount = 0;
7142 do
7143 {
7144 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) == utlSUCCESS)
7145 {
7146 commandcount = parser_p->commands_in_line;
7147 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
7148 break;
7149 }
7150 } while (1);
7151
7152 if (commandcount > 1)
7153 {
7154 utlError(utlParseLine99, "goto process next command\n");
7155 do
7156 {
7157 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) == utlSUCCESS)
7158 {
7159 if (utlIsListEmpty(parser_p->states.async_responses.pending))
7160 {
7161 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
7162 break;
7163 }
7164
7165 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
7166 }
7167 } while (1);
7168 }
7169
7170 do
7171 {
7172 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) == utlSUCCESS)
7173 {
7174 commandcount = parser_p->commands_in_line;
7175 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
7176 break;
7177 }
7178 } while (1);
7179
7180 if (commandcount == 0)
7181 {
7182 //if pre command abort or error,abandon subsequent commands
7183 //or if no cmd in this cmdline
7184 //utlError(utlParseLine100, "pre command abort or error,abandon subsequent commands\n");
7185 break;
7186 }
7187 }
7188
7189 /*--- apply any pending configuration changes ---*/
7190 if (parser_p->states.dce_io_config_pending_mask != (unsigned int)0)
7191 {
7192 if (utlAtDceIoConfigEvent(parser_p) != utlSUCCESS)
7193 return utlAT_RESULT_CODE_ERROR;
7194 }
7195 if (parser_p->states.sound_config_pending_mask != (unsigned int)0)
7196 {
7197 if (utlAtSoundConfigEvent(parser_p) != utlSUCCESS)
7198 return utlAT_RESULT_CODE_ERROR;
7199 }
7200
7201 /*--- return result-code of last command executed ---*/
7202 return rc;
7203}
7204
7205/*---------------------------------------------------------------------------*
7206* FUNCTION
7207* utAtParse(parser_p, octets_p, n)
7208* INPUT
7209* parser_p == an open AT-command parser
7210* octets_p == more octets to be parsed
7211* n == number of octets pointed to by `octets_p'
7212* OUTPUT
7213* none
7214* RETURNS
7215* utlSUCCESS for success, utlFAILED for failure
7216* DESCRIPTION
7217* Appends the characters specified by `string_p' to a line buffer,
7218* parsing AT-commands when possible. This routine is responsible for:
7219*
7220* - Collecting characters into lines, where lines are terminated using
7221* the character specified by parser_p->parameters.S[utlAT_LINE_TERM_CHAR]
7222* - Echoing accepted text (when echoing is enabled).
7223* - Processing back-space requests. In this implementation one cannot
7224* back-space beyond the first character of the current line.
7225* - Masking out the MSB of each 8-bit character.
7226* - Filtering out characters that are invalid AT-command characters.
7227* - Identifying and processing repeat-last-AT-command requests.
7228* - Identifying and processing embedded AT commands.
7229*---------------------------------------------------------------------------*/
7230utlReturnCode_T utlAtParse(const utlAtParser_P parser_p,
7231 const unsigned char *octets_p,
7232 const size_t n)
7233{
7234 utlReturnCode_T parse_rc;
7235 int echo_increase_num = 1;
7236
7237 utlAssert(parser_p != NULL);
7238 utlAssert(octets_p != NULL);
7239
7240 parse_rc = utlSUCCESS;
7241
7242 /*--- if bypass mode is enabled ---*/
7243 if (parser_p->states.bypass_mode)
7244 {
7245 // FIXME
7246 // BYPASS mode is not supported yet
7247 utlAssert(0);
7248
7249 utlAbsoluteTime_T curr_time;
7250
7251 /*--- fetch current time ---*/
7252 if (utlCurrentTime(&curr_time) != utlSUCCESS)
7253 curr_time = parser_p->states.escape.last_tx_time;
7254
7255 /*--- clear queue ---*/
7256 parser_p->buffers.echo_p = parser_p->buffers.head_p;
7257 parser_p->buffers.tail_p = parser_p->buffers.head_p;
7258
7259 /*--- pass data directly to modem implementation (if possible) ---*/
7260 if ( parser_p->call_backs.tx_line_data_function_p != NULL)
7261 parse_rc = (parser_p->call_backs.tx_line_data_function_p)(octets_p, n, parser_p->call_backs.arg_p);
7262
7263 /*--- update time of last TX ---*/
7264 parser_p->states.escape.last_tx_time = curr_time;
7265
7266 /*--- else if we are on-line ---*/
7267 }
7268 else
7269 {
7270 bool overflow;
7271
7272 overflow = false;
7273
7274 /*--- transfer received characters into queue... ---*/
7275 {
7276 const unsigned char *o_p;
7277 const unsigned char *term_o_p;
7278
7279 term_o_p = octets_p + n;
7280 for (o_p = octets_p; o_p < term_o_p; o_p++)
7281 {
7282 char c;
7283
7284 c = ((char) *o_p); /* include non-ASCII*/
7285
7286 /*--- if we're dealing with a queue overflow, we're going to ignore
7287 all characters from the point of overflow until we reach the
7288 end of the current line */
7289 if (parser_p->buffers.overflow)
7290 {
7291
7292 /*--- have we reached the end of the current line? ---*/
7293 if (c == parser_p->parameters.S[utlAT_LINE_TERM_CHAR])
7294 {
7295
7296 parser_p->buffers.overflow = false;
7297
7298 /*--- arrange to report overflow just before we return ---*/
7299 overflow = true;
7300 }
7301
7302 continue;
7303 }
7304
7305 /*--- append character to queue of accumulated characters ---*/
7306 {
7307 char *next_head_p;
7308
7309 /*--- compute where to place next character ---*/
7310 next_head_p = parser_p->buffers.head_p + 1;
7311 if (next_head_p >= parser_p->buffers.term_p)
7312 next_head_p = parser_p->buffers.queue;
7313
7314 /*--- if queue is full ---*/
7315 if (next_head_p == parser_p->buffers.tail_p)
7316 {
7317 parser_p->buffers.overflow = true;
7318
7319 utlAssert(parser_p->buffers.head_p != parser_p->buffers.tail_p);
7320
7321 /*--- turf from current character back to start of current line ---*/
7322 {
7323 char *prev_p;
7324
7325 if (parser_p->buffers.head_p == parser_p->buffers.queue)
7326 prev_p = parser_p->buffers.term_p - 1;
7327 else
7328 prev_p = parser_p->buffers.head_p - 1;
7329
7330 for (;; )
7331 {
7332
7333 /*--- we reach the end of the previous line? ---*/
7334 if (*prev_p == parser_p->parameters.S[utlAT_LINE_TERM_CHAR])
7335 {
7336
7337 /*--- set head pointer to point just past end of previous line ---*/
7338 prev_p++;
7339 if (prev_p >= parser_p->buffers.term_p)
7340 prev_p = parser_p->buffers.queue;
7341 parser_p->buffers.head_p = prev_p;
7342
7343 break;
7344 }
7345
7346 /*--- no more data? ---*/
7347 if (prev_p == parser_p->buffers.tail_p)
7348 {
7349
7350 /*--- queue must be empty ---*/
7351 parser_p->buffers.head_p = prev_p;
7352 break;
7353 }
7354
7355 /*--- backup on character ---*/
7356 if (prev_p == parser_p->buffers.queue) prev_p = parser_p->buffers.term_p - 1;
7357 else prev_p--;
7358 }
7359 }
7360
7361 /*--- move on, process next character ---*/
7362 continue;
7363 }
7364
7365 /*--- append character to queue ---*/
7366 *(parser_p->buffers.head_p) = c;
7367 parser_p->buffers.head_p = next_head_p;
7368 }
7369 }
7370 }
7371
7372 /*--- if we're not waiting for the raw modem to respond to an async request,
7373 process queued characters... */
7374 /*oxoxoxo
7375 OLD:
7376 if (parser_p->states.async_response.timer_id == utlFAILED) {
7377 FUTURE:
7378 if (!utlIsListEmpty(parser_p->states.async_responses.unused)) {
7379 TEMP HACK:
7380 */
7381 if (utlAcquireExclusiveAccess(&parser_p->queue_semaphore) != utlSUCCESS)
7382 {
7383 utlError(utlAtParse, "Cannot exclusively acquire semaphore!\n");
7384 return utlFAILED;
7385 }
7386#ifndef AT_CMD_ASYNC_MODE
7387 if (utlIsListEmpty(parser_p->states.async_responses.pending))
7388#else
7389 if (!utlIsListEmpty(parser_p->states.async_responses.unused))
7390#endif
7391 {
7392 char *c_p;
7393 int breakout_flag = 0;
7394
7395 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
7396
7397 for (c_p = parser_p->buffers.tail_p; c_p != parser_p->buffers.head_p; )
7398 {
7399
7400 /*--- if we're currently discarding the current line ---*/
7401 if (parser_p->states.discard_current_line)
7402 {
7403
7404 /*--- discard characters until we hit a line-termination character
7405 (or run out of characters) */
7406 while (c_p != parser_p->buffers.head_p)
7407 {
7408
7409 /*--- found line-termination character? ---*/
7410 if (*c_p == parser_p->parameters.S[utlAT_LINE_TERM_CHAR])
7411 {
7412
7413 /*--- skip line-termination character ---*/
7414 if (++c_p >= parser_p->buffers.term_p)
7415 c_p = parser_p->buffers.queue;
7416
7417 parser_p->states.discard_current_line = false;
7418 break;
7419 }
7420
7421 /*--- advance one character ---*/
7422 if (++c_p >= parser_p->buffers.term_p)
7423 c_p = parser_p->buffers.queue;
7424 }
7425
7426 continue;
7427 }
7428
7429 /*--- have we found a potential repeat-last-AT-command (A/) request? ---*/
7430 if (*c_p == '/')
7431 {
7432
7433 /*--- was there a character preceding '/'? ---*/
7434 if (c_p != parser_p->buffers.tail_p)
7435 {
7436 const char *prev_c_p;
7437
7438 /*--- back-up to character preceding '/' ---*/
7439 if (c_p == parser_p->buffers.queue) prev_c_p = parser_p->buffers.term_p - 1;
7440 else prev_c_p = c_p - 1;
7441
7442 /*--- if we found the sequence "A/" or "a/" ---*/
7443 if ((*prev_c_p == 'A') ||
7444 (*prev_c_p == 'a'))
7445 {
7446 char *prev;
7447 bool repeat_flag = true;
7448
7449 if(prev_c_p != parser_p->buffers.tail_p)
7450 {
7451 if(prev_c_p == parser_p->buffers.queue)
7452 prev = parser_p->buffers.term_p - 1;
7453 else
7454 prev = prev_c_p - 1;
7455
7456 if (*prev != parser_p->parameters.S[utlAT_LINE_TERM_CHAR] && *prev != parser_p->parameters.S[utlAT_FORMATTING_CHAR])
7457 repeat_flag = false;
7458 }
7459 if(repeat_flag)
7460 {
7461 /*--- if echoing is enabled, echo everything up to and including the "A/" or "a/" ---*/
7462 if (parser_p->parameters.echo_text == true)
7463 {
7464
7465 if (c_p >= parser_p->buffers.echo_p)
7466 {
7467 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, c_p - parser_p->buffers.echo_p + 1) != utlSUCCESS)
7468 return utlFAILED;
7469
7470 }
7471 else if (c_p < parser_p->buffers.echo_p && (c_p + 1) < parser_p->buffers.echo_p)
7472 {
7473 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, parser_p->buffers.term_p - parser_p->buffers.echo_p) != utlSUCCESS)
7474 return utlFAILED;
7475 if (c_p >= parser_p->buffers.queue)
7476 if (utlSendSubstring(parser_p, parser_p->buffers.queue, c_p - parser_p->buffers.queue + 1) != utlSUCCESS)
7477 return utlFAILED;
7478 }
7479 }
7480 parser_p->buffers.echo_p = c_p + 1;
7481
7482
7483 /*--- re-execute previously executed AT command ---*/
7484 {
7485 utlAtResultCode_T rc;
7486
7487 rc = utlParseLine(parser_p, parser_p->buffers.previous_line, 0);
7488
7489 utlPrintTrace(utlAtParse1, "[%s][%d]utlParseLine for %s is: %d\n", __FUNCTION__, __LINE__, parser_p->buffers.previous_line, rc);
7490
7491 if (utlSendBasicSyntaxResultCode(parser_p, rc, true) != utlSUCCESS)
7492 return utlFAILED;
7493
7494 if (rc == utlAT_RESULT_CODE_ERROR)
7495 {
7496
7497 /*--- discard rest of current line ---*/
7498 parser_p->states.discard_current_line = true;
7499
7500 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
7501 {
7502 utlError(utlAtParse2, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
7503 return utlFAILED;
7504 }
7505
7506 parser_p->commands_in_line = 0;
7507
7508 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
7509
7510 utlAbandonAllPendingAsyncResponse(parser_p);
7511
7512 parse_rc = utlFAILED;
7513 }
7514 }
7515
7516 /*--- advance one character ---*/
7517 if (++c_p >= parser_p->buffers.term_p)
7518 c_p = parser_p->buffers.queue;
7519
7520 /*--- we've now processed up to here ---*/
7521 parser_p->buffers.tail_p = c_p;
7522
7523 /*--- if we're waiting for an asynchronous request to complete ---*/
7524 /*oxoxoxo
7525 OLD:
7526 if (parser_p->states.async_response.timer_id != utlFAILED)
7527 FUTURE:
7528 if (utlIsListEmpty(parser_p->states.async_responses.unused))
7529 TEMP HACK:
7530 */
7531
7532 if (!utlIsListEmpty(parser_p->states.async_responses.pending))
7533 break;
7534
7535 /*--- continue processing characters on current line ---*/
7536 continue;
7537 }
7538 }
7539 }
7540 }
7541
7542 /*--- have we found a command-line editing character? Note that
7543 if S3 (command-line termination) and S5 (command-line edit)
7544 are both set to the same character and if this character is
7545 encountered, we must treat the found character as an S3
7546 (command-line termination) event */
7547 if ((*c_p == parser_p->parameters.S[utlAT_LINE_EDIT_CHAR]) &&
7548 ( parser_p->parameters.S[utlAT_LINE_EDIT_CHAR] != parser_p->parameters.S[utlAT_LINE_TERM_CHAR]))
7549 {
7550
7551 /*--- if echoing is enabled, echo everything up to (but excluding) line-edit character ---*/
7552 if (parser_p->parameters.echo_text == true)
7553 {
7554
7555 if (c_p > parser_p->buffers.echo_p)
7556 {
7557 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, c_p - parser_p->buffers.echo_p) != utlSUCCESS)
7558 return utlFAILED;
7559
7560 }
7561 else if (c_p < parser_p->buffers.echo_p && (c_p + 1) < parser_p->buffers.echo_p)
7562 {
7563 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, parser_p->buffers.term_p - parser_p->buffers.echo_p) != utlSUCCESS)
7564 return utlFAILED;
7565
7566 if (c_p > parser_p->buffers.queue)
7567 if (utlSendSubstring(parser_p, parser_p->buffers.queue, c_p - parser_p->buffers.queue) != utlSUCCESS)
7568 return utlFAILED;
7569 }
7570 }
7571 parser_p->buffers.echo_p = c_p;
7572
7573 /*--- fix up queue ---*/
7574 {
7575 char *prev_c_p;
7576 char *prev_tail_p;
7577 char *src_p;
7578 char *dest_p;
7579
7580 /*--- back-up to character preceding line-edit character (if any) ---*/
7581 if (c_p == parser_p->buffers.queue)
7582 prev_c_p = parser_p->buffers.term_p - 1;
7583 else
7584 prev_c_p = c_p - 1;
7585
7586 /*--- identify queue-slot preceeding tail ---*/
7587 if (parser_p->buffers.tail_p == parser_p->buffers.queue)
7588 prev_tail_p = parser_p->buffers.term_p - 1;
7589 else
7590 prev_tail_p = parser_p->buffers.tail_p - 1;
7591
7592 /*--- if there's a character to back-space over ---*/
7593 if (( prev_c_p != prev_tail_p) &&
7594 (*prev_c_p != parser_p->parameters.S[utlAT_LINE_TERM_CHAR]))
7595 {
7596
7597 /*--- if echoing is enabled and we have something to back-space over, echo a destructive <bs> ---*/
7598 if ((parser_p->parameters.echo_text == true) && (isprint(*prev_c_p)))
7599 if (utlSendString(parser_p, "\b \b") != utlSUCCESS)
7600 return utlFAILED;
7601
7602 /*--- arrange to remove line-edit character and character
7603 preceeding line-edit character from queue */
7604 src_p = c_p;
7605 dest_p = prev_c_p;
7606
7607 c_p = prev_c_p;
7608
7609 }
7610 else
7611 {
7612 /*--- arrange to remove line-edit character from queue ---*/
7613 src_p = c_p;
7614 dest_p = c_p;
7615 }
7616
7617 for (;; )
7618 {
7619 if (++src_p >= parser_p->buffers.term_p)
7620 src_p = parser_p->buffers.queue;
7621
7622 if (src_p == parser_p->buffers.head_p)
7623 break;
7624
7625 *dest_p = *src_p;
7626
7627 if (++dest_p >= parser_p->buffers.term_p)
7628 dest_p = parser_p->buffers.queue;
7629 }
7630 parser_p->buffers.head_p = dest_p;
7631 parser_p->buffers.echo_p = c_p;
7632
7633 continue;
7634 }
7635
7636 /*--- have we found a command-line termination character? ---*/
7637 }
7638 else if (*c_p == parser_p->parameters.S[utlAT_LINE_TERM_CHAR])
7639 {
7640 char line[utlAT_MAX_LINE_LENGTH + 1];
7641 size_t line_off;
7642 char* next_cp;
7643
7644 next_cp = c_p + 1;
7645 if (next_cp >= parser_p->buffers.term_p)
7646 next_cp = parser_p->buffers.queue;
7647
7648 if (*next_cp == parser_p->parameters.S[utlAT_FORMATTING_CHAR]) {
7649 echo_increase_num = 2;
7650 *next_cp = 0;
7651 }
7652
7653 memset(line, 0x0, sizeof(line));
7654 line_off = parser_p->states.line_off;
7655 parser_p->states.line_off = 0;
7656
7657 /*--- if echoing is enabled, echo everything up to and including the termination character ---*/
7658 if (parser_p->parameters.echo_text == true)
7659 {
7660 if (c_p >= parser_p->buffers.echo_p)
7661 {
7662 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, c_p - parser_p->buffers.echo_p + echo_increase_num) != utlSUCCESS)
7663 return utlFAILED;
7664
7665 }
7666 else if (c_p < parser_p->buffers.echo_p && (c_p + 1) < parser_p->buffers.echo_p)
7667 {
7668 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, parser_p->buffers.term_p - parser_p->buffers.echo_p) != utlSUCCESS)
7669 return utlFAILED;
7670 if (c_p >= parser_p->buffers.queue)
7671 if (utlSendSubstring(parser_p, parser_p->buffers.queue, c_p - parser_p->buffers.queue + echo_increase_num) != utlSUCCESS)
7672 return utlFAILED;
7673 }
7674 }
7675 parser_p->buffers.echo_p = c_p + echo_increase_num;
7676 if (parser_p->buffers.echo_p >= parser_p->buffers.term_p)
7677 parser_p->buffers.echo_p = parser_p->buffers.queue;
7678
7679 /*--- transfer one line of text from queue to line buffer... ---*/
7680 {
7681 char *this_p;
7682 char *term_p;
7683 char *src_p;
7684
7685 this_p = line;
7686 term_p = line + utlNumberOf(line);
7687
7688 for (src_p = parser_p->buffers.tail_p; src_p != c_p; )
7689 {
7690
7691 /*--- no more room in line buffer? ---*/
7692 if (this_p >= term_p)
7693 {
7694 utlError(utlAtParse3, "Line too long.");
7695
7696 return utlFAILED;
7697 }
7698
7699 /*--- only process characters that are valid in AT-commands... ---*/
7700 if ((*src_p >= '\0') ||
7701 (*src_p == parser_p->parameters.S[utlAT_ESCAPE_CHAR]) ||
7702 (*src_p == parser_p->parameters.S[utlAT_LINE_TERM_CHAR]) ||
7703 (*src_p == parser_p->parameters.S[utlAT_FORMATTING_CHAR]) ||
7704 (*src_p == parser_p->parameters.S[utlAT_LINE_EDIT_CHAR]) ||
7705 (*src_p == parser_p->parameters.S[utlAT_SEPARATER_CHAR]) ||
7706 (*src_p == parser_p->parameters.S[utlAT_TERMINATER_CHAR]))
7707 {
7708
7709 /*--- append character to line buffer ---*/
7710 *this_p++ = *src_p;
7711 *src_p = 0;
7712 }
7713
7714 if (++src_p >= parser_p->buffers.term_p)
7715 src_p = parser_p->buffers.queue;
7716 }
7717 *this_p = '\0';
7718 }
7719
7720 parser_p->buffers.tail_p = c_p + echo_increase_num;
7721 if (parser_p->buffers.tail_p >= parser_p->buffers.term_p)
7722 parser_p->buffers.tail_p = parser_p->buffers.queue + (parser_p->buffers.tail_p - parser_p->buffers.term_p);
7723
7724 /*--- parse line (if not empty) for AT commands ---*/
7725 if (line[0] != '\0')
7726 {
7727 utlAtResultCode_T rc;
7728
7729 rc = utlParseLine(parser_p, line, line_off);
7730
7731 // comment this line as for some illegal string input might result to printf parsing failure.
7732 //utlPrintTrace("[%s][%d]utlParseLine for %s is: %d\n", __FUNCTION__, __LINE__, line, rc);
7733
7734 if (utlSendBasicSyntaxResultCode(parser_p, rc, true) != utlSUCCESS)
7735 return utlFAILED;
7736
7737 if (rc == utlAT_RESULT_CODE_ERROR)
7738 {
7739 if (utlAcquireExclusiveAccess(&parser_p->cmd_cnt_semaphore) != utlSUCCESS)
7740 {
7741 utlError(utlAtParse4, "%s: Cannot exclusively acquire semaphore!\n", __FUNCTION__);
7742 return utlFAILED;
7743 }
7744
7745 parser_p->commands_in_line = 0;
7746
7747 utlReleaseExclusiveAccess(&parser_p->cmd_cnt_semaphore);
7748
7749 utlAbandonAllPendingAsyncResponse(parser_p);
7750 parse_rc = utlFAILED;
7751
7752 }
7753 else
7754 {
7755 /*--- save good AT-command to support repeat-last-AT-command feature ---*/
7756 strncpy(parser_p->buffers.previous_line, line, sizeof(parser_p->buffers.previous_line) - 1);
7757 }
7758 }
7759 }
7760
7761 /*--- advance to next character ---*/
7762 /*--- in some case, c_p may equal to head_p at this point, and we need to filter out it to avoid endless-loop
7763 mainly happened when user input "A/" in non-canonical mode */
7764 //if (c_p != parser_p->buffers.head_p && ++c_p >= parser_p->buffers.term_p)
7765 //c_p = parser_p->buffers.queue;
7766
7767 c_p = c_p + echo_increase_num;
7768 if (c_p <= parser_p->buffers.head_p && (c_p + echo_increase_num) > parser_p->buffers.head_p) {
7769 breakout_flag = 1;
7770 }
7771
7772 if (c_p >= parser_p->buffers.term_p)
7773 c_p = parser_p->buffers.queue + (c_p - parser_p->buffers.term_p);
7774 /*--- if we're waiting for an asynchronous request to complete ---*/
7775 /*oxoxoxo
7776 OLD:
7777 if (parser_p->states.async_response.timer_id != utlFAILED)
7778 FUTURE:
7779 if (utlIsListEmpty(parser_p->states.async_responses.unused))
7780 TEMP HACK:
7781 */
7782#ifndef AT_CMD_ASYNC_MODE
7783 if (!utlIsListEmpty(parser_p->states.async_responses.pending) || breakout_flag)
7784#else
7785 if (utlIsListEmpty(parser_p->states.async_responses.unused) ||breakout_flag)
7786#endif
7787 break;
7788 else
7789 echo_increase_num = 1;
7790 }
7791
7792 /*--- if echoing is enabled, echo what has not yet been echoed ---*/
7793 if (parser_p->parameters.echo_text == true)
7794 {
7795
7796 if (c_p > parser_p->buffers.echo_p)
7797 {
7798 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, c_p - parser_p->buffers.echo_p) != utlSUCCESS)
7799 return utlFAILED;
7800 }
7801 else if (c_p < parser_p->buffers.echo_p && (c_p + 1) < parser_p->buffers.echo_p)
7802 {
7803 if (utlSendSubstring(parser_p, parser_p->buffers.echo_p, parser_p->buffers.term_p - parser_p->buffers.echo_p) != utlSUCCESS)
7804 return utlFAILED;
7805 if (c_p > parser_p->buffers.queue)
7806 if (utlSendSubstring(parser_p, parser_p->buffers.queue, c_p - parser_p->buffers.queue) != utlSUCCESS)
7807 return utlFAILED;
7808 }
7809 }
7810 parser_p->buffers.echo_p = c_p;
7811 }
7812 else
7813 {
7814 utlReleaseExclusiveAccess(&parser_p->queue_semaphore);
7815 }
7816
7817 if (overflow)
7818 {
7819 utlError(utlAtParse5, "buffer overflow");
7820 return utlFAILED;
7821 }
7822 }
7823
7824 return parse_rc;
7825}
7826
7827////////////////////////////////////////////////////////////////////////////////////////////////
7828////////////////////////////////////////////////////////////////////////////////////////////////
7829// DEBUG FUNCTIONS
7830////////////////////////////////////////////////////////////////////////////////////////////////
7831////////////////////////////////////////////////////////////////////////////////////////////////
7832#if defined(utlDEBUG) || defined(utlTEST)
7833/*---------------------------------------------------------------------------*
7834* FUNCTION
7835* utlVStringDumpAtParser(v_string_p, parser_p, prefix_p)
7836* INPUT
7837* v_string_p == pointer to an initialized utlVString_T structure
7838* parser_p == pointer to an initialized utlAtParser_T structure
7839* prefix_p == pointer to a prefix string
7840* OUTPUT
7841* *v_string_p == the updated utlVString_T structure
7842* RETURNS
7843* nothing
7844* DESCRIPTION
7845* Dumps AT-command parser information to `v_string_p'.
7846*---------------------------------------------------------------------------*/
7847void utlVStringDumpAtParser(const utlVString_P v_string_p,
7848 const utlAtParser_P parser_p,
7849 const char *prefix_p)
7850{
7851 char buf[40];
7852 size_t i, j, k;
7853
7854 utlAssert(v_string_p != NULL);
7855 utlAssert(parser_p != NULL);
7856 utlAssert(prefix_p != NULL);
7857
7858 (void)utlVStringPrintF(v_string_p, "%s:\n", prefix_p);
7859 (void)utlVStringPrintF(v_string_p, "%s: AT-command Parser\n", prefix_p);
7860 (void)utlVStringPrintF(v_string_p, "%s:\n", prefix_p);
7861
7862 if (parser_p->info.id_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: ID: %s\n", prefix_p, parser_p->info.id_p);
7863 if (parser_p->info.manufacturer_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Manufacturer: %s\n", prefix_p, parser_p->info.manufacturer_p);
7864 if (parser_p->info.model_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Model: %s\n", prefix_p, parser_p->info.model_p);
7865 if (parser_p->info.revision_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Revision: %s\n", prefix_p, parser_p->info.revision_p);
7866 if (parser_p->info.serial_number_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Serial Number: %s\n", prefix_p, parser_p->info.serial_number_p);
7867 if (parser_p->info.object_id_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Global Object ID: %s\n", prefix_p, parser_p->info.object_id_p);
7868 if (parser_p->info.country_code_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Country Code: %s\n", prefix_p, parser_p->info.country_code_p);
7869 if (parser_p->info.connect_text_p != NULL) (void)utlVStringPrintF(v_string_p, "%s: Connect Text: %s\n", prefix_p, parser_p->info.connect_text_p);
7870
7871 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7872 (void)utlVStringPrintF(v_string_p, "%s: S-Parameters:\n", prefix_p);
7873 k = (utlAT_NUM_S_PARAMETERS + 3) / 4;
7874 for (i = 0; i < k; i++)
7875 {
7876 (void)utlVStringPrintF(v_string_p, "%s: ", prefix_p);
7877 for (j = 0; j < 4; j++)
7878 {
7879 size_t l;
7880
7881 l = i + (j * k);
7882 if (l < utlAT_NUM_S_PARAMETERS)
7883 (void)utlVStringPrintF(v_string_p, " S[%02u]: %-5u", l, parser_p->parameters.S[l]);
7884 }
7885 (void)utlVStringPrintF(v_string_p, "\n");
7886 }
7887
7888 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7889 (void)utlVStringPrintF(v_string_p, "%s: Allow default S-parameter values: %s\n", prefix_p, (parser_p->options.allow_default_S_parameter_values == true) ? "yes" : "no");
7890 (void)utlVStringPrintF(v_string_p, "%s: Allow string escapes: %s\n", prefix_p, (parser_p->options.allow_string_escapes == true) ? "yes" : "no");
7891 (void)utlVStringPrintF(v_string_p, "%s: Result code: %s\n", prefix_p, (parser_p->options.use_carrier_result_code == true) ? "CARRIER" : "CONNECT");
7892
7893 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7894 (void)utlVStringPrintF(v_string_p, "%s: Previous Line: \"%s\"\n", prefix_p, parser_p->buffers.previous_line);
7895
7896 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7897 (void)utlVStringPrintF(v_string_p, "%s: Recognized AT Commands:\n", prefix_p);
7898 (void)utlVStringPrintF(v_string_p, "%s: Name | Type | Parameters\n", prefix_p);
7899 (void)utlVStringPrintF(v_string_p, "%s: | | Type | Access | Presence\n", prefix_p);
7900 (void)utlVStringPrintF(v_string_p, "%s: -----------------+-----------+-------------+------------+-----------\n", prefix_p);
7901 for (i = 0; i < parser_p->num_commands; i++)
7902 {
7903 size_t j;
7904
7905 if (i > (size_t)0)
7906 (void)utlVStringPrintF(v_string_p, "%s: | | | | \n", prefix_p);
7907
7908 (void)utlVStringPrintF(v_string_p, "%s: %17s | ", prefix_p, parser_p->commands_p[i].name_p);
7909
7910 switch (parser_p->commands_p[i].type)
7911 {
7912 case utlAT_COMMAND_TYPE_BASIC: (void)utlVStringPrintF(v_string_p, "Basic | "); break;
7913 case utlAT_COMMAND_TYPE_EXTENDED: (void)utlVStringPrintF(v_string_p, "Extended | "); break;
7914 case utlAT_COMMAND_TYPE_EXACTION: (void)utlVStringPrintF(v_string_p, "Ex-action | "); break;
7915 case utlAT_COMMAND_TYPE_EXTENDED_EXACTION: (void) utlVStringPrintF(v_string_p, "Extended&Ex-action | "); break;
7916 default:
7917 (void)utlVStringPrintF(v_string_p, "%8d | ", parser_p->commands_p[i].type);
7918 break;
7919 }
7920
7921 if (parser_p->commands_p[i].num_parameters == (size_t)0)
7922 (void)utlVStringPrintF(v_string_p, " - | - | -\n");
7923
7924 else for (j = 0; j < parser_p->commands_p[i].num_parameters; j++)
7925 {
7926 if (j > (size_t)0)
7927 (void)utlVStringPrintF(v_string_p, "%s: | | ", prefix_p);
7928
7929 switch (parser_p->commands_p[i].parameters_p[j].type)
7930 {
7931 case utlAT_DATA_TYPE_DECIMAL: (void)utlVStringPrintF(v_string_p, " Decimal | "); break;
7932 case utlAT_DATA_TYPE_HEXADECIMAL: (void)utlVStringPrintF(v_string_p, "Hexadecimal | "); break;
7933 case utlAT_DATA_TYPE_BINARY: (void)utlVStringPrintF(v_string_p, " Binary | "); break;
7934 case utlAT_DATA_TYPE_STRING: (void)utlVStringPrintF(v_string_p, " String | "); break;
7935 case utlAT_DATA_TYPE_QSTRING: (void)utlVStringPrintF(v_string_p, " QString | "); break;
7936 case utlAT_DATA_TYPE_DIAL_STRING: (void)utlVStringPrintF(v_string_p, "Dial-string | "); break;
7937 default:
7938 (void)utlVStringPrintF(v_string_p, "%10d | ", parser_p->commands_p[i].parameters_p[j].type);
7939 break;
7940 }
7941
7942 switch (parser_p->commands_p[i].parameters_p[j].access)
7943 {
7944 case utlAT_PARAMETER_ACCESS_READ_WRITE: (void)utlVStringPrintF(v_string_p, "Read/Write | "); break;
7945 case utlAT_PARAMETER_ACCESS_READ: (void)utlVStringPrintF(v_string_p, " Read | "); break;
7946 case utlAT_PARAMETER_ACCESS_READ_ONLY: (void)utlVStringPrintF(v_string_p, "Read-only | "); break;
7947 case utlAT_PARAMETER_ACCESS_WRITE_ONLY: (void)utlVStringPrintF(v_string_p, "Write-only | "); break;
7948 default:
7949 (void)utlVStringPrintF(v_string_p, "%10d | ", parser_p->commands_p[i].parameters_p[j].access);
7950 break;
7951 }
7952
7953 switch (parser_p->commands_p[i].parameters_p[j].presence)
7954 {
7955 case utlAT_PARAMETER_PRESENCE_OPTIONAL: (void)utlVStringPrintF(v_string_p, "Optional\n"); break;
7956 case utlAT_PARAMETER_PRESENCE_REQUIRED: (void)utlVStringPrintF(v_string_p, "Required\n"); break;
7957 default:
7958 (void)utlVStringPrintF(v_string_p, "%d\n", parser_p->commands_p[i].parameters_p[j].presence);
7959 break;
7960 }
7961 }
7962 }
7963
7964 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7965 (void)utlVStringPrintF(v_string_p, "%s: Current dial string: %s\n", prefix_p, parser_p->states.dial_string.buf);
7966 (void)utlVStringPrintF(v_string_p, "%s: Last dial string: %s\n", prefix_p, parser_p->states.dial_string.last);
7967 (void)utlVStringPrintF(v_string_p, "%s: Dial string delay: %d\n", prefix_p, parser_p->states.dial_string.dial_string_delay);
7968 (void)utlVStringPrintF(v_string_p, "%s: International: %s\n", prefix_p, (parser_p->states.dial_string.options.international == true) ? "true" : "false");
7969 (void)utlVStringPrintF(v_string_p, "%s: Do call origination: %s\n", prefix_p, (parser_p->states.dial_string.options.do_call_origination == true) ? "true" : "false");
7970 (void)utlVStringPrintF(v_string_p, "%s: Use CCUG SS info: %s\n", prefix_p, (parser_p->states.dial_string.options.use_CCUG_SS_info == true) ? "true" : "false");
7971 (void)utlVStringPrintF(v_string_p, "%s: CLI presentation: %s\n", prefix_p, (parser_p->states.dial_string.options.CLI_presentation == 'I') ? "restrict" :
7972 (parser_p->states.dial_string.options.CLI_presentation == 'i') ? "allow" : "default");
7973
7974 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7975 (void)utlVStringPrintF(v_string_p, "%s: Go on-line: %s\n", prefix_p, (parser_p->states.go_on_line == true) ? "true" : "false");
7976 (void)utlVStringPrintF(v_string_p, "%s: Discard Current Line: %s\n", prefix_p, (parser_p->states.discard_current_line == true) ? "true" : "false");
7977 (void)utlVStringPrintF(v_string_p, "%s: DCE I/O config pending: %x\n", prefix_p, parser_p->states.dce_io_config_pending_mask);
7978 (void)utlVStringPrintF(v_string_p, "%s: Sound config pending: %x\n", prefix_p, parser_p->states.sound_config_pending_mask);
7979 (void)utlVStringPrintF(v_string_p, "%s: Line Offset: %d\n", prefix_p, parser_p->states.line_off);
7980
7981 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
7982 if (utlFormatDateTime(buf, utlNumberOf(buf), &(parser_p->states.escape.last_tx_time)) == utlSUCCESS)
7983 (void)utlVStringPrintF(v_string_p, "%s: Last TX time: %s\n", prefix_p, buf);
7984 (void)utlVStringPrintF(v_string_p, "%s: Escape state: %u\n", prefix_p, parser_p->states.escape.state);
7985
7986 (void)utlVStringPrintF(v_string_p, "%s: Blind dial pause time: %u.%09u\n", prefix_p, parser_p->states.blind_dial_pause_time.seconds,
7987 parser_p->states.blind_dial_pause_time.nanoseconds);
7988 (void)utlVStringPrintF(v_string_p, "%s: Conn. complete timeout: %u.%09u\n", prefix_p, parser_p->states.conn_complete_timeout.seconds,
7989 parser_p->states.conn_complete_timeout.nanoseconds);
7990 (void)utlVStringPrintF(v_string_p, "%s: Dialing pause time: %u.%09u\n", prefix_p, parser_p->states.dialing_pause_time.seconds,
7991 parser_p->states.dialing_pause_time.nanoseconds);
7992 (void)utlVStringPrintF(v_string_p, "%s: Carrier detect time: %u.%09u\n", prefix_p, parser_p->states.carrier_detect_time.seconds,
7993 parser_p->states.carrier_detect_time.nanoseconds);
7994 (void)utlVStringPrintF(v_string_p, "%s: Carrier loss time: %u.%09u\n", prefix_p, parser_p->states.carrier_loss_time.seconds,
7995 parser_p->states.carrier_loss_time.nanoseconds);
7996 (void)utlVStringPrintF(v_string_p, "%s: Hook flash time: %u.%09u\n", prefix_p, parser_p->states.hook_flash_time.seconds,
7997 parser_p->states.hook_flash_time.nanoseconds);
7998 (void)utlVStringPrintF(v_string_p, "%s: Disconnect wait time: %u.%09u\n", prefix_p, parser_p->states.inactivity_time.seconds,
7999 parser_p->states.inactivity_time.nanoseconds);
8000 (void)utlVStringPrintF(v_string_p, "%s: Disconnect wait time: %u.%09u\n", prefix_p, parser_p->states.disconnect_wait_time.seconds,
8001 parser_p->states.disconnect_wait_time.nanoseconds);
8002 (void)utlVStringPrintF(v_string_p, "%s: Delay dialing time: %u.%09u\n", prefix_p, parser_p->states.delay_dialing_time.seconds,
8003 parser_p->states.delay_dialing_time.nanoseconds);
8004 (void)utlVStringPrintF(v_string_p, "%s: Minimum Silence time: %u.%09u\n", prefix_p, parser_p->states.min_silence_time.seconds,
8005 parser_p->states.min_silence_time.nanoseconds);
8006
8007 (void)utlVStringPrintF(v_string_p, "%s: \n", prefix_p);
8008 (void)utlVStringPrintF(v_string_p, "%s: Basic-commands peg count: %d\n", prefix_p, parser_p->peg_counts.basic_commands);
8009 (void)utlVStringPrintF(v_string_p, "%s: Extended-commands peg count: %d\n", prefix_p, parser_p->peg_counts.extended_commands);
8010 (void)utlVStringPrintF(v_string_p, "%s: Undefined-commands peg count: %d\n", prefix_p, parser_p->peg_counts.undefined_commands);
8011 (void)utlVStringPrintF(v_string_p, "%s: Bad-commands peg count: %d\n", prefix_p, parser_p->peg_counts.bad_commands);
8012
8013}
8014/*---------------------------------------------------------------------------*
8015* FUNCTION
8016* utlDumpAtParser(file_p, parser_p)
8017* INPUT
8018* file_p == pointer to an open file
8019* parser_p == pointer to an initialized utlParser_T structure
8020* OUTPUT
8021* none
8022* RETURNS
8023* nothing
8024* DESCRIPTION
8025* Dumps AT-command parser information to `file_p'.
8026*---------------------------------------------------------------------------*/
8027void utlDumpAtParser( FILE *file_p,
8028 const utlAtParser_P parser_p)
8029{
8030 utlVString_T v_string;
8031
8032 utlAssert(file_p != NULL);
8033
8034 utlInitVString(&v_string);
8035
8036 utlVStringDumpAtParser(&v_string, parser_p, "AtParser");
8037
8038 utlVStringPuts(&v_string, file_p);
8039
8040 utlVStringFree(&v_string);
8041}
8042#endif
8043