operate LoRa radio over I2C

Dependencies:   TimeoutAbs lib_i2c_slave_block sx12xx_hal

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 NAmote72 or Murata discovery, then you must import only sx127x driver.

This project is used as slave device with i2c_lora_master on raspberry pi. This i2c_lora_slave offloads the real-time requirements onto microcontroller. Also permits multiple slave radio devices connected to master. Radio MAC layer exists on I2C master, along with application layer.

If beacon operation is enabled, I2C functions which access radio chip are blocked while beacon is loaded and transmitted.
See lib_i2c_slave_block for wiring connections.

Committer:
Wayne Roberts
Date:
Fri Feb 08 11:58:09 2019 -0800
Revision:
0:9eb5b8bf9f7b
first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:9eb5b8bf9f7b 1
Wayne Roberts 0:9eb5b8bf9f7b 2 #include <mbed.h>
Wayne Roberts 0:9eb5b8bf9f7b 3 #include "LowPowerTimeoutAbs.h"
Wayne Roberts 0:9eb5b8bf9f7b 4 #include "radio_device.h"
Wayne Roberts 0:9eb5b8bf9f7b 5
Wayne Roberts 0:9eb5b8bf9f7b 6 #define IRQ_OUT_PIN D6
Wayne Roberts 0:9eb5b8bf9f7b 7
Wayne Roberts 0:9eb5b8bf9f7b 8 #define BEACON_PRELOAD_us 500000
Wayne Roberts 0:9eb5b8bf9f7b 9
Wayne Roberts 0:9eb5b8bf9f7b 10 typedef struct {
Wayne Roberts 0:9eb5b8bf9f7b 11 uint8_t beacon_enabled : 1; // 0
Wayne Roberts 0:9eb5b8bf9f7b 12 uint8_t beacon_guard : 1; // 1
Wayne Roberts 0:9eb5b8bf9f7b 13 uint8_t beacon_loaded : 1; // 2
Wayne Roberts 0:9eb5b8bf9f7b 14 uint8_t beacon_test : 1; // 3
Wayne Roberts 0:9eb5b8bf9f7b 15 uint8_t req_type : 4; // 4,5,6,7
Wayne Roberts 0:9eb5b8bf9f7b 16 } flags_t;
Wayne Roberts 0:9eb5b8bf9f7b 17
Wayne Roberts 0:9eb5b8bf9f7b 18 const int SLAVE_ADDRESS = 0xA0;
Wayne Roberts 0:9eb5b8bf9f7b 19
Wayne Roberts 0:9eb5b8bf9f7b 20 RawSerial pc(USBTX, USBRX);
Wayne Roberts 0:9eb5b8bf9f7b 21
Wayne Roberts 0:9eb5b8bf9f7b 22 EventQueue queue;
Wayne Roberts 0:9eb5b8bf9f7b 23 uint8_t skip_beacon_cnt = 0;
Wayne Roberts 0:9eb5b8bf9f7b 24 uint16_t beaconPreambleSymbs;
Wayne Roberts 0:9eb5b8bf9f7b 25 uint16_t preambleSymbs;
Wayne Roberts 0:9eb5b8bf9f7b 26 unsigned beaconInterval_us;
Wayne Roberts 0:9eb5b8bf9f7b 27 uint8_t beaconSizeBytes;
Wayne Roberts 0:9eb5b8bf9f7b 28 /* low power timer used because hi-speed timer doesnt have crystal, and 32Khz crystal is 20ppm */
Wayne Roberts 0:9eb5b8bf9f7b 29 LowPowerTimeoutAbs send_beaconTimer;
Wayne Roberts 0:9eb5b8bf9f7b 30 LowPowerTimeoutAbs load_beaconTimer;
Wayne Roberts 0:9eb5b8bf9f7b 31 uint8_t beacon_payload[4];
Wayne Roberts 0:9eb5b8bf9f7b 32 cfg_t cfg;
Wayne Roberts 0:9eb5b8bf9f7b 33 uint8_t get_n_rssi;
Wayne Roberts 0:9eb5b8bf9f7b 34
Wayne Roberts 0:9eb5b8bf9f7b 35 volatile flags_t flags;
Wayne Roberts 0:9eb5b8bf9f7b 36 volatile uint8_t bs;
Wayne Roberts 0:9eb5b8bf9f7b 37 volatile uint16_t rx_slot;
Wayne Roberts 0:9eb5b8bf9f7b 38 volatile us_timestamp_t beaconAt;
Wayne Roberts 0:9eb5b8bf9f7b 39 volatile uint8_t blocked_cmd;
Wayne Roberts 0:9eb5b8bf9f7b 40
Wayne Roberts 0:9eb5b8bf9f7b 41 DigitalOut irqOutPin(IRQ_OUT_PIN);
Wayne Roberts 0:9eb5b8bf9f7b 42 irq_t irq;
Wayne Roberts 0:9eb5b8bf9f7b 43
Wayne Roberts 0:9eb5b8bf9f7b 44 uint8_t toI2C_rx_pkt[256];
Wayne Roberts 0:9eb5b8bf9f7b 45 volatile uint16_t toI2C_rx_pkt_idx; // incremented by 32: will overflow 8bit
Wayne Roberts 0:9eb5b8bf9f7b 46
Wayne Roberts 0:9eb5b8bf9f7b 47 int tx_pkt_len;
Wayne Roberts 0:9eb5b8bf9f7b 48 uint8_t tx_pkt_idx;
Wayne Roberts 0:9eb5b8bf9f7b 49
Wayne Roberts 0:9eb5b8bf9f7b 50 void console()
Wayne Roberts 0:9eb5b8bf9f7b 51 {
Wayne Roberts 0:9eb5b8bf9f7b 52 char c;
Wayne Roberts 0:9eb5b8bf9f7b 53 if (pc.readable() != 1)
Wayne Roberts 0:9eb5b8bf9f7b 54 return;
Wayne Roberts 0:9eb5b8bf9f7b 55
Wayne Roberts 0:9eb5b8bf9f7b 56 c = pc.getc();
Wayne Roberts 0:9eb5b8bf9f7b 57
Wayne Roberts 0:9eb5b8bf9f7b 58 if (c == '.') {
Wayne Roberts 0:9eb5b8bf9f7b 59 pc.printf("beacon_guard%u ", flags.beacon_guard);
Wayne Roberts 0:9eb5b8bf9f7b 60 pc.printf("beacon_loaded%u ", flags.beacon_loaded);
Wayne Roberts 0:9eb5b8bf9f7b 61 pc.printf("bs:%u\r\n", bs);
Wayne Roberts 0:9eb5b8bf9f7b 62 }
Wayne Roberts 0:9eb5b8bf9f7b 63 }
Wayne Roberts 0:9eb5b8bf9f7b 64
Wayne Roberts 0:9eb5b8bf9f7b 65 void
Wayne Roberts 0:9eb5b8bf9f7b 66 send_beacon()
Wayne Roberts 0:9eb5b8bf9f7b 67 {
Wayne Roberts 0:9eb5b8bf9f7b 68 bs = 3;
Wayne Roberts 0:9eb5b8bf9f7b 69 if (!flags.beacon_loaded)
Wayne Roberts 0:9eb5b8bf9f7b 70 return;
Wayne Roberts 0:9eb5b8bf9f7b 71
Wayne Roberts 0:9eb5b8bf9f7b 72 bs = 4;
Wayne Roberts 0:9eb5b8bf9f7b 73 Radio::Send(beaconSizeBytes, 0, 0, 0);
Wayne Roberts 0:9eb5b8bf9f7b 74 flags.beacon_loaded = false;
Wayne Roberts 0:9eb5b8bf9f7b 75 }
Wayne Roberts 0:9eb5b8bf9f7b 76
Wayne Roberts 0:9eb5b8bf9f7b 77 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
Wayne Roberts 0:9eb5b8bf9f7b 78 {
Wayne Roberts 0:9eb5b8bf9f7b 79 // The CRC calculation follows CCITT
Wayne Roberts 0:9eb5b8bf9f7b 80 const uint16_t polynom = 0x1021;
Wayne Roberts 0:9eb5b8bf9f7b 81 // CRC initial value
Wayne Roberts 0:9eb5b8bf9f7b 82 uint16_t crc = 0x0000;
Wayne Roberts 0:9eb5b8bf9f7b 83
Wayne Roberts 0:9eb5b8bf9f7b 84 if( buffer == NULL )
Wayne Roberts 0:9eb5b8bf9f7b 85 {
Wayne Roberts 0:9eb5b8bf9f7b 86 return 0;
Wayne Roberts 0:9eb5b8bf9f7b 87 }
Wayne Roberts 0:9eb5b8bf9f7b 88
Wayne Roberts 0:9eb5b8bf9f7b 89 for( uint16_t i = 0; i < length; ++i )
Wayne Roberts 0:9eb5b8bf9f7b 90 {
Wayne Roberts 0:9eb5b8bf9f7b 91 crc ^= ( uint16_t ) buffer[i] << 8;
Wayne Roberts 0:9eb5b8bf9f7b 92 for( uint16_t j = 0; j < 8; ++j )
Wayne Roberts 0:9eb5b8bf9f7b 93 {
Wayne Roberts 0:9eb5b8bf9f7b 94 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
Wayne Roberts 0:9eb5b8bf9f7b 95 }
Wayne Roberts 0:9eb5b8bf9f7b 96 }
Wayne Roberts 0:9eb5b8bf9f7b 97
Wayne Roberts 0:9eb5b8bf9f7b 98 return crc;
Wayne Roberts 0:9eb5b8bf9f7b 99 }
Wayne Roberts 0:9eb5b8bf9f7b 100
Wayne Roberts 0:9eb5b8bf9f7b 101 void
Wayne Roberts 0:9eb5b8bf9f7b 102 _load_beacon()
Wayne Roberts 0:9eb5b8bf9f7b 103 {
Wayne Roberts 0:9eb5b8bf9f7b 104 bool inv_iq = false;
Wayne Roberts 0:9eb5b8bf9f7b 105 uint16_t crc;
Wayne Roberts 0:9eb5b8bf9f7b 106
Wayne Roberts 0:9eb5b8bf9f7b 107 bs = 2;
Wayne Roberts 0:9eb5b8bf9f7b 108 Radio::Standby( );
Wayne Roberts 0:9eb5b8bf9f7b 109
Wayne Roberts 0:9eb5b8bf9f7b 110 if (skip_beacon_cnt > 0) {
Wayne Roberts 0:9eb5b8bf9f7b 111 inv_iq = true;
Wayne Roberts 0:9eb5b8bf9f7b 112 skip_beacon_cnt--;
Wayne Roberts 0:9eb5b8bf9f7b 113 }
Wayne Roberts 0:9eb5b8bf9f7b 114 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 0:9eb5b8bf9f7b 115 Radio::LoRaPacketConfig(beaconPreambleSymbs, true, false, inv_iq);
Wayne Roberts 0:9eb5b8bf9f7b 116
Wayne Roberts 0:9eb5b8bf9f7b 117 Radio::SetFixedPayloadLength(beaconSizeBytes);
Wayne Roberts 0:9eb5b8bf9f7b 118
Wayne Roberts 0:9eb5b8bf9f7b 119 Radio::radio.tx_buf[0] = beacon_payload[0];
Wayne Roberts 0:9eb5b8bf9f7b 120 Radio::radio.tx_buf[1] = beacon_payload[1];
Wayne Roberts 0:9eb5b8bf9f7b 121 Radio::radio.tx_buf[2] = beacon_payload[2];
Wayne Roberts 0:9eb5b8bf9f7b 122 Radio::radio.tx_buf[3] = beacon_payload[3];
Wayne Roberts 0:9eb5b8bf9f7b 123 //beacon_payload[0] = CMD_NONE;
Wayne Roberts 0:9eb5b8bf9f7b 124
Wayne Roberts 0:9eb5b8bf9f7b 125 crc = beacon_crc(Radio::radio.tx_buf, 4);
Wayne Roberts 0:9eb5b8bf9f7b 126 Radio::radio.tx_buf[4] = crc & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 127 Radio::radio.tx_buf[5] = crc >> 8;
Wayne Roberts 0:9eb5b8bf9f7b 128
Wayne Roberts 0:9eb5b8bf9f7b 129 flags.beacon_loaded = true;
Wayne Roberts 0:9eb5b8bf9f7b 130 }
Wayne Roberts 0:9eb5b8bf9f7b 131
Wayne Roberts 0:9eb5b8bf9f7b 132 uint16_t tim_get_current_slot()
Wayne Roberts 0:9eb5b8bf9f7b 133 {
Wayne Roberts 0:9eb5b8bf9f7b 134 us_timestamp_t us_until = beaconAt - send_beaconTimer.read_us();
Wayne Roberts 0:9eb5b8bf9f7b 135 return us_until / 30000;
Wayne Roberts 0:9eb5b8bf9f7b 136 }
Wayne Roberts 0:9eb5b8bf9f7b 137
Wayne Roberts 0:9eb5b8bf9f7b 138 void load_beacon()
Wayne Roberts 0:9eb5b8bf9f7b 139 {
Wayne Roberts 0:9eb5b8bf9f7b 140 if (flags.beacon_enabled) {
Wayne Roberts 0:9eb5b8bf9f7b 141 flags.beacon_guard = true;
Wayne Roberts 0:9eb5b8bf9f7b 142 bs = 1;
Wayne Roberts 0:9eb5b8bf9f7b 143 queue.call_in(200, _load_beacon);
Wayne Roberts 0:9eb5b8bf9f7b 144 }
Wayne Roberts 0:9eb5b8bf9f7b 145 }
Wayne Roberts 0:9eb5b8bf9f7b 146
Wayne Roberts 0:9eb5b8bf9f7b 147 void get_random()
Wayne Roberts 0:9eb5b8bf9f7b 148 {
Wayne Roberts 0:9eb5b8bf9f7b 149 uint32_t r;
Wayne Roberts 0:9eb5b8bf9f7b 150 Radio::Rx(0);
Wayne Roberts 0:9eb5b8bf9f7b 151 wait(0.01);
Wayne Roberts 0:9eb5b8bf9f7b 152 r = Radio::Random();
Wayne Roberts 0:9eb5b8bf9f7b 153
Wayne Roberts 0:9eb5b8bf9f7b 154 irq.buf[1] = r & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 155 r >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 156 irq.buf[2] = r & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 157 r >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 158 irq.buf[3] = r & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 159 r >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 160 irq.buf[4] = r & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 161
Wayne Roberts 0:9eb5b8bf9f7b 162 irq.fields.flags.irq_type = IRQ_TYPE_RANDOM;
Wayne Roberts 0:9eb5b8bf9f7b 163 irqOutPin = 1;
Wayne Roberts 0:9eb5b8bf9f7b 164 }
Wayne Roberts 0:9eb5b8bf9f7b 165
Wayne Roberts 0:9eb5b8bf9f7b 166 void cf_read()
Wayne Roberts 0:9eb5b8bf9f7b 167 {
Wayne Roberts 0:9eb5b8bf9f7b 168 uint32_t hz;
Wayne Roberts 0:9eb5b8bf9f7b 169 float MHz;
Wayne Roberts 0:9eb5b8bf9f7b 170 #ifdef SX127x_H
Wayne Roberts 0:9eb5b8bf9f7b 171 MHz = Radio::radio.get_frf_MHz();
Wayne Roberts 0:9eb5b8bf9f7b 172 #else
Wayne Roberts 0:9eb5b8bf9f7b 173 MHz = Radio::radio.getMHz();
Wayne Roberts 0:9eb5b8bf9f7b 174 #endif
Wayne Roberts 0:9eb5b8bf9f7b 175
Wayne Roberts 0:9eb5b8bf9f7b 176 hz = MHz * 1000000;
Wayne Roberts 0:9eb5b8bf9f7b 177
Wayne Roberts 0:9eb5b8bf9f7b 178 irq.buf[1] = hz & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 179 hz >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 180 irq.buf[2] = hz & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 181 hz >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 182 irq.buf[3] = hz & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 183 hz >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 184 irq.buf[4] = hz & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 185
Wayne Roberts 0:9eb5b8bf9f7b 186 irq.fields.flags.irq_type = IRQ_TYPE_CF;
Wayne Roberts 0:9eb5b8bf9f7b 187 irqOutPin = 1;
Wayne Roberts 0:9eb5b8bf9f7b 188 }
Wayne Roberts 0:9eb5b8bf9f7b 189
Wayne Roberts 0:9eb5b8bf9f7b 190 void measure_ambient(uint8_t n_samples)
Wayne Roberts 0:9eb5b8bf9f7b 191 {
Wayne Roberts 0:9eb5b8bf9f7b 192 int i, acc = 0;
Wayne Roberts 0:9eb5b8bf9f7b 193 float bg_rssi;
Wayne Roberts 0:9eb5b8bf9f7b 194 for (i = 0; i < n_samples; i++) {
Wayne Roberts 0:9eb5b8bf9f7b 195 int rssi = Radio::GetRssiInst();
Wayne Roberts 0:9eb5b8bf9f7b 196 acc += rssi;
Wayne Roberts 0:9eb5b8bf9f7b 197 wait(0.01);
Wayne Roberts 0:9eb5b8bf9f7b 198 }
Wayne Roberts 0:9eb5b8bf9f7b 199 bg_rssi = acc / (float)n_samples;
Wayne Roberts 0:9eb5b8bf9f7b 200 pc.printf("bg_rssi:%.1fdBm ", bg_rssi);
Wayne Roberts 0:9eb5b8bf9f7b 201
Wayne Roberts 0:9eb5b8bf9f7b 202 irq.fields.rssi = bg_rssi * 10;
Wayne Roberts 0:9eb5b8bf9f7b 203 irq.fields.flags.irq_type = IRQ_TYPE_RSSI;
Wayne Roberts 0:9eb5b8bf9f7b 204 irqOutPin = 1;
Wayne Roberts 0:9eb5b8bf9f7b 205 }
Wayne Roberts 0:9eb5b8bf9f7b 206
Wayne Roberts 0:9eb5b8bf9f7b 207 void txDoneCB()
Wayne Roberts 0:9eb5b8bf9f7b 208 {
Wayne Roberts 0:9eb5b8bf9f7b 209 if (flags.beacon_test) {
Wayne Roberts 0:9eb5b8bf9f7b 210 flags.beacon_test = 0;
Wayne Roberts 0:9eb5b8bf9f7b 211 return;
Wayne Roberts 0:9eb5b8bf9f7b 212 }
Wayne Roberts 0:9eb5b8bf9f7b 213
Wayne Roberts 0:9eb5b8bf9f7b 214 if (cfg.fields.flags.rxOnTxDone) {
Wayne Roberts 0:9eb5b8bf9f7b 215 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 0:9eb5b8bf9f7b 216 Radio::LoRaPacketConfig(preambleSymbs, false, true, false);
Wayne Roberts 0:9eb5b8bf9f7b 217
Wayne Roberts 0:9eb5b8bf9f7b 218 Radio::Rx(0);
Wayne Roberts 0:9eb5b8bf9f7b 219
Wayne Roberts 0:9eb5b8bf9f7b 220 bs = 5;
Wayne Roberts 0:9eb5b8bf9f7b 221 if (flags.beacon_guard) { // beacon done transmitting
Wayne Roberts 0:9eb5b8bf9f7b 222 measure_ambient(cfg.fields.n_rssi_samples);
Wayne Roberts 0:9eb5b8bf9f7b 223 flags.beacon_guard = false;
Wayne Roberts 0:9eb5b8bf9f7b 224 bs = 6;
Wayne Roberts 0:9eb5b8bf9f7b 225
Wayne Roberts 0:9eb5b8bf9f7b 226 beaconAt += beaconInterval_us;
Wayne Roberts 0:9eb5b8bf9f7b 227 load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 0:9eb5b8bf9f7b 228 send_beaconTimer.attach_us(send_beacon, beaconAt);
Wayne Roberts 0:9eb5b8bf9f7b 229 }
Wayne Roberts 0:9eb5b8bf9f7b 230 }
Wayne Roberts 0:9eb5b8bf9f7b 231
Wayne Roberts 0:9eb5b8bf9f7b 232 }
Wayne Roberts 0:9eb5b8bf9f7b 233
Wayne Roberts 0:9eb5b8bf9f7b 234 void send_downlink()
Wayne Roberts 0:9eb5b8bf9f7b 235 {
Wayne Roberts 0:9eb5b8bf9f7b 236 if (tx_pkt_len > 0 && tx_pkt_idx >= tx_pkt_len) {
Wayne Roberts 0:9eb5b8bf9f7b 237 Radio::Send(tx_pkt_len,
Wayne Roberts 0:9eb5b8bf9f7b 238 cfg.fields.maxListenTime,
Wayne Roberts 0:9eb5b8bf9f7b 239 cfg.fields.channelFreeTime,
Wayne Roberts 0:9eb5b8bf9f7b 240 cfg.fields.rssiThresh
Wayne Roberts 0:9eb5b8bf9f7b 241 );
Wayne Roberts 0:9eb5b8bf9f7b 242
Wayne Roberts 0:9eb5b8bf9f7b 243 tx_pkt_len = 0; // packet only sent once, as requested by host
Wayne Roberts 0:9eb5b8bf9f7b 244 }
Wayne Roberts 0:9eb5b8bf9f7b 245 }
Wayne Roberts 0:9eb5b8bf9f7b 246
Wayne Roberts 0:9eb5b8bf9f7b 247 void rxDoneCB(uint8_t size, float rssi, float snr)
Wayne Roberts 0:9eb5b8bf9f7b 248 {
Wayne Roberts 0:9eb5b8bf9f7b 249 if (cfg.fields.flags.rxOnTxDone) {
Wayne Roberts 0:9eb5b8bf9f7b 250 queue.call_in(cfg.fields.downlinkOffset, send_downlink);
Wayne Roberts 0:9eb5b8bf9f7b 251 }
Wayne Roberts 0:9eb5b8bf9f7b 252
Wayne Roberts 0:9eb5b8bf9f7b 253 if (irq.fields.flags.rx_pkt == 0) {
Wayne Roberts 0:9eb5b8bf9f7b 254 if (flags.beacon_enabled)
Wayne Roberts 0:9eb5b8bf9f7b 255 irq.fields.rx_slot = tim_get_current_slot();
Wayne Roberts 0:9eb5b8bf9f7b 256 else
Wayne Roberts 0:9eb5b8bf9f7b 257 irq.fields.rx_slot = 0;
Wayne Roberts 0:9eb5b8bf9f7b 258
Wayne Roberts 0:9eb5b8bf9f7b 259 irq.fields.rssi = rssi * 10;
Wayne Roberts 0:9eb5b8bf9f7b 260 irq.fields.pkt_snr = snr;
Wayne Roberts 0:9eb5b8bf9f7b 261 irq.fields.pkt_len = size;
Wayne Roberts 0:9eb5b8bf9f7b 262 memcpy(toI2C_rx_pkt, Radio::radio.rx_buf, size);
Wayne Roberts 0:9eb5b8bf9f7b 263 irq.fields.flags.rx_pkt = 1;
Wayne Roberts 0:9eb5b8bf9f7b 264 irqOutPin = 1;
Wayne Roberts 0:9eb5b8bf9f7b 265 pc.printf("rxlen%u snr:%.1f rssi:%.1f slot:%u\r\n", size, snr, rssi, irq.fields.rx_slot);
Wayne Roberts 0:9eb5b8bf9f7b 266 } else {
Wayne Roberts 0:9eb5b8bf9f7b 267 pc.printf("rx_pkt_overrun\r\n");
Wayne Roberts 0:9eb5b8bf9f7b 268 irq.fields.flags.rx_pkt_overrun = 1;
Wayne Roberts 0:9eb5b8bf9f7b 269 }
Wayne Roberts 0:9eb5b8bf9f7b 270
Wayne Roberts 0:9eb5b8bf9f7b 271 }
Wayne Roberts 0:9eb5b8bf9f7b 272
Wayne Roberts 0:9eb5b8bf9f7b 273 void tim_init()
Wayne Roberts 0:9eb5b8bf9f7b 274 {
Wayne Roberts 0:9eb5b8bf9f7b 275 beaconAt = send_beaconTimer.read_us() + beaconInterval_us;
Wayne Roberts 0:9eb5b8bf9f7b 276 load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 0:9eb5b8bf9f7b 277 send_beaconTimer.attach_us(send_beacon, beaconAt);
Wayne Roberts 0:9eb5b8bf9f7b 278 }
Wayne Roberts 0:9eb5b8bf9f7b 279
Wayne Roberts 0:9eb5b8bf9f7b 280 volatile uint8_t cnt = 0;
Wayne Roberts 0:9eb5b8bf9f7b 281
Wayne Roberts 0:9eb5b8bf9f7b 282 void fill_tx_buf(uint8_t cmd) // called from isr
Wayne Roberts 0:9eb5b8bf9f7b 283 {
Wayne Roberts 0:9eb5b8bf9f7b 284 unsigned i;
Wayne Roberts 0:9eb5b8bf9f7b 285
Wayne Roberts 0:9eb5b8bf9f7b 286 /* Master is reading from slave
Wayne Roberts 0:9eb5b8bf9f7b 287 * Called from ISR; must return immediately */
Wayne Roberts 0:9eb5b8bf9f7b 288
Wayne Roberts 0:9eb5b8bf9f7b 289 if (flags.beacon_guard && cmd >= CMD_RADIO) {
Wayne Roberts 0:9eb5b8bf9f7b 290 blocked_cmd = cmd;
Wayne Roberts 0:9eb5b8bf9f7b 291 return;
Wayne Roberts 0:9eb5b8bf9f7b 292 }
Wayne Roberts 0:9eb5b8bf9f7b 293
Wayne Roberts 0:9eb5b8bf9f7b 294 switch (cmd) {
Wayne Roberts 0:9eb5b8bf9f7b 295 case CMD_TEST:
Wayne Roberts 0:9eb5b8bf9f7b 296 for (i = 0; i < cmd_to_length[CMD_TEST]; i++)
Wayne Roberts 0:9eb5b8bf9f7b 297 i2c.tx_buf[i] = i + cnt;
Wayne Roberts 0:9eb5b8bf9f7b 298 cnt++;
Wayne Roberts 0:9eb5b8bf9f7b 299 break;
Wayne Roberts 0:9eb5b8bf9f7b 300 case CMD_TEST32:
Wayne Roberts 0:9eb5b8bf9f7b 301 for (i = 0; i < cmd_to_length[CMD_TEST32]; i++)
Wayne Roberts 0:9eb5b8bf9f7b 302 i2c.tx_buf[i] = i + cnt;
Wayne Roberts 0:9eb5b8bf9f7b 303 cnt++;
Wayne Roberts 0:9eb5b8bf9f7b 304 break;
Wayne Roberts 0:9eb5b8bf9f7b 305 case CMD_RX_PAYLOAD:
Wayne Roberts 0:9eb5b8bf9f7b 306 memcpy(i2c.tx_buf, toI2C_rx_pkt+toI2C_rx_pkt_idx, sizeof(i2c.tx_buf));
Wayne Roberts 0:9eb5b8bf9f7b 307
Wayne Roberts 0:9eb5b8bf9f7b 308 toI2C_rx_pkt_idx += cmd_to_length[CMD_RX_PAYLOAD];
Wayne Roberts 0:9eb5b8bf9f7b 309 if (toI2C_rx_pkt_idx >= irq.fields.pkt_len) {
Wayne Roberts 0:9eb5b8bf9f7b 310 irq.fields.pkt_len = 0;
Wayne Roberts 0:9eb5b8bf9f7b 311 irq.fields.flags.rx_pkt = 0;
Wayne Roberts 0:9eb5b8bf9f7b 312 if (irq.buf[0] == 0)
Wayne Roberts 0:9eb5b8bf9f7b 313 irqOutPin = 0;
Wayne Roberts 0:9eb5b8bf9f7b 314 }
Wayne Roberts 0:9eb5b8bf9f7b 315 break;
Wayne Roberts 0:9eb5b8bf9f7b 316 case CMD_SKIP_BEACONS:
Wayne Roberts 0:9eb5b8bf9f7b 317 i2c.tx_buf[0] = skip_beacon_cnt;
Wayne Roberts 0:9eb5b8bf9f7b 318 break;
Wayne Roberts 0:9eb5b8bf9f7b 319 case CMD_CURRENT_SLOT:
Wayne Roberts 0:9eb5b8bf9f7b 320 {
Wayne Roberts 0:9eb5b8bf9f7b 321 uint16_t *u16ptr = (uint16_t*)i2c.tx_buf;
Wayne Roberts 0:9eb5b8bf9f7b 322 *u16ptr = tim_get_current_slot();
Wayne Roberts 0:9eb5b8bf9f7b 323 }
Wayne Roberts 0:9eb5b8bf9f7b 324 break;
Wayne Roberts 0:9eb5b8bf9f7b 325 case CMD_REQ_RANDOM:
Wayne Roberts 0:9eb5b8bf9f7b 326 flags.req_type = IRQ_TYPE_RANDOM;
Wayne Roberts 0:9eb5b8bf9f7b 327 break;
Wayne Roberts 0:9eb5b8bf9f7b 328 case CMD_IRQ:
Wayne Roberts 0:9eb5b8bf9f7b 329 if (irq.fields.flags.rx_pkt)
Wayne Roberts 0:9eb5b8bf9f7b 330 toI2C_rx_pkt_idx = 0; // packet reading expected to start
Wayne Roberts 0:9eb5b8bf9f7b 331
Wayne Roberts 0:9eb5b8bf9f7b 332 for (i = 0; i < cmd_to_length[CMD_IRQ]; i++)
Wayne Roberts 0:9eb5b8bf9f7b 333 i2c.tx_buf[i] = irq.buf[i];
Wayne Roberts 0:9eb5b8bf9f7b 334
Wayne Roberts 0:9eb5b8bf9f7b 335 irq.fields.flags.rx_pkt_overrun = 0;
Wayne Roberts 0:9eb5b8bf9f7b 336 irq.fields.flags.irq_type = 0;
Wayne Roberts 0:9eb5b8bf9f7b 337 if (irq.buf[0] == 0)
Wayne Roberts 0:9eb5b8bf9f7b 338 irqOutPin = 0;
Wayne Roberts 0:9eb5b8bf9f7b 339
Wayne Roberts 0:9eb5b8bf9f7b 340 break;
Wayne Roberts 0:9eb5b8bf9f7b 341 }
Wayne Roberts 0:9eb5b8bf9f7b 342
Wayne Roberts 0:9eb5b8bf9f7b 343 } // ..fill_tx_buf()
Wayne Roberts 0:9eb5b8bf9f7b 344
Wayne Roberts 0:9eb5b8bf9f7b 345 void service_i2c_write(uint8_t cmd, uint8_t len, const uint8_t* req)
Wayne Roberts 0:9eb5b8bf9f7b 346 {
Wayne Roberts 0:9eb5b8bf9f7b 347 uint32_t u32;
Wayne Roberts 0:9eb5b8bf9f7b 348 uint8_t s8;
Wayne Roberts 0:9eb5b8bf9f7b 349
Wayne Roberts 0:9eb5b8bf9f7b 350 if (flags.beacon_guard && cmd >= CMD_RADIO) {
Wayne Roberts 0:9eb5b8bf9f7b 351 blocked_cmd = cmd;
Wayne Roberts 0:9eb5b8bf9f7b 352 return;
Wayne Roberts 0:9eb5b8bf9f7b 353 }
Wayne Roberts 0:9eb5b8bf9f7b 354
Wayne Roberts 0:9eb5b8bf9f7b 355 switch (cmd) {
Wayne Roberts 0:9eb5b8bf9f7b 356 case CMD_TEST:
Wayne Roberts 0:9eb5b8bf9f7b 357 case CMD_TEST32:
Wayne Roberts 0:9eb5b8bf9f7b 358 pc.printf("test:");
Wayne Roberts 0:9eb5b8bf9f7b 359 for (s8 = 0; s8 < cmd_to_length[cmd]; s8++)
Wayne Roberts 0:9eb5b8bf9f7b 360 pc.printf("%02x ", req[s8]);
Wayne Roberts 0:9eb5b8bf9f7b 361 pc.printf("\r\n");
Wayne Roberts 0:9eb5b8bf9f7b 362 break;
Wayne Roberts 0:9eb5b8bf9f7b 363 case CMD_CFHZ_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 364 flags.req_type = IRQ_TYPE_CF;
Wayne Roberts 0:9eb5b8bf9f7b 365 break;
Wayne Roberts 0:9eb5b8bf9f7b 366 case CMD_FSK_MODEM_CFG_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 367 flags.req_type = IRQ_TYPE_FSK_MODEM;
Wayne Roberts 0:9eb5b8bf9f7b 368 break;
Wayne Roberts 0:9eb5b8bf9f7b 369 case CMD_FSK_PKT_CFG_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 370 flags.req_type = IRQ_TYPE_FSK_PKT;
Wayne Roberts 0:9eb5b8bf9f7b 371 break;
Wayne Roberts 0:9eb5b8bf9f7b 372 case CMD_FSK_SYNC_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 373 flags.req_type = IRQ_TYPE_FSK_SYNC;
Wayne Roberts 0:9eb5b8bf9f7b 374 break;
Wayne Roberts 0:9eb5b8bf9f7b 375 case CMD_TXDBM_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 376 flags.req_type = IRQ_TYPE_TXDBM;
Wayne Roberts 0:9eb5b8bf9f7b 377 break;
Wayne Roberts 0:9eb5b8bf9f7b 378 case CMD_LORA_MODEM_CFG_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 379 flags.req_type = IRQ_TYPE_LORA_MODEM;
Wayne Roberts 0:9eb5b8bf9f7b 380 break;
Wayne Roberts 0:9eb5b8bf9f7b 381 case CMD_LORA_PKT_CFG_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 382 flags.req_type = IRQ_TYPE_LORA_PKT;
Wayne Roberts 0:9eb5b8bf9f7b 383 break;
Wayne Roberts 0:9eb5b8bf9f7b 384 case CMD_OPMODE_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 385 flags.req_type = IRQ_TYPE_OPMODE;
Wayne Roberts 0:9eb5b8bf9f7b 386 break;
Wayne Roberts 0:9eb5b8bf9f7b 387 case CMD_RADIO_RESET:
Wayne Roberts 0:9eb5b8bf9f7b 388 load_beaconTimer.detach();
Wayne Roberts 0:9eb5b8bf9f7b 389 send_beaconTimer.detach();
Wayne Roberts 0:9eb5b8bf9f7b 390 flags.beacon_enabled = 0;
Wayne Roberts 0:9eb5b8bf9f7b 391 radio_reset();
Wayne Roberts 0:9eb5b8bf9f7b 392 break;
Wayne Roberts 0:9eb5b8bf9f7b 393 case CMD_CFHZ_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 394 u32 = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 395 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 396 u32 |= req[2];
Wayne Roberts 0:9eb5b8bf9f7b 397 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 398 u32 |= req[1];
Wayne Roberts 0:9eb5b8bf9f7b 399 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 400 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 401 pc.printf("setCh %luhz\r\n", u32);
Wayne Roberts 0:9eb5b8bf9f7b 402 Radio::SetChannel(u32);
Wayne Roberts 0:9eb5b8bf9f7b 403 break;
Wayne Roberts 0:9eb5b8bf9f7b 404 case CMD_TXDBM_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 405 s8 = req[0];
Wayne Roberts 0:9eb5b8bf9f7b 406 Radio::set_tx_dbm(s8);
Wayne Roberts 0:9eb5b8bf9f7b 407 pc.printf("set tx dBm:%d\r\n", s8);
Wayne Roberts 0:9eb5b8bf9f7b 408 break;
Wayne Roberts 0:9eb5b8bf9f7b 409 case CMD_LORA_MODEM_CFG_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 410 {
Wayne Roberts 0:9eb5b8bf9f7b 411 uint8_t sf, cr;
Wayne Roberts 0:9eb5b8bf9f7b 412
Wayne Roberts 0:9eb5b8bf9f7b 413 u32 = req[1];
Wayne Roberts 0:9eb5b8bf9f7b 414 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 415 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 416 pc.printf("(%04lx) ", u32);
Wayne Roberts 0:9eb5b8bf9f7b 417 sf = req[2];
Wayne Roberts 0:9eb5b8bf9f7b 418 cr = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 419 pc.printf("modemcfg %luKhz sf%u cr%u\r\n", u32, sf, cr);
Wayne Roberts 0:9eb5b8bf9f7b 420 Radio::LoRaModemConfig(u32, sf, cr);
Wayne Roberts 0:9eb5b8bf9f7b 421 }
Wayne Roberts 0:9eb5b8bf9f7b 422 break;
Wayne Roberts 0:9eb5b8bf9f7b 423 case CMD_RX_START:
Wayne Roberts 0:9eb5b8bf9f7b 424 u32 = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 425 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 426 u32 |= req[2];
Wayne Roberts 0:9eb5b8bf9f7b 427 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 428 u32 |= req[1];
Wayne Roberts 0:9eb5b8bf9f7b 429 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 430 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 431 Radio::Rx(u32);
Wayne Roberts 0:9eb5b8bf9f7b 432 pc.printf("rx(%lu)\r\n", u32);
Wayne Roberts 0:9eb5b8bf9f7b 433 break;
Wayne Roberts 0:9eb5b8bf9f7b 434 case CMD_LORA_PKT_CFG_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 435 {
Wayne Roberts 0:9eb5b8bf9f7b 436 pktcfg_t pktcfg;
Wayne Roberts 0:9eb5b8bf9f7b 437 u32 = req[1];
Wayne Roberts 0:9eb5b8bf9f7b 438 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 439 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 440 preambleSymbs = u32;
Wayne Roberts 0:9eb5b8bf9f7b 441 pktcfg.octet = req[2];
Wayne Roberts 0:9eb5b8bf9f7b 442 pc.printf("pktcfg pre%lu fixlen%u crc%u inv%u\r\n", u32, pktcfg.bits.fixLen, pktcfg.bits.crcOn, pktcfg.bits.invIQ);
Wayne Roberts 0:9eb5b8bf9f7b 443 Radio::LoRaPacketConfig(u32, pktcfg.bits.fixLen, pktcfg.bits.crcOn, pktcfg.bits.invIQ);
Wayne Roberts 0:9eb5b8bf9f7b 444 }
Wayne Roberts 0:9eb5b8bf9f7b 445 break;
Wayne Roberts 0:9eb5b8bf9f7b 446 case CMD_BEACON_CFG_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 447 {
Wayne Roberts 0:9eb5b8bf9f7b 448 us_timestamp_t txStartAt;
Wayne Roberts 0:9eb5b8bf9f7b 449
Wayne Roberts 0:9eb5b8bf9f7b 450 u32 = req[1];
Wayne Roberts 0:9eb5b8bf9f7b 451 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 452 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 453 pc.printf("bi%lu ", u32);
Wayne Roberts 0:9eb5b8bf9f7b 454 beaconInterval_us = u32 * 1000000;
Wayne Roberts 0:9eb5b8bf9f7b 455 pc.printf("{%u} ", beaconInterval_us);
Wayne Roberts 0:9eb5b8bf9f7b 456
Wayne Roberts 0:9eb5b8bf9f7b 457 u32 = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 458 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 459 u32 |= req[2];
Wayne Roberts 0:9eb5b8bf9f7b 460 pc.printf("ps%lu ", u32);
Wayne Roberts 0:9eb5b8bf9f7b 461 beaconPreambleSymbs = u32;
Wayne Roberts 0:9eb5b8bf9f7b 462
Wayne Roberts 0:9eb5b8bf9f7b 463 beaconSizeBytes = req[4];
Wayne Roberts 0:9eb5b8bf9f7b 464 pc.printf("len%u\r\n", beaconSizeBytes);
Wayne Roberts 0:9eb5b8bf9f7b 465
Wayne Roberts 0:9eb5b8bf9f7b 466 if (beaconInterval_us > 0) {
Wayne Roberts 0:9eb5b8bf9f7b 467 _load_beacon();
Wayne Roberts 0:9eb5b8bf9f7b 468 send_beacon();
Wayne Roberts 0:9eb5b8bf9f7b 469 txStartAt = Radio::lpt.read_us();
Wayne Roberts 0:9eb5b8bf9f7b 470 flags.beacon_test = 1;
Wayne Roberts 0:9eb5b8bf9f7b 471 while (flags.beacon_test)
Wayne Roberts 0:9eb5b8bf9f7b 472 Radio::service();
Wayne Roberts 0:9eb5b8bf9f7b 473
Wayne Roberts 0:9eb5b8bf9f7b 474 u32 = Radio::irqAt - txStartAt;
Wayne Roberts 0:9eb5b8bf9f7b 475 pc.printf("beaconDur:%lu, 0x%lx\r\n", u32, u32);
Wayne Roberts 0:9eb5b8bf9f7b 476
Wayne Roberts 0:9eb5b8bf9f7b 477 tim_init();
Wayne Roberts 0:9eb5b8bf9f7b 478 flags.beacon_enabled = 1;
Wayne Roberts 0:9eb5b8bf9f7b 479
Wayne Roberts 0:9eb5b8bf9f7b 480 irq.buf[1] = u32 & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 481 u32 >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 482 irq.buf[2] = u32 & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 483 u32 >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 484 irq.buf[3] = u32 & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 485 u32 >>= 8;
Wayne Roberts 0:9eb5b8bf9f7b 486 irq.buf[4] = u32 & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 487 irq.fields.flags.irq_type = IRQ_TYPE_BEACON_DUR;
Wayne Roberts 0:9eb5b8bf9f7b 488 //pc.printf("BDirq.buf[0]:%02x\r\n", irq.buf[0]);
Wayne Roberts 0:9eb5b8bf9f7b 489 irqOutPin = 1;
Wayne Roberts 0:9eb5b8bf9f7b 490 } else {
Wayne Roberts 0:9eb5b8bf9f7b 491 load_beaconTimer.detach();
Wayne Roberts 0:9eb5b8bf9f7b 492 send_beaconTimer.detach();
Wayne Roberts 0:9eb5b8bf9f7b 493 flags.beacon_enabled = 0;
Wayne Roberts 0:9eb5b8bf9f7b 494 }
Wayne Roberts 0:9eb5b8bf9f7b 495 }
Wayne Roberts 0:9eb5b8bf9f7b 496 break;
Wayne Roberts 0:9eb5b8bf9f7b 497 case CMD_BEACON_PAYLOAD:
Wayne Roberts 0:9eb5b8bf9f7b 498 beacon_payload[0] = req[0];
Wayne Roberts 0:9eb5b8bf9f7b 499 beacon_payload[1] = req[1];
Wayne Roberts 0:9eb5b8bf9f7b 500 beacon_payload[2] = req[2];
Wayne Roberts 0:9eb5b8bf9f7b 501 beacon_payload[3] = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 502 break;
Wayne Roberts 0:9eb5b8bf9f7b 503 case CMD_CFG:
Wayne Roberts 0:9eb5b8bf9f7b 504 memcpy(cfg.buf, req, sizeof(cfg_t));
Wayne Roberts 0:9eb5b8bf9f7b 505 pc.printf("cfg %u\r\n", cfg.fields.n_rssi_samples);
Wayne Roberts 0:9eb5b8bf9f7b 506 break;
Wayne Roberts 0:9eb5b8bf9f7b 507 case CMD_STANDBY:
Wayne Roberts 0:9eb5b8bf9f7b 508 Radio::Standby();
Wayne Roberts 0:9eb5b8bf9f7b 509 break;
Wayne Roberts 0:9eb5b8bf9f7b 510 case CMD_PUBLIC_NET:
Wayne Roberts 0:9eb5b8bf9f7b 511 pc.printf("pubnet%02x\r\n", req[0]);
Wayne Roberts 0:9eb5b8bf9f7b 512 Radio::SetPublicNetwork(req[0] == 0 ? false : true);
Wayne Roberts 0:9eb5b8bf9f7b 513 break;
Wayne Roberts 0:9eb5b8bf9f7b 514 case CMD_MAX_PAYLEN_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 515 pc.printf("maxpay%02x\r\n", req[0]);
Wayne Roberts 0:9eb5b8bf9f7b 516 Radio::SetRxMaxPayloadLength(req[0]);
Wayne Roberts 0:9eb5b8bf9f7b 517 break;
Wayne Roberts 0:9eb5b8bf9f7b 518 case CMD_TX_BUF_START:
Wayne Roberts 0:9eb5b8bf9f7b 519 if (cfg.fields.flags.rxOnTxDone) {
Wayne Roberts 0:9eb5b8bf9f7b 520 /* turn off receiver in preparation for downlink */
Wayne Roberts 0:9eb5b8bf9f7b 521 Radio::Standby();
Wayne Roberts 0:9eb5b8bf9f7b 522
Wayne Roberts 0:9eb5b8bf9f7b 523 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 0:9eb5b8bf9f7b 524 Radio::LoRaPacketConfig(preambleSymbs, false, false, true);
Wayne Roberts 0:9eb5b8bf9f7b 525 }
Wayne Roberts 0:9eb5b8bf9f7b 526
Wayne Roberts 0:9eb5b8bf9f7b 527 tx_pkt_len = req[0];
Wayne Roberts 0:9eb5b8bf9f7b 528 memcpy(Radio::radio.tx_buf, req+1, 31);
Wayne Roberts 0:9eb5b8bf9f7b 529 tx_pkt_idx = 31;
Wayne Roberts 0:9eb5b8bf9f7b 530 break;
Wayne Roberts 0:9eb5b8bf9f7b 531 case CMD_TX_BUF:
Wayne Roberts 0:9eb5b8bf9f7b 532 {
Wayne Roberts 0:9eb5b8bf9f7b 533 uint8_t len = 32;
Wayne Roberts 0:9eb5b8bf9f7b 534 uint8_t end = (tx_pkt_idx + 32) & 0xff;
Wayne Roberts 0:9eb5b8bf9f7b 535 if (end < 32)
Wayne Roberts 0:9eb5b8bf9f7b 536 len -= end;
Wayne Roberts 0:9eb5b8bf9f7b 537 memcpy(Radio::radio.tx_buf + tx_pkt_idx, req, len);
Wayne Roberts 0:9eb5b8bf9f7b 538 tx_pkt_idx += len;
Wayne Roberts 0:9eb5b8bf9f7b 539 }
Wayne Roberts 0:9eb5b8bf9f7b 540 break;
Wayne Roberts 0:9eb5b8bf9f7b 541 case CMD_RSSI_REQ:
Wayne Roberts 0:9eb5b8bf9f7b 542 get_n_rssi = req[0];
Wayne Roberts 0:9eb5b8bf9f7b 543 break;
Wayne Roberts 0:9eb5b8bf9f7b 544 case CMD_SEND:
Wayne Roberts 0:9eb5b8bf9f7b 545 Radio::Send(tx_pkt_len,
Wayne Roberts 0:9eb5b8bf9f7b 546 cfg.fields.maxListenTime,
Wayne Roberts 0:9eb5b8bf9f7b 547 cfg.fields.channelFreeTime,
Wayne Roberts 0:9eb5b8bf9f7b 548 cfg.fields.rssiThresh
Wayne Roberts 0:9eb5b8bf9f7b 549 );
Wayne Roberts 0:9eb5b8bf9f7b 550 break;
Wayne Roberts 0:9eb5b8bf9f7b 551 case CMD_SKIP_BEACONS:
Wayne Roberts 0:9eb5b8bf9f7b 552 skip_beacon_cnt = req[0];
Wayne Roberts 0:9eb5b8bf9f7b 553 break;
Wayne Roberts 0:9eb5b8bf9f7b 554 case CMD_LORA_SYMBTO_WRITE: // 1 byte
Wayne Roberts 0:9eb5b8bf9f7b 555 Radio::SetLoRaSymbolTimeout(req[0]);
Wayne Roberts 0:9eb5b8bf9f7b 556 break;
Wayne Roberts 0:9eb5b8bf9f7b 557 case CMD_FSK_MODEM_CFG_WRITE: // 10bytes
Wayne Roberts 0:9eb5b8bf9f7b 558 {
Wayne Roberts 0:9eb5b8bf9f7b 559 uint32_t bps, fdev_hz;
Wayne Roberts 0:9eb5b8bf9f7b 560 uint16_t khz_bw;
Wayne Roberts 0:9eb5b8bf9f7b 561 u32 = req[3];
Wayne Roberts 0:9eb5b8bf9f7b 562 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 563 u32 |= req[2];
Wayne Roberts 0:9eb5b8bf9f7b 564 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 565 u32 |= req[1];
Wayne Roberts 0:9eb5b8bf9f7b 566 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 567 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 568 bps = u32;
Wayne Roberts 0:9eb5b8bf9f7b 569
Wayne Roberts 0:9eb5b8bf9f7b 570 u32 = req[5];
Wayne Roberts 0:9eb5b8bf9f7b 571 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 572 u32 |= req[4];
Wayne Roberts 0:9eb5b8bf9f7b 573 khz_bw = u32;
Wayne Roberts 0:9eb5b8bf9f7b 574
Wayne Roberts 0:9eb5b8bf9f7b 575 u32 = req[9];
Wayne Roberts 0:9eb5b8bf9f7b 576 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 577 u32 |= req[8];
Wayne Roberts 0:9eb5b8bf9f7b 578 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 579 u32 |= req[7];
Wayne Roberts 0:9eb5b8bf9f7b 580 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 581 u32 |= req[6];
Wayne Roberts 0:9eb5b8bf9f7b 582 fdev_hz = u32;
Wayne Roberts 0:9eb5b8bf9f7b 583 Radio::GFSKModemConfig(bps, khz_bw, fdev_hz);
Wayne Roberts 0:9eb5b8bf9f7b 584 }
Wayne Roberts 0:9eb5b8bf9f7b 585 break;
Wayne Roberts 0:9eb5b8bf9f7b 586 case CMD_FSK_PKT_CFG_WRITE: // 4 bytes
Wayne Roberts 0:9eb5b8bf9f7b 587 u32 = req[1];
Wayne Roberts 0:9eb5b8bf9f7b 588 u32 <<= 8;
Wayne Roberts 0:9eb5b8bf9f7b 589 u32 |= req[0];
Wayne Roberts 0:9eb5b8bf9f7b 590 Radio::GFSKPacketConfig(u32, req[2], req[3]);
Wayne Roberts 0:9eb5b8bf9f7b 591 break;
Wayne Roberts 0:9eb5b8bf9f7b 592 case CMD_FSK_SYNC_WRITE:
Wayne Roberts 0:9eb5b8bf9f7b 593 /* TODO */
Wayne Roberts 0:9eb5b8bf9f7b 594 break;
Wayne Roberts 0:9eb5b8bf9f7b 595 #ifdef DEBUG_SMBUS
Wayne Roberts 0:9eb5b8bf9f7b 596 case CMD_ISR:
Wayne Roberts 0:9eb5b8bf9f7b 597 pc.printf("i%02x ", req[0]); // lsbyte of I2C_ISR
Wayne Roberts 0:9eb5b8bf9f7b 598 break;
Wayne Roberts 0:9eb5b8bf9f7b 599 case CMD_STOPF:
Wayne Roberts 0:9eb5b8bf9f7b 600 pc.printf("STOPF\r\n");
Wayne Roberts 0:9eb5b8bf9f7b 601 break;
Wayne Roberts 0:9eb5b8bf9f7b 602 case CMD_AF:
Wayne Roberts 0:9eb5b8bf9f7b 603 pc.printf("AF%u ", req[0]); // req[0] is dma tx cndtr
Wayne Roberts 0:9eb5b8bf9f7b 604 break;
Wayne Roberts 0:9eb5b8bf9f7b 605 #endif /* DEBUG_SMBUS */
Wayne Roberts 0:9eb5b8bf9f7b 606 case CMD_BUSERR:
Wayne Roberts 0:9eb5b8bf9f7b 607 pc.printf("BUSERR%u\r\n", req[0]);
Wayne Roberts 0:9eb5b8bf9f7b 608 break;
Wayne Roberts 0:9eb5b8bf9f7b 609 /* failures: */
Wayne Roberts 0:9eb5b8bf9f7b 610 case CMD_ARLO:
Wayne Roberts 0:9eb5b8bf9f7b 611 pc.printf("ARLO%u,%u\r\n", toI2C_rx_pkt_idx, req[0]); // req[0] tx_cndtr
Wayne Roberts 0:9eb5b8bf9f7b 612 break;
Wayne Roberts 0:9eb5b8bf9f7b 613 case CMD_TIMEOUT:
Wayne Roberts 0:9eb5b8bf9f7b 614 pc.printf("TIMEOUT(tx%u,rx%u)\r\n", req[0], req[1]); // req[0] tx_cndtr
Wayne Roberts 0:9eb5b8bf9f7b 615 break;
Wayne Roberts 0:9eb5b8bf9f7b 616 default:
Wayne Roberts 0:9eb5b8bf9f7b 617 pc.printf("??%02x??\r\n", cmd);
Wayne Roberts 0:9eb5b8bf9f7b 618 break;
Wayne Roberts 0:9eb5b8bf9f7b 619 } // ..switch (cmd)
Wayne Roberts 0:9eb5b8bf9f7b 620
Wayne Roberts 0:9eb5b8bf9f7b 621 } // ..service_i2c_write()
Wayne Roberts 0:9eb5b8bf9f7b 622
Wayne Roberts 0:9eb5b8bf9f7b 623 const RadioEvents_t rev = {
Wayne Roberts 0:9eb5b8bf9f7b 624 /* Dio0_top_half */ NULL,
Wayne Roberts 0:9eb5b8bf9f7b 625 /* TxDone_topHalf */ NULL,
Wayne Roberts 0:9eb5b8bf9f7b 626 /* TxDone_botHalf */ txDoneCB,
Wayne Roberts 0:9eb5b8bf9f7b 627 /* TxTimeout */ NULL,
Wayne Roberts 0:9eb5b8bf9f7b 628 /* RxDone */ rxDoneCB,
Wayne Roberts 0:9eb5b8bf9f7b 629 /* RxTimeout */ NULL,
Wayne Roberts 0:9eb5b8bf9f7b 630 /* RxError */ NULL,
Wayne Roberts 0:9eb5b8bf9f7b 631 /* FhssChangeChannel */NULL,
Wayne Roberts 0:9eb5b8bf9f7b 632 /* CadDone */ NULL
Wayne Roberts 0:9eb5b8bf9f7b 633 };
Wayne Roberts 0:9eb5b8bf9f7b 634
Wayne Roberts 0:9eb5b8bf9f7b 635 int main()
Wayne Roberts 0:9eb5b8bf9f7b 636 {
Wayne Roberts 0:9eb5b8bf9f7b 637 Thread eventThread(osPriorityNormal, 512);
Wayne Roberts 0:9eb5b8bf9f7b 638 int res;
Wayne Roberts 0:9eb5b8bf9f7b 639
Wayne Roberts 0:9eb5b8bf9f7b 640 pc.baud(115200);
Wayne Roberts 0:9eb5b8bf9f7b 641 pc.printf("\r\nreset\r\n");
Wayne Roberts 0:9eb5b8bf9f7b 642
Wayne Roberts 0:9eb5b8bf9f7b 643 Radio::Init(&rev);
Wayne Roberts 0:9eb5b8bf9f7b 644 radio_device_init();
Wayne Roberts 0:9eb5b8bf9f7b 645
Wayne Roberts 0:9eb5b8bf9f7b 646 res = smbus_init(I2C_SDA, I2C_SCL, SLAVE_ADDRESS);
Wayne Roberts 0:9eb5b8bf9f7b 647 pc.printf("%d = smbus_init()\r\n", res);
Wayne Roberts 0:9eb5b8bf9f7b 648 if (res < 0) {
Wayne Roberts 0:9eb5b8bf9f7b 649 for (;;) asm("nop");
Wayne Roberts 0:9eb5b8bf9f7b 650 }
Wayne Roberts 0:9eb5b8bf9f7b 651
Wayne Roberts 0:9eb5b8bf9f7b 652 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
Wayne Roberts 0:9eb5b8bf9f7b 653
Wayne Roberts 0:9eb5b8bf9f7b 654 while (1) {
Wayne Roberts 0:9eb5b8bf9f7b 655 if (i2c.c_overrun) {
Wayne Roberts 0:9eb5b8bf9f7b 656 pc.printf("c_overrun\r\n");
Wayne Roberts 0:9eb5b8bf9f7b 657 for (;;) asm("nop");
Wayne Roberts 0:9eb5b8bf9f7b 658 }
Wayne Roberts 0:9eb5b8bf9f7b 659
Wayne Roberts 0:9eb5b8bf9f7b 660 service_i2c();
Wayne Roberts 0:9eb5b8bf9f7b 661 console();
Wayne Roberts 0:9eb5b8bf9f7b 662
Wayne Roberts 0:9eb5b8bf9f7b 663 if (get_n_rssi > 0) {
Wayne Roberts 0:9eb5b8bf9f7b 664 measure_ambient(get_n_rssi);
Wayne Roberts 0:9eb5b8bf9f7b 665 get_n_rssi = 0;
Wayne Roberts 0:9eb5b8bf9f7b 666 }
Wayne Roberts 0:9eb5b8bf9f7b 667
Wayne Roberts 0:9eb5b8bf9f7b 668 if (flags.req_type != IRQ_TYPE_PKT) {
Wayne Roberts 0:9eb5b8bf9f7b 669 switch (flags.req_type) {
Wayne Roberts 0:9eb5b8bf9f7b 670 case IRQ_TYPE_CF:
Wayne Roberts 0:9eb5b8bf9f7b 671 cf_read();
Wayne Roberts 0:9eb5b8bf9f7b 672 break;
Wayne Roberts 0:9eb5b8bf9f7b 673 case IRQ_TYPE_RANDOM:
Wayne Roberts 0:9eb5b8bf9f7b 674 get_random();
Wayne Roberts 0:9eb5b8bf9f7b 675 break;
Wayne Roberts 0:9eb5b8bf9f7b 676 case IRQ_TYPE_FSK_MODEM:
Wayne Roberts 0:9eb5b8bf9f7b 677 get_fsk_modem();
Wayne Roberts 0:9eb5b8bf9f7b 678 break;
Wayne Roberts 0:9eb5b8bf9f7b 679 case IRQ_TYPE_FSK_PKT:
Wayne Roberts 0:9eb5b8bf9f7b 680 get_fsk_packet();
Wayne Roberts 0:9eb5b8bf9f7b 681 break;
Wayne Roberts 0:9eb5b8bf9f7b 682 case IRQ_TYPE_FSK_SYNC:
Wayne Roberts 0:9eb5b8bf9f7b 683 get_fsk_sync();
Wayne Roberts 0:9eb5b8bf9f7b 684 break;
Wayne Roberts 0:9eb5b8bf9f7b 685 case IRQ_TYPE_TXDBM:
Wayne Roberts 0:9eb5b8bf9f7b 686 get_tx_dbm();
Wayne Roberts 0:9eb5b8bf9f7b 687 break;
Wayne Roberts 0:9eb5b8bf9f7b 688 case IRQ_TYPE_LORA_MODEM:
Wayne Roberts 0:9eb5b8bf9f7b 689 get_lora_modem();
Wayne Roberts 0:9eb5b8bf9f7b 690 break;
Wayne Roberts 0:9eb5b8bf9f7b 691 case IRQ_TYPE_LORA_PKT:
Wayne Roberts 0:9eb5b8bf9f7b 692 get_lora_packet();
Wayne Roberts 0:9eb5b8bf9f7b 693 break;
Wayne Roberts 0:9eb5b8bf9f7b 694 case IRQ_TYPE_OPMODE:
Wayne Roberts 0:9eb5b8bf9f7b 695 get_opmode();
Wayne Roberts 0:9eb5b8bf9f7b 696 break;
Wayne Roberts 0:9eb5b8bf9f7b 697 } // ..switch (flags.req_type)
Wayne Roberts 0:9eb5b8bf9f7b 698 flags.req_type = IRQ_TYPE_PKT;
Wayne Roberts 0:9eb5b8bf9f7b 699 }
Wayne Roberts 0:9eb5b8bf9f7b 700
Wayne Roberts 0:9eb5b8bf9f7b 701 if (blocked_cmd) {
Wayne Roberts 0:9eb5b8bf9f7b 702 pc.printf("blocked_cmd:%02x\r\n", blocked_cmd);
Wayne Roberts 0:9eb5b8bf9f7b 703 blocked_cmd = 0;
Wayne Roberts 0:9eb5b8bf9f7b 704 }
Wayne Roberts 0:9eb5b8bf9f7b 705
Wayne Roberts 0:9eb5b8bf9f7b 706 Radio::service();
Wayne Roberts 0:9eb5b8bf9f7b 707 } // ..while (1)
Wayne Roberts 0:9eb5b8bf9f7b 708 }
Wayne Roberts 0:9eb5b8bf9f7b 709