Skip to content

CAD detection #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed

Conversation

szotsaki
Copy link

@szotsaki szotsaki commented Oct 11, 2017

It's possible to handle LoRa CAD (channel activity detection) the following way via interrupts:

  • Write your interrupt service routine (ISR) which is executed when an IRQ arrives to the pin which is connected to DIO0.
  • Configure ISR in Arduino for LoRa DIO0 pin: LoRa.setInterruptMode(0, LORA_IRQ_MODE_CADDONE)
  • Start CAD: LoRa.cad()
  • Check if valid CAD detected after an IRQ arrived : LoRa.readInterrupts() & LORA_IRQ_FLAG_CAD_DETECTED
  • Clear IRQs to be able to restart CAD process later: LoRa.clearInterrupts(LORA_IRQ_FLAG_CAD_DETECTED | LORA_IRQ_FLAG_CAD_DONE);

I didn't want to add an internal IRQ handling routine (like handleDio0RiseRx) because that would be too slow for an ISR routine or simply not ideal for someone who wants to implement this in his/her own taste.

Fortunately, their values are the same as in RegIrqFlagsMask but in
the code we access register RegIrqFlags.
Made in binary notation to be more easily checkeable against the data
sheet.

This way it's possible to handle CAD (channel activity detection)
the following way:
- setInterruptMode(0, LORA_IRQ_MODE_CADDONE)
- configure interrupt service routine in Arduino for LoRa DIO0 pin
- cad()
- LoRa.readInterrupts() & LORA_IRQ_FLAG_CAD_DETECTED
Many times these functions run in a while(); loop and that causes
a lot of unnecessary writes to registers when nothing happens in
the LoRa chip. Save some time by writing when only it's necessary.
Contrary to the data sheet, it's not possible to change to CAD mode
from e.g. RXSINGLE. Going to STANDBY first makes it happen.
It's required everywhere where the symbol length exceeds 16 ms
The valid range is between 0x11-0xff
@sandeepmistry
Copy link
Owner

@szotsaki thanks for submitting!

Could you please explain the use case for this feature and add an example sketch.

In general, I'm not too keen to expose interrupt flags to the user.

@szotsaki
Copy link
Author

Yes, of course, I'll upload an example in a few days.

Right now the current design closes the implementation of the IRQ handling and there're some problems with it, too. Like it spends way too much time in the ISR. Normally, only a variable assignment should be done there but now a complete, many-line function is written inside (in case of handleDio0RiseRx).

I also think it's better to give the user the freedom how he wants to handle his interrupts. Do we want to create a separate function for RX_TIMEOUT, PAYLOAD_CRC_ERROR, VALID_HEADER, TX_DONE, CAD_DONE, FHSS_CHANGE_CH, and CAD_DETECTED (like now it's done for RX_DONE)? It'd mean a rather big code size increase. What would their function bodies contain?

I think these are the two main reasons I'd support having the user's responsibility to write his interrupt code. However, I accept any good reasoning against my view :).

Some examples for CAD_DONE (any of them could go into the ISR function):

  • restart CAD detection only if CAD_DETECTED is not set;
  • restart CAD detection anyway after 2 seconds of sleep (because of power saving);
  • blink an LED then enter into receive mode if CAD_DETECTED is set.

@szotsaki
Copy link
Author

Sorry for the delay, I uploaded an example how to use the interrupts and CAD detection. I tried to document as much as possible.

@sandeepmistry
Copy link
Owner

Thanks for the updates and clarification.

On first glance the new API's expose too much of the underlying features of the radios to the sketch, so are not consistent with the current library APIs.

@halukmy
Copy link

halukmy commented Mar 12, 2018

@szotsaki where is sample of cad detection? Thanks

@szotsaki
Copy link
Author

It's in commit 6f254b0 (in directory examples/LoRaCADDetectionWithInterrupt).

@halukmy
Copy link

halukmy commented Mar 13, 2018

@szotsaki i cant find it on your repo or anywhere on github :) when will you upload?

@szotsaki
Copy link
Author

It's a pull request so it will be available in the master branch when @sandeepmistry accepts this. If you don't want to wait until then please use the CAD-detection branch in szotsaki/arduino-LoRa fork.

Please, if you find any issues, report it here.

@halukmy
Copy link

halukmy commented Mar 14, 2018

@szotsaki thanks for super cool share!! your the best bro

@halukmy
Copy link

halukmy commented Apr 1, 2018

@szotsaki thanks for awesome repo!

can you share a simple example for cad detection and connection please

thanks bro

@szotsaki
Copy link
Author

szotsaki commented Apr 3, 2018

Please use the CAD-detection branch in szotsaki/arduino-LoRa fork. There you'll find a directory called examples/LoRaCADDetectionWithInterrupt.

@halukmy
Copy link

halukmy commented Apr 3, 2018

Very nice my friend ! i remember i visit there before, i believe together we will create better repo than lorawan:)
is it possible to share an example cad with lora dublex code for other visitors and developers may help?

(https://github.com/sandeepmistry/arduino-LoRa/tree/6f254b02dd087086774937d4bd7ae86de3a8fa82/examples/LoRaDuplex)

Thanks Mr. @szotsaki

@morganrallen
Copy link
Collaborator

morganrallen commented Aug 3, 2018

In trying to test this I was unable to get it to work but I'm really interested in getting CAD support integrated. Things that need to be done or talked about.

  • Resolve current conflict *
  • Use readRegister/writeRegister consistently like the rest of the code
  • Simplify setInterruptMode
  • Make example work without dependencies or include if needed
  • Add a callback handler similar to onReceive, both should be called from a single IRQ handler
  • Add CAD_DONE? This could also be a separate PR, but FWIW my test boards only have DIO0

Nice work so far @szotsaki, look forward to this landing

* I believe this commit contains the conflicting code f5cae9c

@szotsaki szotsaki closed this Aug 11, 2018
@szotsaki szotsaki deleted the CAD-detection branch August 11, 2018 19:08
@szotsaki
Copy link
Author

@morganrallen

I migrated this pull request and all my other, long-pending pull requests from here to my own repo into the master branch (effectively creating a fork of this repository). You can find it here: https://github.com/szotsaki/arduino-LoRa

I use CAD detection successfully so if anything doesn't work for you, please tell me (or open a bug report in my repo) and I'll try to help you.

Resolve current conflict *

Done when merged all branches together into master.

Use readRegister/writeRegister consistently like the rest of the code

Could you please elaborate on this one a bit? I'd like to use common coding standard as much as possible, please point me where I diverged.

Make example work without dependencies or include if needed

I think you mean <util/atomic.h>. Unfortunately, I don't know a better way to check the current value of a volatile variable which can be changed at any moment by an interrupt.

Simplify setInterruptMode

Hmm, unfortunately I don't have anything in my mind right now how I could do that while keeping its flexibility. Do you have anything in mind?

Add a callback handler similar to onReceive, both should be called from a single IRQ handler

In my opinion this is not a good design choice because

  • the interrupt handler function (LoRaClass::handleDio0Rise()) is already too long and
  • there's the possibility to call your own function (via _onReceive) which can be even longer (and you don't necessarily know that it should be really short because it's an implementation detail that it runs in an ISR).
    The problem with that is during an ISR (Interrupt Service Routine) all other interrupts are disabled. This also mean that e.g. millis() and micros() don't get updated while your LoRa code runs.
  • Besides, I don't want to add a separate handleDioXRiseYYY function for RxDone, TxDone, CadDone, RxTimeout, FhssChCh, CadDetected, ValidHeader, CrcError, PllLock, ModeReady, and ClkOut :).

Add CAD_DONE? This could also be a separate PR, but FWIW my test boards only have DIO0

Good news, already added :). Just use the following three-liner (with comments for you):

pinMode(LORA_DIO0_PIN_TO_ARDUINO, INPUT);
setInterruptMode(0 /*DIO0*/, LORA_IRQ_DIO0_CADDONE /*CAD_DONE on DIO0*/);
attachInterrupt(digitalPinToInterrupt(LORA_DIO0_PIN_TO_ARDUINO), your_irq_fn, RISING);

If you have any suggestion how to improve the code, I'm glad to hear that. Thank you for the suggestions so far!

@halukmy An example for CAD detection with interrupts can be found here.

@halukmy
Copy link

halukmy commented Aug 14, 2018

@szotsaki awesomeeeeee, can you share an cad example with us?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants