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:
Mon Aug 14 11:32:56 2017 -0700
Revision:
18:806cf9b7a904
Parent:
17:763412df6872
Child:
19:c20591c95746
had print filtering for mac and application layers

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