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:
Tue Aug 15 10:45:41 2017 -0700
Revision:
19:c20591c95746
Parent:
18:806cf9b7a904
Child:
21:1ac5ffad2726
revised print filter for appliation layer

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