As is known, when an AT command is sent in cellular modem communication, a requested response must be waited for the next transmission. Unsolicited responses may also be received. Also other active objects can make requests to the modem active object. Is there a similar example project or code with such a design?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The fact that you are aware of the unsolicited responses is already a big positive. I had to rewrite some firmware some years ago because of this. That client would not pay for QP, so I had to re-invent the wheel, but I did implement using the active object pattern.
Here is the starting point for some of my observations on this issue:
Hi dood444,
I'm not aware of a ready-to-use example of an active object for a modem driven by AT commands. The beaten path approach is to send AT command and sleep or wait for the OK response. However, the ERROR responses or some other unsolicited responses are harder to manage this way.
A hierarchical state machine approach, on the other hand, can deal with all this in an elegant way because a state machine doesn't block and can handle any event sequence. I've attached a state machine sketch that could give you an idea how you might approach something like that. I'm assuming that the OK, ERROR, and other responses are converted to events outside the Modem active object.
In the attached Modem state machine, the AT commands are sent in the entry actions to states, and the transtions are triggered by the expected OK events. There is an ERROR event handled at the higer-level state, where it increments the retry counter. If the coutner is below the LIMIT, the transition to History causes re-entry to the last state and repeating the command. When the retry LIMIT is reached, the system enters the error state.
Of course, this is just an initial idea. In a real AO, you might need to handle timeouts (with a QTimeEvt), and many other cases.
I'm assuming that the OK, ERROR, and other responses are converted to events outside the Modem active object."
That is a key point from Samek. Create a parser module. That module can run within the modem/cell AO if you like (the UART Rx ISR could send a character at a time to the AO in events), or run within the UART Tx ISR itself, POSTing output events.
But the key point is the parser module would handle all the incoming bytes/characters until a single completed AT message is received. Then it would translate that into a logical equivalent event (plus any data), would could then be POSTED to the modem/cell AO.
Pro tip: follow a strict TDD process on the parser module. Gather up example strings received from the target modem and use them for testing/unit testing. Parser's like this are great, because they tend to be easy to unit test.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Giulio,
Please see the "Transition to History" design pattern for the description of the concept. Please note that this is the original description of the History pattern from the PSiCC2 book. The QM modeling tool, which has been created after that book was published fully supports transtitions to history (both shallow history and deep history.)
But to make it more concrete for you, let's apply it specifically to the Modem state machine attached in the previous post. So, suppose that your Modem is in the middle of AT-command sequence, say in state "wifi_mode". This state has only only one transition OK, which is expected when everything goes fine. But suppose that ERROR event arrives instead. The "wifi_mode" state does not handle the ERROR event, so it is passed on to the "config" superstate. This "config" state handles ERROR by incrementing the retires counter and checking that it is below limit. If it is, the transition to history of state "config" is taken. This transition goes dynamically to the most recent active substate of "config", which is "wifi_mode" in this case. So, "wifi_mode" is entered, which sends the "AT+CWMMODE" command again. This is precisely what you want when you re-try the most recent AT command. So now if OK comes, you transition to the next state "wifi_conn". If ERROR comes again, the cycle repeats, until the retry counter reaches the LIMIT.
Please note that the history mechanism allows you to put the whole error handling in only one (super)state "config" instead of putting it in each and every substate of config. Similarly, you can handle other problems, like TIMEOUT. I hope you can appreciate the avoidance of repetitions in this hierarchial state machine.
--MMS
Last edit: Quantum Leaps 16 hours ago
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hello,
As is known, when an AT command is sent in cellular modem communication, a requested response must be waited for the next transmission. Unsolicited responses may also be received. Also other active objects can make requests to the modem active object. Is there a similar example project or code with such a design?
The fact that you are aware of the unsolicited responses is already a big positive. I had to rewrite some firmware some years ago because of this. That client would not pay for QP, so I had to re-invent the wheel, but I did implement using the active object pattern.
Here is the starting point for some of my observations on this issue:
https://covemountainsoftware.com/2020/07/18/extreme-asynchronous-firmware-design/
Hi dood444,
I'm not aware of a ready-to-use example of an active object for a modem driven by AT commands. The beaten path approach is to send AT command and sleep or wait for the OK response. However, the ERROR responses or some other unsolicited responses are harder to manage this way.
A hierarchical state machine approach, on the other hand, can deal with all this in an elegant way because a state machine doesn't block and can handle any event sequence. I've attached a state machine sketch that could give you an idea how you might approach something like that. I'm assuming that the OK, ERROR, and other responses are converted to events outside the Modem active object.
In the attached Modem state machine, the AT commands are sent in the entry actions to states, and the transtions are triggered by the expected OK events. There is an ERROR event handled at the higer-level state, where it increments the
retry
counter. If the coutner is below the LIMIT, the transition to History causes re-entry to the last state and repeating the command. When the retry LIMIT is reached, the system enters the error state.Of course, this is just an initial idea. In a real AO, you might need to handle timeouts (with a QTimeEvt), and many other cases.
--MMS
Last edit: Quantum Leaps 1 day ago
That is a key point from Samek. Create a parser module. That module can run within the modem/cell AO if you like (the UART Rx ISR could send a character at a time to the AO in events), or run within the UART Tx ISR itself, POSTing output events.
But the key point is the parser module would handle all the incoming bytes/characters until a single completed AT message is received. Then it would translate that into a logical equivalent event (plus any data), would could then be POSTED to the modem/cell AO.
Pro tip: follow a strict TDD process on the parser module. Gather up example strings received from the target modem and use them for testing/unit testing. Parser's like this are great, because they tend to be easy to unit test.
Hi Miro,
could you explain better (with an example) what do you intend when you say "transition to History"?
Thanks a lot in advance!
Giulio
Hi Giulio,
Please see the "Transition to History" design pattern for the description of the concept. Please note that this is the original description of the History pattern from the PSiCC2 book. The QM modeling tool, which has been created after that book was published fully supports transtitions to history (both shallow history and deep history.)
But to make it more concrete for you, let's apply it specifically to the Modem state machine attached in the previous post. So, suppose that your Modem is in the middle of AT-command sequence, say in state "wifi_mode". This state has only only one transition OK, which is expected when everything goes fine. But suppose that ERROR event arrives instead. The "wifi_mode" state does not handle the ERROR event, so it is passed on to the "config" superstate. This "config" state handles ERROR by incrementing the retires counter and checking that it is below limit. If it is, the transition to history of state "config" is taken. This transition goes dynamically to the most recent active substate of "config", which is "wifi_mode" in this case. So, "wifi_mode" is entered, which sends the "AT+CWMMODE" command again. This is precisely what you want when you re-try the most recent AT command. So now if OK comes, you transition to the next state "wifi_conn". If ERROR comes again, the cycle repeats, until the retry counter reaches the LIMIT.
Please note that the history mechanism allows you to put the whole error handling in only one (super)state "config" instead of putting it in each and every substate of config. Similarly, you can handle other problems, like TIMEOUT. I hope you can appreciate the avoidance of repetitions in this hierarchial state machine.
--MMS
Last edit: Quantum Leaps 16 hours ago