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:
Mon Jun 01 15:59:56 2020 -0700
Revision:
17:5f34cbe2ac53
Parent:
16:34de2ab7eb32
Child:
19:94b5382d3fc6
support platforms without LowPowerTimer, add LR1110

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