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 17:56:02 2017 -0700
Revision:
16:67fa19bc6331
Parent:
15:fea23ad8eafa
Child:
17:763412df6872
add print filter on dev_addr

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 16:67fa19bc6331 209 void decrypted_uplink(uint32_t dev_addr, 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 16:67fa19bc6331 219 LoRaWan::filtered_printf(dev_addr, "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 16:67fa19bc6331 222 LoRaWan::filtered_printf(dev_addr, "TEXT %s\r\n", buf);
dudmuck 9:a0ce66c18ec0 223 } else {
dudmuck 9:a0ce66c18ec0 224 int i;
dudmuck 16:67fa19bc6331 225 LoRaWan::filtered_printf(dev_addr, "port%u: ", port);
dudmuck 9:a0ce66c18ec0 226 for (i = 0; i < buflen; i++)
dudmuck 16:67fa19bc6331 227 LoRaWan::filtered_printf(dev_addr, "%02x ", buf[i]);
dudmuck 16:67fa19bc6331 228 LoRaWan::filtered_printf(dev_addr, "\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 12:9a8c13c4298b 269 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 12:9a8c13c4298b 270 LoRaWan::parse_receive();
dudmuck 12:9a8c13c4298b 271 if (!LoRaWan::do_downlink) {
dudmuck 12:9a8c13c4298b 272 /* if not sending downlink, start receiver now */
dudmuck 3:7c01b8978638 273 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 274 }
dudmuck 12:9a8c13c4298b 275
dudmuck 0:2ff18de8d48b 276 break;
dudmuck 0:2ff18de8d48b 277 } // ..switch (act)
dudmuck 0:2ff18de8d48b 278 }
dudmuck 0:2ff18de8d48b 279
dudmuck 0:2ff18de8d48b 280 volatile float prev_beacon_send_at;
dudmuck 0:2ff18de8d48b 281 volatile float beacon_send_at;
dudmuck 0:2ff18de8d48b 282 volatile float beacon_loaded_at;
dudmuck 0:2ff18de8d48b 283
dudmuck 0:2ff18de8d48b 284 volatile bool beacon_loaded;
dudmuck 0:2ff18de8d48b 285 void
dudmuck 0:2ff18de8d48b 286 send_beacon()
dudmuck 0:2ff18de8d48b 287 {
dudmuck 0:2ff18de8d48b 288 prev_beacon_send_at = beacon_send_at;
dudmuck 0:2ff18de8d48b 289 beacon_send_at = timer.read();
dudmuck 0:2ff18de8d48b 290
dudmuck 0:2ff18de8d48b 291 if (!beacon_loaded)
dudmuck 0:2ff18de8d48b 292 return;
dudmuck 0:2ff18de8d48b 293
dudmuck 0:2ff18de8d48b 294 radio.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 0:2ff18de8d48b 295 beacon_loaded = false;
dudmuck 3:7c01b8978638 296 get_tx_done = true;
dudmuck 12:9a8c13c4298b 297 tx_ms = timer.read_ms();
dudmuck 0:2ff18de8d48b 298 }
dudmuck 0:2ff18de8d48b 299
dudmuck 0:2ff18de8d48b 300 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:2ff18de8d48b 301 {
dudmuck 0:2ff18de8d48b 302 // The CRC calculation follows CCITT
dudmuck 0:2ff18de8d48b 303 const uint16_t polynom = 0x1021;
dudmuck 0:2ff18de8d48b 304 // CRC initial value
dudmuck 0:2ff18de8d48b 305 uint16_t crc = 0x0000;
dudmuck 0:2ff18de8d48b 306
dudmuck 0:2ff18de8d48b 307 if( buffer == NULL )
dudmuck 0:2ff18de8d48b 308 {
dudmuck 0:2ff18de8d48b 309 return 0;
dudmuck 0:2ff18de8d48b 310 }
dudmuck 0:2ff18de8d48b 311
dudmuck 0:2ff18de8d48b 312 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:2ff18de8d48b 313 {
dudmuck 0:2ff18de8d48b 314 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:2ff18de8d48b 315 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:2ff18de8d48b 316 {
dudmuck 0:2ff18de8d48b 317 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:2ff18de8d48b 318 }
dudmuck 0:2ff18de8d48b 319 }
dudmuck 0:2ff18de8d48b 320
dudmuck 0:2ff18de8d48b 321 return crc;
dudmuck 0:2ff18de8d48b 322 }
dudmuck 0:2ff18de8d48b 323
dudmuck 0:2ff18de8d48b 324 void
dudmuck 3:7c01b8978638 325 _load_beacon()
dudmuck 0:2ff18de8d48b 326 {
dudmuck 0:2ff18de8d48b 327 uint16_t crc;
dudmuck 12:9a8c13c4298b 328 radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 12:9a8c13c4298b 329 // clear any flags which might have been set during beacon_guard
dudmuck 12:9a8c13c4298b 330 radio.write_reg(REG_LR_IRQFLAGS, 0xff);
dudmuck 0:2ff18de8d48b 331 lora.RegPayloadLength = BEACON_SIZE;
dudmuck 0:2ff18de8d48b 332 radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 333 lora.setHeaderMode(true);
dudmuck 3:7c01b8978638 334 restore_header_mode = true;
dudmuck 0:2ff18de8d48b 335
dudmuck 0:2ff18de8d48b 336 if (skip_beacon_cnt > 0) {
dudmuck 1:107435401168 337 //printf("skip_beacon_cnt:%d\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 338 lora.invert_tx(true);
dudmuck 0:2ff18de8d48b 339 restore_tx_invert = true;
dudmuck 0:2ff18de8d48b 340 skip_beacon_cnt--;
dudmuck 0:2ff18de8d48b 341 }
dudmuck 0:2ff18de8d48b 342
dudmuck 9:a0ce66c18ec0 343 radio.tx_buf[0] = beacon_payload[0];
dudmuck 9:a0ce66c18ec0 344 radio.tx_buf[1] = beacon_payload[1];
dudmuck 9:a0ce66c18ec0 345 radio.tx_buf[2] = beacon_payload[2];
dudmuck 9:a0ce66c18ec0 346 radio.tx_buf[3] = beacon_payload[3];
dudmuck 9:a0ce66c18ec0 347 beacon_payload[0] = CMD_NONE;
dudmuck 9:a0ce66c18ec0 348
dudmuck 0:2ff18de8d48b 349 crc = beacon_crc(radio.tx_buf, 4);
dudmuck 0:2ff18de8d48b 350 radio.tx_buf[4] = crc & 0xff;
dudmuck 0:2ff18de8d48b 351 radio.tx_buf[5] = crc >> 8;
dudmuck 0:2ff18de8d48b 352
dudmuck 0:2ff18de8d48b 353 // DIO0 to TxDone
dudmuck 3:7c01b8978638 354 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 3:7c01b8978638 355 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 0:2ff18de8d48b 356
dudmuck 0:2ff18de8d48b 357 // set FifoPtrAddr to FifoTxPtrBase
dudmuck 0:2ff18de8d48b 358 radio.write_reg(REG_LR_FIFOADDRPTR, radio.read_reg(REG_LR_FIFOTXBASEADDR));
dudmuck 0:2ff18de8d48b 359
dudmuck 0:2ff18de8d48b 360 // write PayloadLength bytes to fifo
dudmuck 0:2ff18de8d48b 361 lora.write_fifo(lora.RegPayloadLength);
dudmuck 0:2ff18de8d48b 362
dudmuck 0:2ff18de8d48b 363 // prepare for tx to occur in send_beacon()
dudmuck 0:2ff18de8d48b 364 radio.set_opmode(RF_OPMODE_SYNTHESIZER_TX);
dudmuck 0:2ff18de8d48b 365 beacon_loaded = true;
dudmuck 0:2ff18de8d48b 366
dudmuck 0:2ff18de8d48b 367 beacon_loaded_at = timer.read();
dudmuck 0:2ff18de8d48b 368 }
dudmuck 0:2ff18de8d48b 369
dudmuck 3:7c01b8978638 370 void load_beacon()
dudmuck 3:7c01b8978638 371 {
dudmuck 3:7c01b8978638 372 beacon_guard = true;
dudmuck 12:9a8c13c4298b 373 queue.call_in(200, _load_beacon);
dudmuck 3:7c01b8978638 374 }
dudmuck 3:7c01b8978638 375
dudmuck 0:2ff18de8d48b 376 void get_time_till_beacon()
dudmuck 0:2ff18de8d48b 377 {
dudmuck 0:2ff18de8d48b 378 uint16_t slots = tim_get_current_slot();
dudmuck 0:2ff18de8d48b 379 printf("slots:%u\r\n", slots);
dudmuck 0:2ff18de8d48b 380 }
dudmuck 0:2ff18de8d48b 381
dudmuck 4:7e743e402681 382 void rx_isr()
dudmuck 0:2ff18de8d48b 383 {
dudmuck 0:2ff18de8d48b 384 static uint8_t pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 385 static uint8_t prev_len = 0;;
dudmuck 0:2ff18de8d48b 386 char c = pc.getc();
dudmuck 0:2ff18de8d48b 387
dudmuck 0:2ff18de8d48b 388 if (c == 8) {
dudmuck 0:2ff18de8d48b 389 if (pcbuf_idx > 0) {
dudmuck 0:2ff18de8d48b 390 pc.putc(8);
dudmuck 0:2ff18de8d48b 391 pc.putc(' ');
dudmuck 0:2ff18de8d48b 392 pc.putc(8);
dudmuck 0:2ff18de8d48b 393 pcbuf_idx--;
dudmuck 0:2ff18de8d48b 394 }
dudmuck 0:2ff18de8d48b 395 } else if (c == 3) { // ctrl-C
dudmuck 0:2ff18de8d48b 396 pcbuf_len = -1;
dudmuck 0:2ff18de8d48b 397 } else if (c == '\r') {
dudmuck 0:2ff18de8d48b 398 if (pcbuf_idx == 0) {
dudmuck 0:2ff18de8d48b 399 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 400 } else {
dudmuck 0:2ff18de8d48b 401 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:2ff18de8d48b 402 prev_len = pcbuf_idx;
dudmuck 0:2ff18de8d48b 403 pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 404 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 405 }
dudmuck 0:2ff18de8d48b 406 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:2ff18de8d48b 407 pcbuf[pcbuf_idx++] = c;
dudmuck 0:2ff18de8d48b 408 pc.putc(c);
dudmuck 0:2ff18de8d48b 409 }
dudmuck 0:2ff18de8d48b 410 }
dudmuck 0:2ff18de8d48b 411
dudmuck 0:2ff18de8d48b 412 void cmd_skip_beacon(uint8_t idx)
dudmuck 0:2ff18de8d48b 413 {
dudmuck 0:2ff18de8d48b 414 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:2ff18de8d48b 415 sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 416 }
dudmuck 0:2ff18de8d48b 417 printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 418 }
dudmuck 0:2ff18de8d48b 419
dudmuck 0:2ff18de8d48b 420 void cmd_list_motes(uint8_t idx)
dudmuck 0:2ff18de8d48b 421 {
dudmuck 0:2ff18de8d48b 422 int i;
dudmuck 0:2ff18de8d48b 423 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 424 if (motes[i].dev_addr != DEVADDR_NONE) {
dudmuck 13:fa2095be01c4 425 LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
dudmuck 13:fa2095be01c4 426 printf(" %" PRIx32 "\r\n", motes[i].dev_addr);
dudmuck 0:2ff18de8d48b 427 }
dudmuck 0:2ff18de8d48b 428 }
dudmuck 0:2ff18de8d48b 429 }
dudmuck 0:2ff18de8d48b 430
dudmuck 0:2ff18de8d48b 431 void
dudmuck 0:2ff18de8d48b 432 cmd_beacon_payload(uint8_t idx)
dudmuck 0:2ff18de8d48b 433 {
dudmuck 9:a0ce66c18ec0 434 uint32_t i;
dudmuck 9:a0ce66c18ec0 435 uint32_t* ptr;
dudmuck 13:fa2095be01c4 436 sscanf(pcbuf+idx, "%" PRIx32, &i);
dudmuck 13:fa2095be01c4 437 printf("beacon_payload:%08" PRIx32 "\r\n", i);
dudmuck 9:a0ce66c18ec0 438 ptr = (uint32_t*)beacon_payload;
dudmuck 9:a0ce66c18ec0 439 *ptr = i;
dudmuck 8:307f7faeb594 440 }
dudmuck 8:307f7faeb594 441
dudmuck 0:2ff18de8d48b 442 void
dudmuck 0:2ff18de8d48b 443 cmd_send_downlink(uint8_t idx)
dudmuck 0:2ff18de8d48b 444 {
dudmuck 0:2ff18de8d48b 445 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 446 int i;
dudmuck 0:2ff18de8d48b 447 unsigned int dev_addr;
dudmuck 0:2ff18de8d48b 448 sscanf(pcbuf+idx, "%x", &dev_addr);
dudmuck 0:2ff18de8d48b 449 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 450 if (motes[i].dev_addr == dev_addr) {
dudmuck 0:2ff18de8d48b 451 break;
dudmuck 0:2ff18de8d48b 452 }
dudmuck 0:2ff18de8d48b 453 }
dudmuck 0:2ff18de8d48b 454 if (i == N_MOTES) {
dudmuck 0:2ff18de8d48b 455 printf("mote %x not found\r\n", dev_addr);
dudmuck 0:2ff18de8d48b 456 return;
dudmuck 0:2ff18de8d48b 457 }
dudmuck 0:2ff18de8d48b 458 mote = &motes[i];
dudmuck 0:2ff18de8d48b 459
dudmuck 0:2ff18de8d48b 460 while (pcbuf[idx] != ' ') {
dudmuck 0:2ff18de8d48b 461 if (pcbuf[++idx] == 0) {
dudmuck 0:2ff18de8d48b 462 printf("hit end\r\n");
dudmuck 0:2ff18de8d48b 463 return;
dudmuck 0:2ff18de8d48b 464 }
dudmuck 0:2ff18de8d48b 465 }
dudmuck 0:2ff18de8d48b 466 idx++; // step past space
dudmuck 0:2ff18de8d48b 467
dudmuck 0:2ff18de8d48b 468 mote->user_downlink_length = 0;
dudmuck 0:2ff18de8d48b 469 while (pcbuf[idx] > ' ') {
dudmuck 0:2ff18de8d48b 470 int o;
dudmuck 0:2ff18de8d48b 471 sscanf(pcbuf+idx, "%02x", &o);
dudmuck 0:2ff18de8d48b 472 LoRaWan::user_downlink[mote->user_downlink_length++] = o;
dudmuck 0:2ff18de8d48b 473 idx += 2;
dudmuck 0:2ff18de8d48b 474 }
dudmuck 0:2ff18de8d48b 475
dudmuck 13:fa2095be01c4 476 printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
dudmuck 0:2ff18de8d48b 477 }
dudmuck 0:2ff18de8d48b 478
dudmuck 9:a0ce66c18ec0 479 void cmd_rx_restart(uint8_t idx)
dudmuck 9:a0ce66c18ec0 480 {
dudmuck 9:a0ce66c18ec0 481 /*radio.set_opmode(RF_OPMODE_STANDBY);
dudmuck 9:a0ce66c18ec0 482 printf("standby\r\n");*/
dudmuck 9:a0ce66c18ec0 483 radio.set_opmode(RF_OPMODE_SLEEP);
dudmuck 9:a0ce66c18ec0 484 printf("sleep\r\n");
dudmuck 9:a0ce66c18ec0 485 wait(0.05);
dudmuck 9:a0ce66c18ec0 486 radio.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 9:a0ce66c18ec0 487 printf("receive\r\n");
dudmuck 9:a0ce66c18ec0 488 }
dudmuck 9:a0ce66c18ec0 489
dudmuck 9:a0ce66c18ec0 490 void cmd_beacon_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 491 {
dudmuck 9:a0ce66c18ec0 492 int gpo;
dudmuck 9:a0ce66c18ec0 493 sscanf(pcbuf+idx, "%d", &gpo);
dudmuck 9:a0ce66c18ec0 494 beacon_payload[0] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 495 beacon_payload[1] = gpo;
dudmuck 9:a0ce66c18ec0 496 printf("beacon gpo: %d\r\n", gpo);
dudmuck 9:a0ce66c18ec0 497 }
dudmuck 9:a0ce66c18ec0 498
dudmuck 9:a0ce66c18ec0 499 void cmd_beacon_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 500 {
dudmuck 9:a0ce66c18ec0 501 int r, g ,b;
dudmuck 9:a0ce66c18ec0 502 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 9:a0ce66c18ec0 503 beacon_payload[0] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 504 beacon_payload[1] = r;
dudmuck 9:a0ce66c18ec0 505 beacon_payload[2] = g;
dudmuck 9:a0ce66c18ec0 506 beacon_payload[3] = b;
dudmuck 9:a0ce66c18ec0 507 printf("beacon rgb: %d %d %d\r\n", r, g, b);
dudmuck 9:a0ce66c18ec0 508 }
dudmuck 9:a0ce66c18ec0 509
dudmuck 9:a0ce66c18ec0 510 void cmd_downlink_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 511 {
dudmuck 9:a0ce66c18ec0 512 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 513 int i, r, g ,b;
dudmuck 9:a0ce66c18ec0 514 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 515 sscanf(pcbuf+idx, "%x %d %d %d", &dev_addr, &r, &g, &b);
dudmuck 9:a0ce66c18ec0 516 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 517 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 518 break;
dudmuck 9:a0ce66c18ec0 519 }
dudmuck 9:a0ce66c18ec0 520 }
dudmuck 9:a0ce66c18ec0 521 if (i == N_MOTES) {
dudmuck 9:a0ce66c18ec0 522 printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 523 return;
dudmuck 9:a0ce66c18ec0 524 }
dudmuck 9:a0ce66c18ec0 525 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 526
dudmuck 9:a0ce66c18ec0 527 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 528 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 529 LoRaWan::user_downlink[mote->user_downlink_length++] = r;
dudmuck 9:a0ce66c18ec0 530 LoRaWan::user_downlink[mote->user_downlink_length++] = g;
dudmuck 9:a0ce66c18ec0 531 LoRaWan::user_downlink[mote->user_downlink_length++] = b;
dudmuck 9:a0ce66c18ec0 532
dudmuck 13:fa2095be01c4 533 printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 534 }
dudmuck 9:a0ce66c18ec0 535
dudmuck 9:a0ce66c18ec0 536 void cmd_downlink_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 537 {
dudmuck 9:a0ce66c18ec0 538 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 539 int i, gpo;
dudmuck 9:a0ce66c18ec0 540 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 541 sscanf(pcbuf+idx, "%x %d", &dev_addr, &gpo);
dudmuck 9:a0ce66c18ec0 542 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 543 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 544 break;
dudmuck 9:a0ce66c18ec0 545 }
dudmuck 9:a0ce66c18ec0 546 }
dudmuck 9:a0ce66c18ec0 547 if (i == N_MOTES) {
dudmuck 9:a0ce66c18ec0 548 printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 549 return;
dudmuck 9:a0ce66c18ec0 550 }
dudmuck 9:a0ce66c18ec0 551 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 552
dudmuck 9:a0ce66c18ec0 553 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 554 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 555 LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
dudmuck 9:a0ce66c18ec0 556
dudmuck 13:fa2095be01c4 557 printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 558 }
dudmuck 9:a0ce66c18ec0 559
dudmuck 0:2ff18de8d48b 560 void cmd_status(uint8_t idx)
dudmuck 0:2ff18de8d48b 561 {
dudmuck 14:c6284654d1b0 562 radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
dudmuck 14:c6284654d1b0 563 if (radio.RegPaConfig.bits.PaSelect)
dudmuck 14:c6284654d1b0 564 printf("PA_BOOST ");
dudmuck 14:c6284654d1b0 565 else
dudmuck 14:c6284654d1b0 566 printf("RFO ");
dudmuck 14:c6284654d1b0 567
dudmuck 0:2ff18de8d48b 568 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 2:9628d5e4b1bf 569 printf("%.3fMHz sf%ubw%u ", radio.get_frf_MHz(), lora.getSf(), lora.getBw());
dudmuck 0:2ff18de8d48b 570 printOpMode();
dudmuck 0:2ff18de8d48b 571 if (!radio.RegOpMode.bits.LongRangeMode) {
dudmuck 0:2ff18de8d48b 572 printf("FSK\r\n");
dudmuck 0:2ff18de8d48b 573 return;
dudmuck 0:2ff18de8d48b 574 }
dudmuck 0:2ff18de8d48b 575
dudmuck 0:2ff18de8d48b 576 lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
dudmuck 0:2ff18de8d48b 577 printLoraIrqs(false);
dudmuck 0:2ff18de8d48b 578
dudmuck 12:9a8c13c4298b 579 printf(" do_downlink:%u get_tx_done:%u, ", LoRaWan::do_downlink, get_tx_done);
dudmuck 9:a0ce66c18ec0 580 lora.RegTest33.octet = radio.read_reg(REG_LR_TEST33); // invert_i_q
dudmuck 9:a0ce66c18ec0 581 lora.RegDriftInvert.octet = radio.read_reg(REG_LR_DRIFT_INVERT);
dudmuck 9:a0ce66c18ec0 582 printf("modemstat:%02x, rxinv:%x,%x\r\n", radio.read_reg(REG_LR_MODEMSTAT), lora.RegTest33.octet, lora.RegDriftInvert.octet);
dudmuck 2:9628d5e4b1bf 583 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 2:9628d5e4b1bf 584 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 585 printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", radio.read_reg(REG_LR_FIFOADDRPTR), radio.read_reg(REG_LR_FIFORXBASEADDR));
dudmuck 0:2ff18de8d48b 586 }
dudmuck 0:2ff18de8d48b 587
dudmuck 16:67fa19bc6331 588 void cmd_filter(uint8_t idx)
dudmuck 16:67fa19bc6331 589 {
dudmuck 16:67fa19bc6331 590 if (sscanf(pcbuf+idx, "%lx", &LoRaWan::dev_addr_filter) != 1) {
dudmuck 16:67fa19bc6331 591 LoRaWan::dev_addr_filter = 0;
dudmuck 16:67fa19bc6331 592 printf("filter off\r\n");
dudmuck 16:67fa19bc6331 593 } else
dudmuck 16:67fa19bc6331 594 printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
dudmuck 16:67fa19bc6331 595 }
dudmuck 16:67fa19bc6331 596
dudmuck 11:50d0558a4e37 597 void cmd_op(uint8_t idx)
dudmuck 11:50d0558a4e37 598 {
dudmuck 11:50d0558a4e37 599 int i, dbm;
dudmuck 11:50d0558a4e37 600 RegPdsTrim1_t pds_trim;
dudmuck 11:50d0558a4e37 601 uint8_t adr;
dudmuck 11:50d0558a4e37 602 if (radio.type == SX1276)
dudmuck 11:50d0558a4e37 603 adr = REG_PDSTRIM1_SX1276;
dudmuck 11:50d0558a4e37 604 else
dudmuck 11:50d0558a4e37 605 adr = REG_PDSTRIM1_SX1272;
dudmuck 11:50d0558a4e37 606
dudmuck 11:50d0558a4e37 607 pds_trim.octet = radio.read_reg(adr);
dudmuck 11:50d0558a4e37 608
dudmuck 11:50d0558a4e37 609 if (pcbuf[idx] >= '0' && (pcbuf[idx] <= '9' || pcbuf[idx] == '-')) {
dudmuck 11:50d0558a4e37 610 sscanf(pcbuf+idx, "%d", &i);
dudmuck 11:50d0558a4e37 611 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 11:50d0558a4e37 612 /* PABOOST used: +2dbm to +17, or +20 */
dudmuck 11:50d0558a4e37 613 if (i == 20) {
dudmuck 11:50d0558a4e37 614 printf("+20dBm PADAC bias\r\n");
dudmuck 11:50d0558a4e37 615 i -= 3;
dudmuck 11:50d0558a4e37 616 pds_trim.bits.prog_txdac = 7;
dudmuck 11:50d0558a4e37 617 radio.write_reg(adr, pds_trim.octet);
dudmuck 11:50d0558a4e37 618 }
dudmuck 11:50d0558a4e37 619 if (i > 1)
dudmuck 11:50d0558a4e37 620 radio.RegPaConfig.bits.OutputPower = i - 2;
dudmuck 11:50d0558a4e37 621 } else {
dudmuck 11:50d0558a4e37 622 /* RFO used: -1 to +14dbm */
dudmuck 11:50d0558a4e37 623 if (i < 15)
dudmuck 11:50d0558a4e37 624 radio.RegPaConfig.bits.OutputPower = i + 1;
dudmuck 11:50d0558a4e37 625 }
dudmuck 11:50d0558a4e37 626 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 11:50d0558a4e37 627 }
dudmuck 11:50d0558a4e37 628 radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
dudmuck 11:50d0558a4e37 629 if (radio.RegPaConfig.bits.PaSelect) {
dudmuck 11:50d0558a4e37 630 printf("PA_BOOST ");
dudmuck 11:50d0558a4e37 631 dbm = radio.RegPaConfig.bits.OutputPower + pds_trim.bits.prog_txdac - 2;
dudmuck 11:50d0558a4e37 632 } else {
dudmuck 11:50d0558a4e37 633 printf("RFO ");
dudmuck 11:50d0558a4e37 634 dbm = radio.RegPaConfig.bits.OutputPower - 1;
dudmuck 11:50d0558a4e37 635 }
dudmuck 11:50d0558a4e37 636 printf("OutputPower:%ddBm\r\n", dbm);
dudmuck 11:50d0558a4e37 637 }
dudmuck 11:50d0558a4e37 638
dudmuck 14:c6284654d1b0 639 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 640 void cmd_pa_select(uint8_t idx)
dudmuck 14:c6284654d1b0 641 {
dudmuck 14:c6284654d1b0 642 radio.RegPaConfig.bits.PaSelect ^= 1;
dudmuck 14:c6284654d1b0 643 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 14:c6284654d1b0 644 if (radio.RegPaConfig.bits.PaSelect)
dudmuck 14:c6284654d1b0 645 printf("PA_BOOST\r\n");
dudmuck 14:c6284654d1b0 646 else
dudmuck 14:c6284654d1b0 647 printf("RFO\r\n");
dudmuck 14:c6284654d1b0 648 }
dudmuck 14:c6284654d1b0 649 #endif /* TYPE_ABZ */
dudmuck 14:c6284654d1b0 650
dudmuck 12:9a8c13c4298b 651 void cmd_set_time(uint8_t idx)
dudmuck 12:9a8c13c4298b 652 {
dudmuck 12:9a8c13c4298b 653 set_time(0);
dudmuck 13:fa2095be01c4 654 printf("time:%" PRIu32 "\r\n", time(NULL));
dudmuck 12:9a8c13c4298b 655 }
dudmuck 12:9a8c13c4298b 656
dudmuck 13:fa2095be01c4 657
dudmuck 13:fa2095be01c4 658 void cmd_pwm(uint8_t idx)
dudmuck 12:9a8c13c4298b 659 {
dudmuck 13:fa2095be01c4 660 ota_mote_t* mote;
dudmuck 12:9a8c13c4298b 661 int i;
dudmuck 13:fa2095be01c4 662 unsigned dev_addr, p, d;
dudmuck 13:fa2095be01c4 663
dudmuck 13:fa2095be01c4 664 if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
dudmuck 13:fa2095be01c4 665 printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 666 return;
dudmuck 13:fa2095be01c4 667 }
dudmuck 12:9a8c13c4298b 668 for (i = 0; i < N_MOTES; i++) {
dudmuck 12:9a8c13c4298b 669 if (motes[i].dev_addr == dev_addr) {
dudmuck 12:9a8c13c4298b 670 break;
dudmuck 12:9a8c13c4298b 671 }
dudmuck 12:9a8c13c4298b 672 }
dudmuck 12:9a8c13c4298b 673 if (i == N_MOTES) {
dudmuck 12:9a8c13c4298b 674 printf("mote %x not found\r\n", dev_addr);
dudmuck 12:9a8c13c4298b 675 return;
dudmuck 12:9a8c13c4298b 676 }
dudmuck 12:9a8c13c4298b 677
dudmuck 12:9a8c13c4298b 678 mote = &motes[i];
dudmuck 12:9a8c13c4298b 679
dudmuck 12:9a8c13c4298b 680 mote->user_downlink_length = 0;
dudmuck 13:fa2095be01c4 681 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_PWM;
dudmuck 13:fa2095be01c4 682 LoRaWan::user_downlink[mote->user_downlink_length++] = p;
dudmuck 13:fa2095be01c4 683 LoRaWan::user_downlink[mote->user_downlink_length++] = d;
dudmuck 12:9a8c13c4298b 684
dudmuck 13:fa2095be01c4 685 printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
dudmuck 13:fa2095be01c4 686 }
dudmuck 13:fa2095be01c4 687
dudmuck 13:fa2095be01c4 688 void cmd_beacon_pwm(uint8_t idx)
dudmuck 13:fa2095be01c4 689 {
dudmuck 13:fa2095be01c4 690 unsigned p, d;
dudmuck 13:fa2095be01c4 691 if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
dudmuck 13:fa2095be01c4 692 printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 693 return;
dudmuck 13:fa2095be01c4 694 }
dudmuck 13:fa2095be01c4 695
dudmuck 13:fa2095be01c4 696 beacon_payload[0] = CMD_PWM;
dudmuck 13:fa2095be01c4 697 beacon_payload[1] = p;
dudmuck 13:fa2095be01c4 698 beacon_payload[2] = d;
dudmuck 13:fa2095be01c4 699
dudmuck 13:fa2095be01c4 700 printf("period:%u duty:%u\r\n", p, d);
dudmuck 12:9a8c13c4298b 701 }
dudmuck 12:9a8c13c4298b 702
dudmuck 14:c6284654d1b0 703 void cmd_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 704 {
dudmuck 14:c6284654d1b0 705 ota_mote_t* mote;
dudmuck 14:c6284654d1b0 706 int i;
dudmuck 14:c6284654d1b0 707 unsigned dev_addr, txi;
dudmuck 14:c6284654d1b0 708
dudmuck 14:c6284654d1b0 709 if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
dudmuck 14:c6284654d1b0 710 printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 711 return;
dudmuck 14:c6284654d1b0 712 }
dudmuck 14:c6284654d1b0 713 for (i = 0; i < N_MOTES; i++) {
dudmuck 14:c6284654d1b0 714 if (motes[i].dev_addr == dev_addr) {
dudmuck 14:c6284654d1b0 715 break;
dudmuck 14:c6284654d1b0 716 }
dudmuck 14:c6284654d1b0 717 }
dudmuck 14:c6284654d1b0 718 if (i == N_MOTES) {
dudmuck 14:c6284654d1b0 719 printf("mote %x not found\r\n", dev_addr);
dudmuck 14:c6284654d1b0 720 return;
dudmuck 14:c6284654d1b0 721 }
dudmuck 14:c6284654d1b0 722
dudmuck 14:c6284654d1b0 723 mote = &motes[i];
dudmuck 14:c6284654d1b0 724
dudmuck 14:c6284654d1b0 725 mote->user_downlink_length = 0;
dudmuck 14:c6284654d1b0 726 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 727 LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
dudmuck 14:c6284654d1b0 728
dudmuck 14:c6284654d1b0 729 printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
dudmuck 14:c6284654d1b0 730 }
dudmuck 14:c6284654d1b0 731
dudmuck 14:c6284654d1b0 732 void cmd_beacon_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 733 {
dudmuck 14:c6284654d1b0 734 unsigned txi;
dudmuck 14:c6284654d1b0 735 if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
dudmuck 14:c6284654d1b0 736 printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 737 return;
dudmuck 14:c6284654d1b0 738 }
dudmuck 14:c6284654d1b0 739
dudmuck 14:c6284654d1b0 740 beacon_payload[0] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 741 beacon_payload[1] = txi;
dudmuck 14:c6284654d1b0 742
dudmuck 14:c6284654d1b0 743 printf("txp index:%u\r\n", txi);
dudmuck 14:c6284654d1b0 744 }
dudmuck 14:c6284654d1b0 745
dudmuck 0:2ff18de8d48b 746 void cmd_help(uint8_t);
dudmuck 0:2ff18de8d48b 747
dudmuck 0:2ff18de8d48b 748 typedef struct {
dudmuck 0:2ff18de8d48b 749 const char* const cmd;
dudmuck 0:2ff18de8d48b 750 void (*handler)(uint8_t args_at);
dudmuck 0:2ff18de8d48b 751 const char* const arg_descr;
dudmuck 0:2ff18de8d48b 752 const char* const description;
dudmuck 0:2ff18de8d48b 753 } menu_item_t;
dudmuck 0:2ff18de8d48b 754
dudmuck 0:2ff18de8d48b 755 const menu_item_t menu_items[] =
dudmuck 0:2ff18de8d48b 756 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:2ff18de8d48b 757 { "?", cmd_help, "","show available commands"},
dudmuck 0:2ff18de8d48b 758 { ".", cmd_status, "","read status"},
dudmuck 16:67fa19bc6331 759 { "f", cmd_filter, "%x","set dev_addr print filter"},
dudmuck 0:2ff18de8d48b 760 { "b", cmd_beacon_payload, "<%x>","set beacon payload"},
dudmuck 0:2ff18de8d48b 761 { "sb", cmd_skip_beacon, "<%d>","skip beacons"},
dudmuck 0:2ff18de8d48b 762 { "list", cmd_list_motes, "","list active motes"},
dudmuck 0:2ff18de8d48b 763 { "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
dudmuck 9:a0ce66c18ec0 764 { "rxr", cmd_rx_restart, "", "restart RX"},
dudmuck 9:a0ce66c18ec0 765 { "brgb", cmd_beacon_rgb, "%u %u %u", "load RGB command into next beacon" },
dudmuck 9:a0ce66c18ec0 766 { "rgb", cmd_downlink_rgb, "%x %u %u %u", "load RGB command to mote"},
dudmuck 9:a0ce66c18ec0 767 { "bgpo", cmd_beacon_gpo, "%d", "load output pin command into next beacon"},
dudmuck 9:a0ce66c18ec0 768 { "gpo", cmd_downlink_gpo, "%x %d", "load output pin command to mote"},
dudmuck 12:9a8c13c4298b 769 { "op", cmd_op, "<dBm>","(TX) get/set TX power"},
dudmuck 14:c6284654d1b0 770 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 771 { "pas", cmd_pa_select, "","(TX) toggle PaSelect"},
dudmuck 14:c6284654d1b0 772 #endif
dudmuck 13:fa2095be01c4 773 { "tz", cmd_set_time, "", "set seconds to zero"},
dudmuck 13:fa2095be01c4 774 { "p", cmd_pwm, "%x %u %u", "send pwm period, duty to dev_addr"},
dudmuck 13:fa2095be01c4 775 { "bp", cmd_beacon_pwm, "%u %u", "send pwm period, duty on beacon"},
dudmuck 14:c6284654d1b0 776 { "ntxp", cmd_endnode_txp, "%x %u", "send txpower index to dev_addr"},
dudmuck 14:c6284654d1b0 777 { "bntxp", cmd_beacon_endnode_txp, "%u", "send txpower index on beacon"},
dudmuck 0:2ff18de8d48b 778 { NULL, NULL, NULL, NULL }
dudmuck 0:2ff18de8d48b 779 };
dudmuck 0:2ff18de8d48b 780
dudmuck 0:2ff18de8d48b 781 void cmd_help(uint8_t args_at)
dudmuck 0:2ff18de8d48b 782 {
dudmuck 0:2ff18de8d48b 783 int i;
dudmuck 0:2ff18de8d48b 784
dudmuck 0:2ff18de8d48b 785 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 786 printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:2ff18de8d48b 787 }
dudmuck 0:2ff18de8d48b 788
dudmuck 0:2ff18de8d48b 789 }
dudmuck 0:2ff18de8d48b 790
dudmuck 0:2ff18de8d48b 791 void
dudmuck 0:2ff18de8d48b 792 console()
dudmuck 0:2ff18de8d48b 793 {
dudmuck 0:2ff18de8d48b 794 int i;
dudmuck 0:2ff18de8d48b 795 uint8_t user_cmd_len;
dudmuck 0:2ff18de8d48b 796
dudmuck 0:2ff18de8d48b 797 if (pcbuf_len < 0) { // ctrl-C
dudmuck 0:2ff18de8d48b 798 //printf("abort\r\n");
dudmuck 0:2ff18de8d48b 799 return;
dudmuck 0:2ff18de8d48b 800 }
dudmuck 0:2ff18de8d48b 801 if (pcbuf_len == 0)
dudmuck 0:2ff18de8d48b 802 return;
dudmuck 0:2ff18de8d48b 803
dudmuck 0:2ff18de8d48b 804 printf("\r\n");
dudmuck 0:2ff18de8d48b 805
dudmuck 0:2ff18de8d48b 806 /* get end of user-entered command */
dudmuck 0:2ff18de8d48b 807 user_cmd_len = 1; // first character can be any character
dudmuck 0:2ff18de8d48b 808 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:2ff18de8d48b 809 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:2ff18de8d48b 810 user_cmd_len = i;
dudmuck 0:2ff18de8d48b 811 break;
dudmuck 0:2ff18de8d48b 812 }
dudmuck 0:2ff18de8d48b 813 }
dudmuck 0:2ff18de8d48b 814
dudmuck 0:2ff18de8d48b 815 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 816 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:2ff18de8d48b 817
dudmuck 0:2ff18de8d48b 818 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:2ff18de8d48b 819 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:2ff18de8d48b 820 mi_len++;
dudmuck 0:2ff18de8d48b 821 menu_items[i].handler(mi_len);
dudmuck 0:2ff18de8d48b 822 break;
dudmuck 0:2ff18de8d48b 823 }
dudmuck 0:2ff18de8d48b 824 }
dudmuck 0:2ff18de8d48b 825
dudmuck 0:2ff18de8d48b 826 pcbuf_len = 0;
dudmuck 0:2ff18de8d48b 827 printf("> ");
dudmuck 0:2ff18de8d48b 828 fflush(stdout);
dudmuck 0:2ff18de8d48b 829 }
dudmuck 0:2ff18de8d48b 830
dudmuck 0:2ff18de8d48b 831 int main()
dudmuck 0:2ff18de8d48b 832 {
dudmuck 0:2ff18de8d48b 833 Thread eventThread;
dudmuck 3:7c01b8978638 834 pc.baud(38400);
dudmuck 12:9a8c13c4298b 835 printf("\r\nreset %f\r\n", radio.get_frf_MHz());
dudmuck 11:50d0558a4e37 836 set_time(0);
dudmuck 0:2ff18de8d48b 837
dudmuck 0:2ff18de8d48b 838 radio.hw_reset();
dudmuck 12:9a8c13c4298b 839 printf("%fMHz\r\n", radio.get_frf_MHz());
dudmuck 0:2ff18de8d48b 840
dudmuck 10:6783623cc886 841 #ifndef TYPE_ABZ
dudmuck 15:fea23ad8eafa 842 /* LoRa arduino shield... */
dudmuck 15:fea23ad8eafa 843 #ifdef USE_BAND_433
dudmuck 15:fea23ad8eafa 844 radio.RegPaConfig.bits.PaSelect = 0; // RFO_LF connected
dudmuck 15:fea23ad8eafa 845 #else
dudmuck 0:2ff18de8d48b 846 rfsw.input();
dudmuck 0:2ff18de8d48b 847 if (rfsw.read()) {
dudmuck 0:2ff18de8d48b 848 printf("LAS\r\n");
dudmuck 0:2ff18de8d48b 849 /* LAS HF=PA_BOOST LF=RFO */
dudmuck 0:2ff18de8d48b 850 radio.RegPaConfig.bits.PaSelect = 1;
dudmuck 0:2ff18de8d48b 851 } else {
dudmuck 0:2ff18de8d48b 852 printf("MAS\r\n");
dudmuck 0:2ff18de8d48b 853 radio.RegPaConfig.bits.PaSelect = 0;
dudmuck 0:2ff18de8d48b 854 }
dudmuck 15:fea23ad8eafa 855 #endif /* !USE_BAND_433 */
dudmuck 0:2ff18de8d48b 856 rfsw.output();
dudmuck 15:fea23ad8eafa 857 /* ...LoRa arduino shield */
dudmuck 15:fea23ad8eafa 858 #endif
dudmuck 0:2ff18de8d48b 859
dudmuck 0:2ff18de8d48b 860 radio.rf_switch = rfsw_callback;
dudmuck 0:2ff18de8d48b 861
dudmuck 0:2ff18de8d48b 862 init_radio();
dudmuck 0:2ff18de8d48b 863
dudmuck 0:2ff18de8d48b 864 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 0:2ff18de8d48b 865
dudmuck 0:2ff18de8d48b 866 eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
dudmuck 0:2ff18de8d48b 867 LoRaWan::init();
dudmuck 0:2ff18de8d48b 868
dudmuck 0:2ff18de8d48b 869 timer.start();
dudmuck 0:2ff18de8d48b 870 tim_init();
dudmuck 4:7e743e402681 871
dudmuck 4:7e743e402681 872 pc.attach(&rx_isr);
dudmuck 9:a0ce66c18ec0 873
dudmuck 0:2ff18de8d48b 874
dudmuck 0:2ff18de8d48b 875 for (;;) {
dudmuck 0:2ff18de8d48b 876 console();
dudmuck 1:107435401168 877
dudmuck 1:107435401168 878 if (radio.dio0) {
dudmuck 3:7c01b8978638 879 if (get_tx_done) {
dudmuck 3:7c01b8978638 880 get_tx_done = false;
dudmuck 3:7c01b8978638 881 lora.RegIrqFlags.octet = 0;
dudmuck 3:7c01b8978638 882 lora.RegIrqFlags.bits.TxDone = 1;
dudmuck 3:7c01b8978638 883 radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
dudmuck 3:7c01b8978638 884
dudmuck 3:7c01b8978638 885 if (restore_tx_invert) {
dudmuck 3:7c01b8978638 886 lora.invert_tx(false);
dudmuck 3:7c01b8978638 887 restore_tx_invert = false;
dudmuck 3:7c01b8978638 888 }
dudmuck 3:7c01b8978638 889
dudmuck 3:7c01b8978638 890 if (restore_header_mode) {
dudmuck 3:7c01b8978638 891 lora.setHeaderMode(false);
dudmuck 3:7c01b8978638 892 restore_header_mode = false;
dudmuck 3:7c01b8978638 893 }
dudmuck 12:9a8c13c4298b 894
dudmuck 3:7c01b8978638 895 lora.start_rx(RF_OPMODE_RECEIVER);
dudmuck 12:9a8c13c4298b 896
dudmuck 12:9a8c13c4298b 897 if (beacon_guard) { // beacon done transmitting
dudmuck 12:9a8c13c4298b 898 measure_ambient();
dudmuck 12:9a8c13c4298b 899 beacon_guard = false;
dudmuck 12:9a8c13c4298b 900 }
dudmuck 3:7c01b8978638 901 } else {
dudmuck 3:7c01b8978638 902 if (!beacon_guard)
dudmuck 3:7c01b8978638 903 service_radio();
dudmuck 3:7c01b8978638 904 }
dudmuck 12:9a8c13c4298b 905 } else if (get_tx_done) {
dudmuck 12:9a8c13c4298b 906 /* dio0 not yet asserted */
dudmuck 12:9a8c13c4298b 907 uint32_t since = timer.read_ms() - tx_ms;
dudmuck 12:9a8c13c4298b 908 if (since > 4000) {
dudmuck 12:9a8c13c4298b 909 radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
dudmuck 12:9a8c13c4298b 910 if (radio.RegOpMode.bits.Mode == RF_OPMODE_STANDBY) {
dudmuck 12:9a8c13c4298b 911 /* done transmitting, but dio0 not asserted */
dudmuck 12:9a8c13c4298b 912 printf("txDone but no dio0\r\n");
dudmuck 12:9a8c13c4298b 913 radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
dudmuck 12:9a8c13c4298b 914 if (radio.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 12:9a8c13c4298b 915 printf("dio0mapping-fail\r\n");
dudmuck 12:9a8c13c4298b 916 radio.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 12:9a8c13c4298b 917 radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
dudmuck 12:9a8c13c4298b 918 }
dudmuck 12:9a8c13c4298b 919 }
dudmuck 12:9a8c13c4298b 920 }
dudmuck 12:9a8c13c4298b 921 }
dudmuck 12:9a8c13c4298b 922
dudmuck 12:9a8c13c4298b 923 if (LoRaWan::do_downlink && !beacon_guard) {
dudmuck 12:9a8c13c4298b 924 uint32_t since = timer.read_ms() - LoRaWan::rx_ms;
dudmuck 12:9a8c13c4298b 925 if (since > 110)
dudmuck 13:fa2095be01c4 926 printf("since-tx:%lu\r\n", since);
dudmuck 12:9a8c13c4298b 927 if (since > 500) {
dudmuck 12:9a8c13c4298b 928 LoRaWan::do_downlink = false;
dudmuck 12:9a8c13c4298b 929 printf("stalled-tx\r\n");
dudmuck 12:9a8c13c4298b 930 cmd_rx_restart(0);
dudmuck 12:9a8c13c4298b 931 }
dudmuck 1:107435401168 932 }
dudmuck 8:307f7faeb594 933
dudmuck 0:2ff18de8d48b 934 } // ..for(;;)
dudmuck 0:2ff18de8d48b 935 }