]>
git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/net/cellular/CellularModem/at/ATCommandsInterface.cpp
1 /* ATCommandsInterface.cpp */
2 /* Copyright (C) 2012 mbed.org, MIT License
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in all copies or
11 * substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 #define __DEBUG__ 2 //ERR+WARN
22 #define __MODULE__ "ATCommandsInterface.cpp"
28 #include <cstring> //For memset, strstr...
32 #include "ATCommandsInterface.h"
34 ATCommandsInterface :: ATCommandsInterface ( IOStream
* pStream
) :
35 m_pStream ( pStream
), m_open ( false ), m_transactionState ( IDLE
), m_env2AT (), m_AT2Env (), m_processingMtx (),
36 m_processingThread (& ATCommandsInterface :: staticCallback
, this , ( osPriority
) AT_THREAD_PRIORITY
, 4 * 192 ),
37 m_eventsMgmtMtx (), m_eventsProcessingMtx ()
39 memset ( m_eventsHandlers
, 0 , MAX_AT_EVENTS_HANDLERS
* sizeof ( IATEventsHandler
*));
41 m_processingMtx
. lock ();
44 //Open connection to AT Interface in order to execute command & register/unregister events
45 int ATCommandsInterface :: open ()
49 WARN ( "AT interface is already open" );
52 DBG ( "Opening AT interface" );
54 m_processingThread
. signal_set ( AT_SIG_PROCESSING_START
);
56 m_processingMtx
. unlock ();
60 DBG ( "AT interface opened" );
65 //Initialize AT link & start events processing
66 int ATCommandsInterface :: init ( bool reset
/* = true*/ )
69 //Lock transaction mutex
70 m_transactionMtx
. lock ();
74 DBG ( "Sending ATZ E1 V1" );
75 //Should we flush m_pStream at this point ???
80 err
= executeInternal ( "ATZ E1 V1" , this , NULL
, 3000 ); //Enable echo and verbosity
83 WARN ( "No response, trying again" );
84 Thread :: wait ( 1000 ); //Give dongle time to recover
86 } while ( err
&& tries
--);
89 ERR ( "Sending ATZ E1 V1 returned with err code %d" , err
);
90 m_transactionMtx
. unlock ();
95 //Enable events handling and execute events enabling commands
98 DBG ( "AT interface initialized" );
100 //Unlock transaction mutex
101 m_transactionMtx
. unlock ();
107 int ATCommandsInterface :: close ()
111 WARN ( "AT interface is already closed" );
115 DBG ( "Closing AT interface" );
117 //Lock transaction mutex
118 m_transactionMtx
. lock ();
120 //Disable events handling and advertize this to the events handlers
124 m_processingThread
. signal_set ( AT_SIG_PROCESSING_STOP
);
125 //m_stopSphre.release();
127 int * msg
= m_env2AT
. alloc ( osWaitForever
);
129 m_env2AT
. put ( msg
); //Used to unstall the process if needed
131 //Unlock process routine (abort read)
132 m_pStream
-> abortRead (); //This is thread-safe
133 m_processingMtx
. lock ();
136 //Unlock transaction mutex
137 m_transactionMtx
. unlock ();
139 DBG ( "AT interface closed" );
143 bool ATCommandsInterface :: isOpen ()
148 int ATCommandsInterface :: executeSimple ( const char * command
, ATResult
* pResult
, uint32_t timeout
/*=1000*/ )
150 return execute ( command
, this , pResult
, timeout
);
153 int ATCommandsInterface :: execute ( const char * command
, IATCommandsProcessor
* pProcessor
, ATResult
* pResult
, uint32_t timeout
/*=1000*/ )
157 WARN ( "Interface is not open!" );
161 //Lock transaction mutex
162 m_transactionMtx
. lock ();
164 disableEvents (); //Disable unsollicited result codes
165 int ret
= executeInternal ( command
, pProcessor
, pResult
, timeout
);
166 enableEvents (); //Re-enable unsollicited result codes whatever the result of the command is
168 //Unlock transaction mutex
169 m_transactionMtx
. unlock ();
174 int ATCommandsInterface :: registerEventsHandler ( IATEventsHandler
* pHdlr
)
176 m_eventsMgmtMtx
. lock ();
177 m_eventsProcessingMtx
. lock ();
178 for ( int i
= 0 ; i
< MAX_AT_EVENTS_HANDLERS
; i
++) //Find a free slot
180 if ( m_eventsHandlers
[ i
] == NULL
)
182 m_eventsHandlers
[ i
] = pHdlr
;
183 m_eventsProcessingMtx
. unlock ();
184 m_eventsMgmtMtx
. unlock ();
188 m_eventsProcessingMtx
. unlock ();
189 m_eventsMgmtMtx
. unlock ();
190 return NET_OOM
; //No room left
193 int ATCommandsInterface :: deregisterEventsHandler ( IATEventsHandler
* pHdlr
)
195 m_eventsMgmtMtx
. lock ();
196 m_eventsProcessingMtx
. lock ();
197 for ( int i
= 0 ; i
< MAX_AT_EVENTS_HANDLERS
; i
++) //Find handler in list
199 if ( m_eventsHandlers
[ i
] == pHdlr
)
201 m_eventsHandlers
[ i
] = NULL
;
202 m_eventsProcessingMtx
. unlock ();
203 m_eventsMgmtMtx
. unlock ();
207 m_eventsProcessingMtx
. unlock ();
208 m_eventsMgmtMtx
. unlock ();
209 return NET_NOTFOUND
; //Not found
214 int ATCommandsInterface :: executeInternal ( const char * command
, IATCommandsProcessor
* pProcessor
, ATResult
* pResult
, uint32_t timeout
/*=1000*/ )
216 DBG ( "Executing command %s" , command
);
218 //Discard previous result if it arrived too late
219 osEvent evt
= m_AT2Env
. get ( 0 );
221 if ( evt
. status
== osEventMail
)
223 m_AT2Env
. free (( int *) evt
. value
. p
);
224 WARN ( "Previous result discarded" );
227 //Send params to the process routine
228 m_transactionCommand
= command
;
229 if ( pProcessor
!= NULL
)
231 m_pTransactionProcessor
= pProcessor
;
235 m_pTransactionProcessor
= this ; //Use default behaviour
238 DBG ( "Sending command ready signal to AT thread & aborting current blocking read operation" );
240 //Produce command ready signal
241 int * msg
= m_env2AT
. alloc ( osWaitForever
);
245 DBG ( "Trying to enter abortRead()" );
246 //Unlock process routine (abort read)
247 m_pStream
-> abortRead (); //This is thread-safe
249 //Wait for a result (get result message)
250 evt
= m_AT2Env
. get ( timeout
);
252 if ( evt
. status
!= osEventMail
)
255 msg
= m_env2AT
. alloc ( osWaitForever
);
259 DBG ( "Trying to enter abortRead()" );
260 //Unlock process routine (abort read)
261 m_pStream
-> abortRead (); //This is thread-safe
263 //Wait for acknowledge
267 evt
= m_AT2Env
. get ( osWaitForever
);
268 msgResult
= *(( int *) evt
. value
. p
);
269 m_AT2Env
. free (( int *) evt
. value
. p
);
270 } while ( msgResult
!= AT_TIMEOUT
);
272 WARN ( "Command returned no message" );
273 WARN ( "Command \" %s \" returned no message" , command
);
276 DBG ( "Command returned with message %d" , * msg
);
278 m_AT2Env
. free (( int *) evt
. value
. p
);
282 * pResult
= m_transactionResult
;
285 int ret
= ATResultToReturnCode ( m_transactionResult
);
288 WARN ( "Command returned AT result %d with code %d" , m_transactionResult
. result
, m_transactionResult
. code
);
289 WARN ( "Command \" %s \" returned AT result %d with code %d" , command
, m_transactionResult
. result
, m_transactionResult
. code
);
292 DBG ( "Command returned successfully" );
297 int ATCommandsInterface :: tryReadLine ()
299 static bool lineDetected
= false ;
301 //Block on serial read or incoming command
302 DBG ( "Trying to read a new line from stream" );
303 int ret
= m_pStream
-> waitAvailable (); //This can be aborted
307 ret
= m_pStream
-> read (( uint8_t *) m_inputBuf
+ m_inputPos
, & readLen
, AT_INPUT_BUF_SIZE
- 1 - m_inputPos
, 0 ); //Do NOT wait at this point
312 m_inputBuf
[ m_inputPos
] = '\0' ; //Add null terminating character to ease the use of str* functions
313 DBG ( "In buffer: [%s]" , m_inputBuf
);
316 if ( ret
== NET_INTERRUPTED
) //It is worth checking readLen as data might have been read even though the read was interrupted
318 DBG ( "Read was interrupted" );
319 return NET_INTERRUPTED
; //0 chars were read
321 else if ( readLen
== 0 )
324 return OK
; //0 chars were read
327 DBG ( "Trying to process incoming line" );
328 bool lineProcessed
= false ;
332 lineProcessed
= false ; //Reset flag
334 DBG ( "New iteration" );
336 //Look for a new line
339 DBG ( "No line detected yet" );
340 //Try to look for a starting CRLF
341 char * crPtr
= strchr ( m_inputBuf
, CR
);
343 Different cases at this point:
344 - CRLF%c sequence: this is the start of a line
345 - CRLFCR(LF) sequence: this is the end of a line (followed by the beginning of the next one)
346 - LF: this is the trailing LF char of the previous line, discard
347 - CR / CRLF incomplete sequence: more data is needed to determine which action to take
348 - %c ... CR sequence: this should be the echo of the previous sequence
349 - %c sequence: This might be the echo of the previous command; more data is needed to determine which action to take
351 In every case, move mem at the beginning
355 DBG ( "CR char found" );
358 //Discard all preceding characters (can do nothing if m_inputBuf == crPtr)
359 memmove ( m_inputBuf
, crPtr
, ( m_inputPos
+ 1 ) - ( crPtr
- m_inputBuf
)); //Move null-terminating char as well
360 m_inputPos
= m_inputPos
- ( crPtr
- m_inputBuf
); //Adjust m_inputPos
363 //If the line starts with CR, this should be a result code
364 if ( crPtr
== m_inputBuf
)
366 //To determine the sequence we need at least 3 chars
369 //Look for a LF char next to the CR char
370 if ( m_inputBuf
[ 1 ] == LF
)
372 //At this point we can check whether this is the end of a preceding line or the beginning of a new one
373 if ( m_inputBuf
[ 2 ] != CR
)
375 DBG ( "Beginning of new line found" );
376 //Beginning of a line
377 lineDetected
= true ; //Move to next state-machine step
381 //End of an unprocessed line
382 WARN ( "End of unprocessed line" );
384 //In both cases discard CRLF
385 DBG ( "Discarding CRLF" );
386 memmove ( m_inputBuf
, m_inputBuf
+ 2 , ( m_inputPos
+ 1 ) - 2 ); //Move null-terminating char as well
387 m_inputPos
= m_inputPos
- 2 ; //Adjust m_inputPos
391 //This is completely unexpected, discard the CR char to try to recover good state
392 WARN ( "Unexpected %c char (%02d code) found after CR char" , m_inputBuf
[ 1 ]);
393 memmove ( m_inputBuf
, m_inputBuf
+ 1 , ( m_inputPos
+ 1 ) - 1 ); //Move null-terminating char as well
394 m_inputPos
= m_inputPos
- 1 ; //Adjust m_inputPos
398 //if the line does NOT begin with CR, this can be an echo of the previous command, process it
401 int crPos
= crPtr
- m_inputBuf
;
402 int lfOff
= 0 ; //Offset for LF if present
403 DBG ( "New line found (possible echo of command)" );
404 //This is the end of line
405 //Replace m_inputBuf[crPos] with null-terminating char
406 m_inputBuf
[ crPos
] = '\0' ;
407 //Check if there is a LF char afterwards
408 if ( m_inputPos
- crPos
>= 1 )
410 if ( m_inputBuf
[ crPos
+ 1 ] == LF
)
412 lfOff
++; //We will discard LF char as well
416 int ret
= processReadLine ();
420 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
421 lineDetected
= false ;
425 //If sendData has been called, all incoming data has been discarded
428 memmove ( m_inputBuf
, m_inputBuf
+ crPos
+ lfOff
+ 1 , ( m_inputPos
+ 1 ) - ( crPos
+ lfOff
+ 1 )); //Move null-terminating char as well
429 m_inputPos
= m_inputPos
- ( crPos
+ lfOff
+ 1 ); //Adjust m_inputPos
431 DBG ( "One line was successfully processed" );
432 lineProcessed
= true ; //Line was processed with success
433 lineDetected
= false ; //Search now for a new line
436 else if ( m_inputBuf
[ 0 ] == LF
) //If there is a remaining LF char from the previous line, discard it
438 DBG ( "Discarding single LF char" );
439 memmove ( m_inputBuf
, m_inputBuf
+ 1 , ( m_inputPos
+ 1 ) - 1 ); //Move null-terminating char as well
440 m_inputPos
= m_inputPos
- 1 ; //Adjust m_inputPos
444 //Look for the end of line
447 DBG ( "Looking for end of line" );
448 //Try to look for a terminating CRLF
449 char * crPtr
= strchr ( m_inputBuf
, CR
);
451 Different cases at this point:
452 - CRLF sequence: this is the end of the line
453 - CR%c sequence : unexpected
454 - CR incomplete sequence: more data is needed to determine which action to take
457 //Try to look for a '>' (greater than character) that marks an entry prompt
458 char * greaterThanPtr
= strchr ( m_inputBuf
, GD
);
460 This character must be detected as there is no CRLF sequence at the end of an entry prompt
465 DBG ( "CR char found" );
466 int crPos
= crPtr
- m_inputBuf
;
467 //To determine the sequence we need at least 2 chars
468 if ( m_inputPos
- crPos
>= 2 )
470 //Look for a LF char next to the CR char
471 if ( m_inputBuf
[ crPos
+ 1 ] == LF
)
473 DBG ( "End of new line found" );
474 //This is the end of line
475 //Replace m_inputBuf[crPos] with null-terminating char
476 m_inputBuf
[ crPos
] = '\0' ;
478 int ret
= processReadLine ();
482 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
483 lineDetected
= false ;
487 //If sendData has been called, all incoming data has been discarded
490 //Shift remaining data to beginning of buffer
491 memmove ( m_inputBuf
, m_inputBuf
+ crPos
+ 2 , ( m_inputPos
+ 1 ) - ( crPos
+ 2 )); //Move null-terminating char as well
492 m_inputPos
= m_inputPos
- ( crPos
+ 2 ); //Adjust m_inputPos
495 DBG ( "One line was successfully processed" );
496 lineProcessed
= true ; //Line was processed with success
500 //This is completely unexpected, discard all chars till the CR char to try to recover good state
501 WARN ( "Unexpected %c char (%02d code) found in incoming line" , m_inputBuf
[ crPos
+ 1 ]);
502 memmove ( m_inputBuf
, m_inputBuf
+ crPos
+ 1 , ( m_inputPos
+ 1 ) - ( crPos
+ 1 )); //Move null-terminating char as well
503 m_inputPos
= m_inputPos
- ( crPos
+ 1 ); //Adjust m_inputPos
505 lineDetected
= false ; //In both case search now for a new line
508 else if ( greaterThanPtr
!= NULL
)
511 int gdPos
= greaterThanPtr
- m_inputBuf
;
512 //To determine the sequence we need at least 2 chars
513 if ( m_inputPos
- gdPos
>= 2 )
515 //Look for a space char next to the GD char
516 if ( m_inputBuf
[ gdPos
+ 1 ] == ' ' )
518 //This is an entry prompt
519 //Replace m_inputBuf[gdPos] with null-terminating char
520 m_inputBuf
[ gdPos
] = '\0' ;
522 //Shift remaining data to beginning of buffer
523 memmove ( m_inputBuf
, m_inputBuf
+ gdPos
+ 1 , ( m_inputPos
+ 1 ) - ( gdPos
+ 1 )); //Move null-terminating char as well
524 m_inputPos
= m_inputPos
- ( gdPos
+ 1 ); //Adjust m_inputPos
527 ret
= processEntryPrompt ();
531 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
532 lineDetected
= false ;
536 DBG ( "One line was successfully processed" );
537 lineProcessed
= true ; //Line was processed with success
541 //This is completely unexpected, discard all chars till the GD char to try to recover good state
542 WARN ( "Unexpected %c char (%02d code) found in incoming line" , m_inputBuf
[ gdPos
+ 1 ]);
543 memmove ( m_inputBuf
, m_inputBuf
+ gdPos
+ 1 , ( m_inputPos
+ 1 ) - ( gdPos
+ 1 )); //Move null-terminating char as well
544 m_inputPos
= m_inputPos
- ( gdPos
+ 1 ); //Adjust m_inputPos
546 lineDetected
= false ; //In both case search now for a new line
550 } while ( lineProcessed
); //If one complete line was processed there might be other incoming lines that can also be processed without reading the buffer again
552 //If the line could not be processed AND buffer is full, it means that we won't ever be able to process it (buffer too short)
553 if ( m_inputPos
== AT_INPUT_BUF_SIZE
- 1 )
557 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
558 WARN ( "Incoming buffer is too short to process incoming line" );
559 //Look for a new line
560 lineDetected
= false ;
563 DBG ( "Processed every full incoming lines" );
568 int ATCommandsInterface :: trySendCommand ()
570 osEvent evt
= m_env2AT
. get ( 0 );
571 DBG ( "status = %d, msg = %d" , evt
. status
, evt
. value
. p
);
572 if ( evt
. status
== osEventMail
)
574 int * msg
= ( int *) evt
. value
. p
;
575 if ( * msg
== AT_CMD_READY
) //Command pending
577 if ( m_transactionState
!= IDLE
)
579 WARN ( "Previous command not processed!" );
581 DBG ( "Sending pending command" );
582 m_pStream
-> write (( uint8_t *) m_transactionCommand
, strlen ( m_transactionCommand
), osWaitForever
);
584 m_pStream
-> write (( uint8_t *)& cr
, 1 , osWaitForever
); //Carriage return line terminator
585 m_transactionState
= COMMAND_SENT
;
590 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
592 m_AT2Env
. put ( msg
); //Command has timed out
593 m_transactionState
= IDLE
; //State-machine reset
600 int ATCommandsInterface :: processReadLine ()
602 DBG ( "Processing read line [%s]" , m_inputBuf
);
603 //The line is stored in m_inputBuf
604 if ( m_transactionState
== COMMAND_SENT
)
606 //If the command has been sent, checks echo to see if it has been received properly
607 if ( strcmp ( m_transactionCommand
, m_inputBuf
) == 0 )
609 DBG ( "Command echo received" );
610 //If so, it means that the following lines will only be solicited results
611 m_transactionState
= READING_RESULT
;
615 if ( m_transactionState
== IDLE
|| m_transactionState
== COMMAND_SENT
)
618 char * pSemicol
= strchr ( m_inputBuf
, ':' );
620 if ( pSemicol
!= NULL
) //Split the identifier & the result code (if it exists)
623 pData
= pSemicol
+ 1 ;
626 pData
++; //Suppress whitespace
629 //Looks for a unsolicited result code; we can have m_transactionState == COMMAND_SENT as the code may have arrived just before we sent the command
630 m_eventsProcessingMtx
. lock ();
631 //Go through the list
632 for ( int i
= 0 ; i
< MAX_AT_EVENTS_HANDLERS
; i
++) //Find a free slot
634 if ( m_eventsHandlers
[ i
] != NULL
)
636 if ( m_eventsHandlers
[ i
]-> isATCodeHandled ( m_inputBuf
) )
638 m_eventsHandlers
[ i
]-> onEvent ( m_inputBuf
, pData
);
639 found
= true ; //Do not break here as there might be multiple handlers for one event type
643 m_eventsProcessingMtx
. unlock ();
649 if ( m_transactionState
== READING_RESULT
)
651 //The following lines can either be a command response or a result code (OK / ERROR / CONNECT / +CME ERROR: %s / +CMS ERROR: %s)
652 if ( strcmp ( "OK" , m_inputBuf
) == 0 )
654 DBG ( "OK result received" );
655 m_transactionResult
. code
= 0 ;
656 m_transactionResult
. result
= ATResult :: AT_OK
;
657 m_transactionState
= IDLE
;
658 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
659 * msg
= AT_RESULT_READY
;
660 m_AT2Env
. put ( msg
); //Command has been processed
663 else if ( strcmp ( "ERROR" , m_inputBuf
) == 0 )
665 DBG ( "ERROR result received" );
666 m_transactionResult
. code
= 0 ;
667 m_transactionResult
. result
= ATResult :: AT_ERROR
;
668 m_transactionState
= IDLE
;
669 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
670 * msg
= AT_RESULT_READY
;
671 m_AT2Env
. put ( msg
); //Command has been processed
674 else if ( strncmp ( "CONNECT" , m_inputBuf
, 7 /*=strlen("CONNECT")*/ ) == 0 ) //Result can be "CONNECT" or "CONNECT %d", indicating baudrate
676 DBG ( "CONNECT result received" );
677 m_transactionResult
. code
= 0 ;
678 m_transactionResult
. result
= ATResult :: AT_CONNECT
;
679 m_transactionState
= IDLE
;
680 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
681 * msg
= AT_RESULT_READY
;
682 m_AT2Env
. put ( msg
); //Command has been processed
685 else if ( strcmp ( "COMMAND NOT SUPPORT" , m_inputBuf
) == 0 ) //Huawei-specific, not normalized
687 DBG ( "COMMAND NOT SUPPORT result received" );
688 m_transactionResult
. code
= 0 ;
689 m_transactionResult
. result
= ATResult :: AT_ERROR
;
690 m_transactionState
= IDLE
;
691 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
692 * msg
= AT_RESULT_READY
;
693 m_AT2Env
. put ( msg
); //Command has been processed
696 else if ( strstr ( m_inputBuf
, "+CME ERROR:" ) == m_inputBuf
) //Mobile Equipment Error
698 std :: sscanf ( m_inputBuf
+ 12 /* =strlen("+CME ERROR: ") */ , "%d" , & m_transactionResult
. code
);
699 DBG ( "+CME ERROR: %d result received" , m_transactionResult
. code
);
700 m_transactionResult
. result
= ATResult :: AT_CME_ERROR
;
701 m_transactionState
= IDLE
;
702 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
703 * msg
= AT_RESULT_READY
;
704 m_AT2Env
. put ( msg
); //Command has been processed
707 else if ( strstr ( m_inputBuf
, "+CMS ERROR:" ) == m_inputBuf
) //SIM Error
709 std :: sscanf ( m_inputBuf
+ 13 /* =strlen("+CME ERROR: ") */ , "%d" , & m_transactionResult
. code
);
710 DBG ( "+CMS ERROR: %d result received" , m_transactionResult
. code
);
711 m_transactionResult
. result
= ATResult :: AT_CMS_ERROR
;
712 m_transactionState
= IDLE
;
713 int * msg
= m_AT2Env
. alloc ( osWaitForever
);
714 * msg
= AT_RESULT_READY
;
715 m_AT2Env
. put ( msg
); //Command has been processed
720 DBG ( "Unprocessed result received: '%s'" , m_inputBuf
);
721 //Must call transaction processor to complete line processing
722 int ret
= m_pTransactionProcessor
-> onNewATResponseLine ( this , m_inputBuf
); //Here sendData can be called
730 int ATCommandsInterface :: processEntryPrompt ()
732 DBG ( "Calling prompt handler" );
733 int ret
= m_pTransactionProcessor
-> onNewEntryPrompt ( this ); //Here sendData can be called
735 if ( ret
!= NET_MOREINFO
) //A new prompt is expected
737 DBG ( "Sending break character" );
738 //Send CTRL+Z (break sequence) to exit prompt
739 char seq
[ 2 ] = { BRK
, 0x00 };
745 //This will be called on initialization & after the execution of a command
746 void ATCommandsInterface :: enableEvents ()
748 //Advertize this to events handlers
749 m_eventsMgmtMtx
. lock ();
750 for ( int i
= 0 ; i
< MAX_AT_EVENTS_HANDLERS
; i
++) //Find a free slot
752 if ( m_eventsHandlers
[ i
] != NULL
)
754 m_eventsHandlers
[ i
]-> onDispatchStart ();
755 //Enable this kind of events
756 const char * cmd
= m_eventsHandlers
[ i
]-> getEventsEnableCommand ();
759 int ret
= executeInternal ( cmd
, this , NULL
); //Execute enable command
762 WARN ( "Events enabling command \" %s \" failed" , cmd
);
767 m_eventsMgmtMtx
. unlock ();
770 //This will be called on de-initialization & before the execution of a command to prevent unsollicited result codes from polluting the results
771 void ATCommandsInterface :: disableEvents ()
773 //Advertize this to events handlers
774 m_eventsMgmtMtx
. lock ();
775 for ( int i
= 0 ; i
< MAX_AT_EVENTS_HANDLERS
; i
++) //Find a free slot
777 if ( m_eventsHandlers
[ i
] != NULL
)
779 m_eventsHandlers
[ i
]-> onDispatchStart ();
780 //Disable this kind of events
781 const char * cmd
= m_eventsHandlers
[ i
]-> getEventsDisableCommand ();
784 int ret
= executeInternal ( cmd
, this , NULL
); //Execute disable command
787 WARN ( "Events disabling command \" %s \" failed" , cmd
);
792 m_eventsMgmtMtx
. unlock ();
795 //Commands that can be called during onNewATResponseLine callback, additionally to close()
796 //Access to this method is protected (can ONLY be called on processing thread during IATCommandsProcessor::onNewATResponseLine execution)
797 int ATCommandsInterface :: sendData ( const char * data
)
799 //m_inputBuf is cleared at this point (and MUST therefore be empty)
800 int dataLen
= strlen ( data
);
801 DBG ( "Sending raw string of length %d" , dataLen
);
802 int ret
= m_pStream
-> write (( uint8_t *) data
, dataLen
, osWaitForever
);
805 WARN ( "Could not write to stream (returned %d)" , ret
);
814 int ret
= m_pStream
-> read (( uint8_t *) m_inputBuf
, & readLen
, MIN ( dataLen
- dataPos
, AT_INPUT_BUF_SIZE
- 1 ), osWaitForever
); //Make sure we do not read more than needed otherwise it could break the parser
817 WARN ( "Could not read from stream (returned %d)" , ret
);
818 m_inputPos
= 0 ; //Reset input buffer state
819 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
823 if ( memcmp ( m_inputBuf
, data
+ dataPos
, readLen
) != 0 )
825 //Echo does not match output
826 m_inputBuf
[ readLen
] = '\0' ;
827 WARN ( "Echo does not match output, got '%s' instead" , m_inputBuf
);
828 m_inputPos
= 0 ; //Reset input buffer state
829 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
834 //If all characters have not been read yet
836 } while ( dataPos
< dataLen
);
838 DBG ( "String sent successfully" );
840 m_inputPos
= 0 ; //Reset input buffer state
841 m_inputBuf
[ 0 ] = '\0' ; //Always have a null-terminating char at start of buffer
846 /*static*/ void ATCommandsInterface :: staticCallback ( void const * p
)
848 (( ATCommandsInterface
*) p
)-> process ();
851 int ATCommandsInterface :: ATResultToReturnCode ( ATResult result
) //Helper
853 if ( result
. result
== ATResult :: AT_OK
)
863 /*virtual*/ int ATCommandsInterface :: onNewATResponseLine ( ATCommandsInterface
* pInst
, const char * line
) //Default implementation for simple commands handling
868 /*virtual*/ int ATCommandsInterface :: onNewEntryPrompt ( ATCommandsInterface
* pInst
) //Default implementation (just sends Ctrl+Z to exit the prompt by returning OK right-away)
873 void ATCommandsInterface :: process () //Processing thread
875 DBG ( "AT Thread started" );
878 DBG ( "AT Processing on hold" );
879 m_processingThread
. signal_wait ( AT_SIG_PROCESSING_START
); //Block until the process is started
881 m_processingMtx
. lock ();
882 DBG ( "AT Processing started" );
883 //First of all discard buffer
888 ret
= m_pStream
-> read (( uint8_t *) m_inputBuf
, & readLen
, AT_INPUT_BUF_SIZE
- 1 , 0 ); //Do NOT wait at this point
890 m_inputPos
= 0 ; //Clear input buffer
893 DBG ( "Trying to send a pending command" );
894 trySendCommand (); //This must be tried first as we discarded the buffer before and therefore would be blocking though there is a pending command
895 DBG ( "Trying to read a new line" );
897 } while ( m_processingThread
. signal_wait ( AT_SIG_PROCESSING_STOP
, 0 ). status
!= osEventSignal
); //Loop until the process is interrupted
898 m_processingMtx
. unlock ();
899 DBG ( "AT Processing stopped" );