EmbeddedRelated.com
Forums

AT commands: how to detect unsolicited result codes

Started by Unknown May 8, 2014
On 2014-05-10, upsidedown@downunder.com <upsidedown@downunder.com> wrote:
> On Sat, 10 May 2014 09:15:37 +0200, pozz <pozzugno@gmail.com> wrote: > >>Il 09/05/2014 14:29, Simon Clubley ha scritto: >>> I would have implemented this as a state machine in the upper layers of >>> the code with clearly defined state transitions depending on (1) timeouts, >>> (2) the responses you are waiting for and (3) unsolicited events such >>> as ring. >>> >>> The next layer down would include a parser which extracts any printable >>> text, on a per line basis, from the modem and either tokenises it or >>> passes it as-is back up to the state machine. >> >>Even the "per line basis" parser approach doesn't work everytime. >>The answer to the AT command that sends SMS isn't <CR><LF> as usual, but >>it is the 2-characters prompt "> ". The lower layer (the driver?) can't >>decide to wait for <CR><LF> before passing the incoming characters to >>the application layer. >> >>One possibility is to change at run-time the ending suffix: normally it >>is <CR><LF>, but it could be "> ". Anyway this suffix will be used only >>for answers to pass to the application layer. At the same time >>unsolicited messages (ending with <CR><LF>) could arrive and must be >>managed. >>
In that case, my first try at implementing this would be to switch to traditional per character parsing and tokenising the response. If you see "> ", then that's one token and it can be pushed upstairs without any wait. If OTOH you see a alphanumeric character, you continue scanning until you see a non-alphanumeric character, (although you may choose to treat a space as part of the sequence and look for a non-printable character instead).
>> >>> If the state machine sees a ring while waiting for OK, it can decide >>> if it wants to transition to a new state at that point or wait for >>> the expected response (or timeout). >>> >>> That means in the event of RING followed on the next line by OK, your >>> state machine would see two distinct responses from the modem. >> >>You're thinking of a lower level that is able to separate two messages, >>even if they are strictly *consecutive*: answer-unsolicited or >>unsolicited-answer. >> >>This is the starting question: what is the best method to separate >>incoming characters from modem into *distinct* messages in *all* >>possible situations (answers, unsolicited...)? >><CR><LF> prefix/suffix could be a method, but in some situation the >>suffix changes. >> >>Are you thinking of a lower level that pass to the application layer >>*all* the messages: answers and unsolicited? IMHO it's not feasible. All >>the upper complex FSMs (there are many, one for sensing SMS, another for >>receiving SMS, another for making voice calls, another for making data >>calls, ...) should decide, in *every* state, what to do in case of >>unsolicited messages. >>
The FSM should know what are the possible responses in each state, both expected and unsolicited. I agree it can get complicated, but if you are getting those messages you have to handle them somehow, even if you transition back to the same state, thereby ignoring the message.
>> >>> You would of course have to make sure your state machine always >>> terminated any possible successful connect so you were not running up >>> connect charges after recovery from any unexpected events. >>> >>> Is the above how others here would implement this or would you >>> use a different approach ? > > Why bother with a fuss like that above. If your application layer > doesn't understand the response, just resend the original command a > few times until you get a valid response or declare the connection > dead. >
It matters because you need to handle error recovery in a robust manner. Your commands may have side effects, such as changing a configuration, sending a message, or establishing a connection. You can't just blindly send them multiple times. You might get away with that in some circumstances, but not always. There's enough lousy embedded software out there without us adding to the problem. :-) Simon. -- Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP Microsoft: Bringing you 1980s technology to a 21st century world
upsid...@downunder.com ha scritto:
> In the interrupt service routine (which should be kept very simple to > avoid blocking other interrupts) just use the idle timeout. > > It is to the upper level logic to find out the actual framing, e.g. by > knowing the structure of the expected response (such as ending in > <LF>).
I implemented the mechanism you suggested: mark the end of a message after a small timeout (4-5 characters frame length) without receiving any character. In this way, I will have a buffer with the complete message from the modem, answer from a previous command or unsolicited code... most of the time. During developing I noticed the following. When an incoming SMS arrives, the modem sends an unsolicited message +CNMI to inform about the event. This message could appear concatenated to an answer to a previous AT command. In other words, the modem doesn't insert a pause, even small, between the answer to a previous AT command and the +CNMI unsolicited message. Detecting the start and stop of a message just using the timeout between receiving characters is a broken approach: I could have a concatenated message (answer plus unsolicited). I know the application layer can break this concatenated message depending on the content and expected answer, knowing the previous AT command send, but this approach will complicate the problem. I hoped the modem gave the opportunity to the host microcontroller to separate the messages at a low-level, without parsing the content, breaking the stream of incoming characters in messages separated at the presence of a long pause between characters. Unfortunately this approach doesn't work, at least with my modem (SIM900 of SimCom). IMHO, if the application layer should be the only responsible to separate the stream of incoming characters in messages, parsing the content, the low-level timeout mechanism isn't needed at all. It's sufficient to have a FIFO buffer where the incoming characters will be pushed in ISR and popped in the application code.