Skip to content

Commit

Permalink
Fix #208: complete the Class C implementation
Browse files Browse the repository at this point in the history
This is a breaking change, because clients previously could use
`LMIC.rxtime` to schedule a receive. This no longer works;
`LMIC.nextRxTime` is used to schedule the receive, and now
`LMIC.rxtime` only is used to report the time of last receive.

But in addition, this adds a new configuration variable,
`LMIC_ENABLE_class_c`, a new API for run-time enabling (if
configured in), and support for starting class C receives at
the appropriate times. This seemed to require an additional receive
buffer, to avoid collisions; and therefore client code that depends
on results showing up in LMIC.frame[] may be rudely surprised.
  • Loading branch information
terrillmoore committed Feb 28, 2022
1 parent 9960bf3 commit 0e5c776
Show file tree
Hide file tree
Showing 12 changed files with 982 additions and 315 deletions.
14 changes: 7 additions & 7 deletions doc/CLASS-C.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ These are working notes for Class C implementation, not really permanent documen
- [x] make this modular (so that we don't make tiny devices carry the extra code footprint)
- [x] add code for enabling / disabling class C mode (I think maybe there's a required uplink to announce that you're in class C)
- [x] define in header file
- [ ] write code - when class C is enabled, need to set a flag and re-evaluate the FSM; in other words, if someone turns on class C while the LMIC is busy, we need to synchronize things. Ditto, I think, for turning things off.
- [ ] modify the radio driver to look for the class C flag on entry and stop reception without crashing.
- [ ] add api for stopping an ongoing reception (for switching from RX2 to TX or RX1)
- [ ] add code for processing class C downlinks
- [ ] add api for starting a class C reception (rework the RX2 start-reception api from class A?)
- [ ] add the code to the various states to start class C reception.
- [x] write code - when class C is enabled, need to set a flag and re-evaluate the FSM; in other words, if someone turns on class C while the LMIC is busy, we need to synchronize things. Ditto, I think, for turning things off.
- [x] distinguish class C reception from Class A or Class B.
- [x] change os_radio() to facilitate stopping ongoing Class C reception for Class A.
- [x] add code for processing class C downlinks
- [x] add API for starting a class C reception
- [x] add the code to the various states to start class C reception.

## Decisions

- Define "RX2 channel" to mean the channel, bandwidth and spreading factor used for class A RX2 downlinks, and for Class C downlinks.
- Further parameterize radio driver so it gets most of its parameters via LMIC.radio.
- We often will say "RX2 channel is open" to mean that the radio is (supposed to be) receiving on the RX2 channel.
- Define "RX2 Window" to be the *time window* for a class A RX2 Window. The spec uses this also to mean "the RX2 channel is receiving" but we need to keep this straight.
- `LMIC_ENABLE_class_c` if non-zero enables the class C code.
Expand Down
75 changes: 40 additions & 35 deletions doc/RadioDriver.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,26 @@
- [`os_radio(RADIO_TX)`](#os_radioradio_tx)
- [`os_radio(RADIO_RX)`](#os_radioradio_rx)
- [`os_radio(RADIO_RXON)`](#os_radioradio_rxon)
- [`os_radio(RADIO_RXON_C)`](#os_radioradio_rxon_c)
- [`os_radio(RADIO_TX_AT)`](#os_radioradio_tx_at)
- [Common parameters](#common-parameters)
- [`LMIC.rps` (IN)](#lmicrps-in)
- [`LMIC.freq` (IN)](#lmicfreq-in)
- [`LMIC.radio.rps` (IN)](#lmicradiorps-in)
- [`LMIC.radio.freq` (IN)](#lmicradiofreq-in)
- [`LMIC.saveIrqFlags` (OUT)](#lmicsaveirqflags-out)
- [`LMIC.osjob` (IN/OUT)](#lmicosjob-inout)
- [`LMIC.radio.pRadioDoneJob` (IN/OUT)](#lmicradiopradiodonejob-inout)
- [Transmit parameters](#transmit-parameters)
- [`LMIC.radio_txpow` (IN)](#lmicradio_txpow-in)
- [`LMIC.frame[]` (IN)](#lmicframe-in)
- [`LMIC.datalen` (IN)](#lmicdatalen-in)
- [`LMIC.radio.txpow` (IN)](#lmicradiotxpow-in)
- [`LMIC.radio.pFrame[]` (IN)](#lmicradiopframe-in)
- [`LMIC.radio.datalen` (IN)](#lmicradiodatalen-in)
- [`LMIC.txend` (IN, OUT)](#lmictxend-in-out)
- [Receive parameters](#receive-parameters)
- [`LMIC.frame[]` (OUT)](#lmicframe-out)
- [`LMIC.datalen` (OUT)](#lmicdatalen-out)
- [`LMIC.rxtime` (IN/OUT)](#lmicrxtime-inout)
- [`LMIC.lbt_ticks` (IN)](#lmiclbt_ticks-in)
- [`LMIC.lbt_dbmax` (IN)](#lmiclbt_dbmax-in)
- [`LMIC.rxsyms` (IN)](#lmicrxsyms-in)
- [`LMIC.noRXIQinversion` (IN)](#lmicnorxiqinversion-in)
- [Receive parameters](#receive-parameters)
- [`LMIC.radio.pFrame[]` (OUT)](#lmicradiopframe-out)
- [`LMIC.radio.dataLen` (OUT)](#lmicradiodatalen-out)
- [`LMIC.radio.rxtime` (IN/OUT)](#lmicradiorxtime-inout)
- [`LMIC.radio.rxsyms` (IN)](#lmicradiorxsyms-in)
- [`LMIC.radio.flags` (IN)](#lmicradioflags-in)
- [`LMIC.snr` (OUT)](#lmicsnr-out)
- [`LMIC.rssi` (OUT)](#lmicrssi-out)

Expand Down Expand Up @@ -68,17 +69,21 @@ When the operation completes, `LMIC.osjob` is scheduled.

### `os_radio(RADIO_RXON)`

The radio is placed in continuous receive mode. If a frame is received, `LMIC.osjob` is scheduled. Continuous receive is canceled by calling [`os_radio(RADIO_RST)`](#os_radioradio_rst).
The radio is placed in continuous receive mode. If a frame is received, `LMIC.osjob` is scheduled. Continuous receive is explicitly canceled by calling [`os_radio(RADIO_RST)`](#os_radioradio_rst) or implicitly by calling any other radio function.

This operation is not supported in FSK mode.

### `os_radio(RADIO_RXON_C)`

This operation is identical to `os_radio(RADIO_RXON)`, but redundant calls are suppressed.

### `os_radio(RADIO_TX_AT)`

This is like `os_radio(RADIO_TX)`, but the transmission is scheduled at `LMIC.txend`.

## Common parameters

### `LMIC.rps` (IN)
### `LMIC.radio.rps` (IN)

This is the "radio parameter setting", and it encodes several radio settings.

Expand All @@ -88,29 +93,29 @@ This is the "radio parameter setting", and it encodes several radio settings.
- CRC enabled/disabled
- Implicit header mode on/off. (If on, receive length must be known in advance.)

### `LMIC.freq` (IN)
### `LMIC.radio.freq` (IN)

This specifies the frequency, in Hertz.

### `LMIC.saveIrqFlags` (OUT)

Updated for LoRa operations only; the IRQ flags at the time of interrupt.

### `LMIC.osjob` (IN/OUT)
### `LMIC.radio.pRadioDoneJob` (IN/OUT)

When asynchronous operations complete, `LMIC.osjob.func` is used as the callback function, and `LMIC.osjob` is used to schedule the work.
When asynchronous operations complete, `LMIC.radio.pRadioDoneJob->func` is used as the callback function, and `LMIC.radio.pRadioDoneJob` is used to schedule the work.

## Transmit parameters

### `LMIC.radio_txpow` (IN)
### `LMIC.radio.txpow` (IN)

This specifies the transmit power in dBm.

### `LMIC.frame[]` (IN)
### `LMIC.radio.pFrame[]` (IN)

The array of data to be sent.

### `LMIC.datalen` (IN)
### `LMIC.radio.datalen` (IN)

The length of the array to be sent.

Expand All @@ -120,37 +125,37 @@ For `RADIO_TX_AT`, an input parameter, for the scheduled TX time.

For all transmissions, updated to the OS time at which the TX end interrupt was recognized.

## Receive parameters
### `LMIC.lbt_ticks` (IN)

### `LMIC.frame[]` (OUT)
How long to monitor for LBT, in OS ticks.

Filled with data received.
### `LMIC.lbt_dbmax` (IN)

### `LMIC.datalen` (OUT)
Maximum RSSI on channel before transmit.

Set to number of bytes received in total.
## Receive parameters

### `LMIC.rxtime` (IN/OUT)
### `LMIC.radio.pFrame[]` (OUT)

Input: When to start receiving, in OS tick time.
Filled with data received.

Output: time of RXDONE interrupt. (Note: FSK timeout doesn't currently set this cell on RX timeout.)
### `LMIC.radio.dataLen` (OUT)

### `LMIC.lbt_ticks` (IN)
Set to number of bytes received in total.

How long to monitor for LBT, in OS ticks.
### `LMIC.radio.rxtime` (IN/OUT)

### `LMIC.lbt_dbmax` (IN)
Input: When to start receiving, in OS tick time. Only used for `os_radio(RADIO_RX)`; not used for continuous receive.

Maximum RSSI on channel before transmit.
Output: time of RXDONE interrupt. (Note: FSK timeout doesn't currently set this cell on RX timeout.)

### `LMIC.rxsyms` (IN)
### `LMIC.radio.rxsyms` (IN)

The timeout in symbols. Only used for `os_radio(RADIO_RX)`; not used for continuous receive.

### `LMIC.noRXIQinversion` (IN)
### `LMIC.radio.flags` (IN)

If true, disable IQ inversion during receive.
If the bit `LMIC_RADIO_FLAGS_NO_RX_IQ_INVERSION` is set, disable IQ inversion during receive.

### `LMIC.snr` (OUT)

Expand Down
4 changes: 2 additions & 2 deletions examples/raw-feather/raw-feather.ino
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ static void tx_func (osjob_t* job);
// Transmit the given string and call the given function afterwards
void tx(const char *str, osjobcb_t func) {
// the radio is probably in RX mode; stop it.
os_radio(RADIO_RST);
os_radio(RADIO_RST, NULL);
// wait a bit so the radio can come out of RX mode
delay(1);

Expand All @@ -199,7 +199,7 @@ void tx(const char *str, osjobcb_t func) {
// Enable rx mode and call func when a packet is received
void rx(osjobcb_t func) {
LMIC.osjob.func = func;
LMIC.rxtime = os_getTime(); // RX _now_
LMIC.nextRxTime = os_getTime(); // RX _now_
// Enable "continuous" RX (e.g. without a timeout, still stops after
// receiving a packet)
os_radio(RADIO_RXON);
Expand Down
2 changes: 1 addition & 1 deletion examples/raw-halconfig/raw-halconfig.ino
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void tx(const char *str, osjobcb_t func) {
// Enable rx mode and call func when a packet is received
void rx(osjobcb_t func) {
LMIC.osjob.func = func;
LMIC.rxtime = os_getTime(); // RX _now_
LMIC.nextRxTime = os_getTime(); // RX _now_
// Enable "continuous" RX (e.g. without a timeout, still stops after
// receiving a packet)
os_radio(RADIO_RXON);
Expand Down
2 changes: 1 addition & 1 deletion examples/raw/raw.ino
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void tx(const char *str, osjobcb_t func) {
// Enable rx mode and call func when a packet is received
void rx(osjobcb_t func) {
LMIC.osjob.func = func;
LMIC.rxtime = os_getTime(); // RX _now_
LMIC.nextRxTime = os_getTime(); // RX _now_
// Enable "continuous" RX (e.g. without a timeout, still stops after
// receiving a packet)
os_radio(RADIO_RXON);
Expand Down
Loading

0 comments on commit 0e5c776

Please sign in to comment.