wayne roberts / Mbed OS LoRaWAN_singlechannel_gateway

Dependencies:   SX127x sx12xx_hal

Committer:
dudmuck
Date:
Mon Aug 07 12:41:55 2017 -0700
Revision:
14:c6284654d1b0
Parent:
13:fa2095be01c4
Child:
15:fea23ad8eafa
add command to send downlink with power instruction

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:2ff18de8d48b 1 #include "lorawan.h"
dudmuck 0:2ff18de8d48b 2 #include "tim.h"
dudmuck 8:307f7faeb594 3 #include "commands.h"
dudmuck 13:fa2095be01c4 4 #define __STDC_FORMAT_MACROS
dudmuck 13:fa2095be01c4 5 #include <inttypes.h>
dudmuck 0:2ff18de8d48b 6
dudmuck 12:9a8c13c4298b 7 #define TYPE_ABZ
dudmuck 4:7e743e402681 8 RawSerial pc(USBTX, USBRX);
dudmuck 0:2ff18de8d48b 9 Timer timer;
dudmuck 0:2ff18de8d48b 10
dudmuck 10:6783623cc886 11 //#if defined(TARGET_DISCO_L072CZ_LRWAN1)
dudmuck 10:6783623cc886 12 #if defined(TARGET_NUCLEO_L073RZ) && defined(TYPE_ABZ)
dudmuck 2:9628d5e4b1bf 13 SPI spi(PA_7, PA_6, PB_3); // mosi, miso, sclk
dudmuck 2:9628d5e4b1bf 14 // dio0, dio1, nss, spi, rst
dudmuck 2:9628d5e4b1bf 15 SX127x radio(PB_4, PB_1, PA_15, spi, PC_0); // sx1276 arduino shield
dudmuck 2:9628d5e4b1bf 16
dudmuck 2:9628d5e4b1bf 17 #define CRF1 PA_1
dudmuck 2:9628d5e4b1bf 18 #define CRF2 PC_2
dudmuck 2:9628d5e4b1bf 19 #define CRF3 PC_1
dudmuck 2:9628d5e4b1bf 20 DigitalOut Vctl1(CRF1);
dudmuck 2:9628d5e4b1bf 21 DigitalOut Vctl2(CRF2);
dudmuck 2:9628d5e4b1bf 22 DigitalOut Vctl3(CRF3);
dudmuck 2:9628d5e4b1bf 23
dudmuck 2:9628d5e4b1bf 24 void rfsw_callback()
dudmuck 2:9628d5e4b1bf 25 {
dudmuck 2:9628d5e4b1bf 26 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) {
dudmuck 2:9628d5e4b1bf 27 Vctl1 = 0;
dudmuck 2:9628d5e4b1bf 28 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 2:9628d5e4b1bf 29 Vctl2 = 0;
dudmuck 2:9628d5e4b1bf 30 Vctl3 = 1;
dudmuck 2:9628d5e4b1bf 31 } else {
dudmuck 2:9628d5e4b1bf 32 Vctl2 = 1;
dudmuck 2:9628d5e4b1bf 33 Vctl3 = 0;
dudmuck 2:9628d5e4b1bf 34 }
dudmuck 2:9628d5e4b1bf 35 } else {
dudmuck 2:9628d5e4b1bf 36 if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE)
dudmuck 2:9628d5e4b1bf 37 Vctl1 = 1;
dudmuck 2:9628d5e4b1bf 38 else
dudmuck 2:9628d5e4b1bf 39 Vctl1 = 0;
dudmuck 2:9628d5e4b1bf 40
dudmuck 2:9628d5e4b1bf 41 Vctl2 = 0;
dudmuck 2:9628d5e4b1bf 42 Vctl3 = 0;
dudmuck 2:9628d5e4b1bf 43 }
dudmuck 2:9628d5e4b1bf 44 }
dudmuck 2:9628d5e4b1bf 45 #else
dudmuck 2:9628d5e4b1bf 46 SPI spi(D11, D12, D13); // mosi, miso, sclk
dudmuck 2:9628d5e4b1bf 47 // dio0, dio1, nss, spi, rst
dudmuck 2:9628d5e4b1bf 48 SX127x radio( D2, D3, D10, spi, A0); // sx1276 arduino shield
dudmuck 2:9628d5e4b1bf 49
dudmuck 2:9628d5e4b1bf 50 DigitalInOut rfsw(A4);
dudmuck 2:9628d5e4b1bf 51
dudmuck 2:9628d5e4b1bf 52 void rfsw_callback()
dudmuck 2:9628d5e4b1bf 53 {
dudmuck 2:9628d5e4b1bf 54 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER)
dudmuck 2:9628d5e4b1bf 55 rfsw = 1;
dudmuck 2:9628d5e4b1bf 56 else
dudmuck 2:9628d5e4b1bf 57 rfsw = 0;
dudmuck 2:9628d5e4b1bf 58 }
dudmuck 2:9628d5e4b1bf 59 #endif
dudmuck 0:2ff18de8d48b 60
dudmuck 0:2ff18de8d48b 61 char pcbuf[64];
dudmuck 0:2ff18de8d48b 62 int pcbuf_len;
dudmuck 9:a0ce66c18ec0 63 uint8_t beacon_payload[4];
dudmuck 12:9a8c13c4298b 64 uint32_t tx_ms;
dudmuck 0:2ff18de8d48b 65
dudmuck 0:2ff18de8d48b 66 unsigned int skip_beacon_cnt;
dudmuck 0:2ff18de8d48b 67
dudmuck 0:2ff18de8d48b 68 SX127x_lora lora(radio);
dudmuck 0:2ff18de8d48b 69
dudmuck 12:9a8c13c4298b 70 float starting_bg_rssi;
dudmuck 0:2ff18de8d48b 71
dudmuck 0:2ff18de8d48b 72 #define N_SAMPLES 64
dudmuck 0:2ff18de8d48b 73 void channel_scan()
dudmuck 0:2ff18de8d48b 74 {
dudmuck 0:2ff18de8d48b 75 int min_ch, ch;
dudmuck 0:2ff18de8d48b 76 uint32_t hz = LORAMAC_FIRST_CHANNEL;
dudmuck 0:2ff18de8d48b 77 int acc[LORA_MAX_NB_CHANNELS];
dudmuck 0:2ff18de8d48b 78
dudmuck 0:2ff18de8d48b 79 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 80
dudmuck 0:2ff18de8d48b 81 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 82 int i;
dudmuck 0:2ff18de8d48b 83 float MHz = (float)hz / 1e6;
dudmuck 0:2ff18de8d48b 84 radio.set_frf_MHz(MHz);
dudmuck 0:2ff18de8d48b 85 radio.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 86 acc[ch] = 0;
dudmuck 0:2ff18de8d48b 87 for (i = 0; i < N_SAMPLES; i++) {
dudmuck 0:2ff18de8d48b 88 int rssi = lora.get_current_rssi();
dudmuck 0:2ff18de8d48b 89 acc[ch] += rssi;
dudmuck 0:2ff18de8d48b 90 wait(0.01);
dudmuck 0:2ff18de8d48b 91 }
dudmuck 0:2ff18de8d48b 92 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 93 printf("ch%u: %f\r\n", ch, acc[ch] / (float)N_SAMPLES);
dudmuck 0:2ff18de8d48b 94 hz += LORAMAC_STEPWIDTH_CHANNEL;
dudmuck 0:2ff18de8d48b 95 radio.set_frf_MHz((float)hz/1e6);
dudmuck 0:2ff18de8d48b 96 }
dudmuck 0:2ff18de8d48b 97
dudmuck 0:2ff18de8d48b 98 int min = 0x7fffffff;
dudmuck 0:2ff18de8d48b 99 min_ch = 0;
dudmuck 0:2ff18de8d48b 100 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 101 if (acc[ch] < min) {
dudmuck 0:2ff18de8d48b 102 min = acc[ch];
dudmuck 0:2ff18de8d48b 103 min_ch = ch;
dudmuck 0:2ff18de8d48b 104 }
dudmuck 0:2ff18de8d48b 105 }
dudmuck 0:2ff18de8d48b 106 hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
dudmuck 0:2ff18de8d48b 107 printf("using ch%u, %luhz\r\n", min_ch, hz);
dudmuck 0:2ff18de8d48b 108 radio.set_frf_MHz((float)hz/1e6);
dudmuck 12:9a8c13c4298b 109
dudmuck 12:9a8c13c4298b 110 starting_bg_rssi = acc[min_ch] / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 111 }
dudmuck 12:9a8c13c4298b 112
dudmuck 12:9a8c13c4298b 113 void measure_ambient()
dudmuck 12:9a8c13c4298b 114 {
dudmuck 12:9a8c13c4298b 115 int i, acc = 0;
dudmuck 12:9a8c13c4298b 116 float bg_rssi;
dudmuck 12:9a8c13c4298b 117 float diff;
dudmuck 12:9a8c13c4298b 118 static unsigned cnt = 0;
dudmuck 12:9a8c13c4298b 119
dudmuck 12:9a8c13c4298b 120 for (i = 0; i < N_SAMPLES; i++) {
dudmuck 12:9a8c13c4298b 121 int rssi = lora.get_current_rssi();
dudmuck 12:9a8c13c4298b 122 acc += rssi;
dudmuck 12:9a8c13c4298b 123 wait(0.01);
dudmuck 12:9a8c13c4298b 124 }
dudmuck 12:9a8c13c4298b 125 bg_rssi = acc / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 126 diff = bg_rssi - starting_bg_rssi;
dudmuck 12:9a8c13c4298b 127 printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
dudmuck 12:9a8c13c4298b 128 if (diff > 10) {
dudmuck 12:9a8c13c4298b 129 if (++cnt > 3) {
dudmuck 12:9a8c13c4298b 130 /* find better channel */
dudmuck 12:9a8c13c4298b 131 channel_scan();
dudmuck 12:9a8c13c4298b 132 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 12:9a8c13c4298b 133 cnt = 0;
dudmuck 12:9a8c13c4298b 134 }
dudmuck 12:9a8c13c4298b 135 } else
dudmuck 12:9a8c13c4298b 136 cnt = 0;
dudmuck 0:2ff18de8d48b 137 }
dudmuck 0:2ff18de8d48b 138
dudmuck 0:2ff18de8d48b 139 void init_radio()
dudmuck 0:2ff18de8d48b 140 {
dudmuck 0:2ff18de8d48b 141 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 142
dudmuck 0:2ff18de8d48b 143 radio.RegPaConfig.bits.OutputPower = 15;
dudmuck 0:2ff18de8d48b 144 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 0:2ff18de8d48b 145 lora.enable();
dudmuck 13:fa2095be01c4 146 lora.setBw_KHz(BANDWIDTH_KHZ);
dudmuck 0:2ff18de8d48b 147 lora.setSf(LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:2ff18de8d48b 148 printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:2ff18de8d48b 149
dudmuck 0:2ff18de8d48b 150 channel_scan();
dudmuck 0:2ff18de8d48b 151
dudmuck 0:2ff18de8d48b 152 radio.write_reg(REG_LR_SYNC_BYTE, LORA_MAC_PUBLIC_SYNCWORD);
dudmuck 0:2ff18de8d48b 153 radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, 255);
dudmuck 0:2ff18de8d48b 154 }
dudmuck 0:2ff18de8d48b 155
dudmuck 0:2ff18de8d48b 156 void printLoraIrqs(bool clear)
dudmuck 0:2ff18de8d48b 157 {
dudmuck 0:2ff18de8d48b 158 printf("\r\nIrqFlags:");
dudmuck 0:2ff18de8d48b 159 if (lora.RegIrqFlags.bits.CadDetected)
dudmuck 0:2ff18de8d48b 160 printf("CadDetected ");
dudmuck 0:2ff18de8d48b 161 if (lora.RegIrqFlags.bits.FhssChangeChannel) {
dudmuck 0:2ff18de8d48b 162 printf("FhssChangeChannel:%d ", lora.RegHopChannel.bits.FhssPresentChannel);
dudmuck 0:2ff18de8d48b 163 }
dudmuck 0:2ff18de8d48b 164 if (lora.RegIrqFlags.bits.CadDone)
dudmuck 0:2ff18de8d48b 165 printf("CadDone ");
dudmuck 0:2ff18de8d48b 166 if (lora.RegIrqFlags.bits.TxDone)
dudmuck 12:9a8c13c4298b 167 printf("TxDone-dio0:%d ", radio.dio0.read());
dudmuck 0:2ff18de8d48b 168 if (lora.RegIrqFlags.bits.ValidHeader)
dudmuck 0:2ff18de8d48b 169 printf("ValidHeader ");
dudmuck 0:2ff18de8d48b 170 if (lora.RegIrqFlags.bits.PayloadCrcError)
dudmuck 0:2ff18de8d48b 171 printf("PayloadCrcError ");
dudmuck 0:2ff18de8d48b 172 if (lora.RegIrqFlags.bits.RxDone)
dudmuck 0:2ff18de8d48b 173 printf("RxDone ");
dudmuck 0:2ff18de8d48b 174 if (lora.RegIrqFlags.bits.RxTimeout)
dudmuck 0:2ff18de8d48b 175 printf("RxTimeout ");
dudmuck 0:2ff18de8d48b 176
dudmuck 0:2ff18de8d48b 177 printf("\r\n");
dudmuck 0:2ff18de8d48b 178
dudmuck 0:2ff18de8d48b 179 if (clear)
dudmuck 0:2ff18de8d48b 180 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 0:2ff18de8d48b 181 }
dudmuck 0:2ff18de8d48b 182
dudmuck 0:2ff18de8d48b 183 void printOpMode()
dudmuck 0:2ff18de8d48b 184 {
dudmuck 0:2ff18de8d48b 185 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 0:2ff18de8d48b 186 switch (radio.RegOpMode.bits.Mode) {
dudmuck 0:2ff18de8d48b 187 case RF_OPMODE_SLEEP: printf("sleep"); break;
dudmuck 0:2ff18de8d48b 188 case RF_OPMODE_STANDBY: printf("stby"); break;
dudmuck 0:2ff18de8d48b 189 case RF_OPMODE_SYNTHESIZER_TX: printf("fstx"); break;
dudmuck 0:2ff18de8d48b 190 case RF_OPMODE_TRANSMITTER: printf("tx"); break;
dudmuck 0:2ff18de8d48b 191 case RF_OPMODE_SYNTHESIZER_RX: printf("fsrx"); break;
dudmuck 0:2ff18de8d48b 192 case RF_OPMODE_RECEIVER: printf("rx"); break;
dudmuck 0:2ff18de8d48b 193 case 6:
dudmuck 0:2ff18de8d48b 194 if (radio.RegOpMode.bits.LongRangeMode)
dudmuck 0:2ff18de8d48b 195 printf("rxs");
dudmuck 0:2ff18de8d48b 196 else
dudmuck 0:2ff18de8d48b 197 printf("-6-");
dudmuck 0:2ff18de8d48b 198 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 199 case 7:
dudmuck 0:2ff18de8d48b 200 if (radio.RegOpMode.bits.LongRangeMode)
dudmuck 0:2ff18de8d48b 201 printf("cad");
dudmuck 0:2ff18de8d48b 202 else
dudmuck 0:2ff18de8d48b 203 printf("-7-");
dudmuck 0:2ff18de8d48b 204 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 205 }
dudmuck 0:2ff18de8d48b 206 }
dudmuck 0:2ff18de8d48b 207
dudmuck 9:a0ce66c18ec0 208 #define GPO_IDX 6
dudmuck 9:a0ce66c18ec0 209 void decrypted_uplink(uint8_t* buf, uint8_t buflen, uint8_t port)
dudmuck 9:a0ce66c18ec0 210 {
dudmuck 9:a0ce66c18ec0 211 if (port == SENSOR_PORT) {
dudmuck 9:a0ce66c18ec0 212 uint16_t a_1, a_3, lum;
dudmuck 9:a0ce66c18ec0 213 a_1 = buf[0] << 8;
dudmuck 9:a0ce66c18ec0 214 a_1 += buf[1];
dudmuck 9:a0ce66c18ec0 215 a_3 = buf[2] << 8;
dudmuck 9:a0ce66c18ec0 216 a_3 += buf[3];
dudmuck 9:a0ce66c18ec0 217 lum = buf[4] << 8;
dudmuck 9:a0ce66c18ec0 218 lum += buf[5];
dudmuck 10:6783623cc886 219 printf("SENSOR gpi:%u, gpo:%u, a1:%u, a3:%u, lum:%u\r\n", (buf[GPO_IDX] & 2) >> 1, buf[GPO_IDX] & 1, a_1, a_3, lum);
dudmuck 9:a0ce66c18ec0 220 } else if (port == TEXT_PORT) {
dudmuck 9:a0ce66c18ec0 221 buf[buflen] = 0;
dudmuck 9:a0ce66c18ec0 222 printf("TEXT %s\r\n", buf);
dudmuck 9:a0ce66c18ec0 223 } else {
dudmuck 9:a0ce66c18ec0 224 int i;
dudmuck 9:a0ce66c18ec0 225 printf("port%u: ", port);
dudmuck 9:a0ce66c18ec0 226 for (i = 0; i < buflen; i++)
dudmuck 9:a0ce66c18ec0 227 printf("%02x ", buf[i]);
dudmuck 9:a0ce66c18ec0 228 printf("\r\n");
dudmuck 9:a0ce66c18ec0 229 }
dudmuck 9:a0ce66c18ec0 230 }
dudmuck 9:a0ce66c18ec0 231
dudmuck 0:2ff18de8d48b 232 EventQueue queue;
dudmuck 3:7c01b8978638 233
dudmuck 3:7c01b8978638 234 volatile bool get_tx_done;
dudmuck 3:7c01b8978638 235 volatile bool beacon_guard;
dudmuck 0:2ff18de8d48b 236 bool restore_tx_invert;
dudmuck 3:7c01b8978638 237 bool restore_header_mode;
dudmuck 0:2ff18de8d48b 238
dudmuck 0:2ff18de8d48b 239 void send_downlink()
dudmuck 0:2ff18de8d48b 240 {
dudmuck 12:9a8c13c4298b 241 if (!beacon_guard && LoRaWan::do_downlink) {
dudmuck 0:2ff18de8d48b 242 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 243 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 244 lora.invert_tx(true);
dudmuck 0:2ff18de8d48b 245 restore_tx_invert = true;
dudmuck 0:2ff18de8d48b 246 lora.setRxPayloadCrcOn(false);
dudmuck 0:2ff18de8d48b 247 lora.start_tx(lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 248 LoRaWan::do_downlink = false;
dudmuck 3:7c01b8978638 249 get_tx_done = true;
dudmuck 12:9a8c13c4298b 250 tx_ms = timer.read_ms();
dudmuck 0:2ff18de8d48b 251 }
dudmuck 0:2ff18de8d48b 252 }
dudmuck 0:2ff18de8d48b 253
dudmuck 12:9a8c13c4298b 254
dudmuck 0:2ff18de8d48b 255 void
dudmuck 0:2ff18de8d48b 256 service_radio()
dudmuck 0:2ff18de8d48b 257 {
dudmuck 0:2ff18de8d48b 258 service_action_e act = lora.service();
dudmuck 0:2ff18de8d48b 259
dudmuck 0:2ff18de8d48b 260 switch (act) {
dudmuck 0:2ff18de8d48b 261 case SERVICE_ERROR:
dudmuck 0:2ff18de8d48b 262 printf("SERVICE_ERROR\r\n");
dudmuck 0:2ff18de8d48b 263 case SERVICE_TX_DONE:
dudmuck 0:2ff18de8d48b 264 case SERVICE_NONE:
dudmuck 0:2ff18de8d48b 265 break;
dudmuck 0:2ff18de8d48b 266 case SERVICE_READ_FIFO:
dudmuck 3:7c01b8978638 267 LoRaWan::rx_slot = tim_get_current_slot();
dudmuck 3:7c01b8978638 268 LoRaWan::rx_ms = timer.read_ms();
dudmuck 14:c6284654d1b0 269 printf("%u, %lu, %.1fdB, %ddBm, ",
dudmuck 14:c6284654d1b0 270 LoRaWan::rx_slot,
dudmuck 14:c6284654d1b0 271 time(NULL),
dudmuck 14:c6284654d1b0 272 lora.RegPktSnrValue / 4.0,
dudmuck 14:c6284654d1b0 273 lora.get_pkt_rssi()
dudmuck 14:c6284654d1b0 274 );
dudmuck 12:9a8c13c4298b 275 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 12:9a8c13c4298b 276 LoRaWan::parse_receive();
dudmuck 12:9a8c13c4298b 277 if (!LoRaWan::do_downlink) {
dudmuck 12:9a8c13c4298b 278 /* if not sending downlink, start receiver now */
dudmuck 3:7c01b8978638 279 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 280 }
dudmuck 12:9a8c13c4298b 281
dudmuck 0:2ff18de8d48b 282 break;
dudmuck 0:2ff18de8d48b 283 } // ..switch (act)
dudmuck 0:2ff18de8d48b 284 }
dudmuck 0:2ff18de8d48b 285
dudmuck 0:2ff18de8d48b 286 volatile float prev_beacon_send_at;
dudmuck 0:2ff18de8d48b 287 volatile float beacon_send_at;
dudmuck 0:2ff18de8d48b 288 volatile float beacon_loaded_at;
dudmuck 0:2ff18de8d48b 289
dudmuck 0:2ff18de8d48b 290 volatile bool beacon_loaded;
dudmuck 0:2ff18de8d48b 291 void
dudmuck 0:2ff18de8d48b 292 send_beacon()
dudmuck 0:2ff18de8d48b 293 {
dudmuck 0:2ff18de8d48b 294 prev_beacon_send_at = beacon_send_at;
dudmuck 0:2ff18de8d48b 295 beacon_send_at = timer.read();
dudmuck 0:2ff18de8d48b 296
dudmuck 0:2ff18de8d48b 297 if (!beacon_loaded)
dudmuck 0:2ff18de8d48b 298 return;
dudmuck 0:2ff18de8d48b 299
dudmuck 0:2ff18de8d48b 300 radio.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 0:2ff18de8d48b 301 beacon_loaded = false;
dudmuck 3:7c01b8978638 302 get_tx_done = true;
dudmuck 12:9a8c13c4298b 303 tx_ms = timer.read_ms();
dudmuck 0:2ff18de8d48b 304 }
dudmuck 0:2ff18de8d48b 305
dudmuck 0:2ff18de8d48b 306 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:2ff18de8d48b 307 {
dudmuck 0:2ff18de8d48b 308 // The CRC calculation follows CCITT
dudmuck 0:2ff18de8d48b 309 const uint16_t polynom = 0x1021;
dudmuck 0:2ff18de8d48b 310 // CRC initial value
dudmuck 0:2ff18de8d48b 311 uint16_t crc = 0x0000;
dudmuck 0:2ff18de8d48b 312
dudmuck 0:2ff18de8d48b 313 if( buffer == NULL )
dudmuck 0:2ff18de8d48b 314 {
dudmuck 0:2ff18de8d48b 315 return 0;
dudmuck 0:2ff18de8d48b 316 }
dudmuck 0:2ff18de8d48b 317
dudmuck 0:2ff18de8d48b 318 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:2ff18de8d48b 319 {
dudmuck 0:2ff18de8d48b 320 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:2ff18de8d48b 321 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:2ff18de8d48b 322 {
dudmuck 0:2ff18de8d48b 323 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:2ff18de8d48b 324 }
dudmuck 0:2ff18de8d48b 325 }
dudmuck 0:2ff18de8d48b 326
dudmuck 0:2ff18de8d48b 327 return crc;
dudmuck 0:2ff18de8d48b 328 }
dudmuck 0:2ff18de8d48b 329
dudmuck 0:2ff18de8d48b 330 void
dudmuck 3:7c01b8978638 331 _load_beacon()
dudmuck 0:2ff18de8d48b 332 {
dudmuck 0:2ff18de8d48b 333 uint16_t crc;
dudmuck 12:9a8c13c4298b 334 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 12:9a8c13c4298b 335 // clear any flags which might have been set during beacon_guard
dudmuck 12:9a8c13c4298b 336 radio.write_reg(REG_LR_IRQFLAGS, 0xff);
dudmuck 0:2ff18de8d48b 337 lora.RegPayloadLength = BEACON_SIZE;
dudmuck 0:2ff18de8d48b 338 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 339 lora.setHeaderMode(true);
dudmuck 3:7c01b8978638 340 restore_header_mode = true;
dudmuck 0:2ff18de8d48b 341
dudmuck 0:2ff18de8d48b 342 if (skip_beacon_cnt > 0) {
dudmuck 1:107435401168 343 //printf("skip_beacon_cnt:%d\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 344 lora.invert_tx(true);
dudmuck 0:2ff18de8d48b 345 restore_tx_invert = true;
dudmuck 0:2ff18de8d48b 346 skip_beacon_cnt--;
dudmuck 0:2ff18de8d48b 347 }
dudmuck 0:2ff18de8d48b 348
dudmuck 9:a0ce66c18ec0 349 radio.tx_buf[0] = beacon_payload[0];
dudmuck 9:a0ce66c18ec0 350 radio.tx_buf[1] = beacon_payload[1];
dudmuck 9:a0ce66c18ec0 351 radio.tx_buf[2] = beacon_payload[2];
dudmuck 9:a0ce66c18ec0 352 radio.tx_buf[3] = beacon_payload[3];
dudmuck 9:a0ce66c18ec0 353 beacon_payload[0] = CMD_NONE;
dudmuck 9:a0ce66c18ec0 354
dudmuck 0:2ff18de8d48b 355 crc = beacon_crc(radio.tx_buf, 4);
dudmuck 0:2ff18de8d48b 356 radio.tx_buf[4] = crc & 0xff;
dudmuck 0:2ff18de8d48b 357 radio.tx_buf[5] = crc >> 8;
dudmuck 0:2ff18de8d48b 358
dudmuck 0:2ff18de8d48b 359 // DIO0 to TxDone
dudmuck 3:7c01b8978638 360 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 3:7c01b8978638 361 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 0:2ff18de8d48b 362
dudmuck 0:2ff18de8d48b 363 // set FifoPtrAddr to FifoTxPtrBase
dudmuck 0:2ff18de8d48b 364 radio.write_reg(REG_LR_FIFOADDRPTR, radio.read_reg(REG_LR_FIFOTXBASEADDR));
dudmuck 0:2ff18de8d48b 365
dudmuck 0:2ff18de8d48b 366 // write PayloadLength bytes to fifo
dudmuck 0:2ff18de8d48b 367 lora.write_fifo(lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 368
dudmuck 0:2ff18de8d48b 369 // prepare for tx to occur in send_beacon()
dudmuck 0:2ff18de8d48b 370 radio.set_opmode(RF_OPMODE_SYNTHESIZER_TX);
dudmuck 0:2ff18de8d48b 371 beacon_loaded = true;
dudmuck 0:2ff18de8d48b 372
dudmuck 0:2ff18de8d48b 373 beacon_loaded_at = timer.read();
dudmuck 0:2ff18de8d48b 374 }
dudmuck 0:2ff18de8d48b 375
dudmuck 3:7c01b8978638 376 void load_beacon()
dudmuck 3:7c01b8978638 377 {
dudmuck 3:7c01b8978638 378 beacon_guard = true;
dudmuck 12:9a8c13c4298b 379 queue.call_in(200, _load_beacon);
dudmuck 3:7c01b8978638 380 }
dudmuck 3:7c01b8978638 381
dudmuck 0:2ff18de8d48b 382 void get_time_till_beacon()
dudmuck 0:2ff18de8d48b 383 {
dudmuck 0:2ff18de8d48b 384 uint16_t slots = tim_get_current_slot();
dudmuck 0:2ff18de8d48b 385 printf("slots:%u\r\n", slots);
dudmuck 0:2ff18de8d48b 386 }
dudmuck 0:2ff18de8d48b 387
dudmuck 4:7e743e402681 388 void rx_isr()
dudmuck 0:2ff18de8d48b 389 {
dudmuck 0:2ff18de8d48b 390 static uint8_t pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 391 static uint8_t prev_len = 0;;
dudmuck 0:2ff18de8d48b 392 char c = pc.getc();
dudmuck 0:2ff18de8d48b 393
dudmuck 0:2ff18de8d48b 394 if (c == 8) {
dudmuck 0:2ff18de8d48b 395 if (pcbuf_idx > 0) {
dudmuck 0:2ff18de8d48b 396 pc.putc(8);
dudmuck 0:2ff18de8d48b 397 pc.putc(' ');
dudmuck 0:2ff18de8d48b 398 pc.putc(8);
dudmuck 0:2ff18de8d48b 399 pcbuf_idx--;
dudmuck 0:2ff18de8d48b 400 }
dudmuck 0:2ff18de8d48b 401 } else if (c == 3) { // ctrl-C
dudmuck 0:2ff18de8d48b 402 pcbuf_len = -1;
dudmuck 0:2ff18de8d48b 403 } else if (c == '\r') {
dudmuck 0:2ff18de8d48b 404 if (pcbuf_idx == 0) {
dudmuck 0:2ff18de8d48b 405 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 406 } else {
dudmuck 0:2ff18de8d48b 407 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:2ff18de8d48b 408 prev_len = pcbuf_idx;
dudmuck 0:2ff18de8d48b 409 pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 410 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 411 }
dudmuck 0:2ff18de8d48b 412 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:2ff18de8d48b 413 pcbuf[pcbuf_idx++] = c;
dudmuck 0:2ff18de8d48b 414 pc.putc(c);
dudmuck 0:2ff18de8d48b 415 }
dudmuck 0:2ff18de8d48b 416 }
dudmuck 0:2ff18de8d48b 417
dudmuck 0:2ff18de8d48b 418 void cmd_skip_beacon(uint8_t idx)
dudmuck 0:2ff18de8d48b 419 {
dudmuck 0:2ff18de8d48b 420 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:2ff18de8d48b 421 sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 422 }
dudmuck 0:2ff18de8d48b 423 printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 424 }
dudmuck 0:2ff18de8d48b 425
dudmuck 0:2ff18de8d48b 426 void cmd_list_motes(uint8_t idx)
dudmuck 0:2ff18de8d48b 427 {
dudmuck 0:2ff18de8d48b 428 int i;
dudmuck 0:2ff18de8d48b 429 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 430 if (motes[i].dev_addr != DEVADDR_NONE) {
dudmuck 13:fa2095be01c4 431 LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
dudmuck 13:fa2095be01c4 432 printf(" %" PRIx32 "\r\n", motes[i].dev_addr);
dudmuck 0:2ff18de8d48b 433 }
dudmuck 0:2ff18de8d48b 434 }
dudmuck 0:2ff18de8d48b 435 }
dudmuck 0:2ff18de8d48b 436
dudmuck 0:2ff18de8d48b 437 void
dudmuck 0:2ff18de8d48b 438 cmd_beacon_payload(uint8_t idx)
dudmuck 0:2ff18de8d48b 439 {
dudmuck 9:a0ce66c18ec0 440 uint32_t i;
dudmuck 9:a0ce66c18ec0 441 uint32_t* ptr;
dudmuck 13:fa2095be01c4 442 sscanf(pcbuf+idx, "%" PRIx32, &i);
dudmuck 13:fa2095be01c4 443 printf("beacon_payload:%08" PRIx32 "\r\n", i);
dudmuck 9:a0ce66c18ec0 444 ptr = (uint32_t*)beacon_payload;
dudmuck 9:a0ce66c18ec0 445 *ptr = i;
dudmuck 8:307f7faeb594 446 }
dudmuck 8:307f7faeb594 447
dudmuck 0:2ff18de8d48b 448 void
dudmuck 0:2ff18de8d48b 449 cmd_send_downlink(uint8_t idx)
dudmuck 0:2ff18de8d48b 450 {
dudmuck 0:2ff18de8d48b 451 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 452 int i;
dudmuck 0:2ff18de8d48b 453 unsigned int dev_addr;
dudmuck 0:2ff18de8d48b 454 sscanf(pcbuf+idx, "%x", &dev_addr);
dudmuck 0:2ff18de8d48b 455 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 456 if (motes[i].dev_addr == dev_addr) {
dudmuck 0:2ff18de8d48b 457 break;
dudmuck 0:2ff18de8d48b 458 }
dudmuck 0:2ff18de8d48b 459 }
dudmuck 0:2ff18de8d48b 460 if (i == N_MOTES) {
dudmuck 0:2ff18de8d48b 461 printf("mote %x not found\r\n", dev_addr);
dudmuck 0:2ff18de8d48b 462 return;
dudmuck 0:2ff18de8d48b 463 }
dudmuck 0:2ff18de8d48b 464 mote = &motes[i];
dudmuck 0:2ff18de8d48b 465
dudmuck 0:2ff18de8d48b 466 while (pcbuf[idx] != ' ') {
dudmuck 0:2ff18de8d48b 467 if (pcbuf[++idx] == 0) {
dudmuck 0:2ff18de8d48b 468 printf("hit end\r\n");
dudmuck 0:2ff18de8d48b 469 return;
dudmuck 0:2ff18de8d48b 470 }
dudmuck 0:2ff18de8d48b 471 }
dudmuck 0:2ff18de8d48b 472 idx++; // step past space
dudmuck 0:2ff18de8d48b 473
dudmuck 0:2ff18de8d48b 474 mote->user_downlink_length = 0;
dudmuck 0:2ff18de8d48b 475 while (pcbuf[idx] > ' ') {
dudmuck 0:2ff18de8d48b 476 int o;
dudmuck 0:2ff18de8d48b 477 sscanf(pcbuf+idx, "%02x", &o);
dudmuck 0:2ff18de8d48b 478 LoRaWan::user_downlink[mote->user_downlink_length++] = o;
dudmuck 0:2ff18de8d48b 479 idx += 2;
dudmuck 0:2ff18de8d48b 480 }
dudmuck 0:2ff18de8d48b 481
dudmuck 13:fa2095be01c4 482 printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
dudmuck 0:2ff18de8d48b 483 }
dudmuck 0:2ff18de8d48b 484
dudmuck 9:a0ce66c18ec0 485 void cmd_rx_restart(uint8_t idx)
dudmuck 9:a0ce66c18ec0 486 {
dudmuck 9:a0ce66c18ec0 487 /*radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 9:a0ce66c18ec0 488 printf("standby\r\n");*/
dudmuck 9:a0ce66c18ec0 489 radio.set_opmode(RF_OPMODE_SLEEP);
dudmuck 9:a0ce66c18ec0 490 printf("sleep\r\n");
dudmuck 9:a0ce66c18ec0 491 wait(0.05);
dudmuck 9:a0ce66c18ec0 492 radio.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 9:a0ce66c18ec0 493 printf("receive\r\n");
dudmuck 9:a0ce66c18ec0 494 }
dudmuck 9:a0ce66c18ec0 495
dudmuck 9:a0ce66c18ec0 496 void cmd_beacon_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 497 {
dudmuck 9:a0ce66c18ec0 498 int gpo;
dudmuck 9:a0ce66c18ec0 499 sscanf(pcbuf+idx, "%d", &gpo);
dudmuck 9:a0ce66c18ec0 500 beacon_payload[0] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 501 beacon_payload[1] = gpo;
dudmuck 9:a0ce66c18ec0 502 printf("beacon gpo: %d\r\n", gpo);
dudmuck 9:a0ce66c18ec0 503 }
dudmuck 9:a0ce66c18ec0 504
dudmuck 9:a0ce66c18ec0 505 void cmd_beacon_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 506 {
dudmuck 9:a0ce66c18ec0 507 int r, g ,b;
dudmuck 9:a0ce66c18ec0 508 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 9:a0ce66c18ec0 509 beacon_payload[0] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 510 beacon_payload[1] = r;
dudmuck 9:a0ce66c18ec0 511 beacon_payload[2] = g;
dudmuck 9:a0ce66c18ec0 512 beacon_payload[3] = b;
dudmuck 9:a0ce66c18ec0 513 printf("beacon rgb: %d %d %d\r\n", r, g, b);
dudmuck 9:a0ce66c18ec0 514 }
dudmuck 9:a0ce66c18ec0 515
dudmuck 9:a0ce66c18ec0 516 void cmd_downlink_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 517 {
dudmuck 9:a0ce66c18ec0 518 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 519 int i, r, g ,b;
dudmuck 9:a0ce66c18ec0 520 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 521 sscanf(pcbuf+idx, "%x %d %d %d", &dev_addr, &r, &g, &b);
dudmuck 9:a0ce66c18ec0 522 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 523 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 524 break;
dudmuck 9:a0ce66c18ec0 525 }
dudmuck 9:a0ce66c18ec0 526 }
dudmuck 9:a0ce66c18ec0 527 if (i == N_MOTES) {
dudmuck 9:a0ce66c18ec0 528 printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 529 return;
dudmuck 9:a0ce66c18ec0 530 }
dudmuck 9:a0ce66c18ec0 531 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 532
dudmuck 9:a0ce66c18ec0 533 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 534 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 535 LoRaWan::user_downlink[mote->user_downlink_length++] = r;
dudmuck 9:a0ce66c18ec0 536 LoRaWan::user_downlink[mote->user_downlink_length++] = g;
dudmuck 9:a0ce66c18ec0 537 LoRaWan::user_downlink[mote->user_downlink_length++] = b;
dudmuck 9:a0ce66c18ec0 538
dudmuck 13:fa2095be01c4 539 printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 540 }
dudmuck 9:a0ce66c18ec0 541
dudmuck 9:a0ce66c18ec0 542 void cmd_downlink_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 543 {
dudmuck 9:a0ce66c18ec0 544 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 545 int i, gpo;
dudmuck 9:a0ce66c18ec0 546 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 547 sscanf(pcbuf+idx, "%x %d", &dev_addr, &gpo);
dudmuck 9:a0ce66c18ec0 548 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 549 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 550 break;
dudmuck 9:a0ce66c18ec0 551 }
dudmuck 9:a0ce66c18ec0 552 }
dudmuck 9:a0ce66c18ec0 553 if (i == N_MOTES) {
dudmuck 9:a0ce66c18ec0 554 printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 555 return;
dudmuck 9:a0ce66c18ec0 556 }
dudmuck 9:a0ce66c18ec0 557 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 558
dudmuck 9:a0ce66c18ec0 559 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 560 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 561 LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
dudmuck 9:a0ce66c18ec0 562
dudmuck 13:fa2095be01c4 563 printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 564 }
dudmuck 9:a0ce66c18ec0 565
dudmuck 0:2ff18de8d48b 566 void cmd_status(uint8_t idx)
dudmuck 0:2ff18de8d48b 567 {
dudmuck 14:c6284654d1b0 568 radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
dudmuck 14:c6284654d1b0 569 if (radio.RegPaConfig.bits.PaSelect)
dudmuck 14:c6284654d1b0 570 printf("PA_BOOST ");
dudmuck 14:c6284654d1b0 571 else
dudmuck 14:c6284654d1b0 572 printf("RFO ");
dudmuck 14:c6284654d1b0 573
dudmuck 0:2ff18de8d48b 574 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 2:9628d5e4b1bf 575 printf("%.3fMHz sf%ubw%u ", radio.get_frf_MHz(), lora.getSf(), lora.getBw());
dudmuck 0:2ff18de8d48b 576 printOpMode();
dudmuck 0:2ff18de8d48b 577 if (!radio.RegOpMode.bits.LongRangeMode) {
dudmuck 0:2ff18de8d48b 578 printf("FSK\r\n");
dudmuck 0:2ff18de8d48b 579 return;
dudmuck 0:2ff18de8d48b 580 }
dudmuck 0:2ff18de8d48b 581
dudmuck 0:2ff18de8d48b 582 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
dudmuck 0:2ff18de8d48b 583 printLoraIrqs(false);
dudmuck 0:2ff18de8d48b 584
dudmuck 12:9a8c13c4298b 585 printf(" do_downlink:%u get_tx_done:%u, ", LoRaWan::do_downlink, get_tx_done);
dudmuck 9:a0ce66c18ec0 586 lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); // invert_i_q
dudmuck 9:a0ce66c18ec0 587 lora.RegDriftInvert.octet = radio.read_reg(REG_LR_DRIFT_INVERT);
dudmuck 9:a0ce66c18ec0 588 printf("modemstat:%02x, rxinv:%x,%x\r\n", radio.read_reg(REG_LR_MODEMSTAT), lora.RegTest33.octet, lora.RegDriftInvert.octet);
dudmuck 2:9628d5e4b1bf 589 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 2:9628d5e4b1bf 590 printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), radio.RegDioMapping1.bits.Dio0Mapping);
dudmuck 12:9a8c13c4298b 591 printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", radio.read_reg(REG_LR_FIFOADDRPTR), radio.read_reg(REG_LR_FIFORXBASEADDR));
dudmuck 0:2ff18de8d48b 592 }
dudmuck 0:2ff18de8d48b 593
dudmuck 11:50d0558a4e37 594 void cmd_op(uint8_t idx)
dudmuck 11:50d0558a4e37 595 {
dudmuck 11:50d0558a4e37 596 int i, dbm;
dudmuck 11:50d0558a4e37 597 RegPdsTrim1_t pds_trim;
dudmuck 11:50d0558a4e37 598 uint8_t adr;
dudmuck 11:50d0558a4e37 599 if (radio.type == SX1276)
dudmuck 11:50d0558a4e37 600 adr = REG_PDSTRIM1_SX1276;
dudmuck 11:50d0558a4e37 601 else
dudmuck 11:50d0558a4e37 602 adr = REG_PDSTRIM1_SX1272;
dudmuck 11:50d0558a4e37 603
dudmuck 11:50d0558a4e37 604 pds_trim.octet = radio.read_reg(adr);
dudmuck 11:50d0558a4e37 605
dudmuck 11:50d0558a4e37 606 if (pcbuf[idx] >= '0' && (pcbuf[idx] <= '9' || pcbuf[idx] == '-')) {
dudmuck 11:50d0558a4e37 607 sscanf(pcbuf+idx, "%d", &i);
dudmuck 11:50d0558a4e37 608 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 11:50d0558a4e37 609 /* PABOOST used: +2dbm to +17, or +20 */
dudmuck 11:50d0558a4e37 610 if (i == 20) {
dudmuck 11:50d0558a4e37 611 printf("+20dBm PADAC bias\r\n");
dudmuck 11:50d0558a4e37 612 i -= 3;
dudmuck 11:50d0558a4e37 613 pds_trim.bits.prog_txdac = 7;
dudmuck 11:50d0558a4e37 614 radio.write_reg(adr, pds_trim.octet);
dudmuck 11:50d0558a4e37 615 }
dudmuck 11:50d0558a4e37 616 if (i > 1)
dudmuck 11:50d0558a4e37 617 radio.RegPaConfig.bits.OutputPower = i - 2;
dudmuck 11:50d0558a4e37 618 } else {
dudmuck 11:50d0558a4e37 619 /* RFO used: -1 to +14dbm */
dudmuck 11:50d0558a4e37 620 if (i < 15)
dudmuck 11:50d0558a4e37 621 radio.RegPaConfig.bits.OutputPower = i + 1;
dudmuck 11:50d0558a4e37 622 }
dudmuck 11:50d0558a4e37 623 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 11:50d0558a4e37 624 }
dudmuck 11:50d0558a4e37 625 radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
dudmuck 11:50d0558a4e37 626 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 11:50d0558a4e37 627 printf("PA_BOOST ");
dudmuck 11:50d0558a4e37 628 dbm = radio.RegPaConfig.bits.OutputPower + pds_trim.bits.prog_txdac - 2;
dudmuck 11:50d0558a4e37 629 } else {
dudmuck 11:50d0558a4e37 630 printf("RFO ");
dudmuck 11:50d0558a4e37 631 dbm = radio.RegPaConfig.bits.OutputPower - 1;
dudmuck 11:50d0558a4e37 632 }
dudmuck 11:50d0558a4e37 633 printf("OutputPower:%ddBm\r\n", dbm);
dudmuck 11:50d0558a4e37 634 }
dudmuck 11:50d0558a4e37 635
dudmuck 14:c6284654d1b0 636 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 637 void cmd_pa_select(uint8_t idx)
dudmuck 14:c6284654d1b0 638 {
dudmuck 14:c6284654d1b0 639 radio.RegPaConfig.bits.PaSelect ^= 1;
dudmuck 14:c6284654d1b0 640 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 14:c6284654d1b0 641 if (radio.RegPaConfig.bits.PaSelect)
dudmuck 14:c6284654d1b0 642 printf("PA_BOOST\r\n");
dudmuck 14:c6284654d1b0 643 else
dudmuck 14:c6284654d1b0 644 printf("RFO\r\n");
dudmuck 14:c6284654d1b0 645 }
dudmuck 14:c6284654d1b0 646 #endif /* TYPE_ABZ */
dudmuck 14:c6284654d1b0 647
dudmuck 12:9a8c13c4298b 648 void cmd_set_time(uint8_t idx)
dudmuck 12:9a8c13c4298b 649 {
dudmuck 12:9a8c13c4298b 650 set_time(0);
dudmuck 13:fa2095be01c4 651 printf("time:%" PRIu32 "\r\n", time(NULL));
dudmuck 12:9a8c13c4298b 652 }
dudmuck 12:9a8c13c4298b 653
dudmuck 13:fa2095be01c4 654
dudmuck 13:fa2095be01c4 655 void cmd_pwm(uint8_t idx)
dudmuck 12:9a8c13c4298b 656 {
dudmuck 13:fa2095be01c4 657 ota_mote_t* mote;
dudmuck 12:9a8c13c4298b 658 int i;
dudmuck 13:fa2095be01c4 659 unsigned dev_addr, p, d;
dudmuck 13:fa2095be01c4 660
dudmuck 13:fa2095be01c4 661 if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
dudmuck 13:fa2095be01c4 662 printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 663 return;
dudmuck 13:fa2095be01c4 664 }
dudmuck 12:9a8c13c4298b 665 for (i = 0; i < N_MOTES; i++) {
dudmuck 12:9a8c13c4298b 666 if (motes[i].dev_addr == dev_addr) {
dudmuck 12:9a8c13c4298b 667 break;
dudmuck 12:9a8c13c4298b 668 }
dudmuck 12:9a8c13c4298b 669 }
dudmuck 12:9a8c13c4298b 670 if (i == N_MOTES) {
dudmuck 12:9a8c13c4298b 671 printf("mote %x not found\r\n", dev_addr);
dudmuck 12:9a8c13c4298b 672 return;
dudmuck 12:9a8c13c4298b 673 }
dudmuck 12:9a8c13c4298b 674
dudmuck 12:9a8c13c4298b 675 mote = &motes[i];
dudmuck 12:9a8c13c4298b 676
dudmuck 12:9a8c13c4298b 677 mote->user_downlink_length = 0;
dudmuck 13:fa2095be01c4 678 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_PWM;
dudmuck 13:fa2095be01c4 679 LoRaWan::user_downlink[mote->user_downlink_length++] = p;
dudmuck 13:fa2095be01c4 680 LoRaWan::user_downlink[mote->user_downlink_length++] = d;
dudmuck 12:9a8c13c4298b 681
dudmuck 13:fa2095be01c4 682 printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
dudmuck 13:fa2095be01c4 683 }
dudmuck 13:fa2095be01c4 684
dudmuck 13:fa2095be01c4 685 void cmd_beacon_pwm(uint8_t idx)
dudmuck 13:fa2095be01c4 686 {
dudmuck 13:fa2095be01c4 687 unsigned p, d;
dudmuck 13:fa2095be01c4 688 if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
dudmuck 13:fa2095be01c4 689 printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 690 return;
dudmuck 13:fa2095be01c4 691 }
dudmuck 13:fa2095be01c4 692
dudmuck 13:fa2095be01c4 693 beacon_payload[0] = CMD_PWM;
dudmuck 13:fa2095be01c4 694 beacon_payload[1] = p;
dudmuck 13:fa2095be01c4 695 beacon_payload[2] = d;
dudmuck 13:fa2095be01c4 696
dudmuck 13:fa2095be01c4 697 printf("period:%u duty:%u\r\n", p, d);
dudmuck 12:9a8c13c4298b 698 }
dudmuck 12:9a8c13c4298b 699
dudmuck 14:c6284654d1b0 700 void cmd_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 701 {
dudmuck 14:c6284654d1b0 702 ota_mote_t* mote;
dudmuck 14:c6284654d1b0 703 int i;
dudmuck 14:c6284654d1b0 704 unsigned dev_addr, txi;
dudmuck 14:c6284654d1b0 705
dudmuck 14:c6284654d1b0 706 if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
dudmuck 14:c6284654d1b0 707 printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 708 return;
dudmuck 14:c6284654d1b0 709 }
dudmuck 14:c6284654d1b0 710 for (i = 0; i < N_MOTES; i++) {
dudmuck 14:c6284654d1b0 711 if (motes[i].dev_addr == dev_addr) {
dudmuck 14:c6284654d1b0 712 break;
dudmuck 14:c6284654d1b0 713 }
dudmuck 14:c6284654d1b0 714 }
dudmuck 14:c6284654d1b0 715 if (i == N_MOTES) {
dudmuck 14:c6284654d1b0 716 printf("mote %x not found\r\n", dev_addr);
dudmuck 14:c6284654d1b0 717 return;
dudmuck 14:c6284654d1b0 718 }
dudmuck 14:c6284654d1b0 719
dudmuck 14:c6284654d1b0 720 mote = &motes[i];
dudmuck 14:c6284654d1b0 721
dudmuck 14:c6284654d1b0 722 mote->user_downlink_length = 0;
dudmuck 14:c6284654d1b0 723 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 724 LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
dudmuck 14:c6284654d1b0 725
dudmuck 14:c6284654d1b0 726 printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
dudmuck 14:c6284654d1b0 727 }
dudmuck 14:c6284654d1b0 728
dudmuck 14:c6284654d1b0 729 void cmd_beacon_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 730 {
dudmuck 14:c6284654d1b0 731 unsigned txi;
dudmuck 14:c6284654d1b0 732 if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
dudmuck 14:c6284654d1b0 733 printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 734 return;
dudmuck 14:c6284654d1b0 735 }
dudmuck 14:c6284654d1b0 736
dudmuck 14:c6284654d1b0 737 beacon_payload[0] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 738 beacon_payload[1] = txi;
dudmuck 14:c6284654d1b0 739
dudmuck 14:c6284654d1b0 740 printf("txp index:%u\r\n", txi);
dudmuck 14:c6284654d1b0 741 }
dudmuck 14:c6284654d1b0 742
dudmuck 0:2ff18de8d48b 743 void cmd_help(uint8_t);
dudmuck 0:2ff18de8d48b 744
dudmuck 0:2ff18de8d48b 745 typedef struct {
dudmuck 0:2ff18de8d48b 746 const char* const cmd;
dudmuck 0:2ff18de8d48b 747 void (*handler)(uint8_t args_at);
dudmuck 0:2ff18de8d48b 748 const char* const arg_descr;
dudmuck 0:2ff18de8d48b 749 const char* const description;
dudmuck 0:2ff18de8d48b 750 } menu_item_t;
dudmuck 0:2ff18de8d48b 751
dudmuck 0:2ff18de8d48b 752 const menu_item_t menu_items[] =
dudmuck 0:2ff18de8d48b 753 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:2ff18de8d48b 754 { "?", cmd_help, "","show available commands"},
dudmuck 0:2ff18de8d48b 755 { ".", cmd_status, "","read status"},
dudmuck 0:2ff18de8d48b 756 { "b", cmd_beacon_payload, "<%x>","set beacon payload"},
dudmuck 0:2ff18de8d48b 757 { "sb", cmd_skip_beacon, "<%d>","skip beacons"},
dudmuck 0:2ff18de8d48b 758 { "list", cmd_list_motes, "","list active motes"},
dudmuck 0:2ff18de8d48b 759 { "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
dudmuck 9:a0ce66c18ec0 760 { "rxr", cmd_rx_restart, "", "restart RX"},
dudmuck 9:a0ce66c18ec0 761 { "brgb", cmd_beacon_rgb, "%u %u %u", "load RGB command into next beacon" },
dudmuck 9:a0ce66c18ec0 762 { "rgb", cmd_downlink_rgb, "%x %u %u %u", "load RGB command to mote"},
dudmuck 9:a0ce66c18ec0 763 { "bgpo", cmd_beacon_gpo, "%d", "load output pin command into next beacon"},
dudmuck 9:a0ce66c18ec0 764 { "gpo", cmd_downlink_gpo, "%x %d", "load output pin command to mote"},
dudmuck 12:9a8c13c4298b 765 { "op", cmd_op, "<dBm>","(TX) get/set TX power"},
dudmuck 14:c6284654d1b0 766 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 767 { "pas", cmd_pa_select, "","(TX) toggle PaSelect"},
dudmuck 14:c6284654d1b0 768 #endif
dudmuck 13:fa2095be01c4 769 { "tz", cmd_set_time, "", "set seconds to zero"},
dudmuck 13:fa2095be01c4 770 { "p", cmd_pwm, "%x %u %u", "send pwm period, duty to dev_addr"},
dudmuck 13:fa2095be01c4 771 { "bp", cmd_beacon_pwm, "%u %u", "send pwm period, duty on beacon"},
dudmuck 14:c6284654d1b0 772 { "ntxp", cmd_endnode_txp, "%x %u", "send txpower index to dev_addr"},
dudmuck 14:c6284654d1b0 773 { "bntxp", cmd_beacon_endnode_txp, "%u", "send txpower index on beacon"},
dudmuck 0:2ff18de8d48b 774 { NULL, NULL, NULL, NULL }
dudmuck 0:2ff18de8d48b 775 };
dudmuck 0:2ff18de8d48b 776
dudmuck 0:2ff18de8d48b 777 void cmd_help(uint8_t args_at)
dudmuck 0:2ff18de8d48b 778 {
dudmuck 0:2ff18de8d48b 779 int i;
dudmuck 0:2ff18de8d48b 780
dudmuck 0:2ff18de8d48b 781 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 782 printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:2ff18de8d48b 783 }
dudmuck 0:2ff18de8d48b 784
dudmuck 0:2ff18de8d48b 785 }
dudmuck 0:2ff18de8d48b 786
dudmuck 0:2ff18de8d48b 787 void
dudmuck 0:2ff18de8d48b 788 console()
dudmuck 0:2ff18de8d48b 789 {
dudmuck 0:2ff18de8d48b 790 int i;
dudmuck 0:2ff18de8d48b 791 uint8_t user_cmd_len;
dudmuck 0:2ff18de8d48b 792
dudmuck 0:2ff18de8d48b 793 if (pcbuf_len < 0) { // ctrl-C
dudmuck 0:2ff18de8d48b 794 //printf("abort\r\n");
dudmuck 0:2ff18de8d48b 795 return;
dudmuck 0:2ff18de8d48b 796 }
dudmuck 0:2ff18de8d48b 797 if (pcbuf_len == 0)
dudmuck 0:2ff18de8d48b 798 return;
dudmuck 0:2ff18de8d48b 799
dudmuck 0:2ff18de8d48b 800 printf("\r\n");
dudmuck 0:2ff18de8d48b 801
dudmuck 0:2ff18de8d48b 802 /* get end of user-entered command */
dudmuck 0:2ff18de8d48b 803 user_cmd_len = 1; // first character can be any character
dudmuck 0:2ff18de8d48b 804 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:2ff18de8d48b 805 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:2ff18de8d48b 806 user_cmd_len = i;
dudmuck 0:2ff18de8d48b 807 break;
dudmuck 0:2ff18de8d48b 808 }
dudmuck 0:2ff18de8d48b 809 }
dudmuck 0:2ff18de8d48b 810
dudmuck 0:2ff18de8d48b 811 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 812 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:2ff18de8d48b 813
dudmuck 0:2ff18de8d48b 814 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:2ff18de8d48b 815 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:2ff18de8d48b 816 mi_len++;
dudmuck 0:2ff18de8d48b 817 menu_items[i].handler(mi_len);
dudmuck 0:2ff18de8d48b 818 break;
dudmuck 0:2ff18de8d48b 819 }
dudmuck 0:2ff18de8d48b 820 }
dudmuck 0:2ff18de8d48b 821
dudmuck 0:2ff18de8d48b 822 pcbuf_len = 0;
dudmuck 0:2ff18de8d48b 823 printf("> ");
dudmuck 0:2ff18de8d48b 824 fflush(stdout);
dudmuck 0:2ff18de8d48b 825 }
dudmuck 0:2ff18de8d48b 826
dudmuck 0:2ff18de8d48b 827 int main()
dudmuck 0:2ff18de8d48b 828 {
dudmuck 0:2ff18de8d48b 829 Thread eventThread;
dudmuck 3:7c01b8978638 830 pc.baud(38400);
dudmuck 12:9a8c13c4298b 831 printf("\r\nreset %f\r\n", radio.get_frf_MHz());
dudmuck 11:50d0558a4e37 832 set_time(0);
dudmuck 0:2ff18de8d48b 833
dudmuck 0:2ff18de8d48b 834 radio.hw_reset();
dudmuck 12:9a8c13c4298b 835 printf("%fMHz\r\n", radio.get_frf_MHz());
dudmuck 0:2ff18de8d48b 836
dudmuck 10:6783623cc886 837 //#ifndef TARGET_DISCO_L072CZ_LRWAN1
dudmuck 10:6783623cc886 838 #ifndef TYPE_ABZ
dudmuck 0:2ff18de8d48b 839 rfsw.input();
dudmuck 0:2ff18de8d48b 840 if (rfsw.read()) {
dudmuck 0:2ff18de8d48b 841 printf("LAS\r\n");
dudmuck 0:2ff18de8d48b 842 /* LAS HF=PA_BOOST LF=RFO */
dudmuck 0:2ff18de8d48b 843 radio.RegPaConfig.bits.PaSelect = 1;
dudmuck 0:2ff18de8d48b 844 } else {
dudmuck 0:2ff18de8d48b 845 printf("MAS\r\n");
dudmuck 0:2ff18de8d48b 846 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:2ff18de8d48b 847 }
dudmuck 0:2ff18de8d48b 848 rfsw.output();
dudmuck 5:ceacaa560cfd 849 #endif /* !TARGET_DISCO_L072CZ_LRWAN1 */
dudmuck 0:2ff18de8d48b 850
dudmuck 0:2ff18de8d48b 851 radio.rf_switch = rfsw_callback;
dudmuck 0:2ff18de8d48b 852
dudmuck 0:2ff18de8d48b 853 init_radio();
dudmuck 0:2ff18de8d48b 854
dudmuck 0:2ff18de8d48b 855 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 856
dudmuck 0:2ff18de8d48b 857 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
dudmuck 0:2ff18de8d48b 858 LoRaWan::init();
dudmuck 0:2ff18de8d48b 859
dudmuck 0:2ff18de8d48b 860 timer.start();
dudmuck 0:2ff18de8d48b 861 tim_init();
dudmuck 4:7e743e402681 862
dudmuck 4:7e743e402681 863 pc.attach(&rx_isr);
dudmuck 9:a0ce66c18ec0 864
dudmuck 0:2ff18de8d48b 865
dudmuck 0:2ff18de8d48b 866 for (;;) {
dudmuck 0:2ff18de8d48b 867 console();
dudmuck 1:107435401168 868
dudmuck 1:107435401168 869 if (radio.dio0) {
dudmuck 3:7c01b8978638 870 if (get_tx_done) {
dudmuck 3:7c01b8978638 871 get_tx_done = false;
dudmuck 3:7c01b8978638 872 lora.RegIrqFlags.octet = 0;
dudmuck 3:7c01b8978638 873 lora.RegIrqFlags.bits.TxDone = 1;
dudmuck 3:7c01b8978638 874 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 3:7c01b8978638 875
dudmuck 3:7c01b8978638 876 if (restore_tx_invert) {
dudmuck 3:7c01b8978638 877 lora.invert_tx(false);
dudmuck 3:7c01b8978638 878 restore_tx_invert = false;
dudmuck 3:7c01b8978638 879 }
dudmuck 3:7c01b8978638 880
dudmuck 3:7c01b8978638 881 if (restore_header_mode) {
dudmuck 3:7c01b8978638 882 lora.setHeaderMode(false);
dudmuck 3:7c01b8978638 883 restore_header_mode = false;
dudmuck 3:7c01b8978638 884 }
dudmuck 12:9a8c13c4298b 885
dudmuck 3:7c01b8978638 886 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 12:9a8c13c4298b 887
dudmuck 12:9a8c13c4298b 888 if (beacon_guard) { // beacon done transmitting
dudmuck 12:9a8c13c4298b 889 measure_ambient();
dudmuck 12:9a8c13c4298b 890 beacon_guard = false;
dudmuck 12:9a8c13c4298b 891 }
dudmuck 3:7c01b8978638 892 } else {
dudmuck 3:7c01b8978638 893 if (!beacon_guard)
dudmuck 3:7c01b8978638 894 service_radio();
dudmuck 3:7c01b8978638 895 }
dudmuck 12:9a8c13c4298b 896 } else if (get_tx_done) {
dudmuck 12:9a8c13c4298b 897 /* dio0 not yet asserted */
dudmuck 12:9a8c13c4298b 898 uint32_t since = timer.read_ms() - tx_ms;
dudmuck 12:9a8c13c4298b 899 if (since > 4000) {
dudmuck 12:9a8c13c4298b 900 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 12:9a8c13c4298b 901 if (radio.RegOpMode.bits.Mode == RF_OPMODE_STANDBY) {
dudmuck 12:9a8c13c4298b 902 /* done transmitting, but dio0 not asserted */
dudmuck 12:9a8c13c4298b 903 printf("txDone but no dio0\r\n");
dudmuck 12:9a8c13c4298b 904 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 12:9a8c13c4298b 905 if (radio.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 12:9a8c13c4298b 906 printf("dio0mapping-fail\r\n");
dudmuck 12:9a8c13c4298b 907 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 12:9a8c13c4298b 908 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 12:9a8c13c4298b 909 }
dudmuck 12:9a8c13c4298b 910 }
dudmuck 12:9a8c13c4298b 911 }
dudmuck 12:9a8c13c4298b 912 }
dudmuck 12:9a8c13c4298b 913
dudmuck 12:9a8c13c4298b 914 if (LoRaWan::do_downlink && !beacon_guard) {
dudmuck 12:9a8c13c4298b 915 uint32_t since = timer.read_ms() - LoRaWan::rx_ms;
dudmuck 12:9a8c13c4298b 916 if (since > 110)
dudmuck 13:fa2095be01c4 917 printf("since-tx:%lu\r\n", since);
dudmuck 12:9a8c13c4298b 918 if (since > 500) {
dudmuck 12:9a8c13c4298b 919 LoRaWan::do_downlink = false;
dudmuck 12:9a8c13c4298b 920 printf("stalled-tx\r\n");
dudmuck 12:9a8c13c4298b 921 cmd_rx_restart(0);
dudmuck 12:9a8c13c4298b 922 }
dudmuck 1:107435401168 923 }
dudmuck 8:307f7faeb594 924
dudmuck 0:2ff18de8d48b 925 } // ..for(;;)
dudmuck 0:2ff18de8d48b 926 }