First of all I’m new in the TTN community and Im surprised how many people are sharing Information here. Wow!
We build a single Channel gateway for development and an Atmega328p based node with the LMIC library.
Now the problem: After successful OTAA I call LMIC_disableChannel(i); for each channel except channel 0 to force the Node to use our single channel gateway frequency.
When I try to send a confirmed Downlink message, the message is received by the node but no ACK message is received by the Gateway/TTN. At another place with a multichannel gateway everything works as expected.
So my thoughts were that the ACK package in single channel mode isn’t sent because of the duty cycle . If I add delay(60*1000); in the event handler method right after the downlink message is parsed the ACK packet is sent after a minute without a problem (100% reproducible).
I don’t want to hardcode the minute delay because the duty cycle time depends on the Payload and SF.
So my question: Is there any option to get the next possible TX window time for a channel from the LMIC library? If not maybe someone already wrote a method to calculate the delay between the windows?
Who is sending the ACK? Your own code, or the LMIC library? Please show us your changes.
If your own code is sending it, then for regular uplinks I’ve always seen LMIC postpone the transmission until a channel became available, without any additional hacks. So I guess it’s in the LMIC code?
As an aside, maybe the application shouldn’t care how soon your device acknowledges. You could even wait for the next uplink, emphasis mine:
4.3.1.2 Message acknowledge bit and acknowledgement procedure (ACK in FCtrl)
When receiving a confirmed data message, the receiver shall respond with a data frame that has the acknowledgment bit (ACK) set. If the sender is an end-device, the network will send the acknowledgement using one of the receive windows opened by the end-device after the send operation. If the sender is a gateway, the end-device transmits an acknowledgment at its own discretion.
…
Note: To allow the end-devices to be as simple as possible and have as few states as possible it may transmit an explicit (possibly empty) acknowledgement data message immediately after the reception of a data message requiring a confirmation. Alternatively the end-device may defer the transmission of an acknowledgement to piggyback it with its next data message.
And making all other code stop by using delay might not be a great idea either? Finally, as you’re new to TTN, be sure to read Fair Use Policy explained. Welcome!
The ACK is sent by the library. LMIC send a message with empty payload. If the Node is able to use multiple channels the ACK is sent right after the downlink is received. If I use the single channel mode, the Library tells me that something is sent (Must be the ACK) but this isn’t the case in fact. The gateway receives nothing. It can’t be the case because an immediately ACK after receiving a downlink message would violate the duty cycle.
Alternatively the end-device may defer the transmission of an acknowledgement to piggyback it with its next data message.
That would be really nice. It saves airtime and the result is the same. How can I archive this in LMIC?
This my current code:
It first sends the ACK (its automatically scheduled) and then the next frame after TX_INTERVAL seconds
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.print(F("Received "));
Serial.print(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
byte received[LMIC.dataLen];
for (int i = 0; i < LMIC.dataLen; i++) {
if (LMIC.frame[LMIC.dataBeg + i] < 0x10) {
Serial.print(F("0"));
}
received[i] = LMIC.frame[LMIC.dataBeg + i];
Serial.print(received[i], HEX);
}
Serial.println();
handleCommand(received, LMIC.dataLen);
#ifdef SINGLE_CHANNEL
//Duty cycle ACK
delay(60000);
#endif
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
Maybe this should work but then a Frame without payload would be sent even if no ACK was requested.
Alternatively the end-device may defer the transmission of an acknowledgement to piggyback it with its next data message.
I think this is the best solution even for the production use with all channels enabled. Thank you for the tip! I tested it with the SF12 mode to see if the library calculates the duty cycle correct (See the code below which works perfectly for me). If I schedule a data message without delay the LMIC library waits as expected for the next free TX window even my TX_INTERVAL is to short.
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.print(F("Received "));
Serial.print(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
byte received[LMIC.dataLen];
for (int i = 0; i < LMIC.dataLen; i++) {
if (LMIC.frame[LMIC.dataBeg + i] < 0x10) {
Serial.print(F("0"));
}
received[i] = LMIC.frame[LMIC.dataBeg + i];
Serial.print(received[i], HEX);
}
Serial.println();
handleCommand(received, LMIC.dataLen);
// Schedule next transmission
//os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
}
//Just for debugging to finish the Serial.println(xy) before going to sleep
delay(100);
for (int i = 0; i < int(TX_INTERVAL / 8); i++) {
// Use library from https://github.com/rocketscream/Low-Power
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
do_send(&sendjob);
break;
Of course its possible to replace the LowPower with a simple delay(TX_Interval);
Yes of course! This limitations are no problem for us. We plan with one transmission every 30 minutes on SF 7 and maybe two downlinks per Day to adjust settings and later when everything works one downlink per week. I hope it is ok too exceed this limitations during development. My lab is in a cellar so I should disturb no one.
Another question wich is off topic but I don’t want to annoy the community with another topic because its a simple one : The RAK831 supports 8 channels. So is it able to use the 9th TTN RX2 channel (switching one channel temporarily for downlink)?
Determining if an ACK was needed would be your next problem. Peeking into the LMIC code suggests that LMIC.OP_POLL might tell you if an ACK is pending.
OP_POLL = 0x0010, // send empty UP frame to ACK confirmed DN/fetch more DN data
But if sleeping until the next uplink is due does not give you the additional automatic ACK, then that’s even better of course. Are you saying that the code you posted last indeed achieves that, so no empty ACK is transmitted?
The defined channels are for reception. For transmission the backend can specify any frequency in the band used, in fact it will specify the frequency for each downlink even if a defined channel frequency is used.