Hardware Abstraction Layer, permitting any LoRa application to use any LoRa radio chip

Dependents:   alarm_slave alarm_master lora_p2p lorawan1v1 ... more

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
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 SX1280, then import sx1280 driver into your program.
if you're using LR1110, then import LR1110 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.
If you're using Type1SJ select target DISCO_L072CZ_LRWAN1 and import sx126x driver into your program.

Pin assigned to arduino LoRa radio shield form-factor

Committer:
Wayne Roberts
Date:
Wed Sep 11 13:23:37 2019 -0700
Revision:
15:e1c04ec39aa4
Parent:
14:94993ae5b164
Parent:
13:a354f82d12d9
Child:
16:34de2ab7eb32
DioPin_top_half() callback to permit scheduling Radio::service() from ISR rather than main loop

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:9c052ff8dd6a 1 #include "radio.h"
Wayne Roberts 0:9c052ff8dd6a 2 #ifdef SX127x_H
Wayne Roberts 0:9c052ff8dd6a 3
Wayne Roberts 0:9c052ff8dd6a 4 LowPowerTimer Radio::lpt;
Wayne Roberts 0:9c052ff8dd6a 5
Wayne Roberts 0:9c052ff8dd6a 6 void Radio::Sleep()
Wayne Roberts 0:9c052ff8dd6a 7 {
Wayne Roberts 0:9c052ff8dd6a 8 radio.set_opmode(RF_OPMODE_SLEEP);
Wayne Roberts 0:9c052ff8dd6a 9 }
Wayne Roberts 0:9c052ff8dd6a 10
Wayne Roberts 0:9c052ff8dd6a 11 void Radio::Standby()
Wayne Roberts 0:9c052ff8dd6a 12 {
Wayne Roberts 0:9c052ff8dd6a 13 radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 14 }
Wayne Roberts 0:9c052ff8dd6a 15
Wayne Roberts 0:9c052ff8dd6a 16 bool Radio::CheckRfFrequency(unsigned hz)
Wayne Roberts 0:9c052ff8dd6a 17 {
Wayne Roberts 0:9c052ff8dd6a 18 return true;
Wayne Roberts 0:9c052ff8dd6a 19 }
Wayne Roberts 0:9c052ff8dd6a 20
Wayne Roberts 0:9c052ff8dd6a 21 void Radio::SetChannel(unsigned hz)
Wayne Roberts 0:9c052ff8dd6a 22 {
Wayne Roberts 0:9c052ff8dd6a 23 radio.set_frf_MHz(hz / 1000000.0);
Wayne Roberts 0:9c052ff8dd6a 24 }
Wayne Roberts 0:9c052ff8dd6a 25
Wayne Roberts 0:9c052ff8dd6a 26 float Radio::getFrfMHz()
Wayne Roberts 0:9c052ff8dd6a 27 {
Wayne Roberts 0:9c052ff8dd6a 28 return radio.get_frf_MHz();
Wayne Roberts 0:9c052ff8dd6a 29 }
Wayne Roberts 0:9c052ff8dd6a 30
Wayne Roberts 0:9c052ff8dd6a 31 LowPowerTimeout TxTimeoutEvent;
Wayne Roberts 0:9c052ff8dd6a 32
Wayne Roberts 0:9c052ff8dd6a 33 void SX1272OnTimeoutIrq( void )
Wayne Roberts 0:9c052ff8dd6a 34 {
Wayne Roberts 0:9c052ff8dd6a 35 Radio::radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 36 }
Wayne Roberts 0:9c052ff8dd6a 37
Wayne Roberts 0:9c052ff8dd6a 38 void Radio::SetTxContinuousWave(unsigned hz, int8_t dbm, unsigned timeout_us)
Wayne Roberts 0:9c052ff8dd6a 39 {
Wayne Roberts 0:9c052ff8dd6a 40 Radio::SetChannel(hz);
Wayne Roberts 0:9c052ff8dd6a 41 /* TODO: fsk enable, set regPacketConfig2.datamode */
Wayne Roberts 0:9c052ff8dd6a 42 set_tx_dbm(dbm);
Wayne Roberts 0:9c052ff8dd6a 43 TxTimeoutEvent.attach_us(SX1272OnTimeoutIrq, timeout_us);
Wayne Roberts 0:9c052ff8dd6a 44 radio.set_opmode(RF_OPMODE_TRANSMITTER);
Wayne Roberts 0:9c052ff8dd6a 45 }
Wayne Roberts 0:9c052ff8dd6a 46
Wayne Roberts 0:9c052ff8dd6a 47 #define LORA_MAC_PRIVATE_SYNCWORD 0x12
Wayne Roberts 0:9c052ff8dd6a 48 #define LORA_MAC_PUBLIC_SYNCWORD 0x34
Wayne Roberts 0:9c052ff8dd6a 49 void Radio::SetPublicNetwork(bool en)
Wayne Roberts 0:9c052ff8dd6a 50 {
Wayne Roberts 0:9c052ff8dd6a 51 radio.write_reg(REG_LR_SYNC_BYTE, en ? LORA_MAC_PUBLIC_SYNCWORD : LORA_MAC_PRIVATE_SYNCWORD);
Wayne Roberts 0:9c052ff8dd6a 52 }
Wayne Roberts 0:9c052ff8dd6a 53
Wayne Roberts 0:9c052ff8dd6a 54 uint32_t Radio::Random(void)
Wayne Roberts 0:9c052ff8dd6a 55 {
Wayne Roberts 0:9c052ff8dd6a 56 uint32_t ret = 0;
Wayne Roberts 0:9c052ff8dd6a 57 unsigned i;
Wayne Roberts 0:9c052ff8dd6a 58
Wayne Roberts 0:9c052ff8dd6a 59 radio.set_opmode(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 60 for (i = 0; i < 32; i++) {
Wayne Roberts 0:9c052ff8dd6a 61 uint32_t r;
Wayne Roberts 0:9c052ff8dd6a 62 wait_us(3000);
Wayne Roberts 0:9c052ff8dd6a 63 r = radio.read_reg(REG_LR_WIDEBAND_RSSI);
Wayne Roberts 0:9c052ff8dd6a 64 r <<= ((i & 7) << 2);
Wayne Roberts 0:9c052ff8dd6a 65 ret ^= r;
Wayne Roberts 0:9c052ff8dd6a 66 }
Wayne Roberts 0:9c052ff8dd6a 67
Wayne Roberts 0:9c052ff8dd6a 68 return ret;
Wayne Roberts 0:9c052ff8dd6a 69 }
Wayne Roberts 0:9c052ff8dd6a 70
Wayne Roberts 0:9c052ff8dd6a 71 void Radio::LoRaPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn, bool invIQ)
Wayne Roberts 0:9c052ff8dd6a 72 {
Wayne Roberts 0:9c052ff8dd6a 73 lora.RegPreamble = preambleLen;
Wayne Roberts 0:9c052ff8dd6a 74 radio.write_u16(REG_LR_PREAMBLEMSB, lora.RegPreamble);
Wayne Roberts 0:9c052ff8dd6a 75
Wayne Roberts 0:9c052ff8dd6a 76 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 77 lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn = fixLen;
Wayne Roberts 0:9c052ff8dd6a 78 lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 79 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 80 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 81 lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn = fixLen;
Wayne Roberts 0:9c052ff8dd6a 82 lora.RegModemConfig.sx1272bits.RxPayloadCrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 83 }
Wayne Roberts 0:9c052ff8dd6a 84
Wayne Roberts 0:9c052ff8dd6a 85 radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
Wayne Roberts 0:9c052ff8dd6a 86
Wayne Roberts 0:9c052ff8dd6a 87 lora.invert_tx(invIQ);
Wayne Roberts 0:9c052ff8dd6a 88 lora.invert_rx(invIQ);
Wayne Roberts 0:9c052ff8dd6a 89 }
Wayne Roberts 0:9c052ff8dd6a 90
Wayne Roberts 0:9c052ff8dd6a 91 void Radio::GFSKModemConfig(unsigned bps, unsigned bw_hz, unsigned fdev_hz)
Wayne Roberts 0:9c052ff8dd6a 92 {
Wayne Roberts 0:9c052ff8dd6a 93 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 94 fsk.enable(false);
Wayne Roberts 0:9c052ff8dd6a 95
Wayne Roberts 0:9c052ff8dd6a 96 fsk.set_bitrate(bps);
Wayne Roberts 0:9c052ff8dd6a 97
Wayne Roberts 0:9c052ff8dd6a 98 fsk.set_rx_dcc_bw_hz(bw_hz, 0);
Wayne Roberts 0:9c052ff8dd6a 99 fsk.set_rx_dcc_bw_hz(bw_hz * 1.5, 1);
Wayne Roberts 0:9c052ff8dd6a 100
Wayne Roberts 0:9c052ff8dd6a 101 fsk.set_tx_fdev_hz(fdev_hz);
Wayne Roberts 0:9c052ff8dd6a 102 }
Wayne Roberts 0:9c052ff8dd6a 103
Wayne Roberts 0:9c052ff8dd6a 104
Wayne Roberts 0:9c052ff8dd6a 105 void Radio::GFSKPacketConfig(unsigned preambleLen, bool fixLen, bool crcOn)
Wayne Roberts 0:9c052ff8dd6a 106 {
Wayne Roberts 0:9c052ff8dd6a 107 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 108 fsk.enable(false);
Wayne Roberts 0:9c052ff8dd6a 109
Wayne Roberts 0:9c052ff8dd6a 110 radio.write_u16(REG_FSK_PREAMBLEMSB, preambleLen);
Wayne Roberts 0:9c052ff8dd6a 111
Wayne Roberts 0:9c052ff8dd6a 112 fsk.RegPktConfig1.bits.PacketFormatVariable = fixLen ? 0 : 1;
Wayne Roberts 0:9c052ff8dd6a 113 fsk.RegPktConfig1.bits.CrcOn = crcOn;
Wayne Roberts 0:9c052ff8dd6a 114 radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
Wayne Roberts 0:9c052ff8dd6a 115 }
Wayne Roberts 0:9c052ff8dd6a 116
Wayne Roberts 13:a354f82d12d9 117 void Radio::SetLoRaSymbolTimeout(uint16_t symbs)
Wayne Roberts 0:9c052ff8dd6a 118 {
Wayne Roberts 0:9c052ff8dd6a 119 if (!radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 120 lora.enable();
Wayne Roberts 0:9c052ff8dd6a 121
Wayne Roberts 13:a354f82d12d9 122 radio.write_reg(REG_LR_SYMBTIMEOUTLSB, symbs & 0xff);
Wayne Roberts 13:a354f82d12d9 123 symbs >>= 8;
Wayne Roberts 13:a354f82d12d9 124 lora.RegModemConfig2.sx1272bits.SymbTimeoutMsb = symbs;
Wayne Roberts 0:9c052ff8dd6a 125 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 126 }
Wayne Roberts 0:9c052ff8dd6a 127
Wayne Roberts 0:9c052ff8dd6a 128 void Radio::LoRaModemConfig(unsigned bwKHz, uint8_t sf, uint8_t coderate)
Wayne Roberts 0:9c052ff8dd6a 129 {
Wayne Roberts 0:9c052ff8dd6a 130 float sp;
Wayne Roberts 0:9c052ff8dd6a 131 if (!radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 0:9c052ff8dd6a 132 lora.enable();
Wayne Roberts 0:9c052ff8dd6a 133
Wayne Roberts 0:9c052ff8dd6a 134 lora.RegModemConfig2.sx1276bits.SpreadingFactor = sf;
Wayne Roberts 0:9c052ff8dd6a 135 radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
Wayne Roberts 0:9c052ff8dd6a 136
Wayne Roberts 0:9c052ff8dd6a 137 lora.setBw_KHz(bwKHz);
Wayne Roberts 0:9c052ff8dd6a 138
Wayne Roberts 0:9c052ff8dd6a 139 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 140 lora.RegModemConfig.sx1276bits.CodingRate = coderate;
Wayne Roberts 0:9c052ff8dd6a 141
Wayne Roberts 0:9c052ff8dd6a 142 sp = lora.get_symbol_period();
Wayne Roberts 0:9c052ff8dd6a 143 if (sp > 16)
Wayne Roberts 0:9c052ff8dd6a 144 lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
Wayne Roberts 0:9c052ff8dd6a 145 else
Wayne Roberts 0:9c052ff8dd6a 146 lora.RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
Wayne Roberts 0:9c052ff8dd6a 147
Wayne Roberts 0:9c052ff8dd6a 148 radio.write_reg(REG_LR_MODEMCONFIG3, lora.RegModemConfig3.octet);
Wayne Roberts 0:9c052ff8dd6a 149 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 150 lora.RegModemConfig.sx1272bits.CodingRate = coderate;
Wayne Roberts 0:9c052ff8dd6a 151
Wayne Roberts 0:9c052ff8dd6a 152 if (lora.get_symbol_period() > 16)
Wayne Roberts 0:9c052ff8dd6a 153 lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
Wayne Roberts 0:9c052ff8dd6a 154 else
Wayne Roberts 0:9c052ff8dd6a 155 lora.RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
Wayne Roberts 0:9c052ff8dd6a 156 }
Wayne Roberts 0:9c052ff8dd6a 157 radio.write_reg(REG_LR_MODEMCONFIG, lora.RegModemConfig.octet);
Wayne Roberts 0:9c052ff8dd6a 158 }
Wayne Roberts 0:9c052ff8dd6a 159
Wayne Roberts 1:e79b0a55135f 160 void Radio::SetRxMaxPayloadLength(uint8_t max)
Wayne Roberts 0:9c052ff8dd6a 161 {
Wayne Roberts 1:e79b0a55135f 162 if (radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 1:e79b0a55135f 163 radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, max);
Wayne Roberts 1:e79b0a55135f 164 else
Wayne Roberts 1:e79b0a55135f 165 radio.write_reg(REG_FSK_PAYLOADLENGTH, max);
Wayne Roberts 0:9c052ff8dd6a 166 }
Wayne Roberts 0:9c052ff8dd6a 167
Wayne Roberts 6:b7bbf31e06e4 168 void Radio::SetFixedPayloadLength(uint8_t len)
Wayne Roberts 6:b7bbf31e06e4 169 {
Wayne Roberts 6:b7bbf31e06e4 170 lora.RegPayloadLength = len;
Wayne Roberts 6:b7bbf31e06e4 171 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
Wayne Roberts 6:b7bbf31e06e4 172 }
Wayne Roberts 6:b7bbf31e06e4 173
Wayne Roberts 0:9c052ff8dd6a 174 const RadioEvents_t* RadioEvents;
Wayne Roberts 0:9c052ff8dd6a 175
Wayne Roberts 0:9c052ff8dd6a 176
Wayne Roberts 0:9c052ff8dd6a 177 volatile struct pe {
Wayne Roberts 0:9c052ff8dd6a 178 uint8_t dio0 : 1;
Wayne Roberts 0:9c052ff8dd6a 179 uint8_t dio1 : 1;
Wayne Roberts 0:9c052ff8dd6a 180 uint8_t txing : 1;
Wayne Roberts 0:9c052ff8dd6a 181 } pinEvent;
Wayne Roberts 0:9c052ff8dd6a 182
Wayne Roberts 0:9c052ff8dd6a 183 void
Wayne Roberts 0:9c052ff8dd6a 184 Radio::dio0UserContext()
Wayne Roberts 0:9c052ff8dd6a 185 {
Wayne Roberts 0:9c052ff8dd6a 186 service_action_e act = lora.service();
Wayne Roberts 0:9c052ff8dd6a 187
Wayne Roberts 0:9c052ff8dd6a 188 if (!pinEvent.txing) {
Wayne Roberts 0:9c052ff8dd6a 189 if (act == SERVICE_READ_FIFO && RadioEvents->RxDone) {
Wayne Roberts 0:9c052ff8dd6a 190 int8_t rssi;
Wayne Roberts 0:9c052ff8dd6a 191 float snr = lora.RegPktSnrValue / 4.0;
Wayne Roberts 0:9c052ff8dd6a 192
Wayne Roberts 0:9c052ff8dd6a 193 rssi = lora.get_pkt_rssi();
Wayne Roberts 0:9c052ff8dd6a 194 if (snr < 0)
Wayne Roberts 0:9c052ff8dd6a 195 rssi += snr;
Wayne Roberts 0:9c052ff8dd6a 196 RadioEvents->RxDone(lora.RegRxNbBytes, rssi, snr);
Wayne Roberts 0:9c052ff8dd6a 197 }
Wayne Roberts 0:9c052ff8dd6a 198 } else if (act == SERVICE_TX_DONE) {
Wayne Roberts 0:9c052ff8dd6a 199 if (RadioEvents->TxDone_botHalf)
Wayne Roberts 0:9c052ff8dd6a 200 RadioEvents->TxDone_botHalf();
Wayne Roberts 0:9c052ff8dd6a 201 }
Wayne Roberts 0:9c052ff8dd6a 202 }
Wayne Roberts 0:9c052ff8dd6a 203
Wayne Roberts 0:9c052ff8dd6a 204 volatile us_timestamp_t Radio::irqAt;
Wayne Roberts 0:9c052ff8dd6a 205
Wayne Roberts 0:9c052ff8dd6a 206 void Radio::dio0isr()
Wayne Roberts 0:9c052ff8dd6a 207 {
Wayne Roberts 0:9c052ff8dd6a 208 irqAt = lpt.read_us();
Wayne Roberts 14:94993ae5b164 209
Wayne Roberts 14:94993ae5b164 210 if (RadioEvents->DioPin_top_half)
Wayne Roberts 14:94993ae5b164 211 RadioEvents->DioPin_top_half();
Wayne Roberts 0:9c052ff8dd6a 212
Wayne Roberts 0:9c052ff8dd6a 213 if (pinEvent.txing) {
Wayne Roberts 0:9c052ff8dd6a 214 /* TxDone handling requires low latency */
Wayne Roberts 0:9c052ff8dd6a 215 if (RadioEvents->TxDone_topHalf)
Wayne Roberts 0:9c052ff8dd6a 216 RadioEvents->TxDone_topHalf(); // TODO in callback read irqAt for timestamp of interrupt
Wayne Roberts 0:9c052ff8dd6a 217
Wayne Roberts 0:9c052ff8dd6a 218 }
Wayne Roberts 0:9c052ff8dd6a 219
Wayne Roberts 0:9c052ff8dd6a 220 pinEvent.dio0 = 1;
Wayne Roberts 0:9c052ff8dd6a 221 }
Wayne Roberts 0:9c052ff8dd6a 222
Wayne Roberts 0:9c052ff8dd6a 223 void Radio::dio1UserContext()
Wayne Roberts 0:9c052ff8dd6a 224 {
Wayne Roberts 0:9c052ff8dd6a 225 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
Wayne Roberts 0:9c052ff8dd6a 226
Wayne Roberts 0:9c052ff8dd6a 227 if (RadioEvents->RxTimeout)
Wayne Roberts 0:9c052ff8dd6a 228 RadioEvents->RxTimeout();
Wayne Roberts 0:9c052ff8dd6a 229
Wayne Roberts 0:9c052ff8dd6a 230 radio.write_reg(REG_LR_IRQFLAGS, 0x80); // ensure RxTimeout is cleared
Wayne Roberts 0:9c052ff8dd6a 231 }
Wayne Roberts 0:9c052ff8dd6a 232
Wayne Roberts 0:9c052ff8dd6a 233 void Radio::dio1isr()
Wayne Roberts 0:9c052ff8dd6a 234 {
Wayne Roberts 0:9c052ff8dd6a 235 pinEvent.dio1 = 1;
Wayne Roberts 14:94993ae5b164 236
Wayne Roberts 14:94993ae5b164 237 if (RadioEvents->DioPin_top_half)
Wayne Roberts 14:94993ae5b164 238 RadioEvents->DioPin_top_half();
Wayne Roberts 0:9c052ff8dd6a 239 }
Wayne Roberts 0:9c052ff8dd6a 240
Wayne Roberts 13:a354f82d12d9 241 void Radio::Init(const RadioEvents_t* e, unsigned spi_hz)
Wayne Roberts 0:9c052ff8dd6a 242 {
Wayne Roberts 13:a354f82d12d9 243 radio.m_spi.frequency(spi_hz);
Wayne Roberts 13:a354f82d12d9 244
Wayne Roberts 8:0518c6e68b79 245 while (radio.dio0.read() || radio.dio1.read()) {
Wayne Roberts 8:0518c6e68b79 246 radio.write_reg(REG_LR_IRQFLAGS, 0xff); // clear stagnant interrupt
Wayne Roberts 8:0518c6e68b79 247 }
Wayne Roberts 0:9c052ff8dd6a 248 dio0.rise(dio0isr);
Wayne Roberts 0:9c052ff8dd6a 249 dio1.rise(dio1isr);
Wayne Roberts 0:9c052ff8dd6a 250
Wayne Roberts 0:9c052ff8dd6a 251 radio.rf_switch = rfsw_callback;
Wayne Roberts 0:9c052ff8dd6a 252 boardInit();
Wayne Roberts 0:9c052ff8dd6a 253
Wayne Roberts 0:9c052ff8dd6a 254 RadioEvents = e;
Wayne Roberts 0:9c052ff8dd6a 255 lpt.start();
Wayne Roberts 0:9c052ff8dd6a 256 }
Wayne Roberts 0:9c052ff8dd6a 257
Wayne Roberts 7:ba81f66e56d1 258 float Radio::GetRssiInst()
Wayne Roberts 7:ba81f66e56d1 259 {
Wayne Roberts 7:ba81f66e56d1 260 return lora.get_current_rssi();
Wayne Roberts 7:ba81f66e56d1 261 }
Wayne Roberts 7:ba81f66e56d1 262
Wayne Roberts 0:9c052ff8dd6a 263 int Radio::Send(uint8_t size, timestamp_t maxListenTime, timestamp_t channelFreeTime, int rssiThresh)
Wayne Roberts 0:9c052ff8dd6a 264 {
Wayne Roberts 0:9c052ff8dd6a 265 if (radio.RegOpMode.bits.Mode == RF_OPMODE_SLEEP) {
Wayne Roberts 0:9c052ff8dd6a 266 radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 0:9c052ff8dd6a 267 wait_us(1000);
Wayne Roberts 0:9c052ff8dd6a 268 }
Wayne Roberts 0:9c052ff8dd6a 269 radio.write_reg(REG_LR_IRQFLAGS, 0x08); // ensure TxDone is cleared
Wayne Roberts 0:9c052ff8dd6a 270 lora.RegPayloadLength = size;
Wayne Roberts 0:9c052ff8dd6a 271 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
Wayne Roberts 0:9c052ff8dd6a 272
Wayne Roberts 0:9c052ff8dd6a 273 if (maxListenTime > 0) {
Wayne Roberts 0:9c052ff8dd6a 274 int rssi;
Wayne Roberts 0:9c052ff8dd6a 275 us_timestamp_t startAt, chFreeAt, now;
Wayne Roberts 0:9c052ff8dd6a 276 lora.start_rx(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 277 startAt = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 278 Lstart:
Wayne Roberts 0:9c052ff8dd6a 279 do {
Wayne Roberts 0:9c052ff8dd6a 280 now = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 281 if ((now - startAt) > maxListenTime) {
Wayne Roberts 0:9c052ff8dd6a 282 return -1;
Wayne Roberts 0:9c052ff8dd6a 283 }
Wayne Roberts 0:9c052ff8dd6a 284 rssi = lora.get_current_rssi();
Wayne Roberts 0:9c052ff8dd6a 285 } while (rssi > rssiThresh);
Wayne Roberts 0:9c052ff8dd6a 286 chFreeAt = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 287 do {
Wayne Roberts 0:9c052ff8dd6a 288 now = lpt.read_us();
Wayne Roberts 0:9c052ff8dd6a 289 rssi = lora.get_current_rssi();
Wayne Roberts 0:9c052ff8dd6a 290 if (rssi > rssiThresh) {
Wayne Roberts 0:9c052ff8dd6a 291 goto Lstart;
Wayne Roberts 0:9c052ff8dd6a 292 }
Wayne Roberts 0:9c052ff8dd6a 293 } while ((now - chFreeAt) < channelFreeTime);
Wayne Roberts 0:9c052ff8dd6a 294 }
Wayne Roberts 0:9c052ff8dd6a 295
Wayne Roberts 0:9c052ff8dd6a 296 lora.start_tx(size);
Wayne Roberts 0:9c052ff8dd6a 297 pinEvent.txing = 1;
Wayne Roberts 0:9c052ff8dd6a 298
Wayne Roberts 0:9c052ff8dd6a 299 return 0;
Wayne Roberts 0:9c052ff8dd6a 300 }
Wayne Roberts 0:9c052ff8dd6a 301
Wayne Roberts 0:9c052ff8dd6a 302 void Radio::Rx(unsigned timeout)
Wayne Roberts 0:9c052ff8dd6a 303 {
Wayne Roberts 0:9c052ff8dd6a 304 if (timeout == 0) {
Wayne Roberts 0:9c052ff8dd6a 305 lora.start_rx(RF_OPMODE_RECEIVER);
Wayne Roberts 0:9c052ff8dd6a 306 } else {
Wayne Roberts 0:9c052ff8dd6a 307 lora.start_rx(RF_OPMODE_RECEIVER_SINGLE);
Wayne Roberts 0:9c052ff8dd6a 308 }
Wayne Roberts 0:9c052ff8dd6a 309
Wayne Roberts 0:9c052ff8dd6a 310 pinEvent.txing = 0;
Wayne Roberts 0:9c052ff8dd6a 311 }
Wayne Roberts 0:9c052ff8dd6a 312
Wayne Roberts 0:9c052ff8dd6a 313
Wayne Roberts 0:9c052ff8dd6a 314 void Radio::ocp(uint8_t ma)
Wayne Roberts 0:9c052ff8dd6a 315 {
Wayne Roberts 0:9c052ff8dd6a 316 if (ma < 130)
Wayne Roberts 0:9c052ff8dd6a 317 radio.RegOcp.bits.OcpTrim = (ma - 45) / 5;
Wayne Roberts 0:9c052ff8dd6a 318 else
Wayne Roberts 0:9c052ff8dd6a 319 radio.RegOcp.bits.OcpTrim = (ma + 30) / 10;
Wayne Roberts 0:9c052ff8dd6a 320 radio.write_reg(REG_OCP, radio.RegOcp.octet);
Wayne Roberts 0:9c052ff8dd6a 321
Wayne Roberts 0:9c052ff8dd6a 322 radio.RegOcp.octet = radio.read_reg(REG_OCP);
Wayne Roberts 0:9c052ff8dd6a 323 if (radio.RegOcp.bits.OcpTrim < 16)
Wayne Roberts 0:9c052ff8dd6a 324 ma = 45 + (5 * radio.RegOcp.bits.OcpTrim);
Wayne Roberts 0:9c052ff8dd6a 325 else if (radio.RegOcp.bits.OcpTrim < 28)
Wayne Roberts 0:9c052ff8dd6a 326 ma = (10 * radio.RegOcp.bits.OcpTrim) - 30;
Wayne Roberts 0:9c052ff8dd6a 327 else
Wayne Roberts 0:9c052ff8dd6a 328 ma = 240;
Wayne Roberts 0:9c052ff8dd6a 329 }
Wayne Roberts 0:9c052ff8dd6a 330
Wayne Roberts 0:9c052ff8dd6a 331
Wayne Roberts 0:9c052ff8dd6a 332 #if 0
Wayne Roberts 0:9c052ff8dd6a 333 void Radio::PrintStatus()
Wayne Roberts 0:9c052ff8dd6a 334 {
Wayne Roberts 0:9c052ff8dd6a 335 #ifdef MAC_DEBUG
Wayne Roberts 0:9c052ff8dd6a 336 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
Wayne Roberts 0:9c052ff8dd6a 337 switch (radio.RegOpMode.bits.Mode) {
Wayne Roberts 0:9c052ff8dd6a 338 case RF_OPMODE_SLEEP: printf("SLEEP "); break;
Wayne Roberts 0:9c052ff8dd6a 339 case RF_OPMODE_STANDBY: printf("STBY "); break;
Wayne Roberts 0:9c052ff8dd6a 340 case RF_OPMODE_SYNTHESIZER_TX: printf("FSTX "); break;
Wayne Roberts 0:9c052ff8dd6a 341 case RF_OPMODE_TRANSMITTER: printf("TX "); break;
Wayne Roberts 0:9c052ff8dd6a 342 case RF_OPMODE_SYNTHESIZER_RX: printf("FSRX "); break;
Wayne Roberts 0:9c052ff8dd6a 343 case RF_OPMODE_RECEIVER: printf("RXC "); break;
Wayne Roberts 0:9c052ff8dd6a 344 case RF_OPMODE_RECEIVER_SINGLE: printf("RXS "); break;
Wayne Roberts 0:9c052ff8dd6a 345 case RF_OPMODE_CAD: printf("CAD "); break;
Wayne Roberts 0:9c052ff8dd6a 346 }
Wayne Roberts 0:9c052ff8dd6a 347
Wayne Roberts 0:9c052ff8dd6a 348 printf("dio:%u:%u opmode:%02x %.2fMHz sf%ubw%u ", radio.dio0.read(), radio.dio1.read(), radio.RegOpMode.octet, radio.get_frf_MHz(), lora.getSf(), lora.getBw());
Wayne Roberts 0:9c052ff8dd6a 349 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
Wayne Roberts 0:9c052ff8dd6a 350 printf("irqFlags:%02x\r\n", lora.RegIrqFlags.octet);
Wayne Roberts 0:9c052ff8dd6a 351 #endif /* MAC_DEBUG */
Wayne Roberts 0:9c052ff8dd6a 352 }
Wayne Roberts 0:9c052ff8dd6a 353 #endif /* if 0 */
Wayne Roberts 0:9c052ff8dd6a 354
Wayne Roberts 0:9c052ff8dd6a 355 #ifdef DUTY_ENABLE
Wayne Roberts 0:9c052ff8dd6a 356 us_timestamp_t
Wayne Roberts 0:9c052ff8dd6a 357 Radio::TimeOnAir(RadioModems_t m, uint8_t pktLen)
Wayne Roberts 0:9c052ff8dd6a 358 {
Wayne Roberts 0:9c052ff8dd6a 359 uint32_t airTime = 0;
Wayne Roberts 0:9c052ff8dd6a 360
Wayne Roberts 0:9c052ff8dd6a 361 switch (m)
Wayne Roberts 0:9c052ff8dd6a 362 {
Wayne Roberts 0:9c052ff8dd6a 363 case MODEM_FSK:
Wayne Roberts 0:9c052ff8dd6a 364 {
Wayne Roberts 0:9c052ff8dd6a 365 /* TODO
Wayne Roberts 0:9c052ff8dd6a 366 airTime = round( ( 8 * ( SX1272.Settings.Fsk.PreambleLen +
Wayne Roberts 0:9c052ff8dd6a 367 ( ( SX1272Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) +
Wayne Roberts 0:9c052ff8dd6a 368 ( ( SX1272.Settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) +
Wayne Roberts 0:9c052ff8dd6a 369 ( ( ( SX1272Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) +
Wayne Roberts 0:9c052ff8dd6a 370 pktLen +
Wayne Roberts 0:9c052ff8dd6a 371 ( ( SX1272.Settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 372 SX1272.Settings.Fsk.Datarate ) * 1e3 );
Wayne Roberts 0:9c052ff8dd6a 373 */
Wayne Roberts 0:9c052ff8dd6a 374 }
Wayne Roberts 0:9c052ff8dd6a 375 break;
Wayne Roberts 0:9c052ff8dd6a 376 case MODEM_LORA:
Wayne Roberts 0:9c052ff8dd6a 377 {
Wayne Roberts 0:9c052ff8dd6a 378 double bw = 0.0;
Wayne Roberts 0:9c052ff8dd6a 379 uint8_t fixLen, bandwidth, LowDatarateOptimize, coderate, crcOn ;
Wayne Roberts 0:9c052ff8dd6a 380 if (radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 381 coderate = lora.RegModemConfig.sx1276bits.CodingRate;
Wayne Roberts 0:9c052ff8dd6a 382 LowDatarateOptimize = lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 383 fixLen = lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 384 bandwidth = lora.RegModemConfig.sx1276bits.Bw - 7;
Wayne Roberts 0:9c052ff8dd6a 385 crcOn = lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 386 } else if (radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 387 coderate = lora.RegModemConfig.sx1272bits.CodingRate;
Wayne Roberts 0:9c052ff8dd6a 388 LowDatarateOptimize = lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 389 fixLen = lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 390 bandwidth = lora.RegModemConfig.sx1272bits.Bw;
Wayne Roberts 0:9c052ff8dd6a 391 crcOn = lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 392 } else
Wayne Roberts 0:9c052ff8dd6a 393 return 0;
Wayne Roberts 0:9c052ff8dd6a 394
Wayne Roberts 0:9c052ff8dd6a 395 switch( bandwidth )
Wayne Roberts 0:9c052ff8dd6a 396 {
Wayne Roberts 0:9c052ff8dd6a 397 case 0: // 125 kHz
Wayne Roberts 0:9c052ff8dd6a 398 bw = 125;//ms: 125e3;
Wayne Roberts 0:9c052ff8dd6a 399 break;
Wayne Roberts 0:9c052ff8dd6a 400 case 1: // 250 kHz
Wayne Roberts 0:9c052ff8dd6a 401 bw = 250;//ms:250e3;
Wayne Roberts 0:9c052ff8dd6a 402 break;
Wayne Roberts 0:9c052ff8dd6a 403 case 2: // 500 kHz
Wayne Roberts 0:9c052ff8dd6a 404 bw = 500;//ms:500e3;
Wayne Roberts 0:9c052ff8dd6a 405 break;
Wayne Roberts 0:9c052ff8dd6a 406 }
Wayne Roberts 0:9c052ff8dd6a 407
Wayne Roberts 0:9c052ff8dd6a 408 // Symbol rate : time for one symbol (secs)
Wayne Roberts 0:9c052ff8dd6a 409 double rs = bw / ( 1 << lora.RegModemConfig2.sx1276bits.SpreadingFactor );
Wayne Roberts 0:9c052ff8dd6a 410 double ts = 1 / rs;
Wayne Roberts 0:9c052ff8dd6a 411 // time of preamble
Wayne Roberts 0:9c052ff8dd6a 412 double tPreamble;
Wayne Roberts 0:9c052ff8dd6a 413 tPreamble = (lora.RegPreamble + 4.25 ) * ts;
Wayne Roberts 0:9c052ff8dd6a 414 // Symbol length of payload and time
Wayne Roberts 0:9c052ff8dd6a 415 double tmp = ceil( ( 8 * pktLen - 4 * lora.RegModemConfig2.sx1276bits.SpreadingFactor +
Wayne Roberts 0:9c052ff8dd6a 416 28 + 16 * crcOn -
Wayne Roberts 0:9c052ff8dd6a 417 ( fixLen ? 20 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 418 ( double )( 4 * ( lora.RegModemConfig2.sx1276bits.SpreadingFactor -
Wayne Roberts 0:9c052ff8dd6a 419 ( ( LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
Wayne Roberts 0:9c052ff8dd6a 420 ( coderate + 4 );
Wayne Roberts 0:9c052ff8dd6a 421 double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
Wayne Roberts 0:9c052ff8dd6a 422 double tPayload = nPayload * ts;
Wayne Roberts 0:9c052ff8dd6a 423 // Time on air
Wayne Roberts 0:9c052ff8dd6a 424 double tOnAir = tPreamble + tPayload;
Wayne Roberts 0:9c052ff8dd6a 425 // return ms secs
Wayne Roberts 0:9c052ff8dd6a 426 airTime = floor( tOnAir * 1e3 + 0.999 );
Wayne Roberts 0:9c052ff8dd6a 427 }
Wayne Roberts 0:9c052ff8dd6a 428 break;
Wayne Roberts 0:9c052ff8dd6a 429 }
Wayne Roberts 0:9c052ff8dd6a 430 return airTime;
Wayne Roberts 0:9c052ff8dd6a 431
Wayne Roberts 0:9c052ff8dd6a 432 }
Wayne Roberts 0:9c052ff8dd6a 433 #endif /* DUTY_ENABLE */
Wayne Roberts 0:9c052ff8dd6a 434
Wayne Roberts 0:9c052ff8dd6a 435 void Radio::service()
Wayne Roberts 0:9c052ff8dd6a 436 {
Wayne Roberts 0:9c052ff8dd6a 437 if (pinEvent.dio0) {
Wayne Roberts 0:9c052ff8dd6a 438 dio0UserContext();
Wayne Roberts 0:9c052ff8dd6a 439 pinEvent.txing = 0;
Wayne Roberts 0:9c052ff8dd6a 440 pinEvent.dio0 = 0;
Wayne Roberts 10:3303cf2867d4 441 } else if (radio.dio0.read()) {
Wayne Roberts 10:3303cf2867d4 442 /* fail: missed interrupt */
Wayne Roberts 10:3303cf2867d4 443 dio0isr();
Wayne Roberts 0:9c052ff8dd6a 444 }
Wayne Roberts 0:9c052ff8dd6a 445
Wayne Roberts 0:9c052ff8dd6a 446 if (pinEvent.dio1) {
Wayne Roberts 0:9c052ff8dd6a 447 dio1UserContext();
Wayne Roberts 0:9c052ff8dd6a 448 pinEvent.dio1 = 0;
Wayne Roberts 0:9c052ff8dd6a 449 }
Wayne Roberts 0:9c052ff8dd6a 450 }
Wayne Roberts 0:9c052ff8dd6a 451
Wayne Roberts 0:9c052ff8dd6a 452 uint32_t Radio::lora_toa_us( uint8_t pktLen )
Wayne Roberts 0:9c052ff8dd6a 453 {
Wayne Roberts 0:9c052ff8dd6a 454 uint32_t airTime = 0;
Wayne Roberts 0:9c052ff8dd6a 455 uint8_t chipBW = Radio::lora.getBw();
Wayne Roberts 0:9c052ff8dd6a 456 double bwKHz;
Wayne Roberts 0:9c052ff8dd6a 457 uint8_t LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 458 bool FixLen;
Wayne Roberts 0:9c052ff8dd6a 459 uint8_t crcOn;
Wayne Roberts 0:9c052ff8dd6a 460 uint16_t preambleLen = Radio::radio.read_u16(REG_LR_PREAMBLEMSB);
Wayne Roberts 0:9c052ff8dd6a 461
Wayne Roberts 0:9c052ff8dd6a 462 Radio::lora.RegModemConfig2.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG2);
Wayne Roberts 0:9c052ff8dd6a 463 Radio::lora.RegModemConfig.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG);
Wayne Roberts 0:9c052ff8dd6a 464
Wayne Roberts 0:9c052ff8dd6a 465 if (Radio::radio.type == SX1276) {
Wayne Roberts 0:9c052ff8dd6a 466 chipBW -= 7;
Wayne Roberts 0:9c052ff8dd6a 467 Radio::lora.RegModemConfig3.octet = Radio::radio.read_reg(REG_LR_MODEMCONFIG3);
Wayne Roberts 0:9c052ff8dd6a 468 LowDataRateOptimize = Radio::lora.RegModemConfig3.sx1276bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 469 FixLen = Radio::lora.RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 470 crcOn = Radio::lora.RegModemConfig2.sx1276bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 471 } else if (Radio::radio.type == SX1272) {
Wayne Roberts 0:9c052ff8dd6a 472 LowDataRateOptimize = Radio::lora.RegModemConfig.sx1272bits.LowDataRateOptimize;
Wayne Roberts 0:9c052ff8dd6a 473 FixLen = Radio::lora.RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
Wayne Roberts 0:9c052ff8dd6a 474 crcOn = Radio::lora.RegModemConfig.sx1272bits.RxPayloadCrcOn;
Wayne Roberts 0:9c052ff8dd6a 475 } else
Wayne Roberts 0:9c052ff8dd6a 476 return 0;
Wayne Roberts 0:9c052ff8dd6a 477
Wayne Roberts 0:9c052ff8dd6a 478 switch (chipBW) {
Wayne Roberts 0:9c052ff8dd6a 479 case 0: bwKHz = 125; break;
Wayne Roberts 0:9c052ff8dd6a 480 case 1: bwKHz = 250; break;
Wayne Roberts 0:9c052ff8dd6a 481 case 2: bwKHz = 500; break;
Wayne Roberts 0:9c052ff8dd6a 482 default: return 0;
Wayne Roberts 0:9c052ff8dd6a 483 }
Wayne Roberts 0:9c052ff8dd6a 484
Wayne Roberts 0:9c052ff8dd6a 485 // Symbol rate : time for one symbol (secs)
Wayne Roberts 0:9c052ff8dd6a 486 double rs = bwKHz / ( 1 << Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor );
Wayne Roberts 0:9c052ff8dd6a 487 double ts = 1 / rs;
Wayne Roberts 0:9c052ff8dd6a 488 // time of preamble
Wayne Roberts 0:9c052ff8dd6a 489 double tPreamble = ( preambleLen + 4.25 ) * ts;
Wayne Roberts 0:9c052ff8dd6a 490 // Symbol length of payload and time
Wayne Roberts 0:9c052ff8dd6a 491 double tmp = ceil( ( 8 * pktLen - 4 * Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor +
Wayne Roberts 0:9c052ff8dd6a 492 28 + 16 * crcOn -
Wayne Roberts 0:9c052ff8dd6a 493 ( FixLen ? 20 : 0 ) ) /
Wayne Roberts 0:9c052ff8dd6a 494 ( double )( 4 * ( Radio::lora.RegModemConfig2.sx1276bits.SpreadingFactor -
Wayne Roberts 0:9c052ff8dd6a 495 ( ( LowDataRateOptimize > 0 ) ? 2 : 0 ) ) ) ) *
Wayne Roberts 0:9c052ff8dd6a 496 ( Radio::lora.getCodingRate(false) + 4 );
Wayne Roberts 0:9c052ff8dd6a 497 double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 );
Wayne Roberts 0:9c052ff8dd6a 498 double tPayload = nPayload * ts;
Wayne Roberts 0:9c052ff8dd6a 499 // Time on air
Wayne Roberts 0:9c052ff8dd6a 500 double tOnAir = tPreamble + tPayload;
Wayne Roberts 0:9c052ff8dd6a 501 // return microseconds
Wayne Roberts 0:9c052ff8dd6a 502 airTime = floor( tOnAir * 1000 + 0.999 );
Wayne Roberts 0:9c052ff8dd6a 503
Wayne Roberts 0:9c052ff8dd6a 504 return airTime;
Wayne Roberts 0:9c052ff8dd6a 505 }
Wayne Roberts 0:9c052ff8dd6a 506 #endif /* ..SX127x_H */
Wayne Roberts 0:9c052ff8dd6a 507