Synchronous wireless star LoRa network, central device.

Dependencies:   SX127x 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.


Alternate to this project gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Synchronous Star Network

This project acts as central node for LoRaWAN-like network operating on single radio channel. Intended for use where network infrastructure would never exist due to cost and/or complexity of standard network. This project uses the class-B method of beacon generation to synchronize the end nodes with the gateway. OTA mode must be used. End-node will be allocated an uplink time slot upon joining. End node may transmit uplink at this assigned timeslot, if it desires to do so. This time slot is always referenced to the beacon sent by gateway.

LoRaWAN server is not necessary. All network control is implemented by this project. User can observe network activity on the mbed serial port. Downlinks can be scheduled using command on serial port.

This implementation must not be used on radio channels requiring duty-cycle transmit limiting.

alterations from LoRaWAN specification

This mode of operation uses a single datarate on single radio channel. ADR is not implemented, because datarate cannot be changed. OTA mode must be used. When join-accept is sent by gateway, it will have appended (instead of CFlist) the beacon timing answer to inform of when next beacon occurs, and two timing values: the time slot allocated to this end-node and the periodicity of the network. Periodicity means how often the end-node may again transmit. /media/uploads/dudmuck/class-b-single.png Beacon is sent for purpose of providing timing reference to end-nodes. The beacon payload may contain a broadcast command to end nodes. Time value is not sent in beacon payload. The time at which beacon is sent provides timing reference: every 128 seconds as standard.

Rx2 receive window is not implemented. Only Rx1 is used because a single radio channel is used. Rx1 delay is reduced to 100 milliseconds. Original LoRaWAN has 1000 millisecond Rx1 delay to accommodate internet latency.

LoRaWAN standard class-B beacon requires GPS timing reference. This implementation does not use GPS, instead a hardware timer peripheral generates interrupts to send beacons. Absolute accuracy is not required, only relative crystal drift between gateway and end-nodes is considered.

Timing values are always specified as 30ms per step as in LoRaWAN standard. Each beacon period has 4096 30ms steps per beacon period.

join OTA procedure

The join procedure has changed the join-accept delay to 100 milliseconds (standard is 5 seconds). This allows end-node to hunt for gateway on several channels during joining. When gateway starts, it will scan available channels for the optimal choice based on ambient noise on the channels. End node will retry join request until it finds the gateway. Gateway might change channel during operation if it deems current channel too busy.

configuration of network

End nodes must be provisioned by editing file Comissioning.h. The array motes lists every end node permitted on network. It contains appEui, devEUI and appKey just as specified in standard LoRaWAN. All provisioning is hard-coded; changing provisioning requires reprogramming gateway. When changing number of motes, N_MOTES definition must be changed in lorawan.h.

lorawan.h

#define N_MOTES     8
extern ota_mote_t motes[N_MOTES];   /* from Comissioning.h */

configuring number of end-nodes vs transmit rate

Trade-off can be selected between number of end-nodes on network vs. how often each end-node can transmit.
In this example, where DR_13 is SF7 at 500KHz:

lorawan.cpp

    #elif (LORAMAC_DEFAULT_DATARATE == DR_13)
        #define TX_SLOT_STEPPING        8  //approx 0.25 seconds
        #define PERIODICITY_SLOTS       (TX_SLOT_STEPPING * 6)
    #endif

Here, each end-node is given time of 240ms = 8 * 30ms; accommodating maximum payload length for both uplink and downlink.
6 in this code is the maximum count of end nodes using this gateway. Each end-node can transmit every 1.44 seconds, in this example.
If you wanted to change 6 to 20 end-nodes, each would be able to use network every 4.8 seconds.
Another example: If you wanted to use DR_12 = SF8, you would have approx 2.5 to 3dB more gain compared to SF7, but each end-node must be given double time, resulting in 20 nodes able to use network every 9.6 seconds at DR_12.

network capacity limitation

The number of end-nodes which can be supported is determined by number of SLOT_STEPPING's which can occur during BEACON_PERIOD. Beacon guard is implemented same as standard LoRaWAN, which is 3 seconds prior to beacon start and 2.12 seconds after beacon start, which gives 122.88 seconds for network traffic for each beacon period.

gateway configuration

spreading factor is declared at #define LORAMAC_DEFAULT_DATARATE in lorawan.h, valid rates are DR_8 to DR_13 (sf12 to sf7). In the end-node, the same definition must be configured in LoRaMac-definitions.h. This network operates at this constant datarate for all packets.
Band plan can be selected by defining USE_BAND_* in lorawan.h. 434MHz can be used on SX1276 shield. TypeABZ module and sx1272 only support 800/900MHz channels band.

end-node provisioning

Security permits only matching DevEUI / AppEui to join the network, due to unique AES root key for each end device; in this case the DevEUI must be programmed in advance into gateway. However, if the same AES root key could be used for each end device , then any number of end devices could be added at a later time, without checking DevEUI on the gateway when an end device joins the network. On the gateway, the end device join acceptance is performed in file lorawan.cpp LoRaWan::parse_receive() where MType == MTYPE_JOIN_REQ. A memcmp() is performed on both DevEUI and AppEUI.

If you wish to allow any DevEUI to join, define ANY_DEVEUI at top of lorawan.cpp . In this configuration, all end devices must use same AppEUI and AES key. N_MOTES must be defined to the maximum number of end devices expected. Test end device by commenting BoardGetUniqueId() in end node, and replace DevEui[] with 8 arbitrary bytes to verify gateway permits any DevEUI to join.

RAM usage

For gateway CPU, recommend to consider larger RAM size depending on number of end devices required. ota_motes_t has size of 123 bytes. Each end device has one of these, however if less RAM usage is required for more end-devices, the MAC command queue size may be reduced.

hardware support

The radio driver supports both SX1272 and SX1276, sx126x kit, sx126x radio-only shield, and sx128x 2.4GHz.. The selection of radio chip type is made by your choice of importing radio driver library.



Beacon generation requires low power ticker to be clocked from crystal, not internal RC oscillator.

Gateway Serial Interface

Gateway serial port operates at 115200bps.

commandargumentdescription
list-list joined end nodes
?-list available commands
dl<mote-hex-dev-addr> <hex-payload>send downlink, sent after uplink received
gpo<mote-hex-dev-addr> <0 or 1>set output PC6 pin level on end device
b32bit hex valueset beacon payload to be sent at next beacon
. (period)-print current status
opdBmconfigure TX power of gateway
sbcountskip sending beacons, for testing end node
fhex devAddrprinter filtering, show only single end node
hm-print filtering, hide MAC layer printing
hp-print filtering, hide APP layer printing
sa-print filtering, show all, undo hm and hp

Any received uplink will be printed with DevAddr and decrypted payload.

Committer:
dudmuck
Date:
Wed May 24 20:32:38 2017 +0000
Revision:
2:9628d5e4b1bf
Parent:
1:107435401168
Child:
3:7c01b8978638
run on Murata TypeABZ

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 0:2ff18de8d48b 3
dudmuck 2:9628d5e4b1bf 4 #if defined TARGET_NUCLEO_L073RZ
dudmuck 2:9628d5e4b1bf 5 #define TYPE_ABZ // using Murata TypeABZ
dudmuck 2:9628d5e4b1bf 6 #endif
dudmuck 2:9628d5e4b1bf 7
dudmuck 0:2ff18de8d48b 8 Serial pc(USBTX, USBRX);
dudmuck 0:2ff18de8d48b 9 Timer timer;
dudmuck 0:2ff18de8d48b 10
dudmuck 2:9628d5e4b1bf 11 #if defined(TARGET_NUCLEO_L073RZ) && defined(TYPE_ABZ)
dudmuck 2:9628d5e4b1bf 12 SPI spi(PA_7, PA_6, PB_3); // mosi, miso, sclk
dudmuck 2:9628d5e4b1bf 13 // dio0, dio1, nss, spi, rst
dudmuck 2:9628d5e4b1bf 14 SX127x radio(PB_4, PB_1, PA_15, spi, PC_0); // sx1276 arduino shield
dudmuck 2:9628d5e4b1bf 15
dudmuck 2:9628d5e4b1bf 16 #define CRF1 PA_1
dudmuck 2:9628d5e4b1bf 17 #define CRF2 PC_2
dudmuck 2:9628d5e4b1bf 18 #define CRF3 PC_1
dudmuck 2:9628d5e4b1bf 19 DigitalOut Vctl1(CRF1);
dudmuck 2:9628d5e4b1bf 20 DigitalOut Vctl2(CRF2);
dudmuck 2:9628d5e4b1bf 21 DigitalOut Vctl3(CRF3);
dudmuck 2:9628d5e4b1bf 22
dudmuck 2:9628d5e4b1bf 23 void rfsw_callback()
dudmuck 2:9628d5e4b1bf 24 {
dudmuck 2:9628d5e4b1bf 25 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) {
dudmuck 2:9628d5e4b1bf 26 Vctl1 = 0;
dudmuck 2:9628d5e4b1bf 27 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 2:9628d5e4b1bf 28 Vctl2 = 0;
dudmuck 2:9628d5e4b1bf 29 Vctl3 = 1;
dudmuck 2:9628d5e4b1bf 30 } else {
dudmuck 2:9628d5e4b1bf 31 Vctl2 = 1;
dudmuck 2:9628d5e4b1bf 32 Vctl3 = 0;
dudmuck 2:9628d5e4b1bf 33 }
dudmuck 2:9628d5e4b1bf 34 } else {
dudmuck 2:9628d5e4b1bf 35 if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE)
dudmuck 2:9628d5e4b1bf 36 Vctl1 = 1;
dudmuck 2:9628d5e4b1bf 37 else
dudmuck 2:9628d5e4b1bf 38 Vctl1 = 0;
dudmuck 2:9628d5e4b1bf 39
dudmuck 2:9628d5e4b1bf 40 Vctl2 = 0;
dudmuck 2:9628d5e4b1bf 41 Vctl3 = 0;
dudmuck 2:9628d5e4b1bf 42 }
dudmuck 2:9628d5e4b1bf 43 }
dudmuck 2:9628d5e4b1bf 44 #else
dudmuck 2:9628d5e4b1bf 45 SPI spi(D11, D12, D13); // mosi, miso, sclk
dudmuck 2:9628d5e4b1bf 46 // dio0, dio1, nss, spi, rst
dudmuck 2:9628d5e4b1bf 47 SX127x radio( D2, D3, D10, spi, A0); // sx1276 arduino shield
dudmuck 2:9628d5e4b1bf 48
dudmuck 2:9628d5e4b1bf 49 DigitalInOut rfsw(A4);
dudmuck 2:9628d5e4b1bf 50
dudmuck 2:9628d5e4b1bf 51 void rfsw_callback()
dudmuck 2:9628d5e4b1bf 52 {
dudmuck 2:9628d5e4b1bf 53 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER)
dudmuck 2:9628d5e4b1bf 54 rfsw = 1;
dudmuck 2:9628d5e4b1bf 55 else
dudmuck 2:9628d5e4b1bf 56 rfsw = 0;
dudmuck 2:9628d5e4b1bf 57 }
dudmuck 2:9628d5e4b1bf 58 #endif
dudmuck 0:2ff18de8d48b 59
dudmuck 0:2ff18de8d48b 60 char pcbuf[64];
dudmuck 0:2ff18de8d48b 61 int pcbuf_len;
dudmuck 0:2ff18de8d48b 62 unsigned int beacon_payload;
dudmuck 0:2ff18de8d48b 63
dudmuck 0:2ff18de8d48b 64 unsigned int skip_beacon_cnt;
dudmuck 0:2ff18de8d48b 65
dudmuck 2:9628d5e4b1bf 66
dudmuck 0:2ff18de8d48b 67
dudmuck 0:2ff18de8d48b 68 SX127x_lora lora(radio);
dudmuck 0:2ff18de8d48b 69
dudmuck 0:2ff18de8d48b 70 #define LORAMAC_FIRST_CHANNEL ( (uint32_t)910.0e6 )
dudmuck 0:2ff18de8d48b 71 #define LORAMAC_STEPWIDTH_CHANNEL ( (uint32_t)800e3 )
dudmuck 0:2ff18de8d48b 72 #define LORA_MAX_NB_CHANNELS 8
dudmuck 0:2ff18de8d48b 73
dudmuck 0:2ff18de8d48b 74 #define N_SAMPLES 64
dudmuck 0:2ff18de8d48b 75 void channel_scan()
dudmuck 0:2ff18de8d48b 76 {
dudmuck 0:2ff18de8d48b 77 int min_ch, ch;
dudmuck 0:2ff18de8d48b 78 uint32_t hz = LORAMAC_FIRST_CHANNEL;
dudmuck 0:2ff18de8d48b 79 int acc[LORA_MAX_NB_CHANNELS];
dudmuck 0:2ff18de8d48b 80
dudmuck 0:2ff18de8d48b 81 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 82
dudmuck 0:2ff18de8d48b 83 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 84 int i;
dudmuck 0:2ff18de8d48b 85 float MHz = (float)hz / 1e6;
dudmuck 0:2ff18de8d48b 86 radio.set_frf_MHz(MHz);
dudmuck 0:2ff18de8d48b 87 radio.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 88 acc[ch] = 0;
dudmuck 0:2ff18de8d48b 89 for (i = 0; i < N_SAMPLES; i++) {
dudmuck 0:2ff18de8d48b 90 int rssi = lora.get_current_rssi();
dudmuck 0:2ff18de8d48b 91 acc[ch] += rssi;
dudmuck 0:2ff18de8d48b 92 wait(0.01);
dudmuck 0:2ff18de8d48b 93 }
dudmuck 0:2ff18de8d48b 94 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 95 printf("ch%u: %f\r\n", ch, acc[ch] / (float)N_SAMPLES);
dudmuck 0:2ff18de8d48b 96 hz += LORAMAC_STEPWIDTH_CHANNEL;
dudmuck 0:2ff18de8d48b 97 radio.set_frf_MHz((float)hz/1e6);
dudmuck 0:2ff18de8d48b 98 }
dudmuck 0:2ff18de8d48b 99
dudmuck 0:2ff18de8d48b 100 int min = 0x7fffffff;
dudmuck 0:2ff18de8d48b 101 min_ch = 0;
dudmuck 0:2ff18de8d48b 102 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 103 if (acc[ch] < min) {
dudmuck 0:2ff18de8d48b 104 min = acc[ch];
dudmuck 0:2ff18de8d48b 105 min_ch = ch;
dudmuck 0:2ff18de8d48b 106 }
dudmuck 0:2ff18de8d48b 107 }
dudmuck 0:2ff18de8d48b 108 hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
dudmuck 0:2ff18de8d48b 109 printf("using ch%u, %luhz\r\n", min_ch, hz);
dudmuck 0:2ff18de8d48b 110 radio.set_frf_MHz((float)hz/1e6);
dudmuck 0:2ff18de8d48b 111 }
dudmuck 0:2ff18de8d48b 112
dudmuck 0:2ff18de8d48b 113 void init_radio()
dudmuck 0:2ff18de8d48b 114 {
dudmuck 0:2ff18de8d48b 115 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 116
dudmuck 0:2ff18de8d48b 117 radio.RegPaConfig.bits.OutputPower = 15;
dudmuck 0:2ff18de8d48b 118 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 0:2ff18de8d48b 119 lora.enable();
dudmuck 0:2ff18de8d48b 120 lora.setBw_KHz(500);
dudmuck 0:2ff18de8d48b 121 lora.setSf(LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:2ff18de8d48b 122 printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
dudmuck 0:2ff18de8d48b 123
dudmuck 0:2ff18de8d48b 124 channel_scan();
dudmuck 0:2ff18de8d48b 125
dudmuck 0:2ff18de8d48b 126 radio.write_reg(REG_LR_SYNC_BYTE, LORA_MAC_PUBLIC_SYNCWORD);
dudmuck 0:2ff18de8d48b 127 radio.write_reg(REG_LR_RX_MAX_PAYLOADLENGTH, 255);
dudmuck 0:2ff18de8d48b 128 }
dudmuck 0:2ff18de8d48b 129
dudmuck 0:2ff18de8d48b 130 void printLoraIrqs(bool clear)
dudmuck 0:2ff18de8d48b 131 {
dudmuck 0:2ff18de8d48b 132 printf("\r\nIrqFlags:");
dudmuck 0:2ff18de8d48b 133 if (lora.RegIrqFlags.bits.CadDetected)
dudmuck 0:2ff18de8d48b 134 printf("CadDetected ");
dudmuck 0:2ff18de8d48b 135 if (lora.RegIrqFlags.bits.FhssChangeChannel) {
dudmuck 0:2ff18de8d48b 136 printf("FhssChangeChannel:%d ", lora.RegHopChannel.bits.FhssPresentChannel);
dudmuck 0:2ff18de8d48b 137 }
dudmuck 0:2ff18de8d48b 138 if (lora.RegIrqFlags.bits.CadDone)
dudmuck 0:2ff18de8d48b 139 printf("CadDone ");
dudmuck 0:2ff18de8d48b 140 if (lora.RegIrqFlags.bits.TxDone)
dudmuck 0:2ff18de8d48b 141 printf("TxDone ");
dudmuck 0:2ff18de8d48b 142 if (lora.RegIrqFlags.bits.ValidHeader)
dudmuck 0:2ff18de8d48b 143 printf("ValidHeader ");
dudmuck 0:2ff18de8d48b 144 if (lora.RegIrqFlags.bits.PayloadCrcError)
dudmuck 0:2ff18de8d48b 145 printf("PayloadCrcError ");
dudmuck 0:2ff18de8d48b 146 if (lora.RegIrqFlags.bits.RxDone)
dudmuck 0:2ff18de8d48b 147 printf("RxDone ");
dudmuck 0:2ff18de8d48b 148 if (lora.RegIrqFlags.bits.RxTimeout)
dudmuck 0:2ff18de8d48b 149 printf("RxTimeout ");
dudmuck 0:2ff18de8d48b 150
dudmuck 0:2ff18de8d48b 151 printf("\r\n");
dudmuck 0:2ff18de8d48b 152
dudmuck 0:2ff18de8d48b 153 if (clear)
dudmuck 0:2ff18de8d48b 154 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 0:2ff18de8d48b 155 }
dudmuck 0:2ff18de8d48b 156
dudmuck 0:2ff18de8d48b 157 void printOpMode()
dudmuck 0:2ff18de8d48b 158 {
dudmuck 0:2ff18de8d48b 159 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 0:2ff18de8d48b 160 switch (radio.RegOpMode.bits.Mode) {
dudmuck 0:2ff18de8d48b 161 case RF_OPMODE_SLEEP: printf("sleep"); break;
dudmuck 0:2ff18de8d48b 162 case RF_OPMODE_STANDBY: printf("stby"); break;
dudmuck 0:2ff18de8d48b 163 case RF_OPMODE_SYNTHESIZER_TX: printf("fstx"); break;
dudmuck 0:2ff18de8d48b 164 case RF_OPMODE_TRANSMITTER: printf("tx"); break;
dudmuck 0:2ff18de8d48b 165 case RF_OPMODE_SYNTHESIZER_RX: printf("fsrx"); break;
dudmuck 0:2ff18de8d48b 166 case RF_OPMODE_RECEIVER: printf("rx"); break;
dudmuck 0:2ff18de8d48b 167 case 6:
dudmuck 0:2ff18de8d48b 168 if (radio.RegOpMode.bits.LongRangeMode)
dudmuck 0:2ff18de8d48b 169 printf("rxs");
dudmuck 0:2ff18de8d48b 170 else
dudmuck 0:2ff18de8d48b 171 printf("-6-");
dudmuck 0:2ff18de8d48b 172 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 173 case 7:
dudmuck 0:2ff18de8d48b 174 if (radio.RegOpMode.bits.LongRangeMode)
dudmuck 0:2ff18de8d48b 175 printf("cad");
dudmuck 0:2ff18de8d48b 176 else
dudmuck 0:2ff18de8d48b 177 printf("-7-");
dudmuck 0:2ff18de8d48b 178 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 179 }
dudmuck 0:2ff18de8d48b 180 }
dudmuck 0:2ff18de8d48b 181
dudmuck 0:2ff18de8d48b 182 EventQueue queue;
dudmuck 0:2ff18de8d48b 183 bool need_tx_done;
dudmuck 0:2ff18de8d48b 184 bool need_tx_done_beacon;
dudmuck 0:2ff18de8d48b 185 bool restore_tx_invert;
dudmuck 0:2ff18de8d48b 186
dudmuck 0:2ff18de8d48b 187 void send_downlink()
dudmuck 0:2ff18de8d48b 188 {
dudmuck 0:2ff18de8d48b 189 if (LoRaWan::do_downlink) {
dudmuck 0:2ff18de8d48b 190 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 191 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 192 lora.invert_tx(true);
dudmuck 0:2ff18de8d48b 193 restore_tx_invert = true;
dudmuck 0:2ff18de8d48b 194 lora.setRxPayloadCrcOn(false);
dudmuck 0:2ff18de8d48b 195 lora.start_tx(lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 196 LoRaWan::do_downlink = false;
dudmuck 0:2ff18de8d48b 197 need_tx_done = true;
dudmuck 0:2ff18de8d48b 198 }
dudmuck 0:2ff18de8d48b 199 }
dudmuck 0:2ff18de8d48b 200
dudmuck 0:2ff18de8d48b 201 void
dudmuck 0:2ff18de8d48b 202 service_radio()
dudmuck 0:2ff18de8d48b 203 {
dudmuck 0:2ff18de8d48b 204 service_action_e act = lora.service();
dudmuck 0:2ff18de8d48b 205
dudmuck 0:2ff18de8d48b 206 switch (act) {
dudmuck 0:2ff18de8d48b 207 case SERVICE_ERROR:
dudmuck 0:2ff18de8d48b 208 printf("SERVICE_ERROR\r\n");
dudmuck 0:2ff18de8d48b 209 case SERVICE_TX_DONE:
dudmuck 0:2ff18de8d48b 210 case SERVICE_NONE:
dudmuck 0:2ff18de8d48b 211 break;
dudmuck 0:2ff18de8d48b 212 case SERVICE_READ_FIFO:
dudmuck 0:2ff18de8d48b 213 if (need_tx_done || need_tx_done_beacon) {
dudmuck 0:2ff18de8d48b 214 printf("service-read-fifo txbusy\r\n");
dudmuck 0:2ff18de8d48b 215 } else {
dudmuck 0:2ff18de8d48b 216 LoRaWan::rx_slot = tim_get_current_slot();
dudmuck 0:2ff18de8d48b 217 LoRaWan::rx_ms = timer.read_ms();
dudmuck 0:2ff18de8d48b 218 if (LoRaWan::parse_receive()) {
dudmuck 0:2ff18de8d48b 219 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 220 wait(0.05);
dudmuck 0:2ff18de8d48b 221 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 222 }
dudmuck 0:2ff18de8d48b 223 }
dudmuck 0:2ff18de8d48b 224 break;
dudmuck 0:2ff18de8d48b 225 } // ..switch (act)
dudmuck 0:2ff18de8d48b 226 }
dudmuck 0:2ff18de8d48b 227
dudmuck 0:2ff18de8d48b 228 void clear_TxDone()
dudmuck 0:2ff18de8d48b 229 {
dudmuck 0:2ff18de8d48b 230 lora.RegIrqFlags.octet = 0;
dudmuck 0:2ff18de8d48b 231 lora.RegIrqFlags.bits.TxDone = 1;
dudmuck 0:2ff18de8d48b 232 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 0:2ff18de8d48b 233 }
dudmuck 0:2ff18de8d48b 234
dudmuck 0:2ff18de8d48b 235 void dio0_callback()
dudmuck 0:2ff18de8d48b 236 {
dudmuck 0:2ff18de8d48b 237 if (radio.RegDioMapping1.bits.Dio0Mapping == 1) {
dudmuck 0:2ff18de8d48b 238 clear_TxDone();
dudmuck 0:2ff18de8d48b 239 if (restore_tx_invert) {
dudmuck 0:2ff18de8d48b 240 lora.invert_tx(false);
dudmuck 0:2ff18de8d48b 241 restore_tx_invert = false;
dudmuck 0:2ff18de8d48b 242 }
dudmuck 0:2ff18de8d48b 243
dudmuck 0:2ff18de8d48b 244 if (need_tx_done) {
dudmuck 0:2ff18de8d48b 245 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 246 need_tx_done = false;
dudmuck 0:2ff18de8d48b 247 } else if (need_tx_done_beacon) {
dudmuck 0:2ff18de8d48b 248 lora.setHeaderMode(false);
dudmuck 0:2ff18de8d48b 249 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 250 need_tx_done_beacon = false;
dudmuck 0:2ff18de8d48b 251 }
dudmuck 0:2ff18de8d48b 252 } else if (radio.RegDioMapping1.bits.Dio0Mapping == 0 && LoRaWan::do_downlink) {
dudmuck 2:9628d5e4b1bf 253 printf("dio0-rxdone-while-pending-tx\r\n");
dudmuck 0:2ff18de8d48b 254 return;
dudmuck 0:2ff18de8d48b 255 }
dudmuck 0:2ff18de8d48b 256
dudmuck 0:2ff18de8d48b 257 service_radio();
dudmuck 0:2ff18de8d48b 258 }
dudmuck 0:2ff18de8d48b 259
dudmuck 0:2ff18de8d48b 260
dudmuck 0:2ff18de8d48b 261 volatile float prev_beacon_send_at;
dudmuck 0:2ff18de8d48b 262 volatile float beacon_send_at;
dudmuck 0:2ff18de8d48b 263 volatile float beacon_loaded_at;
dudmuck 0:2ff18de8d48b 264
dudmuck 0:2ff18de8d48b 265 volatile bool beacon_loaded;
dudmuck 0:2ff18de8d48b 266 void
dudmuck 0:2ff18de8d48b 267 send_beacon()
dudmuck 0:2ff18de8d48b 268 {
dudmuck 0:2ff18de8d48b 269 prev_beacon_send_at = beacon_send_at;
dudmuck 0:2ff18de8d48b 270 beacon_send_at = timer.read();
dudmuck 0:2ff18de8d48b 271
dudmuck 0:2ff18de8d48b 272 if (!beacon_loaded)
dudmuck 0:2ff18de8d48b 273 return;
dudmuck 0:2ff18de8d48b 274
dudmuck 0:2ff18de8d48b 275 radio.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 0:2ff18de8d48b 276 beacon_loaded = false;
dudmuck 0:2ff18de8d48b 277
dudmuck 0:2ff18de8d48b 278 need_tx_done_beacon = true;
dudmuck 0:2ff18de8d48b 279 }
dudmuck 0:2ff18de8d48b 280
dudmuck 0:2ff18de8d48b 281 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:2ff18de8d48b 282 {
dudmuck 0:2ff18de8d48b 283 // The CRC calculation follows CCITT
dudmuck 0:2ff18de8d48b 284 const uint16_t polynom = 0x1021;
dudmuck 0:2ff18de8d48b 285 // CRC initial value
dudmuck 0:2ff18de8d48b 286 uint16_t crc = 0x0000;
dudmuck 0:2ff18de8d48b 287
dudmuck 0:2ff18de8d48b 288 if( buffer == NULL )
dudmuck 0:2ff18de8d48b 289 {
dudmuck 0:2ff18de8d48b 290 return 0;
dudmuck 0:2ff18de8d48b 291 }
dudmuck 0:2ff18de8d48b 292
dudmuck 0:2ff18de8d48b 293 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:2ff18de8d48b 294 {
dudmuck 0:2ff18de8d48b 295 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:2ff18de8d48b 296 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:2ff18de8d48b 297 {
dudmuck 0:2ff18de8d48b 298 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:2ff18de8d48b 299 }
dudmuck 0:2ff18de8d48b 300 }
dudmuck 0:2ff18de8d48b 301
dudmuck 0:2ff18de8d48b 302 return crc;
dudmuck 0:2ff18de8d48b 303 }
dudmuck 0:2ff18de8d48b 304
dudmuck 0:2ff18de8d48b 305 void
dudmuck 0:2ff18de8d48b 306 load_beacon()
dudmuck 0:2ff18de8d48b 307 {
dudmuck 0:2ff18de8d48b 308 uint16_t crc;
dudmuck 0:2ff18de8d48b 309 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 0:2ff18de8d48b 310 lora.RegPayloadLength = BEACON_SIZE;
dudmuck 0:2ff18de8d48b 311 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 312 lora.setHeaderMode(true);
dudmuck 0:2ff18de8d48b 313
dudmuck 0:2ff18de8d48b 314 if (skip_beacon_cnt > 0) {
dudmuck 1:107435401168 315 //printf("skip_beacon_cnt:%d\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 316 lora.invert_tx(true);
dudmuck 0:2ff18de8d48b 317 restore_tx_invert = true;
dudmuck 0:2ff18de8d48b 318 skip_beacon_cnt--;
dudmuck 0:2ff18de8d48b 319 }
dudmuck 0:2ff18de8d48b 320
dudmuck 0:2ff18de8d48b 321 radio.tx_buf[0] = beacon_payload & 0xff;
dudmuck 0:2ff18de8d48b 322 radio.tx_buf[1] = (beacon_payload >> 8) & 0xff;
dudmuck 0:2ff18de8d48b 323 radio.tx_buf[2] = (beacon_payload >> 16) & 0xff;
dudmuck 0:2ff18de8d48b 324 radio.tx_buf[3] = (beacon_payload >> 24) & 0xff;
dudmuck 0:2ff18de8d48b 325 crc = beacon_crc(radio.tx_buf, 4);
dudmuck 0:2ff18de8d48b 326 radio.tx_buf[4] = crc & 0xff;
dudmuck 0:2ff18de8d48b 327 radio.tx_buf[5] = crc >> 8;
dudmuck 0:2ff18de8d48b 328
dudmuck 0:2ff18de8d48b 329 // DIO0 to TxDone
dudmuck 0:2ff18de8d48b 330 if (radio.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 0:2ff18de8d48b 331 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 0:2ff18de8d48b 332 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 0:2ff18de8d48b 333 }
dudmuck 0:2ff18de8d48b 334
dudmuck 0:2ff18de8d48b 335 // set FifoPtrAddr to FifoTxPtrBase
dudmuck 0:2ff18de8d48b 336 radio.write_reg(REG_LR_FIFOADDRPTR, radio.read_reg(REG_LR_FIFOTXBASEADDR));
dudmuck 0:2ff18de8d48b 337
dudmuck 0:2ff18de8d48b 338 // write PayloadLength bytes to fifo
dudmuck 0:2ff18de8d48b 339 lora.write_fifo(lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 340
dudmuck 0:2ff18de8d48b 341 // prepare for tx to occur in send_beacon()
dudmuck 0:2ff18de8d48b 342 radio.set_opmode(RF_OPMODE_SYNTHESIZER_TX);
dudmuck 0:2ff18de8d48b 343 beacon_loaded = true;
dudmuck 0:2ff18de8d48b 344
dudmuck 0:2ff18de8d48b 345 beacon_loaded_at = timer.read();
dudmuck 0:2ff18de8d48b 346
dudmuck 0:2ff18de8d48b 347 beacon_payload = 0; // sent once
dudmuck 0:2ff18de8d48b 348 }
dudmuck 0:2ff18de8d48b 349
dudmuck 0:2ff18de8d48b 350 void get_time_till_beacon()
dudmuck 0:2ff18de8d48b 351 {
dudmuck 0:2ff18de8d48b 352 uint16_t slots = tim_get_current_slot();
dudmuck 0:2ff18de8d48b 353 printf("slots:%u\r\n", slots);
dudmuck 0:2ff18de8d48b 354 }
dudmuck 0:2ff18de8d48b 355
dudmuck 0:2ff18de8d48b 356 void rx_callback()
dudmuck 0:2ff18de8d48b 357 {
dudmuck 0:2ff18de8d48b 358 static uint8_t pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 359 static uint8_t prev_len = 0;;
dudmuck 0:2ff18de8d48b 360 char c = pc.getc();
dudmuck 0:2ff18de8d48b 361
dudmuck 0:2ff18de8d48b 362 if (c == 8) {
dudmuck 0:2ff18de8d48b 363 if (pcbuf_idx > 0) {
dudmuck 0:2ff18de8d48b 364 pc.putc(8);
dudmuck 0:2ff18de8d48b 365 pc.putc(' ');
dudmuck 0:2ff18de8d48b 366 pc.putc(8);
dudmuck 0:2ff18de8d48b 367 pcbuf_idx--;
dudmuck 0:2ff18de8d48b 368 }
dudmuck 0:2ff18de8d48b 369 } else if (c == 3) { // ctrl-C
dudmuck 0:2ff18de8d48b 370 pcbuf_len = -1;
dudmuck 0:2ff18de8d48b 371 } else if (c == '\r') {
dudmuck 0:2ff18de8d48b 372 if (pcbuf_idx == 0) {
dudmuck 0:2ff18de8d48b 373 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 374 } else {
dudmuck 0:2ff18de8d48b 375 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:2ff18de8d48b 376 prev_len = pcbuf_idx;
dudmuck 0:2ff18de8d48b 377 pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 378 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 379 }
dudmuck 0:2ff18de8d48b 380 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:2ff18de8d48b 381 pcbuf[pcbuf_idx++] = c;
dudmuck 0:2ff18de8d48b 382 pc.putc(c);
dudmuck 0:2ff18de8d48b 383 }
dudmuck 0:2ff18de8d48b 384 }
dudmuck 0:2ff18de8d48b 385
dudmuck 0:2ff18de8d48b 386 void cmd_skip_beacon(uint8_t idx)
dudmuck 0:2ff18de8d48b 387 {
dudmuck 0:2ff18de8d48b 388 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:2ff18de8d48b 389 sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 390 }
dudmuck 0:2ff18de8d48b 391 printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 392 }
dudmuck 0:2ff18de8d48b 393
dudmuck 0:2ff18de8d48b 394 void cmd_list_motes(uint8_t idx)
dudmuck 0:2ff18de8d48b 395 {
dudmuck 0:2ff18de8d48b 396 int i;
dudmuck 0:2ff18de8d48b 397 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 398 if (motes[i].dev_addr != DEVADDR_NONE) {
dudmuck 0:2ff18de8d48b 399 printf("%lx\r\n", motes[i].dev_addr);
dudmuck 0:2ff18de8d48b 400 }
dudmuck 0:2ff18de8d48b 401 }
dudmuck 0:2ff18de8d48b 402 }
dudmuck 0:2ff18de8d48b 403
dudmuck 0:2ff18de8d48b 404 void
dudmuck 0:2ff18de8d48b 405 cmd_beacon_payload(uint8_t idx)
dudmuck 0:2ff18de8d48b 406 {
dudmuck 0:2ff18de8d48b 407 sscanf(pcbuf+idx, "%x", &beacon_payload);
dudmuck 0:2ff18de8d48b 408 printf("beacon_payload:%08x\r\n", beacon_payload);
dudmuck 0:2ff18de8d48b 409 }
dudmuck 0:2ff18de8d48b 410
dudmuck 0:2ff18de8d48b 411 void
dudmuck 0:2ff18de8d48b 412 cmd_send_downlink(uint8_t idx)
dudmuck 0:2ff18de8d48b 413 {
dudmuck 0:2ff18de8d48b 414 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 415 int i;
dudmuck 0:2ff18de8d48b 416 unsigned int dev_addr;
dudmuck 0:2ff18de8d48b 417 sscanf(pcbuf+idx, "%x", &dev_addr);
dudmuck 0:2ff18de8d48b 418 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 419 if (motes[i].dev_addr == dev_addr) {
dudmuck 0:2ff18de8d48b 420 break;
dudmuck 0:2ff18de8d48b 421 }
dudmuck 0:2ff18de8d48b 422 }
dudmuck 0:2ff18de8d48b 423 if (i == N_MOTES) {
dudmuck 0:2ff18de8d48b 424 printf("mote %x not found\r\n", dev_addr);
dudmuck 0:2ff18de8d48b 425 return;
dudmuck 0:2ff18de8d48b 426 }
dudmuck 0:2ff18de8d48b 427 mote = &motes[i];
dudmuck 0:2ff18de8d48b 428
dudmuck 0:2ff18de8d48b 429 while (pcbuf[idx] != ' ') {
dudmuck 0:2ff18de8d48b 430 if (pcbuf[++idx] == 0) {
dudmuck 0:2ff18de8d48b 431 printf("hit end\r\n");
dudmuck 0:2ff18de8d48b 432 return;
dudmuck 0:2ff18de8d48b 433 }
dudmuck 0:2ff18de8d48b 434 }
dudmuck 0:2ff18de8d48b 435 idx++; // step past space
dudmuck 0:2ff18de8d48b 436
dudmuck 0:2ff18de8d48b 437 mote->user_downlink_length = 0;
dudmuck 0:2ff18de8d48b 438 while (pcbuf[idx] > ' ') {
dudmuck 0:2ff18de8d48b 439 int o;
dudmuck 0:2ff18de8d48b 440 sscanf(pcbuf+idx, "%02x", &o);
dudmuck 0:2ff18de8d48b 441 LoRaWan::user_downlink[mote->user_downlink_length++] = o;
dudmuck 0:2ff18de8d48b 442 idx += 2;
dudmuck 0:2ff18de8d48b 443 }
dudmuck 0:2ff18de8d48b 444
dudmuck 0:2ff18de8d48b 445 printf("%u bytes scheduled for %lx\r\n", mote->user_downlink_length, mote->dev_addr);
dudmuck 0:2ff18de8d48b 446 }
dudmuck 0:2ff18de8d48b 447
dudmuck 0:2ff18de8d48b 448 void cmd_status(uint8_t idx)
dudmuck 0:2ff18de8d48b 449 {
dudmuck 0:2ff18de8d48b 450 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 2:9628d5e4b1bf 451 printf("%.3fMHz sf%ubw%u ", radio.get_frf_MHz(), lora.getSf(), lora.getBw());
dudmuck 0:2ff18de8d48b 452 printOpMode();
dudmuck 0:2ff18de8d48b 453 if (!radio.RegOpMode.bits.LongRangeMode) {
dudmuck 0:2ff18de8d48b 454 printf("FSK\r\n");
dudmuck 0:2ff18de8d48b 455 return;
dudmuck 0:2ff18de8d48b 456 }
dudmuck 0:2ff18de8d48b 457
dudmuck 0:2ff18de8d48b 458 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
dudmuck 0:2ff18de8d48b 459 printLoraIrqs(false);
dudmuck 0:2ff18de8d48b 460
dudmuck 2:9628d5e4b1bf 461 printf("modemstat:%02x\r\n", radio.read_reg(REG_LR_MODEMSTAT));
dudmuck 2:9628d5e4b1bf 462 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 2:9628d5e4b1bf 463 printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), radio.RegDioMapping1.bits.Dio0Mapping);
dudmuck 2:9628d5e4b1bf 464
dudmuck 0:2ff18de8d48b 465 }
dudmuck 0:2ff18de8d48b 466
dudmuck 0:2ff18de8d48b 467 void cmd_help(uint8_t);
dudmuck 0:2ff18de8d48b 468
dudmuck 0:2ff18de8d48b 469 typedef struct {
dudmuck 0:2ff18de8d48b 470 const char* const cmd;
dudmuck 0:2ff18de8d48b 471 void (*handler)(uint8_t args_at);
dudmuck 0:2ff18de8d48b 472 const char* const arg_descr;
dudmuck 0:2ff18de8d48b 473 const char* const description;
dudmuck 0:2ff18de8d48b 474 } menu_item_t;
dudmuck 0:2ff18de8d48b 475
dudmuck 0:2ff18de8d48b 476 const menu_item_t menu_items[] =
dudmuck 0:2ff18de8d48b 477 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:2ff18de8d48b 478 { "?", cmd_help, "","show available commands"},
dudmuck 0:2ff18de8d48b 479 { ".", cmd_status, "","read status"},
dudmuck 0:2ff18de8d48b 480 { "b", cmd_beacon_payload, "<%x>","set beacon payload"},
dudmuck 0:2ff18de8d48b 481 { "sb", cmd_skip_beacon, "<%d>","skip beacons"},
dudmuck 0:2ff18de8d48b 482 { "list", cmd_list_motes, "","list active motes"},
dudmuck 0:2ff18de8d48b 483 { "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
dudmuck 0:2ff18de8d48b 484 { NULL, NULL, NULL, NULL }
dudmuck 0:2ff18de8d48b 485 };
dudmuck 0:2ff18de8d48b 486
dudmuck 0:2ff18de8d48b 487 void cmd_help(uint8_t args_at)
dudmuck 0:2ff18de8d48b 488 {
dudmuck 0:2ff18de8d48b 489 int i;
dudmuck 0:2ff18de8d48b 490
dudmuck 0:2ff18de8d48b 491 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 492 printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:2ff18de8d48b 493 }
dudmuck 0:2ff18de8d48b 494
dudmuck 0:2ff18de8d48b 495 }
dudmuck 0:2ff18de8d48b 496
dudmuck 0:2ff18de8d48b 497 void
dudmuck 0:2ff18de8d48b 498 console()
dudmuck 0:2ff18de8d48b 499 {
dudmuck 0:2ff18de8d48b 500 int i;
dudmuck 0:2ff18de8d48b 501 uint8_t user_cmd_len;
dudmuck 0:2ff18de8d48b 502
dudmuck 0:2ff18de8d48b 503 if (pcbuf_len < 0) { // ctrl-C
dudmuck 0:2ff18de8d48b 504 //printf("abort\r\n");
dudmuck 0:2ff18de8d48b 505 return;
dudmuck 0:2ff18de8d48b 506 }
dudmuck 0:2ff18de8d48b 507 if (pcbuf_len == 0)
dudmuck 0:2ff18de8d48b 508 return;
dudmuck 0:2ff18de8d48b 509
dudmuck 0:2ff18de8d48b 510 printf("\r\n");
dudmuck 0:2ff18de8d48b 511
dudmuck 0:2ff18de8d48b 512 /* get end of user-entered command */
dudmuck 0:2ff18de8d48b 513 user_cmd_len = 1; // first character can be any character
dudmuck 0:2ff18de8d48b 514 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:2ff18de8d48b 515 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:2ff18de8d48b 516 user_cmd_len = i;
dudmuck 0:2ff18de8d48b 517 break;
dudmuck 0:2ff18de8d48b 518 }
dudmuck 0:2ff18de8d48b 519 }
dudmuck 0:2ff18de8d48b 520
dudmuck 0:2ff18de8d48b 521 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 522 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:2ff18de8d48b 523
dudmuck 0:2ff18de8d48b 524 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:2ff18de8d48b 525 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:2ff18de8d48b 526 mi_len++;
dudmuck 0:2ff18de8d48b 527 menu_items[i].handler(mi_len);
dudmuck 0:2ff18de8d48b 528 break;
dudmuck 0:2ff18de8d48b 529 }
dudmuck 0:2ff18de8d48b 530 }
dudmuck 0:2ff18de8d48b 531
dudmuck 0:2ff18de8d48b 532 pcbuf_len = 0;
dudmuck 0:2ff18de8d48b 533 printf("> ");
dudmuck 0:2ff18de8d48b 534 fflush(stdout);
dudmuck 0:2ff18de8d48b 535 }
dudmuck 0:2ff18de8d48b 536
dudmuck 0:2ff18de8d48b 537 int main()
dudmuck 0:2ff18de8d48b 538 {
dudmuck 0:2ff18de8d48b 539 Thread eventThread;
dudmuck 0:2ff18de8d48b 540 pc.baud(115200);
dudmuck 1:107435401168 541 printf("\r\nreset\r\n");
dudmuck 0:2ff18de8d48b 542
dudmuck 0:2ff18de8d48b 543 radio.hw_reset();
dudmuck 0:2ff18de8d48b 544
dudmuck 2:9628d5e4b1bf 545 #ifndef TYPE_ABZ
dudmuck 0:2ff18de8d48b 546 rfsw.input();
dudmuck 0:2ff18de8d48b 547 if (rfsw.read()) {
dudmuck 0:2ff18de8d48b 548 printf("LAS\r\n");
dudmuck 0:2ff18de8d48b 549 /* LAS HF=PA_BOOST LF=RFO */
dudmuck 0:2ff18de8d48b 550 radio.RegPaConfig.bits.PaSelect = 1;
dudmuck 0:2ff18de8d48b 551 } else {
dudmuck 0:2ff18de8d48b 552 printf("MAS\r\n");
dudmuck 0:2ff18de8d48b 553 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:2ff18de8d48b 554 }
dudmuck 0:2ff18de8d48b 555 rfsw.output();
dudmuck 2:9628d5e4b1bf 556 #endif /* !TYPE_ABZ */
dudmuck 0:2ff18de8d48b 557
dudmuck 0:2ff18de8d48b 558 radio.rf_switch = rfsw_callback;
dudmuck 0:2ff18de8d48b 559
dudmuck 0:2ff18de8d48b 560 init_radio();
dudmuck 0:2ff18de8d48b 561
dudmuck 0:2ff18de8d48b 562 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 563
dudmuck 0:2ff18de8d48b 564 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
dudmuck 0:2ff18de8d48b 565 LoRaWan::init();
dudmuck 0:2ff18de8d48b 566
dudmuck 0:2ff18de8d48b 567 timer.start();
dudmuck 0:2ff18de8d48b 568 tim_init();
dudmuck 0:2ff18de8d48b 569
dudmuck 0:2ff18de8d48b 570 for (;;) {
dudmuck 0:2ff18de8d48b 571 console();
dudmuck 1:107435401168 572
dudmuck 1:107435401168 573 if (pc.readable())
dudmuck 1:107435401168 574 rx_callback();
dudmuck 1:107435401168 575
dudmuck 1:107435401168 576 if (radio.dio0) {
dudmuck 1:107435401168 577 dio0_callback();
dudmuck 1:107435401168 578 }
dudmuck 0:2ff18de8d48b 579 } // ..for(;;)
dudmuck 0:2ff18de8d48b 580 }