EV_TXDONE and transmission complete #640
terrillmoore
started this conversation in
General
Replies: 1 comment 2 replies
-
Thanks for the detailed explanation, that's very helpful. Would it be possible to add a method to query the time to the next time critical job, instead of having to call os_queryTimeCriticalJobs() with artificial timeframes? |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
It's very easy to be confused by
EV_TXDONE
when writing code that sends uplinks, especially when sending back-to-back uplinks or sending at fixed periods that are short relative to network times. In sorting out issues, I came across this topic a lot. For example, #588 (comment)The LMIC (as of v3.2) really is compliant with LoRaWAN. In addition, it reliably receives and processes downlink MAC control frames. (Before v3.2, any MAC control downlinks were largely ignored, or not handled compliantly)
Networks try to manage device transmit power, and so they send downlinks a lot more than you might expect. These downlinks require responses.
Downlinks are sent (and processed) in response to uplinks.
EV_TXDONE
has never meant that the LMIC was idle; it only means that the work for transmitting user data is complete (including any associated RX downlink windows). It might mean that the LMIC is idle.EV_TXDONE
is necessary for the LMIC to be idle, but it's not sufficient.If the network sends you a downlink, the LMIC is not idle when it reports
EV_TXDONE
; it's already sending its uplink response. The LMIC cannot accept a new message until it's finished sending the uplink.Furthermore, after sending the uplink, the LMIC must open another downlink window. That downlink window can contain another message, which might require another response.
As a practical matter, then, the application must inspect the LMIC state to know whether the LMIC is idle. The network can keep the LMIC busy for an arbitrarily long period of time. If your program doesn't cater for this, it is incorrect and can be forced to fail by a broken or malicious network. (This problem is probably not unique to the LMIC but is likely to manifest in different ways in different LoRaWAN stacks, depending on implementation strategy.)
If you try to transmit while the uplink path is busy, the send attempt will return an error code. The examples are not good about checking for this. (In older versions, the send APIs would silently fail, or silently malfunction.)
If you put the CPU to sleep while the LMIC is not idle, when you wake up, things are not going to be right in the LMIC.
Consequences:
Avoid using
LMIC_setTxData()
andLMIC_setTxData_strict()
, because they don't return error status - you have no way to know if they worked. Instead useLMIC_setTxData2()
,LMIC_setTxData2_strict()
,LMIC_sendWithCallback()
orLMIC_sendWithCallback_strict()
. Footnote: older apps that usedLMIC_setTxData()
typically checked the flags inLMIC.opmode
. But this is a bad idea, because when the LMIC is refactored to have a proper FSM,LMIC.opmode
will necessarily change or go away entirely.Check for errors when you try to transmit, and recover. The LMIC will not post a completion (
EV_TXDONE
) if the transmit didn't launch.After calling one of the transmit APIs, avoid putting the CPU to sleep unless you know that the LMIC is not busy managing the link. Find out whether a given sleep interval is safe by calling the LMIC API
os_queryTimeCriticalJobs()
. Pass it how long you would like to sleep, inostime_t
ticks; it will return non-zero if there are time-critical jobs in the interval, and zero otherwise.Beta Was this translation helpful? Give feedback.
All reactions