Closed w-ockham closed 1 year ago
Hi, I believe CAD is to detect if any TX activity on the channel by other LoRa nodes to avoid interference.
In the example, I see we do onCad and if there is signal we do onReceive.
What is the advantage if we dont use onCad and use onReceive right away? Less power consumption or something else?
Thanks a lot.
That's right. The example is intended to provide a minimum description of CAD. In the latter half of the CAD cycle, power consumption is roughly half of the full receiver mode. You can also implement collision avoidance with onCADdone as follows,
onCADdone(boolean detected) {
if (detected) {
channelBusy = true;
LoRa.receive();
} else {
...
}
}
void loop() {
if (txReady) {
if (channelBusy) {
// Backoff for a while.
} else {
LoRa.beginPacket();
....
}
Yes, now I understand. Thanks a lot for your response.
One thing, as far as I was able to understand there are two interrupts possible with CAD one is triggered on any preamble and the other on your specific one. The later one i believe should be mapped to a different dio pin, would it be possible to add that one as well. Thanks!
As I pointed out in the inline comment.. https://github.com/sandeepmistry/arduino-LoRa/pull/334#discussion_r376877207
One, CADDone, is triggered when the CAD is complete, on DIO0 & DIO2 The other, CADDetected is triggered only if a signal is detected, on DIO1
ideally, would it be possible to add another interrupt on DIO1? or its sufficient to short them and use single pin on MCU as long as onReceive is not enabled at the same time. but we would still need to check the relevant register on the radio.
As I pointed out in the inline comment.. #334 (comment)
One, CADDone, is triggered when the CAD is complete, on DIO0 & DIO2 The other, CADDetected is triggered only if a signal is detected, on DIO1
I don't think you'd want to just short them, but yes, we should add that, I believe there's an open issue outlining it. But as you suggested, the same functionality can be achieved with just DIO0. When CadDone is raised on this pin, in software you can check the IRQ flag for CadDetected.
I create this Branch a long time, and use cad to detect receiving data with sf7, sf8, sf9, sf10, sf11 or sf12. I used the dio0 and dio1 on the same interrupt pin with some diodes. The ideia was to create some single gateway or something.
@w-ockham : I'm going to use your CAD code for my deep-sleep node. By right, if I do CAD then make my ESP32 go to deep sleep (and wake up via DIO1) Will my ESP32 wake up and able to receive the current coming message?
Is this possible? I see from here https://learn.circuit.rocks/esp32-lora-gateway-battery-optimized He needs to init LoRa correctly after wakeup otherwise the current coming message is gone. Thanks millions for your effort.
// register the channel activity dectection callback
LoRa.onCadDone(onCadDone);
// register the receive callback
LoRa.onReceive(onReceive);
// put the radio into CAD mode
LoRa.channelActivityDetection();
// Then ESP32 go deep sleep at DIO1
// Setup deep sleep with wakeup by external source
esp_sleep_enable_ext0_wakeup((gpio_num_t)PIN_LORA_DIO_1, RISING);
// Finally set ESP32 into sleep
esp_deep_sleep_start();
@ricaun Will your CAD code wake up a deep sleep MCU and receive the current incoming message? Thanks millions.
@w-ockham : Would you mind explain to me what is B111 in isTransmitting()? Even if it is a hex, then it should be 0xb111. Thanks a lot for your effort.
@ricaun Will your CAD code wake up a deep sleep MCU and receive the current incoming message? Thanks millions.
I believe so, but I design the code to find the spreading factor when the node receiving a message, It's not perfect but It's possible to receive a message from sf7 to sf12 (with some loss). In the end, I don't know if how much consumption the Lora module has on the CAD state, and if it makes sense to make the Lora module to wake up the MCU with some interruption when the CAD trigger.
Is this possible? I see from here https://learn.circuit.rocks/esp32-lora-gateway-battery-optimized He needs to init LoRa correctly after wakeup otherwise the current coming message is gone.
Interesting, the SX126x has this SetRxDutyCycle function to make the LoRa module switch to receive and sleep. I don't know if the SX127x has some similar functions. 😞
The current CAD code syncs CadDone to dio0. Then check flag for cadDetected. The check for cadDetected flag is not possible as the MCU sleeps. If wakeup on Dio0 then it is pointless as I need CadDetected only for incoming messages.
I think I will add new code to sync CadDetected to Dio1. Then use dio1 to wakeup MCU.
Thanks a lot for your CAD code. :D
The current CAD code syncs CadDone to dio0. Then check flag for cadDetected. The check for cadDetected flag is not possible as the MCU sleeps. If wakeup on Dio0 then it is pointless as I need CadDetected only for incoming messages.
I think I will add new code to sync CadDetected to Dio1. Then use dio1 to wakeup MCU.
Thanks a lot for your CAD code. :D
On my code, I used the MAP_DIO0_LORA_CADDONE
and MAP_DIO1_LORA_CADDETECT
and if I remembered ready when the module goes to CAD mode, the CARDONE
trigger after some time and put the module on the Standby
, and if the module detects something on this window the CADDETECT
triggers.
I guess the SX127x
Lora module is not designed to wake up the MCU with CAD. 😞
@ricaun Most of the LoRa boards don't have DIO1 connected. e.g: TTGO, Heltec or Ready-made LoRa PCB. After doing the CAD, it will issue a CADDone. But not all CADDone events lead to CadDetected. Hence, we can not base on DIO0 to know when to wakeup MCU.
We need DIO1 for CadDetected. BTW, it may be for another PR :D Let me try for CadDetected.
@w-ockham : Would you mind explain to me what is B111 in isTransmitting()? Even if it is a hex, then it should be 0xb111. Thanks a lot for your effort.
@w-ockham Could you advise me on the B111? So curious. Thanks a lot :(y)
B111 is binary 111 or 0x07. It should be MODE_CAD instead.
bool LoRaClass::isTransmitting()
{
if ((readRegister(REG_OP_MODE) & B111) == MODE_TX) {
return true;
}
...
This example from @w-ockham has something "not right" too me. https://github.com/w-ockham/arduino-LoRa/blob/master/examples/LoRaCADCallback/LoRaCADCallback.ino
void onCadDone(boolean signalDetected) {
// detect preamble
if (signalDetected) {
Serial.println("Signal detected");
// put the radio into continuous receive mode
LoRa.receive(); <======= This line is likely to clear the current message and only receive the NEXT message.
} else {
// try next activity dectection
LoRa.channelActivityDetection();
}
}
When a CadDetected is detected, LoRa.receive() seems to clear the incoming data? And only receive the next incoming message using Continuous RX. Hence, the receiving node on the right only received HALF of the messages.
By right, after CADDetected and set to Single RX or RX Continous Mode, we should receive the current incoming message.
If I use SingleRX by parsePacket, the size will be 0.
I have been trying to get this code to work for the last few hours, and I was running into the same problem as IOTThinks where only every other packet was being received.
I think this is caused by the LoRa module not switching back to CAD mode properly after entering the receive state (after the call to receive()
in onCadDone()
).
After trying several other things which didn't work, I added a call to idle()
at the start of channelActivityDetection()
:
void LoRaClass::channelActivityDetection(void)
{
idle(); // <-- set state to idle first
writeRegister(REG_DIO_MAPPING_1, 0x80);// DIO0 => CADDONE
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_CAD);
}
This seems to have fixed the problem and CAD is working as expected and I'm now receiving all packets! 😄
@Cangjie103 there are still fixes that need to be addressed on this, please look at the inline comments and fix those before merging.
This PR has been modified, tested and merged and currently is available in the 'master' branch. Please test and check for side effects.
Additionally while reading some of the details on CAD Flow
in the SX1276 datasheet, Pages 43 and specifically 44 I realized there is a point that probably needs clarification. CAD seems to only work to detect a packet preamble.
From the datasheet page 44...
During a CAD the following operations take place:
The radio receiver captures LoRa preamble symbol of data from the channel
. ...If a preamble was detected, clear the interrupt, then initiate the reception by putting the radio in RX single mode or RX continuous mode.
This last line in particular seems to indicate the purpose is to detect if you are able to receive, not if you're able to transmit. Maybe further testing will indicate if both are the case.
This modification adds the following functions. LoRa.onCadDone(callback) : Register the callback function for channel activity detection. LoRa.CAD(void) : Activate channel activity detection mode.