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:
Thu Aug 10 14:53:12 2017 -0700
Revision:
15:fea23ad8eafa
Parent:
14:c6284654d1b0
Child:
16:67fa19bc6331
PaSelect=RFO for 434MHz on shield board

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 15:fea23ad8eafa 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 TYPE_ABZ
dudmuck 15:fea23ad8eafa 838 /* LoRa arduino shield... */
dudmuck 15:fea23ad8eafa 839 #ifdef USE_BAND_433
dudmuck 15:fea23ad8eafa 840 radio.RegPaConfig.bits.PaSelect = 0; // RFO_LF connected
dudmuck 15:fea23ad8eafa 841 #else
dudmuck 0:2ff18de8d48b 842 rfsw.input();
dudmuck 0:2ff18de8d48b 843 if (rfsw.read()) {
dudmuck 0:2ff18de8d48b 844 printf("LAS\r\n");
dudmuck 0:2ff18de8d48b 845 /* LAS HF=PA_BOOST LF=RFO */
dudmuck 0:2ff18de8d48b 846 radio.RegPaConfig.bits.PaSelect = 1;
dudmuck 0:2ff18de8d48b 847 } else {
dudmuck 0:2ff18de8d48b 848 printf("MAS\r\n");
dudmuck 0:2ff18de8d48b 849 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:2ff18de8d48b 850 }
dudmuck 15:fea23ad8eafa 851 #endif /* !USE_BAND_433 */
dudmuck 0:2ff18de8d48b 852 rfsw.output();
dudmuck 15:fea23ad8eafa 853 /* ...LoRa arduino shield */
dudmuck 15:fea23ad8eafa 854 #endif
dudmuck 0:2ff18de8d48b 855
dudmuck 0:2ff18de8d48b 856 radio.rf_switch = rfsw_callback;
dudmuck 0:2ff18de8d48b 857
dudmuck 0:2ff18de8d48b 858 init_radio();
dudmuck 0:2ff18de8d48b 859
dudmuck 0:2ff18de8d48b 860 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 861
dudmuck 0:2ff18de8d48b 862 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
dudmuck 0:2ff18de8d48b 863 LoRaWan::init();
dudmuck 0:2ff18de8d48b 864
dudmuck 0:2ff18de8d48b 865 timer.start();
dudmuck 0:2ff18de8d48b 866 tim_init();
dudmuck 4:7e743e402681 867
dudmuck 4:7e743e402681 868 pc.attach(&rx_isr);
dudmuck 9:a0ce66c18ec0 869
dudmuck 0:2ff18de8d48b 870
dudmuck 0:2ff18de8d48b 871 for (;;) {
dudmuck 0:2ff18de8d48b 872 console();
dudmuck 1:107435401168 873
dudmuck 1:107435401168 874 if (radio.dio0) {
dudmuck 3:7c01b8978638 875 if (get_tx_done) {
dudmuck 3:7c01b8978638 876 get_tx_done = false;
dudmuck 3:7c01b8978638 877 lora.RegIrqFlags.octet = 0;
dudmuck 3:7c01b8978638 878 lora.RegIrqFlags.bits.TxDone = 1;
dudmuck 3:7c01b8978638 879 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 3:7c01b8978638 880
dudmuck 3:7c01b8978638 881 if (restore_tx_invert) {
dudmuck 3:7c01b8978638 882 lora.invert_tx(false);
dudmuck 3:7c01b8978638 883 restore_tx_invert = false;
dudmuck 3:7c01b8978638 884 }
dudmuck 3:7c01b8978638 885
dudmuck 3:7c01b8978638 886 if (restore_header_mode) {
dudmuck 3:7c01b8978638 887 lora.setHeaderMode(false);
dudmuck 3:7c01b8978638 888 restore_header_mode = false;
dudmuck 3:7c01b8978638 889 }
dudmuck 12:9a8c13c4298b 890
dudmuck 3:7c01b8978638 891 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 12:9a8c13c4298b 892
dudmuck 12:9a8c13c4298b 893 if (beacon_guard) { // beacon done transmitting
dudmuck 12:9a8c13c4298b 894 measure_ambient();
dudmuck 12:9a8c13c4298b 895 beacon_guard = false;
dudmuck 12:9a8c13c4298b 896 }
dudmuck 3:7c01b8978638 897 } else {
dudmuck 3:7c01b8978638 898 if (!beacon_guard)
dudmuck 3:7c01b8978638 899 service_radio();
dudmuck 3:7c01b8978638 900 }
dudmuck 12:9a8c13c4298b 901 } else if (get_tx_done) {
dudmuck 12:9a8c13c4298b 902 /* dio0 not yet asserted */
dudmuck 12:9a8c13c4298b 903 uint32_t since = timer.read_ms() - tx_ms;
dudmuck 12:9a8c13c4298b 904 if (since > 4000) {
dudmuck 12:9a8c13c4298b 905 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 12:9a8c13c4298b 906 if (radio.RegOpMode.bits.Mode == RF_OPMODE_STANDBY) {
dudmuck 12:9a8c13c4298b 907 /* done transmitting, but dio0 not asserted */
dudmuck 12:9a8c13c4298b 908 printf("txDone but no dio0\r\n");
dudmuck 12:9a8c13c4298b 909 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 12:9a8c13c4298b 910 if (radio.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 12:9a8c13c4298b 911 printf("dio0mapping-fail\r\n");
dudmuck 12:9a8c13c4298b 912 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 12:9a8c13c4298b 913 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 12:9a8c13c4298b 914 }
dudmuck 12:9a8c13c4298b 915 }
dudmuck 12:9a8c13c4298b 916 }
dudmuck 12:9a8c13c4298b 917 }
dudmuck 12:9a8c13c4298b 918
dudmuck 12:9a8c13c4298b 919 if (LoRaWan::do_downlink && !beacon_guard) {
dudmuck 12:9a8c13c4298b 920 uint32_t since = timer.read_ms() - LoRaWan::rx_ms;
dudmuck 12:9a8c13c4298b 921 if (since > 110)
dudmuck 13:fa2095be01c4 922 printf("since-tx:%lu\r\n", since);
dudmuck 12:9a8c13c4298b 923 if (since > 500) {
dudmuck 12:9a8c13c4298b 924 LoRaWan::do_downlink = false;
dudmuck 12:9a8c13c4298b 925 printf("stalled-tx\r\n");
dudmuck 12:9a8c13c4298b 926 cmd_rx_restart(0);
dudmuck 12:9a8c13c4298b 927 }
dudmuck 1:107435401168 928 }
dudmuck 8:307f7faeb594 929
dudmuck 0:2ff18de8d48b 930 } // ..for(;;)
dudmuck 0:2ff18de8d48b 931 }