LoRaWAN end device MAC layer for SX1272 and SX1276. Supports LoRaWAN-1.0 and LoRaWAN-1.1

Dependencies:   sx12xx_hal

Dependents:   LoRaWAN-SanJose_Bootcamp LoRaWAN-grove-cayenne LoRaWAN-classC-demo LoRaWAN-grove-cayenne ... more

radio chip selection

Radio chip driver is not included, because two options are available.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

application project requirements

This library requires mbed TLS to be enabled.
The file mbed_app.json must be present in the project using this library:

{
    "macros": [ "MBEDTLS_CMAC_C" ]
}

regional PHY selection

All end device configuration is done in Commissioning.h, define desired radio frequency band of operation in this header file.
Commissioning.h is located in the application using this library.

end device provisioning

End device is provisioned by editing Commissioning.h in the application which is using this library
To use LoRaWAN-1.0 OTA: make sure LORAWAN_ROOT_APPKEY is undefined.
To use LoRaWAN-1.1 OTA, define LORAWAN_ROOT_APPKEY.
To select OTA operation, define LORAWAN_JOIN_EUI, then LORAWAN_DEVICE_EUI must be defined, along with root key(s).
To select ABP operation, undefine LORAWAN_JOIN_EUI: then define session keys

LoRaWAN 1.0 nameLoRaWAN 1.1 nameComissioning.h defnedescription
OTADevEUIDevEUILORAWAN_DEVICE_EUIuniquely identifies end device
OTAAppEUIJoinEUILORAWAN_JOIN_EUI
OTAAppKeyNwkKeyLORAWAN_ROOT_NWKKEYroot key for network server
OTA(note 1)AppKeyLORAWAN_ROOT_APPKEYroot key for application server
ABPNwkSKey(note 3)LORAWAN_FNwkSIntKeynetwork session key
ABP(note 2)SNwkSIntKeyLORAWAN_SNwkSIntKeymac layer network integrity key
ABP(note 2)NwkSEncKeyLORAWAN_NwkSEncKeynetwork session encryption key
ABP(note 2)FNwkSIntKeyLORAWAN_FNwkSIntKeyforwarding network session integrity key
ABPAppSKeyAppSKeyLORAWAN_APPSKEYapplication session encryption key

(note 1): LoRaWAN-1.0 OTA uses a single root key for both network server and application server.

In LoRaWAN-1.0 OTA: the single root AppKey is used to generate NwkSkey and AppSKey.
(note 2): In LoRaWAN-1.0 (both OTA and ABP) SNwkSIntKey, NwkSEncKey. FNwkSIntKey are of same value and are collectively known as NwkSKey.
(note 3): LoRaWAN-1.0 uses single network session key, LoRaWAN-1.1 uses 3 network session keys. Both use a unique application session key.


In LoRaWAN-1.1 OTA: the root NwkKey is used to generate SNwkSIntKey, NwkSEncKey, FNwkSIntKey
In LoRaWAN-1.1 OTA: the root AppKey is used to generate AppSKey


in ABP mode, the DevAddr, and session keys are fixed (never change), and frame counters never reset to zero.
ABP operation has no concept of: root keys, or DevEUI or JoinEUI/AppEUI.
in OTA mode, the DevAddr and session keys are assigned at join procedure, and frame counters reset at join.

eeprom

This library includes eeprom driver to support non-volatile storage required by LoRaWAN specification.
Currently eeprom is implemented for STM32L1 family and STM32L0 family.
Writing of values are wear-leveled to increase endurance; each write operation circulates across several memory locations. A read operation returns the highest value found. This simple method is used for sequence numbers which only increase.

value nameused in
DevNonceOTAfor Join request (note 1)
RJcount1OTAfor ReJoin Type 1 request
FCntUpABPuplink frame counter
NFCntDownABPdownlink frame counter
AFCntDownABPdownlink frame counter

AFCntDown is only used in LoRaWAN-1.1 when application payload is present in downlink and FPort > 0.
NFCntDown is used in LoRaWAN-1.1 when FPort is zero in downlink or application payload not present.
NFCntDown is the only downlink frame counter used in LoRaWAN-1.0
(note 1) OTA DevNonce is random number in LoRaWAN-1.0, therefore not stored in eeprom. DevNonce in LoRaWAN-1.1 is forever increasing (non-volatile) number upon each join request,.
RJcount0 is only stored in RAM because the value resets upon new session from JoinAccept, therefore not stored in eeprom.
Frame counters in OTA mode reset upon new session in join request, therefore are stored in RAM instead of eeprom for OTA.

radio driver support

When SX127x driver is used, both SX1272 and SX1276 are supported without defining at compile time. The chip is detected at start-up.
Supported radio platforms:


Alternately, when SX126x driver is imported, the SX126xDVK1xAS board is used.

low-speed clock oscillator selection

LoRaWAN uses 32768Hz crystal to permit low-power operation.
However, some mbed targets might revert to low-speed internal oscillator, which is not accurate enough for LoRaWAN operation.
An oscillator check is performed at initialization; program will not start if internal oscillator is used.
To force LSE watch crystal, add to mbed_app.json

{
    "macros": [ "MBEDTLS_CMAC_C" ],
    "target_overrides": {
        "<your-target>": {
            "target.lse_available": true
        }
    }
}
Committer:
Wayne Roberts
Date:
Mon Jun 11 14:09:16 2018 -0700
Revision:
9:fe8e08792ae9
Parent:
8:5a5ea7cc946f
sx126x: update xfer() calls

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 8:5a5ea7cc946f 1 #include "radio.h"
Wayne Roberts 8:5a5ea7cc946f 2 #ifdef SX126x_H
Wayne Roberts 8:5a5ea7cc946f 3 #include "board.h"
Wayne Roberts 8:5a5ea7cc946f 4 #include "SPIu.h"
Wayne Roberts 8:5a5ea7cc946f 5
Wayne Roberts 8:5a5ea7cc946f 6 LowPowerTimer Radio::lpt;
Wayne Roberts 8:5a5ea7cc946f 7 volatile us_timestamp_t dio1at;
Wayne Roberts 8:5a5ea7cc946f 8
Wayne Roberts 8:5a5ea7cc946f 9 #ifdef TARGET_FF_ARDUINO
Wayne Roberts 8:5a5ea7cc946f 10 SPIu spi(D11, D12, D13); // mosi, miso, sclk
Wayne Roberts 8:5a5ea7cc946f 11 //spi, nss, busy, dio1
Wayne Roberts 8:5a5ea7cc946f 12 SX126x Radio::radio(spi, D7, D3, D5);
Wayne Roberts 8:5a5ea7cc946f 13
Wayne Roberts 8:5a5ea7cc946f 14 DigitalOut antswPower(D8);
Wayne Roberts 8:5a5ea7cc946f 15 AnalogIn xtalSel(A3);
Wayne Roberts 8:5a5ea7cc946f 16
Wayne Roberts 8:5a5ea7cc946f 17 DigitalIn chipType(A2);
Wayne Roberts 8:5a5ea7cc946f 18 #define CHIP_TYPE_SX1262 0
Wayne Roberts 8:5a5ea7cc946f 19 #define CHIP_TYPE_SX1261 1
Wayne Roberts 8:5a5ea7cc946f 20
Wayne Roberts 8:5a5ea7cc946f 21 #define PINNAME_NRST A0
Wayne Roberts 8:5a5ea7cc946f 22 #endif /* TARGET_FF_ARDUINO */
Wayne Roberts 8:5a5ea7cc946f 23
Wayne Roberts 8:5a5ea7cc946f 24 const RadioEvents_t* RadioEvents;
Wayne Roberts 8:5a5ea7cc946f 25 PacketParams_t Radio::pp;
Wayne Roberts 8:5a5ea7cc946f 26 RadioModems_t Radio::_m_;
Wayne Roberts 8:5a5ea7cc946f 27
Wayne Roberts 8:5a5ea7cc946f 28 #ifdef TARGET_FF_MORPHO
Wayne Roberts 8:5a5ea7cc946f 29 DigitalOut pc3(PC_3); // debug RX indication, for nucleo boards
Wayne Roberts 8:5a5ea7cc946f 30 #endif /* TARGET_FF_MORPHO */
Wayne Roberts 8:5a5ea7cc946f 31
Wayne Roberts 8:5a5ea7cc946f 32 void Radio::Rx(unsigned timeout)
Wayne Roberts 8:5a5ea7cc946f 33 {
Wayne Roberts 8:5a5ea7cc946f 34 antswPower = 1;
Wayne Roberts 8:5a5ea7cc946f 35
Wayne Roberts 8:5a5ea7cc946f 36 {
Wayne Roberts 8:5a5ea7cc946f 37 uint8_t buf[8];
Wayne Roberts 8:5a5ea7cc946f 38 IrqFlags_t irqEnable;
Wayne Roberts 8:5a5ea7cc946f 39 irqEnable.word = 0;
Wayne Roberts 8:5a5ea7cc946f 40 irqEnable.bits.RxDone = 1;
Wayne Roberts 8:5a5ea7cc946f 41 irqEnable.bits.Timeout = 1;
Wayne Roberts 8:5a5ea7cc946f 42
Wayne Roberts 8:5a5ea7cc946f 43 buf[0] = irqEnable.word >> 8; // enable bits
Wayne Roberts 8:5a5ea7cc946f 44 buf[1] = irqEnable.word; // enable bits
Wayne Roberts 8:5a5ea7cc946f 45 buf[2] = irqEnable.word >> 8; // dio1
Wayne Roberts 8:5a5ea7cc946f 46 buf[3] = irqEnable.word; // dio1
Wayne Roberts 8:5a5ea7cc946f 47 buf[4] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 48 buf[5] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 49 buf[6] = 0; // dio3
Wayne Roberts 8:5a5ea7cc946f 50 buf[7] = 0; // dio3
Wayne Roberts 9:fe8e08792ae9 51 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 52 }
Wayne Roberts 8:5a5ea7cc946f 53
Wayne Roberts 8:5a5ea7cc946f 54 #ifdef TARGET_FF_MORPHO
Wayne Roberts 8:5a5ea7cc946f 55 pc3 = 1;
Wayne Roberts 8:5a5ea7cc946f 56 #endif /* TARGET_FF_MORPHO */
Wayne Roberts 8:5a5ea7cc946f 57 if (timeout == 0)
Wayne Roberts 8:5a5ea7cc946f 58 radio.start_rx(RX_TIMEOUT_CONTINUOUS);
Wayne Roberts 8:5a5ea7cc946f 59 else
Wayne Roberts 8:5a5ea7cc946f 60 radio.start_rx(timeout * RC_TICKS_PER_US);
Wayne Roberts 8:5a5ea7cc946f 61 }
Wayne Roberts 8:5a5ea7cc946f 62
Wayne Roberts 8:5a5ea7cc946f 63 void Radio::Standby()
Wayne Roberts 8:5a5ea7cc946f 64 {
Wayne Roberts 8:5a5ea7cc946f 65 radio.setStandby(STBY_RC); // STBY_XOSC
Wayne Roberts 8:5a5ea7cc946f 66
Wayne Roberts 8:5a5ea7cc946f 67 antswPower = 0;
Wayne Roberts 8:5a5ea7cc946f 68 }
Wayne Roberts 8:5a5ea7cc946f 69
Wayne Roberts 8:5a5ea7cc946f 70 void Radio::Sleep()
Wayne Roberts 8:5a5ea7cc946f 71 {
Wayne Roberts 8:5a5ea7cc946f 72 radio.setSleep(true, false);
Wayne Roberts 8:5a5ea7cc946f 73
Wayne Roberts 8:5a5ea7cc946f 74 antswPower = 0;
Wayne Roberts 8:5a5ea7cc946f 75 }
Wayne Roberts 8:5a5ea7cc946f 76
Wayne Roberts 8:5a5ea7cc946f 77 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
Wayne Roberts 8:5a5ea7cc946f 78 {
Wayne Roberts 8:5a5ea7cc946f 79 SetChannel(hz);
Wayne Roberts 8:5a5ea7cc946f 80 radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm);
Wayne Roberts 9:fe8e08792ae9 81 radio.xfer(OPCODE_SET_TX_CONTINUOUS, 0, 0, NULL);
Wayne Roberts 8:5a5ea7cc946f 82 }
Wayne Roberts 8:5a5ea7cc946f 83
Wayne Roberts 8:5a5ea7cc946f 84 uint32_t Radio::Random(void)
Wayne Roberts 8:5a5ea7cc946f 85 {
Wayne Roberts 8:5a5ea7cc946f 86 uint32_t ret;
Wayne Roberts 8:5a5ea7cc946f 87
Wayne Roberts 8:5a5ea7cc946f 88 radio.start_rx(RX_TIMEOUT_CONTINUOUS);
Wayne Roberts 8:5a5ea7cc946f 89
Wayne Roberts 8:5a5ea7cc946f 90 ret = radio.readReg(REG_ADDR_RANDOM, 4);
Wayne Roberts 8:5a5ea7cc946f 91
Wayne Roberts 8:5a5ea7cc946f 92 Standby();
Wayne Roberts 8:5a5ea7cc946f 93
Wayne Roberts 8:5a5ea7cc946f 94 return ret;
Wayne Roberts 8:5a5ea7cc946f 95 }
Wayne Roberts 8:5a5ea7cc946f 96
Wayne Roberts 8:5a5ea7cc946f 97 bool Radio::CheckRfFrequency(unsigned hz)
Wayne Roberts 8:5a5ea7cc946f 98 {
Wayne Roberts 8:5a5ea7cc946f 99 return true;
Wayne Roberts 8:5a5ea7cc946f 100 }
Wayne Roberts 8:5a5ea7cc946f 101
Wayne Roberts 8:5a5ea7cc946f 102 void Radio::SetChannel(unsigned hz)
Wayne Roberts 8:5a5ea7cc946f 103 {
Wayne Roberts 8:5a5ea7cc946f 104 radio.setMHz(hz / 1000000.0);
Wayne Roberts 8:5a5ea7cc946f 105 }
Wayne Roberts 8:5a5ea7cc946f 106
Wayne Roberts 8:5a5ea7cc946f 107 void Radio::SetRxConfig(
Wayne Roberts 8:5a5ea7cc946f 108 RadioModems_t modem,
Wayne Roberts 8:5a5ea7cc946f 109 uint32_t bandwidth,
Wayne Roberts 8:5a5ea7cc946f 110 uint32_t datarate,
Wayne Roberts 8:5a5ea7cc946f 111 uint8_t coderate,
Wayne Roberts 8:5a5ea7cc946f 112 uint32_t bandwidthAfc,
Wayne Roberts 8:5a5ea7cc946f 113 uint16_t preambleLen,
Wayne Roberts 8:5a5ea7cc946f 114 uint16_t symbTimeout,
Wayne Roberts 8:5a5ea7cc946f 115 bool fixLen,
Wayne Roberts 8:5a5ea7cc946f 116 uint8_t payloadLen,
Wayne Roberts 8:5a5ea7cc946f 117 bool crcOn,
Wayne Roberts 8:5a5ea7cc946f 118 bool iqInverted)
Wayne Roberts 8:5a5ea7cc946f 119 {
Wayne Roberts 8:5a5ea7cc946f 120 uint8_t buf[8];
Wayne Roberts 8:5a5ea7cc946f 121
Wayne Roberts 8:5a5ea7cc946f 122 if (modem == MODEM_FSK)
Wayne Roberts 8:5a5ea7cc946f 123 buf[0] = PACKET_TYPE_GFSK;
Wayne Roberts 8:5a5ea7cc946f 124 else
Wayne Roberts 8:5a5ea7cc946f 125 buf[0] = PACKET_TYPE_LORA;
Wayne Roberts 8:5a5ea7cc946f 126
Wayne Roberts 9:fe8e08792ae9 127 radio.xfer(OPCODE_SET_PACKET_TYPE, 1, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 128
Wayne Roberts 8:5a5ea7cc946f 129 buf[0] = 0; // TX base address
Wayne Roberts 8:5a5ea7cc946f 130 buf[1] = 0; // RX base address
Wayne Roberts 9:fe8e08792ae9 131 radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 132
Wayne Roberts 8:5a5ea7cc946f 133 if (modem == MODEM_FSK) {
Wayne Roberts 8:5a5ea7cc946f 134 FSKConfig(bandwidth, datarate, 0, preambleLen, fixLen, crcOn);
Wayne Roberts 8:5a5ea7cc946f 135
Wayne Roberts 8:5a5ea7cc946f 136 pp.gfsk.PayloadLength = payloadLen;
Wayne Roberts 8:5a5ea7cc946f 137
Wayne Roberts 8:5a5ea7cc946f 138 memcpy(buf, pp.buf, 8);
Wayne Roberts 9:fe8e08792ae9 139 radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 140 } else if (modem == MODEM_LORA) {
Wayne Roberts 8:5a5ea7cc946f 141 LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn, iqInverted);
Wayne Roberts 8:5a5ea7cc946f 142
Wayne Roberts 8:5a5ea7cc946f 143 pp.lora.PayloadLength = payloadLen;
Wayne Roberts 8:5a5ea7cc946f 144
Wayne Roberts 8:5a5ea7cc946f 145 memcpy(buf, pp.buf, 6);
Wayne Roberts 9:fe8e08792ae9 146 radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 147
Wayne Roberts 8:5a5ea7cc946f 148 buf[0] = symbTimeout;
Wayne Roberts 9:fe8e08792ae9 149 radio.xfer(OPCODE_SET_LORA_SYMBOL_TIMEOUT, 1, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 150 }
Wayne Roberts 8:5a5ea7cc946f 151
Wayne Roberts 8:5a5ea7cc946f 152 {
Wayne Roberts 8:5a5ea7cc946f 153 IrqFlags_t irqEnable;
Wayne Roberts 8:5a5ea7cc946f 154 irqEnable.word = 0;
Wayne Roberts 8:5a5ea7cc946f 155 irqEnable.bits.RxDone = 1;
Wayne Roberts 8:5a5ea7cc946f 156 irqEnable.bits.Timeout = 1;
Wayne Roberts 8:5a5ea7cc946f 157
Wayne Roberts 8:5a5ea7cc946f 158 buf[0] = irqEnable.word >> 8; // enable bits
Wayne Roberts 8:5a5ea7cc946f 159 buf[1] = irqEnable.word; // enable bits
Wayne Roberts 8:5a5ea7cc946f 160 buf[2] = irqEnable.word >> 8; // dio1
Wayne Roberts 8:5a5ea7cc946f 161 buf[3] = irqEnable.word; // dio1
Wayne Roberts 8:5a5ea7cc946f 162 buf[4] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 163 buf[5] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 164 buf[6] = 0; // dio3
Wayne Roberts 8:5a5ea7cc946f 165 buf[7] = 0; // dio3
Wayne Roberts 9:fe8e08792ae9 166 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 167 }
Wayne Roberts 8:5a5ea7cc946f 168
Wayne Roberts 8:5a5ea7cc946f 169 } // ..SetRxConfig()
Wayne Roberts 8:5a5ea7cc946f 170
Wayne Roberts 8:5a5ea7cc946f 171 void Radio::FSKConfig(
Wayne Roberts 8:5a5ea7cc946f 172 uint32_t bandwidth,
Wayne Roberts 8:5a5ea7cc946f 173 uint32_t datarate,
Wayne Roberts 8:5a5ea7cc946f 174 uint32_t fdev,
Wayne Roberts 8:5a5ea7cc946f 175 uint32_t preambleLen,
Wayne Roberts 8:5a5ea7cc946f 176 bool fixLen,
Wayne Roberts 8:5a5ea7cc946f 177 bool crcOn)
Wayne Roberts 8:5a5ea7cc946f 178 {
Wayne Roberts 8:5a5ea7cc946f 179 ModulationParams_t mp;
Wayne Roberts 8:5a5ea7cc946f 180 uint32_t u32;
Wayne Roberts 8:5a5ea7cc946f 181
Wayne Roberts 9:fe8e08792ae9 182 u32 = 32 * (XTAL_FREQ_HZ / datarate);
Wayne Roberts 9:fe8e08792ae9 183 mp.gfsk.bitrateHi = u32 >> 16; // param1
Wayne Roberts 9:fe8e08792ae9 184 mp.gfsk.bitrateMid = u32 >> 8; // param2
Wayne Roberts 9:fe8e08792ae9 185 mp.gfsk.bitrateLo = u32; // param3
Wayne Roberts 8:5a5ea7cc946f 186 mp.gfsk.PulseShape = GFSK_SHAPE_BT1_0; // param4
Wayne Roberts 8:5a5ea7cc946f 187 // param5:
Wayne Roberts 8:5a5ea7cc946f 188 if (bandwidth < 5800)
Wayne Roberts 9:fe8e08792ae9 189 mp.gfsk.bandwidth = GFSK_RX_BW_4800;
Wayne Roberts 8:5a5ea7cc946f 190 else if (bandwidth < 7300)
Wayne Roberts 9:fe8e08792ae9 191 mp.gfsk.bandwidth = GFSK_RX_BW_5800;
Wayne Roberts 8:5a5ea7cc946f 192 else if (bandwidth < 9700)
Wayne Roberts 9:fe8e08792ae9 193 mp.gfsk.bandwidth = GFSK_RX_BW_7300;
Wayne Roberts 8:5a5ea7cc946f 194 else if (bandwidth < 11700)
Wayne Roberts 9:fe8e08792ae9 195 mp.gfsk.bandwidth = GFSK_RX_BW_9700;
Wayne Roberts 8:5a5ea7cc946f 196 else if (bandwidth < 14600)
Wayne Roberts 9:fe8e08792ae9 197 mp.gfsk.bandwidth = GFSK_RX_BW_11700;
Wayne Roberts 8:5a5ea7cc946f 198 else if (bandwidth < 19500)
Wayne Roberts 9:fe8e08792ae9 199 mp.gfsk.bandwidth = GFSK_RX_BW_14600;
Wayne Roberts 8:5a5ea7cc946f 200 else if (bandwidth < 23400)
Wayne Roberts 9:fe8e08792ae9 201 mp.gfsk.bandwidth = GFSK_RX_BW_19500;
Wayne Roberts 8:5a5ea7cc946f 202 else if (bandwidth < 29300)
Wayne Roberts 9:fe8e08792ae9 203 mp.gfsk.bandwidth = GFSK_RX_BW_23400;
Wayne Roberts 8:5a5ea7cc946f 204 else if (bandwidth < 39000)
Wayne Roberts 9:fe8e08792ae9 205 mp.gfsk.bandwidth = GFSK_RX_BW_29300;
Wayne Roberts 8:5a5ea7cc946f 206 else if (bandwidth < 46900)
Wayne Roberts 9:fe8e08792ae9 207 mp.gfsk.bandwidth = GFSK_RX_BW_39000;
Wayne Roberts 8:5a5ea7cc946f 208 else if (bandwidth < 58600)
Wayne Roberts 9:fe8e08792ae9 209 mp.gfsk.bandwidth = GFSK_RX_BW_46900;
Wayne Roberts 8:5a5ea7cc946f 210 else if (bandwidth < 78200)
Wayne Roberts 9:fe8e08792ae9 211 mp.gfsk.bandwidth = GFSK_RX_BW_58600;
Wayne Roberts 8:5a5ea7cc946f 212 else if (bandwidth < 93800)
Wayne Roberts 9:fe8e08792ae9 213 mp.gfsk.bandwidth = GFSK_RX_BW_78200;
Wayne Roberts 8:5a5ea7cc946f 214 else if (bandwidth < 117300)
Wayne Roberts 9:fe8e08792ae9 215 mp.gfsk.bandwidth = GFSK_RX_BW_93800;
Wayne Roberts 8:5a5ea7cc946f 216 else if (bandwidth < 156200)
Wayne Roberts 9:fe8e08792ae9 217 mp.gfsk.bandwidth = GFSK_RX_BW_117300;
Wayne Roberts 8:5a5ea7cc946f 218 else if (bandwidth < 187200)
Wayne Roberts 9:fe8e08792ae9 219 mp.gfsk.bandwidth = GFSK_RX_BW_156200;
Wayne Roberts 8:5a5ea7cc946f 220 else if (bandwidth < 234300)
Wayne Roberts 9:fe8e08792ae9 221 mp.gfsk.bandwidth = GFSK_RX_BW_187200;
Wayne Roberts 8:5a5ea7cc946f 222 else if (bandwidth < 312000)
Wayne Roberts 9:fe8e08792ae9 223 mp.gfsk.bandwidth = GFSK_RX_BW_234300;
Wayne Roberts 8:5a5ea7cc946f 224 else if (bandwidth < 373600)
Wayne Roberts 9:fe8e08792ae9 225 mp.gfsk.bandwidth = GFSK_RX_BW_312000;
Wayne Roberts 8:5a5ea7cc946f 226 else if (bandwidth < 467000)
Wayne Roberts 9:fe8e08792ae9 227 mp.gfsk.bandwidth = GFSK_RX_BW_373600;
Wayne Roberts 8:5a5ea7cc946f 228 else
Wayne Roberts 9:fe8e08792ae9 229 mp.gfsk.bandwidth = GFSK_RX_BW_467000;
Wayne Roberts 8:5a5ea7cc946f 230
Wayne Roberts 8:5a5ea7cc946f 231 if (fdev > 0) {
Wayne Roberts 8:5a5ea7cc946f 232 u32 = fdev / FREQ_STEP;
Wayne Roberts 8:5a5ea7cc946f 233 mp.gfsk.fdevHi = u32 >> 16; // param6
Wayne Roberts 8:5a5ea7cc946f 234 mp.gfsk.fdevMid = u32 >> 8; // param7
Wayne Roberts 8:5a5ea7cc946f 235 mp.gfsk.fdevLo = u32; // param8
Wayne Roberts 8:5a5ea7cc946f 236 }
Wayne Roberts 8:5a5ea7cc946f 237
Wayne Roberts 9:fe8e08792ae9 238 radio.xfer(OPCODE_SET_MODULATION_PARAMS, 8, 0, mp.buf);
Wayne Roberts 8:5a5ea7cc946f 239
Wayne Roberts 8:5a5ea7cc946f 240
Wayne Roberts 8:5a5ea7cc946f 241 pp.gfsk.PreambleLengthHi = preambleLen >> 8;
Wayne Roberts 8:5a5ea7cc946f 242 pp.gfsk.PreambleLengthLo = preambleLen;
Wayne Roberts 8:5a5ea7cc946f 243 pp.gfsk.PreambleDetectorLength = GFSK_PREAMBLE_DETECTOR_LENGTH_16BITS;
Wayne Roberts 8:5a5ea7cc946f 244 pp.gfsk.SyncWordLength = 24; // 0xC194C1
Wayne Roberts 8:5a5ea7cc946f 245 pp.gfsk.AddrComp = 0;
Wayne Roberts 8:5a5ea7cc946f 246 pp.gfsk.PacketType = fixLen;
Wayne Roberts 8:5a5ea7cc946f 247 if (crcOn)
Wayne Roberts 8:5a5ea7cc946f 248 pp.gfsk.CRCType = GFSK_CRC_2_BYTE;
Wayne Roberts 8:5a5ea7cc946f 249 else
Wayne Roberts 8:5a5ea7cc946f 250 pp.gfsk.CRCType = GFSK_CRC_OFF;
Wayne Roberts 8:5a5ea7cc946f 251 }
Wayne Roberts 8:5a5ea7cc946f 252
Wayne Roberts 8:5a5ea7cc946f 253 void Radio::LoRaConfig(
Wayne Roberts 8:5a5ea7cc946f 254 uint32_t bandwidth,
Wayne Roberts 8:5a5ea7cc946f 255 uint8_t datarate,
Wayne Roberts 8:5a5ea7cc946f 256 uint8_t coderate,
Wayne Roberts 8:5a5ea7cc946f 257 uint16_t preambleLen,
Wayne Roberts 8:5a5ea7cc946f 258 bool fixLen,
Wayne Roberts 8:5a5ea7cc946f 259 bool crcOn,
Wayne Roberts 8:5a5ea7cc946f 260 bool iqInverted)
Wayne Roberts 8:5a5ea7cc946f 261 {
Wayne Roberts 8:5a5ea7cc946f 262 ModulationParams_t mp;
Wayne Roberts 8:5a5ea7cc946f 263 float sp, khz;
Wayne Roberts 8:5a5ea7cc946f 264
Wayne Roberts 8:5a5ea7cc946f 265 mp.lora.spreadingFactor = datarate; // param1
Wayne Roberts 8:5a5ea7cc946f 266 mp.lora.bandwidth = bandwidth + 4; // param2
Wayne Roberts 8:5a5ea7cc946f 267 mp.lora.codingRate = coderate; // param3
Wayne Roberts 8:5a5ea7cc946f 268
Wayne Roberts 8:5a5ea7cc946f 269 switch (mp.lora.bandwidth) {
Wayne Roberts 8:5a5ea7cc946f 270 case LORA_BW_7: khz = 7.81; break;
Wayne Roberts 8:5a5ea7cc946f 271 case LORA_BW_10: khz = 10.42; break;
Wayne Roberts 8:5a5ea7cc946f 272 case LORA_BW_15: khz = 15.625; break;
Wayne Roberts 8:5a5ea7cc946f 273 case LORA_BW_20: khz = 20.83; break;
Wayne Roberts 8:5a5ea7cc946f 274 case LORA_BW_31: khz = 31.25; break;
Wayne Roberts 8:5a5ea7cc946f 275 case LORA_BW_41: khz = 41.67; break;
Wayne Roberts 8:5a5ea7cc946f 276 case LORA_BW_62: khz = 62.5; break;
Wayne Roberts 8:5a5ea7cc946f 277 case LORA_BW_125: khz = 125; break;
Wayne Roberts 8:5a5ea7cc946f 278 case LORA_BW_250: khz = 250; break;
Wayne Roberts 8:5a5ea7cc946f 279 case LORA_BW_500: khz = 500; break;
Wayne Roberts 8:5a5ea7cc946f 280 default: khz = 0; break;
Wayne Roberts 8:5a5ea7cc946f 281 }
Wayne Roberts 8:5a5ea7cc946f 282 sp = (1 << mp.lora.spreadingFactor) / khz;
Wayne Roberts 8:5a5ea7cc946f 283 /* TCXO dependent */
Wayne Roberts 8:5a5ea7cc946f 284 if (sp > 16)
Wayne Roberts 8:5a5ea7cc946f 285 mp.lora.LowDatarateOptimize = 1; // param4
Wayne Roberts 8:5a5ea7cc946f 286 else
Wayne Roberts 8:5a5ea7cc946f 287 mp.lora.LowDatarateOptimize = 0; // param4
Wayne Roberts 8:5a5ea7cc946f 288
Wayne Roberts 9:fe8e08792ae9 289 radio.xfer(OPCODE_SET_MODULATION_PARAMS, 4, 0, mp.buf);
Wayne Roberts 8:5a5ea7cc946f 290
Wayne Roberts 8:5a5ea7cc946f 291 pp.lora.PreambleLengthHi = preambleLen >> 8;
Wayne Roberts 8:5a5ea7cc946f 292 pp.lora.PreambleLengthLo = preambleLen;
Wayne Roberts 8:5a5ea7cc946f 293 pp.lora.HeaderType = fixLen;
Wayne Roberts 8:5a5ea7cc946f 294 pp.lora.CRCType = crcOn;
Wayne Roberts 8:5a5ea7cc946f 295 pp.lora.InvertIQ = iqInverted;
Wayne Roberts 8:5a5ea7cc946f 296 }
Wayne Roberts 8:5a5ea7cc946f 297
Wayne Roberts 8:5a5ea7cc946f 298 void Radio::SetTxConfig(
Wayne Roberts 8:5a5ea7cc946f 299 RadioModems_t modem,
Wayne Roberts 8:5a5ea7cc946f 300 int8_t dbm,
Wayne Roberts 8:5a5ea7cc946f 301 uint32_t fdev,
Wayne Roberts 8:5a5ea7cc946f 302 uint32_t bandwidth,
Wayne Roberts 8:5a5ea7cc946f 303 uint32_t datarate,
Wayne Roberts 8:5a5ea7cc946f 304 uint8_t coderate,
Wayne Roberts 8:5a5ea7cc946f 305 uint16_t preambleLen,
Wayne Roberts 8:5a5ea7cc946f 306 bool fixLen,
Wayne Roberts 8:5a5ea7cc946f 307 bool crcOn,
Wayne Roberts 8:5a5ea7cc946f 308 bool iqInverted)
Wayne Roberts 8:5a5ea7cc946f 309 {
Wayne Roberts 8:5a5ea7cc946f 310 uint8_t buf[8];
Wayne Roberts 8:5a5ea7cc946f 311
Wayne Roberts 8:5a5ea7cc946f 312 radio.set_tx_dbm(chipType == CHIP_TYPE_SX1262, dbm);
Wayne Roberts 8:5a5ea7cc946f 313
Wayne Roberts 8:5a5ea7cc946f 314 if (modem == MODEM_FSK)
Wayne Roberts 8:5a5ea7cc946f 315 buf[0] = PACKET_TYPE_GFSK;
Wayne Roberts 8:5a5ea7cc946f 316 else
Wayne Roberts 8:5a5ea7cc946f 317 buf[0] = PACKET_TYPE_LORA;
Wayne Roberts 8:5a5ea7cc946f 318
Wayne Roberts 9:fe8e08792ae9 319 radio.xfer(OPCODE_SET_PACKET_TYPE, 1, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 320
Wayne Roberts 8:5a5ea7cc946f 321
Wayne Roberts 8:5a5ea7cc946f 322 buf[0] = 0; // TX base address
Wayne Roberts 8:5a5ea7cc946f 323 buf[1] = 0; // RX base address
Wayne Roberts 9:fe8e08792ae9 324 radio.xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 325
Wayne Roberts 8:5a5ea7cc946f 326 if (modem == MODEM_FSK) {
Wayne Roberts 8:5a5ea7cc946f 327 FSKConfig(bandwidth, datarate, fdev, preambleLen, fixLen, crcOn);
Wayne Roberts 8:5a5ea7cc946f 328 } else if (modem == MODEM_LORA) {
Wayne Roberts 8:5a5ea7cc946f 329 LoRaConfig(bandwidth, datarate, coderate, preambleLen, fixLen, crcOn, iqInverted);
Wayne Roberts 8:5a5ea7cc946f 330 }
Wayne Roberts 8:5a5ea7cc946f 331
Wayne Roberts 8:5a5ea7cc946f 332 {
Wayne Roberts 8:5a5ea7cc946f 333 IrqFlags_t irqEnable;
Wayne Roberts 8:5a5ea7cc946f 334 irqEnable.word = 0;
Wayne Roberts 8:5a5ea7cc946f 335 irqEnable.bits.TxDone = 1;
Wayne Roberts 8:5a5ea7cc946f 336 irqEnable.bits.Timeout = 1;
Wayne Roberts 8:5a5ea7cc946f 337
Wayne Roberts 8:5a5ea7cc946f 338 buf[0] = irqEnable.word >> 8; // enable bits
Wayne Roberts 8:5a5ea7cc946f 339 buf[1] = irqEnable.word; // enable bits
Wayne Roberts 8:5a5ea7cc946f 340 buf[2] = irqEnable.word >> 8; // dio1
Wayne Roberts 8:5a5ea7cc946f 341 buf[3] = irqEnable.word; // dio1
Wayne Roberts 8:5a5ea7cc946f 342 buf[4] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 343 buf[5] = 0; // dio2
Wayne Roberts 8:5a5ea7cc946f 344 buf[6] = 0; // dio3
Wayne Roberts 8:5a5ea7cc946f 345 buf[7] = 0; // dio3
Wayne Roberts 9:fe8e08792ae9 346 radio.xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 347 }
Wayne Roberts 8:5a5ea7cc946f 348
Wayne Roberts 8:5a5ea7cc946f 349 _m_ = modem;
Wayne Roberts 8:5a5ea7cc946f 350 /* SetPacketParams written at Send() where payloadLength provided */
Wayne Roberts 8:5a5ea7cc946f 351
Wayne Roberts 8:5a5ea7cc946f 352 antswPower = 1;
Wayne Roberts 8:5a5ea7cc946f 353 } // ..SetTxConfig()
Wayne Roberts 8:5a5ea7cc946f 354
Wayne Roberts 8:5a5ea7cc946f 355 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
Wayne Roberts 8:5a5ea7cc946f 356 {
Wayne Roberts 8:5a5ea7cc946f 357 uint8_t buf[8];
Wayne Roberts 8:5a5ea7cc946f 358
Wayne Roberts 8:5a5ea7cc946f 359 if (_m_ == MODEM_FSK) {
Wayne Roberts 8:5a5ea7cc946f 360 pp.gfsk.PayloadLength = size;
Wayne Roberts 8:5a5ea7cc946f 361
Wayne Roberts 8:5a5ea7cc946f 362 memcpy(buf, pp.buf, 8);
Wayne Roberts 9:fe8e08792ae9 363 radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 364 } else if (_m_ == MODEM_LORA) {
Wayne Roberts 8:5a5ea7cc946f 365 pp.lora.PayloadLength = size;
Wayne Roberts 8:5a5ea7cc946f 366
Wayne Roberts 8:5a5ea7cc946f 367 memcpy(buf, pp.buf, 6);
Wayne Roberts 9:fe8e08792ae9 368 radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 369 }
Wayne Roberts 8:5a5ea7cc946f 370
Wayne Roberts 8:5a5ea7cc946f 371 if (maxListenTime > 0) {
Wayne Roberts 8:5a5ea7cc946f 372 int rssi;
Wayne Roberts 8:5a5ea7cc946f 373 us_timestamp_t startAt, chFreeAt, now;
Wayne Roberts 8:5a5ea7cc946f 374 radio.start_rx(RX_TIMEOUT_CONTINUOUS);
Wayne Roberts 8:5a5ea7cc946f 375 startAt = lpt.read_us();
Wayne Roberts 8:5a5ea7cc946f 376 Lstart:
Wayne Roberts 8:5a5ea7cc946f 377 do {
Wayne Roberts 8:5a5ea7cc946f 378 now = lpt.read_us();
Wayne Roberts 8:5a5ea7cc946f 379 if ((now - startAt) > maxListenTime) {
Wayne Roberts 8:5a5ea7cc946f 380 return -1;
Wayne Roberts 8:5a5ea7cc946f 381 }
Wayne Roberts 9:fe8e08792ae9 382 radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
Wayne Roberts 8:5a5ea7cc946f 383 rssi = buf[1] / -2;
Wayne Roberts 8:5a5ea7cc946f 384 } while (rssi > rssiThresh);
Wayne Roberts 8:5a5ea7cc946f 385 chFreeAt = lpt.read_us();
Wayne Roberts 8:5a5ea7cc946f 386 do {
Wayne Roberts 8:5a5ea7cc946f 387 now = lpt.read_us();
Wayne Roberts 9:fe8e08792ae9 388 radio.xfer(OPCODE_GET_RSSIINST, 0, 2, buf);
Wayne Roberts 8:5a5ea7cc946f 389 rssi = buf[1] / -2;
Wayne Roberts 8:5a5ea7cc946f 390 if (rssi > rssiThresh) {
Wayne Roberts 8:5a5ea7cc946f 391 goto Lstart;
Wayne Roberts 8:5a5ea7cc946f 392 }
Wayne Roberts 8:5a5ea7cc946f 393 } while ((now - chFreeAt) < channelFreeTime);
Wayne Roberts 8:5a5ea7cc946f 394 }
Wayne Roberts 8:5a5ea7cc946f 395
Wayne Roberts 8:5a5ea7cc946f 396 radio.start_tx(size);
Wayne Roberts 8:5a5ea7cc946f 397
Wayne Roberts 8:5a5ea7cc946f 398 return 0;
Wayne Roberts 8:5a5ea7cc946f 399 } // ..Send()
Wayne Roberts 8:5a5ea7cc946f 400
Wayne Roberts 8:5a5ea7cc946f 401 void Radio::SetRxMaxPayloadLength(RadioModems_t modem, uint8_t max)
Wayne Roberts 8:5a5ea7cc946f 402 {
Wayne Roberts 8:5a5ea7cc946f 403 uint8_t buf[8];
Wayne Roberts 8:5a5ea7cc946f 404
Wayne Roberts 8:5a5ea7cc946f 405 if (modem == MODEM_FSK) {
Wayne Roberts 8:5a5ea7cc946f 406 pp.gfsk.PayloadLength = max;
Wayne Roberts 8:5a5ea7cc946f 407 memcpy(buf, pp.buf, 8);
Wayne Roberts 9:fe8e08792ae9 408 radio.xfer(OPCODE_SET_PACKET_PARAMS, 8, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 409 } else if (modem == MODEM_LORA) {
Wayne Roberts 8:5a5ea7cc946f 410 pp.lora.PayloadLength = max;
Wayne Roberts 8:5a5ea7cc946f 411 memcpy(buf, pp.buf, 6);
Wayne Roberts 9:fe8e08792ae9 412 radio.xfer(OPCODE_SET_PACKET_PARAMS, 6, 0, buf);
Wayne Roberts 8:5a5ea7cc946f 413 }
Wayne Roberts 8:5a5ea7cc946f 414 }
Wayne Roberts 8:5a5ea7cc946f 415
Wayne Roberts 8:5a5ea7cc946f 416 void Radio::dio1_top_half()
Wayne Roberts 8:5a5ea7cc946f 417 {
Wayne Roberts 8:5a5ea7cc946f 418 dio1at = lpt.read_us();
Wayne Roberts 8:5a5ea7cc946f 419
Wayne Roberts 8:5a5ea7cc946f 420 if (radio.chipMode == CHIPMODE_TX) {
Wayne Roberts 8:5a5ea7cc946f 421 /* TxDone handling requires low latency */
Wayne Roberts 8:5a5ea7cc946f 422 if (RadioEvents->TxDone) {
Wayne Roberts 8:5a5ea7cc946f 423 RadioEvents->TxDone(dio1at);
Wayne Roberts 8:5a5ea7cc946f 424 }
Wayne Roberts 8:5a5ea7cc946f 425 }
Wayne Roberts 8:5a5ea7cc946f 426 #ifdef TARGET_FF_MORPHO
Wayne Roberts 8:5a5ea7cc946f 427 else
Wayne Roberts 8:5a5ea7cc946f 428 pc3 = 0;
Wayne Roberts 8:5a5ea7cc946f 429 #endif /* TARGET_FF_MORPHO */
Wayne Roberts 8:5a5ea7cc946f 430 }
Wayne Roberts 8:5a5ea7cc946f 431
Wayne Roberts 8:5a5ea7cc946f 432 void Radio::timeout_callback(bool tx)
Wayne Roberts 8:5a5ea7cc946f 433 {
Wayne Roberts 8:5a5ea7cc946f 434 if (!tx) {
Wayne Roberts 8:5a5ea7cc946f 435 if (RadioEvents->RxTimeout)
Wayne Roberts 8:5a5ea7cc946f 436 RadioEvents->RxTimeout();
Wayne Roberts 8:5a5ea7cc946f 437 #ifdef TARGET_FF_MORPHO
Wayne Roberts 8:5a5ea7cc946f 438 pc3 = 0;
Wayne Roberts 8:5a5ea7cc946f 439 #endif /* TARGET_FF_MORPHO */
Wayne Roberts 8:5a5ea7cc946f 440 } // else TODO tx timeout
Wayne Roberts 8:5a5ea7cc946f 441 }
Wayne Roberts 8:5a5ea7cc946f 442
Wayne Roberts 8:5a5ea7cc946f 443 void Radio::rx_done(uint8_t size, float rssi, float snr)
Wayne Roberts 8:5a5ea7cc946f 444 {
Wayne Roberts 8:5a5ea7cc946f 445 RadioEvents->RxDone(radio.rx_buf, size, rssi, snr, dio1at);
Wayne Roberts 8:5a5ea7cc946f 446 }
Wayne Roberts 8:5a5ea7cc946f 447
Wayne Roberts 8:5a5ea7cc946f 448 void Radio::Init(const RadioEvents_t* e)
Wayne Roberts 8:5a5ea7cc946f 449 {
Wayne Roberts 8:5a5ea7cc946f 450 radio.txDone = NULL;
Wayne Roberts 8:5a5ea7cc946f 451 radio.rxDone = rx_done;
Wayne Roberts 8:5a5ea7cc946f 452 radio.timeout = timeout_callback;
Wayne Roberts 8:5a5ea7cc946f 453 radio.dio1_topHalf = dio1_top_half;
Wayne Roberts 8:5a5ea7cc946f 454
Wayne Roberts 8:5a5ea7cc946f 455 RadioEvents = e;
Wayne Roberts 8:5a5ea7cc946f 456 lpt.start();
Wayne Roberts 8:5a5ea7cc946f 457
Wayne Roberts 8:5a5ea7cc946f 458 radio.SetDIO2AsRfSwitchCtrl(1);
Wayne Roberts 8:5a5ea7cc946f 459 }
Wayne Roberts 8:5a5ea7cc946f 460
Wayne Roberts 8:5a5ea7cc946f 461 void Radio::UserContext()
Wayne Roberts 8:5a5ea7cc946f 462 {
Wayne Roberts 8:5a5ea7cc946f 463 radio.service();
Wayne Roberts 8:5a5ea7cc946f 464 }
Wayne Roberts 8:5a5ea7cc946f 465
Wayne Roberts 8:5a5ea7cc946f 466 void Radio::SetPublicNetwork(bool en)
Wayne Roberts 8:5a5ea7cc946f 467 {
Wayne Roberts 8:5a5ea7cc946f 468 uint16_t ppg;
Wayne Roberts 8:5a5ea7cc946f 469
Wayne Roberts 8:5a5ea7cc946f 470 if (en)
Wayne Roberts 8:5a5ea7cc946f 471 ppg = 0x3444;
Wayne Roberts 8:5a5ea7cc946f 472 else
Wayne Roberts 8:5a5ea7cc946f 473 ppg = 0x1424;
Wayne Roberts 8:5a5ea7cc946f 474
Wayne Roberts 8:5a5ea7cc946f 475 radio.writeReg(REG_ADDR_LORA_SYNC, ppg, 2);
Wayne Roberts 8:5a5ea7cc946f 476 }
Wayne Roberts 8:5a5ea7cc946f 477
Wayne Roberts 8:5a5ea7cc946f 478 void Radio::PrintStatus()
Wayne Roberts 8:5a5ea7cc946f 479 {
Wayne Roberts 8:5a5ea7cc946f 480 uint8_t buf[4];
Wayne Roberts 8:5a5ea7cc946f 481 status_t status;
Wayne Roberts 8:5a5ea7cc946f 482 IrqFlags_t irqFlags;
Wayne Roberts 9:fe8e08792ae9 483 radio.xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf);
Wayne Roberts 8:5a5ea7cc946f 484 irqFlags.word = buf[1] << 8;
Wayne Roberts 8:5a5ea7cc946f 485 irqFlags.word |= buf[2];
Wayne Roberts 8:5a5ea7cc946f 486
Wayne Roberts 8:5a5ea7cc946f 487 printf("dio1:%u irqFlags:%04x\r\n", radio.getDIO1(), irqFlags.word);
Wayne Roberts 9:fe8e08792ae9 488 radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 8:5a5ea7cc946f 489 radio.PrintChipStatus(status);
Wayne Roberts 8:5a5ea7cc946f 490 }
Wayne Roberts 8:5a5ea7cc946f 491
Wayne Roberts 8:5a5ea7cc946f 492 #endif /* ..SX126x_H */