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:
Wayne Roberts
Date:
Tue Jul 14 11:08:24 2020 -0700
Revision:
23:801d4bd6dccc
Parent:
22:dd3023aac3b1
update to mbed-6

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:2ff18de8d48b 1 #include "lorawan.h"
dudmuck 8:307f7faeb594 2 #include "commands.h"
Wayne Roberts 21:1ac5ffad2726 3 #include "SPIu.h"
dudmuck 13:fa2095be01c4 4 #define __STDC_FORMAT_MACROS
dudmuck 13:fa2095be01c4 5 #include <inttypes.h>
dudmuck 0:2ff18de8d48b 6
Wayne Roberts 21:1ac5ffad2726 7 #define PREAMBLE_SYMBS 8
Wayne Roberts 21:1ac5ffad2726 8
Wayne Roberts 23:801d4bd6dccc 9 const microseconds BEACON_PRELOAD_us(500000);
Wayne Roberts 23:801d4bd6dccc 10 const seconds BEACON_INTERVAL_s(128);
Wayne Roberts 23:801d4bd6dccc 11 HighResClock::time_point beaconAt;
Wayne Roberts 23:801d4bd6dccc 12 Timeout beacon_timeout; /* beacon generator */
Wayne Roberts 21:1ac5ffad2726 13
Wayne Roberts 23:801d4bd6dccc 14 UnbufferedSerial pc( USBTX, USBRX );
dudmuck 0:2ff18de8d48b 15
dudmuck 0:2ff18de8d48b 16 char pcbuf[64];
dudmuck 0:2ff18de8d48b 17 int pcbuf_len;
dudmuck 9:a0ce66c18ec0 18 uint8_t beacon_payload[4];
dudmuck 0:2ff18de8d48b 19
dudmuck 0:2ff18de8d48b 20 unsigned int skip_beacon_cnt;
dudmuck 0:2ff18de8d48b 21
dudmuck 12:9a8c13c4298b 22 float starting_bg_rssi;
Wayne Roberts 22:dd3023aac3b1 23 volatile uint32_t usingChHz;
dudmuck 0:2ff18de8d48b 24
dudmuck 0:2ff18de8d48b 25 #define N_SAMPLES 64
dudmuck 0:2ff18de8d48b 26 void channel_scan()
dudmuck 0:2ff18de8d48b 27 {
dudmuck 0:2ff18de8d48b 28 int min_ch, ch;
dudmuck 0:2ff18de8d48b 29 uint32_t hz = LORAMAC_FIRST_CHANNEL;
dudmuck 0:2ff18de8d48b 30 int acc[LORA_MAX_NB_CHANNELS];
dudmuck 0:2ff18de8d48b 31
Wayne Roberts 21:1ac5ffad2726 32 Radio::Standby( );
Wayne Roberts 23:801d4bd6dccc 33 ThisThread::sleep_for(20ms);
dudmuck 0:2ff18de8d48b 34
dudmuck 0:2ff18de8d48b 35 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 36 int i;
Wayne Roberts 21:1ac5ffad2726 37 Radio::SetChannel(hz);
Wayne Roberts 21:1ac5ffad2726 38 Radio::Rx(0);
dudmuck 0:2ff18de8d48b 39 acc[ch] = 0;
dudmuck 0:2ff18de8d48b 40 for (i = 0; i < N_SAMPLES; i++) {
Wayne Roberts 21:1ac5ffad2726 41 int rssi = Radio::GetRssiInst();
dudmuck 0:2ff18de8d48b 42 acc[ch] += rssi;
Wayne Roberts 23:801d4bd6dccc 43 ThisThread::sleep_for(10ms);
dudmuck 0:2ff18de8d48b 44 }
Wayne Roberts 21:1ac5ffad2726 45 Radio::Standby( );
Wayne Roberts 23:801d4bd6dccc 46 pc_printf("ch%u: %d\r\n", ch, (int)(acc[ch] / (float)N_SAMPLES));
dudmuck 0:2ff18de8d48b 47 hz += LORAMAC_STEPWIDTH_CHANNEL;
Wayne Roberts 23:801d4bd6dccc 48 ThisThread::sleep_for(20ms);
Wayne Roberts 21:1ac5ffad2726 49 Radio::SetChannel(hz);
dudmuck 0:2ff18de8d48b 50 }
dudmuck 0:2ff18de8d48b 51
dudmuck 0:2ff18de8d48b 52 int min = 0x7fffffff;
dudmuck 0:2ff18de8d48b 53 min_ch = 0;
dudmuck 0:2ff18de8d48b 54 for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
dudmuck 0:2ff18de8d48b 55 if (acc[ch] < min) {
dudmuck 0:2ff18de8d48b 56 min = acc[ch];
dudmuck 0:2ff18de8d48b 57 min_ch = ch;
dudmuck 0:2ff18de8d48b 58 }
dudmuck 0:2ff18de8d48b 59 }
dudmuck 0:2ff18de8d48b 60 hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
Wayne Roberts 23:801d4bd6dccc 61 pc_printf("using ch%u, %luhz\r\n", min_ch, hz);
Wayne Roberts 21:1ac5ffad2726 62 Radio::SetChannel(hz);
Wayne Roberts 22:dd3023aac3b1 63 usingChHz = hz;
dudmuck 12:9a8c13c4298b 64
dudmuck 12:9a8c13c4298b 65 starting_bg_rssi = acc[min_ch] / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 66 }
dudmuck 12:9a8c13c4298b 67
dudmuck 12:9a8c13c4298b 68 void measure_ambient()
dudmuck 12:9a8c13c4298b 69 {
dudmuck 12:9a8c13c4298b 70 int i, acc = 0;
dudmuck 12:9a8c13c4298b 71 float bg_rssi;
dudmuck 12:9a8c13c4298b 72 float diff;
dudmuck 12:9a8c13c4298b 73 static unsigned cnt = 0;
dudmuck 12:9a8c13c4298b 74
dudmuck 12:9a8c13c4298b 75 for (i = 0; i < N_SAMPLES; i++) {
Wayne Roberts 21:1ac5ffad2726 76 int rssi = Radio::GetRssiInst();
dudmuck 12:9a8c13c4298b 77 acc += rssi;
Wayne Roberts 23:801d4bd6dccc 78 ThisThread::sleep_for(10ms);
dudmuck 12:9a8c13c4298b 79 }
dudmuck 12:9a8c13c4298b 80 bg_rssi = acc / (float)N_SAMPLES;
dudmuck 12:9a8c13c4298b 81 diff = bg_rssi - starting_bg_rssi;
Wayne Roberts 23:801d4bd6dccc 82 //pc_printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
Wayne Roberts 23:801d4bd6dccc 83 pc_printf("bg_rssi:%ddBm vs %1ddBm, diff:%d, %d\r\n", (int)bg_rssi, (int)starting_bg_rssi, (int)diff, cnt);
dudmuck 12:9a8c13c4298b 84 if (diff > 10) {
dudmuck 12:9a8c13c4298b 85 if (++cnt > 3) {
dudmuck 12:9a8c13c4298b 86 /* find better channel */
dudmuck 12:9a8c13c4298b 87 channel_scan();
Wayne Roberts 21:1ac5ffad2726 88 Radio::Rx(0);
dudmuck 12:9a8c13c4298b 89 cnt = 0;
dudmuck 12:9a8c13c4298b 90 }
dudmuck 12:9a8c13c4298b 91 } else
dudmuck 12:9a8c13c4298b 92 cnt = 0;
dudmuck 0:2ff18de8d48b 93 }
dudmuck 0:2ff18de8d48b 94
dudmuck 0:2ff18de8d48b 95 void init_radio()
dudmuck 0:2ff18de8d48b 96 {
Wayne Roberts 21:1ac5ffad2726 97 Radio::Standby( );
dudmuck 0:2ff18de8d48b 98
Wayne Roberts 21:1ac5ffad2726 99 #ifdef SX126x_H
Wayne Roberts 21:1ac5ffad2726 100 if (Radio::chipType == CHIP_TYPE_SX1262)
Wayne Roberts 21:1ac5ffad2726 101 Radio::set_tx_dbm(22);
Wayne Roberts 21:1ac5ffad2726 102 else
Wayne Roberts 21:1ac5ffad2726 103 Radio::set_tx_dbm(17);
Wayne Roberts 21:1ac5ffad2726 104 #elif defined(SX127x_H)
Wayne Roberts 21:1ac5ffad2726 105 Radio::set_tx_dbm(17);
Wayne Roberts 21:1ac5ffad2726 106 #elif defined(SX128x_H)
Wayne Roberts 21:1ac5ffad2726 107 Radio::set_tx_dbm(5);
Wayne Roberts 21:1ac5ffad2726 108 #endif
Wayne Roberts 21:1ac5ffad2726 109
Wayne Roberts 21:1ac5ffad2726 110 Radio::LoRaModemConfig(BANDWIDTH_KHZ, LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE], 1);
Wayne Roberts 23:801d4bd6dccc 111 pc_printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
Wayne Roberts 21:1ac5ffad2726 112 Radio::SetPublicNetwork(true);
dudmuck 0:2ff18de8d48b 113
dudmuck 0:2ff18de8d48b 114 channel_scan();
dudmuck 0:2ff18de8d48b 115
Wayne Roberts 21:1ac5ffad2726 116 Radio::SetRxMaxPayloadLength(255);
dudmuck 0:2ff18de8d48b 117 }
dudmuck 0:2ff18de8d48b 118
Wayne Roberts 21:1ac5ffad2726 119 #if defined SX127x_H
dudmuck 0:2ff18de8d48b 120 void printLoraIrqs(bool clear)
dudmuck 0:2ff18de8d48b 121 {
Wayne Roberts 23:801d4bd6dccc 122 pc_printf("\r\nIrqFlags:");
Wayne Roberts 21:1ac5ffad2726 123 if (Radio::lora.RegIrqFlags.bits.CadDetected)
Wayne Roberts 23:801d4bd6dccc 124 pc_printf("CadDetected ");
Wayne Roberts 21:1ac5ffad2726 125 if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) {
Wayne Roberts 23:801d4bd6dccc 126 pc_printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
dudmuck 0:2ff18de8d48b 127 }
Wayne Roberts 21:1ac5ffad2726 128 if (Radio::lora.RegIrqFlags.bits.CadDone)
Wayne Roberts 23:801d4bd6dccc 129 pc_printf("CadDone ");
Wayne Roberts 21:1ac5ffad2726 130 if (Radio::lora.RegIrqFlags.bits.TxDone)
Wayne Roberts 23:801d4bd6dccc 131 pc_printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
Wayne Roberts 21:1ac5ffad2726 132 if (Radio::lora.RegIrqFlags.bits.ValidHeader)
Wayne Roberts 23:801d4bd6dccc 133 pc_printf("ValidHeader ");
Wayne Roberts 21:1ac5ffad2726 134 if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
Wayne Roberts 23:801d4bd6dccc 135 pc_printf("PayloadCrcError ");
Wayne Roberts 21:1ac5ffad2726 136 if (Radio::lora.RegIrqFlags.bits.RxDone)
Wayne Roberts 23:801d4bd6dccc 137 pc_printf("RxDone ");
Wayne Roberts 21:1ac5ffad2726 138 if (Radio::lora.RegIrqFlags.bits.RxTimeout)
Wayne Roberts 23:801d4bd6dccc 139 pc_printf("RxTimeout ");
dudmuck 0:2ff18de8d48b 140
Wayne Roberts 23:801d4bd6dccc 141 pc_printf("\r\n");
dudmuck 0:2ff18de8d48b 142
dudmuck 0:2ff18de8d48b 143 if (clear)
Wayne Roberts 21:1ac5ffad2726 144 Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet);
dudmuck 0:2ff18de8d48b 145 }
dudmuck 0:2ff18de8d48b 146
dudmuck 0:2ff18de8d48b 147 void printOpMode()
dudmuck 0:2ff18de8d48b 148 {
Wayne Roberts 21:1ac5ffad2726 149 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 21:1ac5ffad2726 150 switch (Radio::radio.RegOpMode.bits.Mode) {
Wayne Roberts 23:801d4bd6dccc 151 case RF_OPMODE_SLEEP: pc_printf("sleep"); break;
Wayne Roberts 23:801d4bd6dccc 152 case RF_OPMODE_STANDBY: pc_printf("stby"); break;
Wayne Roberts 23:801d4bd6dccc 153 case RF_OPMODE_SYNTHESIZER_TX: pc_printf("fstx"); break;
Wayne Roberts 23:801d4bd6dccc 154 case RF_OPMODE_TRANSMITTER: pc_printf("tx"); break;
Wayne Roberts 23:801d4bd6dccc 155 case RF_OPMODE_SYNTHESIZER_RX: pc_printf("fsrx"); break;
Wayne Roberts 23:801d4bd6dccc 156 case RF_OPMODE_RECEIVER: pc_printf("rx"); break;
dudmuck 0:2ff18de8d48b 157 case 6:
Wayne Roberts 21:1ac5ffad2726 158 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 23:801d4bd6dccc 159 pc_printf("rxs");
dudmuck 0:2ff18de8d48b 160 else
Wayne Roberts 23:801d4bd6dccc 161 pc_printf("-6-");
dudmuck 0:2ff18de8d48b 162 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 163 case 7:
Wayne Roberts 21:1ac5ffad2726 164 if (Radio::radio.RegOpMode.bits.LongRangeMode)
Wayne Roberts 23:801d4bd6dccc 165 pc_printf("cad");
dudmuck 0:2ff18de8d48b 166 else
Wayne Roberts 23:801d4bd6dccc 167 pc_printf("-7-");
dudmuck 0:2ff18de8d48b 168 break; // todo: different lora/fsk
dudmuck 0:2ff18de8d48b 169 }
dudmuck 0:2ff18de8d48b 170 }
Wayne Roberts 21:1ac5ffad2726 171 #endif /* SX127x_H */
dudmuck 0:2ff18de8d48b 172
dudmuck 16:67fa19bc6331 173 void decrypted_uplink(uint32_t dev_addr, uint8_t* buf, uint8_t buflen, uint8_t port)
dudmuck 9:a0ce66c18ec0 174 {
dudmuck 9:a0ce66c18ec0 175 if (port == SENSOR_PORT) {
dudmuck 17:763412df6872 176 uint8_t i = 0;
dudmuck 17:763412df6872 177 uint16_t lum = buf[i++] << 8;
dudmuck 17:763412df6872 178 lum += buf[i++];
dudmuck 19:c20591c95746 179 LoRaWan::filtered_printf(dev_addr, MAC, "SENSOR lum:%u", lum);
dudmuck 19:c20591c95746 180
dudmuck 17:763412df6872 181 while (i < buflen) {
dudmuck 18:806cf9b7a904 182 uint16_t seq, a_a, a_b, p;
dudmuck 18:806cf9b7a904 183 seq = buf[i++] << 8;
dudmuck 18:806cf9b7a904 184 seq += buf[i++];
dudmuck 17:763412df6872 185 a_a = buf[i++] << 8;
dudmuck 17:763412df6872 186 a_a += buf[i++];
dudmuck 17:763412df6872 187 a_b = buf[i++] << 8;
dudmuck 17:763412df6872 188 a_b += buf[i++];
dudmuck 17:763412df6872 189 p = buf[i++];
dudmuck 19:c20591c95746 190 if (!LoRaWan::flags.show_mac)
dudmuck 19:c20591c95746 191 LoRaWan::filtered_printf(dev_addr, APP, "%x", dev_addr);
dudmuck 19:c20591c95746 192
dudmuck 19:c20591c95746 193 LoRaWan::filtered_printf(dev_addr, APP, ", %u, %u, %u, %u, %u",
dudmuck 18:806cf9b7a904 194 seq,
dudmuck 17:763412df6872 195 a_a, /* analog */
dudmuck 17:763412df6872 196 a_b, /* analog */
dudmuck 17:763412df6872 197 (p & 2) >> 1, /* digital in */
dudmuck 17:763412df6872 198 p & 1 /* digital out */
dudmuck 17:763412df6872 199 );
dudmuck 19:c20591c95746 200
dudmuck 19:c20591c95746 201 if (!LoRaWan::flags.show_mac && i < buflen)
dudmuck 19:c20591c95746 202 LoRaWan::filtered_printf(dev_addr, APP, "\r\n");
dudmuck 17:763412df6872 203 }
dudmuck 9:a0ce66c18ec0 204 } else {
dudmuck 9:a0ce66c18ec0 205 int i;
dudmuck 19:c20591c95746 206 LoRaWan::filtered_printf(dev_addr, APP, "port%u: ", port);
dudmuck 9:a0ce66c18ec0 207 for (i = 0; i < buflen; i++)
dudmuck 19:c20591c95746 208 LoRaWan::filtered_printf(dev_addr, APP, "%02x ", buf[i]);
dudmuck 9:a0ce66c18ec0 209 }
dudmuck 9:a0ce66c18ec0 210 }
dudmuck 9:a0ce66c18ec0 211
Wayne Roberts 23:801d4bd6dccc 212 //EventQueue queue;
dudmuck 0:2ff18de8d48b 213
dudmuck 0:2ff18de8d48b 214 void send_downlink()
dudmuck 0:2ff18de8d48b 215 {
Wayne Roberts 22:dd3023aac3b1 216 if (!LoRaWan::flags.do_downlink) {
Wayne Roberts 23:801d4bd6dccc 217 pc_printf("\e[41mno downlink to send\e[0m\r\n");
Wayne Roberts 22:dd3023aac3b1 218 return;
Wayne Roberts 22:dd3023aac3b1 219 }
Wayne Roberts 22:dd3023aac3b1 220
Wayne Roberts 22:dd3023aac3b1 221 LoRaWan::flags.do_downlink = false;
Wayne Roberts 21:1ac5ffad2726 222
Wayne Roberts 22:dd3023aac3b1 223 if (LoRaWan::flags.beacon_guard) {
Wayne Roberts 23:801d4bd6dccc 224 pc_printf("\e[33mdownlink during beacon_guard\e[0m\r\n");
Wayne Roberts 22:dd3023aac3b1 225 return;
Wayne Roberts 22:dd3023aac3b1 226 }
Wayne Roberts 21:1ac5ffad2726 227
Wayne Roberts 22:dd3023aac3b1 228 Radio::Standby( );
Wayne Roberts 22:dd3023aac3b1 229
Wayne Roberts 22:dd3023aac3b1 230 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 22:dd3023aac3b1 231 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, false, true);
Wayne Roberts 22:dd3023aac3b1 232
Wayne Roberts 22:dd3023aac3b1 233 Radio::Send(LoRaWan::_tmp_payload_length, 0, 0, 0);
dudmuck 0:2ff18de8d48b 234 }
dudmuck 0:2ff18de8d48b 235
Wayne Roberts 21:1ac5ffad2726 236 uint16_t tim_get_current_slot()
Wayne Roberts 21:1ac5ffad2726 237 {
Wayne Roberts 23:801d4bd6dccc 238 int us_until = beaconAt.time_since_epoch().count() - HighResClock::now().time_since_epoch().count();
Wayne Roberts 21:1ac5ffad2726 239 return us_until / 30000;
Wayne Roberts 21:1ac5ffad2726 240 }
Wayne Roberts 21:1ac5ffad2726 241
Wayne Roberts 21:1ac5ffad2726 242 static void OnRadioRxDone(uint8_t size, float rssi, float snr)
Wayne Roberts 21:1ac5ffad2726 243 {
Wayne Roberts 21:1ac5ffad2726 244 LoRaWan::rx_slot = tim_get_current_slot();
Wayne Roberts 23:801d4bd6dccc 245 LoRaWan::rx_at = HighResClock::now();
Wayne Roberts 21:1ac5ffad2726 246
Wayne Roberts 21:1ac5ffad2726 247 LoRaWan::parse_receive(size, rssi, snr);
Wayne Roberts 21:1ac5ffad2726 248
Wayne Roberts 21:1ac5ffad2726 249 if (!LoRaWan::flags.do_downlink) {
Wayne Roberts 21:1ac5ffad2726 250 /* if not sending downlink, start receiver now */
Wayne Roberts 21:1ac5ffad2726 251 Radio::Rx(0);
Wayne Roberts 21:1ac5ffad2726 252 }
Wayne Roberts 21:1ac5ffad2726 253 }
Wayne Roberts 21:1ac5ffad2726 254
dudmuck 0:2ff18de8d48b 255 void
dudmuck 0:2ff18de8d48b 256 send_beacon()
dudmuck 0:2ff18de8d48b 257 {
dudmuck 18:806cf9b7a904 258 if (!LoRaWan::flags.beacon_loaded)
dudmuck 0:2ff18de8d48b 259 return;
dudmuck 0:2ff18de8d48b 260
Wayne Roberts 22:dd3023aac3b1 261 LoRaWan::flags.beacon_loaded = false;
Wayne Roberts 21:1ac5ffad2726 262 Radio::Send(LoRaWan::_tmp_payload_length, 0, 0, 0);
dudmuck 0:2ff18de8d48b 263 }
dudmuck 0:2ff18de8d48b 264
dudmuck 0:2ff18de8d48b 265 static uint16_t beacon_crc( uint8_t *buffer, uint16_t length )
dudmuck 0:2ff18de8d48b 266 {
dudmuck 0:2ff18de8d48b 267 // The CRC calculation follows CCITT
dudmuck 0:2ff18de8d48b 268 const uint16_t polynom = 0x1021;
dudmuck 0:2ff18de8d48b 269 // CRC initial value
dudmuck 0:2ff18de8d48b 270 uint16_t crc = 0x0000;
dudmuck 0:2ff18de8d48b 271
dudmuck 0:2ff18de8d48b 272 if( buffer == NULL )
dudmuck 0:2ff18de8d48b 273 {
dudmuck 0:2ff18de8d48b 274 return 0;
dudmuck 0:2ff18de8d48b 275 }
dudmuck 0:2ff18de8d48b 276
dudmuck 0:2ff18de8d48b 277 for( uint16_t i = 0; i < length; ++i )
dudmuck 0:2ff18de8d48b 278 {
dudmuck 0:2ff18de8d48b 279 crc ^= ( uint16_t ) buffer[i] << 8;
dudmuck 0:2ff18de8d48b 280 for( uint16_t j = 0; j < 8; ++j )
dudmuck 0:2ff18de8d48b 281 {
dudmuck 0:2ff18de8d48b 282 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 );
dudmuck 0:2ff18de8d48b 283 }
dudmuck 0:2ff18de8d48b 284 }
dudmuck 0:2ff18de8d48b 285
dudmuck 0:2ff18de8d48b 286 return crc;
dudmuck 0:2ff18de8d48b 287 }
dudmuck 0:2ff18de8d48b 288
dudmuck 0:2ff18de8d48b 289 void
dudmuck 3:7c01b8978638 290 _load_beacon()
dudmuck 0:2ff18de8d48b 291 {
Wayne Roberts 21:1ac5ffad2726 292 bool inv_iq = false;
dudmuck 0:2ff18de8d48b 293 uint16_t crc;
Wayne Roberts 21:1ac5ffad2726 294 Radio::Standby( );
dudmuck 0:2ff18de8d48b 295
Wayne Roberts 23:801d4bd6dccc 296 #if defined SX127x_H
Wayne Roberts 23:801d4bd6dccc 297 while(Radio::radio.dio0) {
Wayne Roberts 23:801d4bd6dccc 298 pc_printf("\e[41mmissed-interrupt\e[0m\r\n");
Wayne Roberts 23:801d4bd6dccc 299 Radio::service();
Wayne Roberts 23:801d4bd6dccc 300 }
Wayne Roberts 23:801d4bd6dccc 301 #elif defined(SX128x_H)
Wayne Roberts 23:801d4bd6dccc 302 #error todo handle missed interrupt sx1280
Wayne Roberts 23:801d4bd6dccc 303 #elif defined(SX126x_H)
Wayne Roberts 23:801d4bd6dccc 304 #error todo handle missed interrupt sx126x
Wayne Roberts 23:801d4bd6dccc 305 #endif /* SX127x_H */
Wayne Roberts 23:801d4bd6dccc 306
dudmuck 0:2ff18de8d48b 307 if (skip_beacon_cnt > 0) {
Wayne Roberts 21:1ac5ffad2726 308 inv_iq = true;
dudmuck 0:2ff18de8d48b 309 skip_beacon_cnt--;
dudmuck 0:2ff18de8d48b 310 }
Wayne Roberts 21:1ac5ffad2726 311 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 312 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, true, false, inv_iq);
dudmuck 0:2ff18de8d48b 313
Wayne Roberts 22:dd3023aac3b1 314 LoRaWan::_tmp_payload_length = BEACON_SIZE;
Wayne Roberts 22:dd3023aac3b1 315 Radio::SetFixedPayloadLength(LoRaWan::_tmp_payload_length);
Wayne Roberts 22:dd3023aac3b1 316
Wayne Roberts 21:1ac5ffad2726 317 Radio::radio.tx_buf[0] = beacon_payload[0];
Wayne Roberts 21:1ac5ffad2726 318 Radio::radio.tx_buf[1] = beacon_payload[1];
Wayne Roberts 21:1ac5ffad2726 319 Radio::radio.tx_buf[2] = beacon_payload[2];
Wayne Roberts 21:1ac5ffad2726 320 Radio::radio.tx_buf[3] = beacon_payload[3];
dudmuck 9:a0ce66c18ec0 321 beacon_payload[0] = CMD_NONE;
dudmuck 9:a0ce66c18ec0 322
Wayne Roberts 21:1ac5ffad2726 323 crc = beacon_crc(Radio::radio.tx_buf, 4);
Wayne Roberts 21:1ac5ffad2726 324 Radio::radio.tx_buf[4] = crc & 0xff;
Wayne Roberts 21:1ac5ffad2726 325 Radio::radio.tx_buf[5] = crc >> 8;
dudmuck 0:2ff18de8d48b 326
dudmuck 18:806cf9b7a904 327 LoRaWan::flags.beacon_loaded = true;
Wayne Roberts 23:801d4bd6dccc 328
Wayne Roberts 23:801d4bd6dccc 329 beacon_timeout.attach_absolute(send_beacon, beaconAt);
dudmuck 0:2ff18de8d48b 330 }
dudmuck 0:2ff18de8d48b 331
dudmuck 3:7c01b8978638 332 void load_beacon()
dudmuck 3:7c01b8978638 333 {
dudmuck 18:806cf9b7a904 334 LoRaWan::flags.beacon_guard = true;
Wayne Roberts 23:801d4bd6dccc 335 beacon_timeout.attach(_load_beacon, 200ms);
dudmuck 3:7c01b8978638 336 }
dudmuck 3:7c01b8978638 337
dudmuck 0:2ff18de8d48b 338 void get_time_till_beacon()
dudmuck 0:2ff18de8d48b 339 {
dudmuck 0:2ff18de8d48b 340 uint16_t slots = tim_get_current_slot();
Wayne Roberts 23:801d4bd6dccc 341 pc_printf("slots:%u\r\n", slots);
dudmuck 0:2ff18de8d48b 342 }
dudmuck 0:2ff18de8d48b 343
dudmuck 4:7e743e402681 344 void rx_isr()
dudmuck 0:2ff18de8d48b 345 {
dudmuck 0:2ff18de8d48b 346 static uint8_t pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 347 static uint8_t prev_len = 0;;
Wayne Roberts 23:801d4bd6dccc 348 char c;
Wayne Roberts 23:801d4bd6dccc 349 pc.read(&c, 1);
dudmuck 0:2ff18de8d48b 350
dudmuck 0:2ff18de8d48b 351 if (c == 8) {
dudmuck 0:2ff18de8d48b 352 if (pcbuf_idx > 0) {
Wayne Roberts 23:801d4bd6dccc 353 uint8_t buf[3] = {8, ' ', 8};
Wayne Roberts 23:801d4bd6dccc 354 pc.write(buf, 3);
dudmuck 0:2ff18de8d48b 355 pcbuf_idx--;
dudmuck 0:2ff18de8d48b 356 }
dudmuck 0:2ff18de8d48b 357 } else if (c == 3) { // ctrl-C
dudmuck 0:2ff18de8d48b 358 pcbuf_len = -1;
dudmuck 0:2ff18de8d48b 359 } else if (c == '\r') {
dudmuck 0:2ff18de8d48b 360 if (pcbuf_idx == 0) {
dudmuck 0:2ff18de8d48b 361 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 362 } else {
dudmuck 0:2ff18de8d48b 363 pcbuf[pcbuf_idx] = 0; // null terminate
dudmuck 0:2ff18de8d48b 364 prev_len = pcbuf_idx;
dudmuck 0:2ff18de8d48b 365 pcbuf_idx = 0;
dudmuck 0:2ff18de8d48b 366 pcbuf_len = prev_len;
dudmuck 0:2ff18de8d48b 367 }
dudmuck 0:2ff18de8d48b 368 } else if (pcbuf_idx < sizeof(pcbuf)) {
dudmuck 0:2ff18de8d48b 369 pcbuf[pcbuf_idx++] = c;
Wayne Roberts 23:801d4bd6dccc 370 pc.write(&c, 1);
dudmuck 0:2ff18de8d48b 371 }
dudmuck 0:2ff18de8d48b 372 }
dudmuck 0:2ff18de8d48b 373
dudmuck 0:2ff18de8d48b 374 void cmd_skip_beacon(uint8_t idx)
dudmuck 0:2ff18de8d48b 375 {
dudmuck 0:2ff18de8d48b 376 if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
dudmuck 0:2ff18de8d48b 377 sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 378 }
Wayne Roberts 23:801d4bd6dccc 379 pc_printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
dudmuck 0:2ff18de8d48b 380 }
dudmuck 0:2ff18de8d48b 381
dudmuck 0:2ff18de8d48b 382 void cmd_list_motes(uint8_t idx)
dudmuck 0:2ff18de8d48b 383 {
dudmuck 0:2ff18de8d48b 384 int i;
dudmuck 0:2ff18de8d48b 385 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 386 if (motes[i].dev_addr != DEVADDR_NONE) {
dudmuck 13:fa2095be01c4 387 LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
Wayne Roberts 23:801d4bd6dccc 388 pc_printf(" %" PRIx32 "\r\n", motes[i].dev_addr);
dudmuck 0:2ff18de8d48b 389 }
dudmuck 0:2ff18de8d48b 390 }
dudmuck 0:2ff18de8d48b 391 }
dudmuck 0:2ff18de8d48b 392
dudmuck 0:2ff18de8d48b 393 void
dudmuck 0:2ff18de8d48b 394 cmd_beacon_payload(uint8_t idx)
dudmuck 0:2ff18de8d48b 395 {
dudmuck 9:a0ce66c18ec0 396 uint32_t i;
dudmuck 9:a0ce66c18ec0 397 uint32_t* ptr;
dudmuck 13:fa2095be01c4 398 sscanf(pcbuf+idx, "%" PRIx32, &i);
Wayne Roberts 23:801d4bd6dccc 399 pc_printf("beacon_payload:%08" PRIx32 "\r\n", i);
dudmuck 9:a0ce66c18ec0 400 ptr = (uint32_t*)beacon_payload;
dudmuck 9:a0ce66c18ec0 401 *ptr = i;
dudmuck 8:307f7faeb594 402 }
dudmuck 8:307f7faeb594 403
dudmuck 0:2ff18de8d48b 404 void
dudmuck 0:2ff18de8d48b 405 cmd_send_downlink(uint8_t idx)
dudmuck 0:2ff18de8d48b 406 {
dudmuck 0:2ff18de8d48b 407 ota_mote_t* mote = NULL;
dudmuck 0:2ff18de8d48b 408 int i;
dudmuck 0:2ff18de8d48b 409 unsigned int dev_addr;
dudmuck 0:2ff18de8d48b 410 sscanf(pcbuf+idx, "%x", &dev_addr);
dudmuck 0:2ff18de8d48b 411 for (i = 0; i < N_MOTES; i++) {
dudmuck 0:2ff18de8d48b 412 if (motes[i].dev_addr == dev_addr) {
dudmuck 0:2ff18de8d48b 413 break;
dudmuck 0:2ff18de8d48b 414 }
dudmuck 0:2ff18de8d48b 415 }
dudmuck 0:2ff18de8d48b 416 if (i == N_MOTES) {
Wayne Roberts 23:801d4bd6dccc 417 pc_printf("mote %x not found\r\n", dev_addr);
dudmuck 0:2ff18de8d48b 418 return;
dudmuck 0:2ff18de8d48b 419 }
dudmuck 0:2ff18de8d48b 420 mote = &motes[i];
dudmuck 0:2ff18de8d48b 421
dudmuck 0:2ff18de8d48b 422 while (pcbuf[idx] != ' ') {
dudmuck 0:2ff18de8d48b 423 if (pcbuf[++idx] == 0) {
Wayne Roberts 23:801d4bd6dccc 424 pc_printf("hit end\r\n");
dudmuck 0:2ff18de8d48b 425 return;
dudmuck 0:2ff18de8d48b 426 }
dudmuck 0:2ff18de8d48b 427 }
dudmuck 0:2ff18de8d48b 428 idx++; // step past space
dudmuck 0:2ff18de8d48b 429
dudmuck 0:2ff18de8d48b 430 mote->user_downlink_length = 0;
dudmuck 0:2ff18de8d48b 431 while (pcbuf[idx] > ' ') {
dudmuck 0:2ff18de8d48b 432 int o;
dudmuck 0:2ff18de8d48b 433 sscanf(pcbuf+idx, "%02x", &o);
dudmuck 0:2ff18de8d48b 434 LoRaWan::user_downlink[mote->user_downlink_length++] = o;
dudmuck 0:2ff18de8d48b 435 idx += 2;
dudmuck 0:2ff18de8d48b 436 }
dudmuck 0:2ff18de8d48b 437
Wayne Roberts 23:801d4bd6dccc 438 pc_printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
dudmuck 0:2ff18de8d48b 439 }
dudmuck 0:2ff18de8d48b 440
Wayne Roberts 21:1ac5ffad2726 441 #if 0
dudmuck 9:a0ce66c18ec0 442 void cmd_rx_restart(uint8_t idx)
dudmuck 9:a0ce66c18ec0 443 {
dudmuck 9:a0ce66c18ec0 444 /*radio.set_opmode(RF_OPMODE_STANDBY);
Wayne Roberts 23:801d4bd6dccc 445 pc_printf("standby\r\n");*/
dudmuck 9:a0ce66c18ec0 446 radio.set_opmode(RF_OPMODE_SLEEP);
Wayne Roberts 23:801d4bd6dccc 447 pc_printf("sleep\r\n");
dudmuck 9:a0ce66c18ec0 448 wait(0.05);
dudmuck 9:a0ce66c18ec0 449 radio.set_opmode(RF_OPMODE_RECEIVER);
Wayne Roberts 23:801d4bd6dccc 450 pc_printf("receive\r\n");
dudmuck 9:a0ce66c18ec0 451 }
Wayne Roberts 21:1ac5ffad2726 452 #endif /* if 0 */
dudmuck 9:a0ce66c18ec0 453
dudmuck 9:a0ce66c18ec0 454 void cmd_beacon_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 455 {
dudmuck 9:a0ce66c18ec0 456 int gpo;
dudmuck 9:a0ce66c18ec0 457 sscanf(pcbuf+idx, "%d", &gpo);
dudmuck 9:a0ce66c18ec0 458 beacon_payload[0] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 459 beacon_payload[1] = gpo;
Wayne Roberts 23:801d4bd6dccc 460 pc_printf("beacon gpo: %d\r\n", gpo);
dudmuck 9:a0ce66c18ec0 461 }
dudmuck 9:a0ce66c18ec0 462
dudmuck 9:a0ce66c18ec0 463 void cmd_beacon_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 464 {
dudmuck 9:a0ce66c18ec0 465 int r, g ,b;
dudmuck 9:a0ce66c18ec0 466 sscanf(pcbuf+idx, "%d %d %d", &r, &g, &b);
dudmuck 9:a0ce66c18ec0 467 beacon_payload[0] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 468 beacon_payload[1] = r;
dudmuck 9:a0ce66c18ec0 469 beacon_payload[2] = g;
dudmuck 9:a0ce66c18ec0 470 beacon_payload[3] = b;
Wayne Roberts 23:801d4bd6dccc 471 pc_printf("beacon rgb: %d %d %d\r\n", r, g, b);
dudmuck 9:a0ce66c18ec0 472 }
dudmuck 9:a0ce66c18ec0 473
dudmuck 9:a0ce66c18ec0 474 void cmd_downlink_rgb(uint8_t idx)
dudmuck 9:a0ce66c18ec0 475 {
dudmuck 9:a0ce66c18ec0 476 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 477 int i, r, g ,b;
dudmuck 9:a0ce66c18ec0 478 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 479 sscanf(pcbuf+idx, "%x %d %d %d", &dev_addr, &r, &g, &b);
dudmuck 9:a0ce66c18ec0 480 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 481 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 482 break;
dudmuck 9:a0ce66c18ec0 483 }
dudmuck 9:a0ce66c18ec0 484 }
dudmuck 9:a0ce66c18ec0 485 if (i == N_MOTES) {
Wayne Roberts 23:801d4bd6dccc 486 pc_printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 487 return;
dudmuck 9:a0ce66c18ec0 488 }
dudmuck 9:a0ce66c18ec0 489 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 490
dudmuck 9:a0ce66c18ec0 491 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 492 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_LED_RGB;
dudmuck 9:a0ce66c18ec0 493 LoRaWan::user_downlink[mote->user_downlink_length++] = r;
dudmuck 9:a0ce66c18ec0 494 LoRaWan::user_downlink[mote->user_downlink_length++] = g;
dudmuck 9:a0ce66c18ec0 495 LoRaWan::user_downlink[mote->user_downlink_length++] = b;
dudmuck 9:a0ce66c18ec0 496
Wayne Roberts 23:801d4bd6dccc 497 pc_printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 498 }
dudmuck 9:a0ce66c18ec0 499
dudmuck 9:a0ce66c18ec0 500 void cmd_downlink_gpo(uint8_t idx)
dudmuck 9:a0ce66c18ec0 501 {
dudmuck 9:a0ce66c18ec0 502 ota_mote_t* mote = NULL;
dudmuck 9:a0ce66c18ec0 503 int i, gpo;
dudmuck 9:a0ce66c18ec0 504 unsigned int dev_addr;
dudmuck 9:a0ce66c18ec0 505 sscanf(pcbuf+idx, "%x %d", &dev_addr, &gpo);
dudmuck 9:a0ce66c18ec0 506 for (i = 0; i < N_MOTES; i++) {
dudmuck 9:a0ce66c18ec0 507 if (motes[i].dev_addr == dev_addr) {
dudmuck 9:a0ce66c18ec0 508 break;
dudmuck 9:a0ce66c18ec0 509 }
dudmuck 9:a0ce66c18ec0 510 }
dudmuck 9:a0ce66c18ec0 511 if (i == N_MOTES) {
Wayne Roberts 23:801d4bd6dccc 512 pc_printf("mote %x not found\r\n", dev_addr);
dudmuck 9:a0ce66c18ec0 513 return;
dudmuck 9:a0ce66c18ec0 514 }
dudmuck 9:a0ce66c18ec0 515 mote = &motes[i];
dudmuck 9:a0ce66c18ec0 516
dudmuck 9:a0ce66c18ec0 517 mote->user_downlink_length = 0;
dudmuck 9:a0ce66c18ec0 518 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
dudmuck 9:a0ce66c18ec0 519 LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
dudmuck 9:a0ce66c18ec0 520
Wayne Roberts 23:801d4bd6dccc 521 pc_printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);
dudmuck 9:a0ce66c18ec0 522 }
dudmuck 9:a0ce66c18ec0 523
dudmuck 0:2ff18de8d48b 524 void cmd_status(uint8_t idx)
dudmuck 0:2ff18de8d48b 525 {
Wayne Roberts 23:801d4bd6dccc 526 pc_printf(" %uHz do_downlink:%u, ", usingChHz, LoRaWan::flags.do_downlink);
Wayne Roberts 23:801d4bd6dccc 527 pc_printf("rssi:%f\r\n", Radio::GetRssiInst());
Wayne Roberts 23:801d4bd6dccc 528 pc_printf("\r\nskip_beacon_cnt:%u, curSlot:%u\r\n", skip_beacon_cnt, tim_get_current_slot());
Wayne Roberts 21:1ac5ffad2726 529 #ifdef SX128x_H
Wayne Roberts 21:1ac5ffad2726 530 status_t status;
Wayne Roberts 21:1ac5ffad2726 531 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 21:1ac5ffad2726 532 switch (status.bits.cmdStatus) {
Wayne Roberts 23:801d4bd6dccc 533 case 1: pc_printf("success"); break;
Wayne Roberts 23:801d4bd6dccc 534 case 2: pc_printf("dataAvail"); break;
Wayne Roberts 23:801d4bd6dccc 535 case 3: pc_printf("cmdTimeout"); break;
Wayne Roberts 23:801d4bd6dccc 536 case 4: pc_printf("cmdErr"); break;
Wayne Roberts 23:801d4bd6dccc 537 case 5: pc_printf("exeFail"); break;
Wayne Roberts 23:801d4bd6dccc 538 case 6: pc_printf("txdone"); break;
Wayne Roberts 23:801d4bd6dccc 539 default: pc_printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
Wayne Roberts 21:1ac5ffad2726 540 }
Wayne Roberts 23:801d4bd6dccc 541 pc_printf(" ");
Wayne Roberts 21:1ac5ffad2726 542 switch (status.bits.chipMode) {
Wayne Roberts 23:801d4bd6dccc 543 case 2: pc_printf("stdby_rc"); break;
Wayne Roberts 23:801d4bd6dccc 544 case 3: pc_printf("stdby_xosc"); break;
Wayne Roberts 23:801d4bd6dccc 545 case 4: pc_printf("fs"); break;
Wayne Roberts 23:801d4bd6dccc 546 case 5: pc_printf("\e[32mrx\e[0m"); break;
Wayne Roberts 23:801d4bd6dccc 547 case 6: pc_printf("\e[31mtx\e[0m"); break;
Wayne Roberts 23:801d4bd6dccc 548 default: pc_printf("chipMode:<%u>", status.bits.chipMode); break;
Wayne Roberts 21:1ac5ffad2726 549 }
Wayne Roberts 21:1ac5ffad2726 550 LoRaPktPar0_t LoRaPktPar0;
Wayne Roberts 21:1ac5ffad2726 551 LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
Wayne Roberts 23:801d4bd6dccc 552 pc_printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
Wayne Roberts 23:801d4bd6dccc 553 pc_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 21:1ac5ffad2726 554 #elif defined SX126x_H
Wayne Roberts 21:1ac5ffad2726 555 status_t status;
Wayne Roberts 21:1ac5ffad2726 556 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
Wayne Roberts 21:1ac5ffad2726 557 switch (status.bits.chipMode) {
Wayne Roberts 23:801d4bd6dccc 558 case 2: pc_printf("STBY_RC"); break;
Wayne Roberts 23:801d4bd6dccc 559 case 3: pc_printf("STBY_XOSC"); break;
Wayne Roberts 23:801d4bd6dccc 560 case 4: pc_printf("FS"); break;
Wayne Roberts 23:801d4bd6dccc 561 case 5: pc_printf("\e[32mRX\e[0m"); break;
Wayne Roberts 23:801d4bd6dccc 562 case 6: pc_printf("\e[31mTX\e[0m"); break;
Wayne Roberts 23:801d4bd6dccc 563 default: pc_printf("%u", status.bits.chipMode); break;
Wayne Roberts 21:1ac5ffad2726 564 }
Wayne Roberts 23:801d4bd6dccc 565 pc_printf(" ");
Wayne Roberts 21:1ac5ffad2726 566 switch (status.bits.cmdStatus) {
Wayne Roberts 23:801d4bd6dccc 567 case 1: pc_printf("rfu"); break;
Wayne Roberts 23:801d4bd6dccc 568 case 2: pc_printf("dataAvail"); break;
Wayne Roberts 23:801d4bd6dccc 569 case 3: pc_printf("timeout"); break;
Wayne Roberts 23:801d4bd6dccc 570 case 4: pc_printf("err"); break;
Wayne Roberts 23:801d4bd6dccc 571 case 5: pc_printf("fail"); break;
Wayne Roberts 23:801d4bd6dccc 572 case 6: pc_printf("txdone"); break;
Wayne Roberts 23:801d4bd6dccc 573 default: pc_printf("%u", status.bits.cmdStatus); break;
Wayne Roberts 21:1ac5ffad2726 574 }
Wayne Roberts 21:1ac5ffad2726 575 loraConfig0_t conf0;
Wayne Roberts 21:1ac5ffad2726 576 conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
Wayne Roberts 21:1ac5ffad2726 577 // bw7=125 bw8=250 b9=500
Wayne Roberts 23:801d4bd6dccc 578 pc_printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
Wayne Roberts 21:1ac5ffad2726 579 loraConfig1_t conf1;
Wayne Roberts 21:1ac5ffad2726 580 conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
Wayne Roberts 23:801d4bd6dccc 581 pc_printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
Wayne Roberts 23:801d4bd6dccc 582 pc_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
Wayne Roberts 21:1ac5ffad2726 583 #elif defined SX127x_H
Wayne Roberts 21:1ac5ffad2726 584 Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG);
Wayne Roberts 21:1ac5ffad2726 585 if (Radio::radio.RegPaConfig.bits.PaSelect)
Wayne Roberts 23:801d4bd6dccc 586 pc_printf("PA_BOOST ");
dudmuck 14:c6284654d1b0 587 else
Wayne Roberts 23:801d4bd6dccc 588 pc_printf("RFO ");
dudmuck 14:c6284654d1b0 589
Wayne Roberts 21:1ac5ffad2726 590 Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
Wayne Roberts 23:801d4bd6dccc 591 pc_printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
Wayne Roberts 23:801d4bd6dccc 592 pc_printf("dio0pin:%u ", Radio::radio.dio0.read());
dudmuck 0:2ff18de8d48b 593 printOpMode();
Wayne Roberts 21:1ac5ffad2726 594 if (!Radio::radio.RegOpMode.bits.LongRangeMode) {
Wayne Roberts 23:801d4bd6dccc 595 pc_printf("FSK\r\n");
dudmuck 0:2ff18de8d48b 596 return;
dudmuck 0:2ff18de8d48b 597 }
dudmuck 0:2ff18de8d48b 598
Wayne Roberts 21:1ac5ffad2726 599 Radio::lora.RegIrqFlags.octet = Radio::radio.read_reg(REG_LR_IRQFLAGS);
dudmuck 0:2ff18de8d48b 600 printLoraIrqs(false);
dudmuck 0:2ff18de8d48b 601
Wayne Roberts 21:1ac5ffad2726 602 Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33); // invert_i_q
Wayne Roberts 21:1ac5ffad2726 603 Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT);
Wayne Roberts 23:801d4bd6dccc 604 pc_printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
Wayne Roberts 21:1ac5ffad2726 605 Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1);
Wayne Roberts 23:801d4bd6dccc 606 pc_printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), Radio::radio.RegDioMapping1.bits.Dio0Mapping);
Wayne Roberts 23:801d4bd6dccc 607 pc_printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
Wayne Roberts 21:1ac5ffad2726 608 #endif
dudmuck 0:2ff18de8d48b 609 }
dudmuck 0:2ff18de8d48b 610
dudmuck 16:67fa19bc6331 611 void cmd_filter(uint8_t idx)
dudmuck 16:67fa19bc6331 612 {
dudmuck 16:67fa19bc6331 613 if (sscanf(pcbuf+idx, "%lx", &LoRaWan::dev_addr_filter) != 1) {
dudmuck 16:67fa19bc6331 614 LoRaWan::dev_addr_filter = 0;
Wayne Roberts 23:801d4bd6dccc 615 pc_printf("filter off\r\n");
dudmuck 16:67fa19bc6331 616 } else
Wayne Roberts 23:801d4bd6dccc 617 pc_printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
dudmuck 16:67fa19bc6331 618 }
dudmuck 16:67fa19bc6331 619
dudmuck 11:50d0558a4e37 620 void cmd_op(uint8_t idx)
dudmuck 11:50d0558a4e37 621 {
Wayne Roberts 21:1ac5ffad2726 622 int dbm;
Wayne Roberts 21:1ac5ffad2726 623 if (sscanf(pcbuf+idx, "%d", &dbm) == 1) {
Wayne Roberts 21:1ac5ffad2726 624 Radio::set_tx_dbm(dbm);
Wayne Roberts 23:801d4bd6dccc 625 pc_printf("OutputPower:%ddBm\r\n", dbm);
dudmuck 11:50d0558a4e37 626 }
dudmuck 11:50d0558a4e37 627 }
dudmuck 11:50d0558a4e37 628
dudmuck 14:c6284654d1b0 629 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 630 void cmd_pa_select(uint8_t idx)
dudmuck 14:c6284654d1b0 631 {
dudmuck 14:c6284654d1b0 632 radio.RegPaConfig.bits.PaSelect ^= 1;
dudmuck 14:c6284654d1b0 633 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
dudmuck 14:c6284654d1b0 634 if (radio.RegPaConfig.bits.PaSelect)
Wayne Roberts 23:801d4bd6dccc 635 pc_printf("PA_BOOST\r\n");
dudmuck 14:c6284654d1b0 636 else
Wayne Roberts 23:801d4bd6dccc 637 pc_printf("RFO\r\n");
dudmuck 14:c6284654d1b0 638 }
dudmuck 14:c6284654d1b0 639 #endif /* TYPE_ABZ */
dudmuck 14:c6284654d1b0 640
dudmuck 12:9a8c13c4298b 641 void cmd_set_time(uint8_t idx)
dudmuck 12:9a8c13c4298b 642 {
dudmuck 12:9a8c13c4298b 643 set_time(0);
Wayne Roberts 23:801d4bd6dccc 644 pc_printf("time:%" PRIu32 "\r\n", time(NULL));
dudmuck 12:9a8c13c4298b 645 }
dudmuck 12:9a8c13c4298b 646
dudmuck 13:fa2095be01c4 647
dudmuck 13:fa2095be01c4 648 void cmd_pwm(uint8_t idx)
dudmuck 12:9a8c13c4298b 649 {
dudmuck 13:fa2095be01c4 650 ota_mote_t* mote;
dudmuck 12:9a8c13c4298b 651 int i;
dudmuck 13:fa2095be01c4 652 unsigned dev_addr, p, d;
dudmuck 13:fa2095be01c4 653
dudmuck 13:fa2095be01c4 654 if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
Wayne Roberts 23:801d4bd6dccc 655 pc_printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 656 return;
dudmuck 13:fa2095be01c4 657 }
dudmuck 12:9a8c13c4298b 658 for (i = 0; i < N_MOTES; i++) {
dudmuck 12:9a8c13c4298b 659 if (motes[i].dev_addr == dev_addr) {
dudmuck 12:9a8c13c4298b 660 break;
dudmuck 12:9a8c13c4298b 661 }
dudmuck 12:9a8c13c4298b 662 }
dudmuck 12:9a8c13c4298b 663 if (i == N_MOTES) {
Wayne Roberts 23:801d4bd6dccc 664 pc_printf("mote %x not found\r\n", dev_addr);
dudmuck 12:9a8c13c4298b 665 return;
dudmuck 12:9a8c13c4298b 666 }
dudmuck 12:9a8c13c4298b 667
dudmuck 12:9a8c13c4298b 668 mote = &motes[i];
dudmuck 12:9a8c13c4298b 669
dudmuck 12:9a8c13c4298b 670 mote->user_downlink_length = 0;
dudmuck 13:fa2095be01c4 671 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_PWM;
dudmuck 13:fa2095be01c4 672 LoRaWan::user_downlink[mote->user_downlink_length++] = p;
dudmuck 13:fa2095be01c4 673 LoRaWan::user_downlink[mote->user_downlink_length++] = d;
dudmuck 12:9a8c13c4298b 674
Wayne Roberts 23:801d4bd6dccc 675 pc_printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
dudmuck 13:fa2095be01c4 676 }
dudmuck 13:fa2095be01c4 677
dudmuck 13:fa2095be01c4 678 void cmd_beacon_pwm(uint8_t idx)
dudmuck 13:fa2095be01c4 679 {
dudmuck 13:fa2095be01c4 680 unsigned p, d;
dudmuck 13:fa2095be01c4 681 if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
Wayne Roberts 23:801d4bd6dccc 682 pc_printf("parse fail\r\n");
dudmuck 13:fa2095be01c4 683 return;
dudmuck 13:fa2095be01c4 684 }
dudmuck 13:fa2095be01c4 685
dudmuck 13:fa2095be01c4 686 beacon_payload[0] = CMD_PWM;
dudmuck 13:fa2095be01c4 687 beacon_payload[1] = p;
dudmuck 13:fa2095be01c4 688 beacon_payload[2] = d;
dudmuck 13:fa2095be01c4 689
Wayne Roberts 23:801d4bd6dccc 690 pc_printf("period:%u duty:%u\r\n", p, d);
dudmuck 12:9a8c13c4298b 691 }
dudmuck 12:9a8c13c4298b 692
dudmuck 14:c6284654d1b0 693 void cmd_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 694 {
dudmuck 14:c6284654d1b0 695 ota_mote_t* mote;
dudmuck 14:c6284654d1b0 696 int i;
dudmuck 14:c6284654d1b0 697 unsigned dev_addr, txi;
dudmuck 14:c6284654d1b0 698
dudmuck 14:c6284654d1b0 699 if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
Wayne Roberts 23:801d4bd6dccc 700 pc_printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 701 return;
dudmuck 14:c6284654d1b0 702 }
dudmuck 14:c6284654d1b0 703 for (i = 0; i < N_MOTES; i++) {
dudmuck 14:c6284654d1b0 704 if (motes[i].dev_addr == dev_addr) {
dudmuck 14:c6284654d1b0 705 break;
dudmuck 14:c6284654d1b0 706 }
dudmuck 14:c6284654d1b0 707 }
dudmuck 14:c6284654d1b0 708 if (i == N_MOTES) {
Wayne Roberts 23:801d4bd6dccc 709 pc_printf("mote %x not found\r\n", dev_addr);
dudmuck 14:c6284654d1b0 710 return;
dudmuck 14:c6284654d1b0 711 }
dudmuck 14:c6284654d1b0 712
dudmuck 14:c6284654d1b0 713 mote = &motes[i];
dudmuck 14:c6284654d1b0 714
dudmuck 14:c6284654d1b0 715 mote->user_downlink_length = 0;
dudmuck 14:c6284654d1b0 716 LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 717 LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
dudmuck 14:c6284654d1b0 718
Wayne Roberts 23:801d4bd6dccc 719 pc_printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
dudmuck 14:c6284654d1b0 720 }
dudmuck 14:c6284654d1b0 721
dudmuck 19:c20591c95746 722 void cmd_hide_mac(uint8_t idx)
dudmuck 18:806cf9b7a904 723 {
dudmuck 19:c20591c95746 724 LoRaWan::flags.show_mac = 0;
Wayne Roberts 23:801d4bd6dccc 725 pc_printf("!show_mac\r\n");
dudmuck 18:806cf9b7a904 726 }
dudmuck 18:806cf9b7a904 727
dudmuck 19:c20591c95746 728 void cmd_hide_payload(uint8_t idx)
dudmuck 18:806cf9b7a904 729 {
dudmuck 19:c20591c95746 730 LoRaWan::flags.show_app = 0;
Wayne Roberts 23:801d4bd6dccc 731 pc_printf("!show_app\r\n");
dudmuck 18:806cf9b7a904 732 }
dudmuck 18:806cf9b7a904 733
dudmuck 19:c20591c95746 734 void cmd_show_all(uint8_t idx)
dudmuck 18:806cf9b7a904 735 {
dudmuck 19:c20591c95746 736 LoRaWan::flags.show_mac = 1;
dudmuck 19:c20591c95746 737 LoRaWan::flags.show_app = 1;
Wayne Roberts 23:801d4bd6dccc 738 pc_printf("show-all\r\n");
dudmuck 18:806cf9b7a904 739 }
dudmuck 18:806cf9b7a904 740
dudmuck 14:c6284654d1b0 741 void cmd_beacon_endnode_txp(uint8_t idx)
dudmuck 14:c6284654d1b0 742 {
dudmuck 14:c6284654d1b0 743 unsigned txi;
dudmuck 14:c6284654d1b0 744 if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
Wayne Roberts 23:801d4bd6dccc 745 pc_printf("parse fail\r\n");
dudmuck 14:c6284654d1b0 746 return;
dudmuck 14:c6284654d1b0 747 }
dudmuck 14:c6284654d1b0 748
dudmuck 14:c6284654d1b0 749 beacon_payload[0] = CMD_TX_POWER;
dudmuck 14:c6284654d1b0 750 beacon_payload[1] = txi;
dudmuck 14:c6284654d1b0 751
Wayne Roberts 23:801d4bd6dccc 752 pc_printf("txp index:%u\r\n", txi);
dudmuck 14:c6284654d1b0 753 }
dudmuck 14:c6284654d1b0 754
dudmuck 0:2ff18de8d48b 755 void cmd_help(uint8_t);
dudmuck 0:2ff18de8d48b 756
dudmuck 0:2ff18de8d48b 757 typedef struct {
dudmuck 0:2ff18de8d48b 758 const char* const cmd;
dudmuck 0:2ff18de8d48b 759 void (*handler)(uint8_t args_at);
dudmuck 0:2ff18de8d48b 760 const char* const arg_descr;
dudmuck 0:2ff18de8d48b 761 const char* const description;
dudmuck 0:2ff18de8d48b 762 } menu_item_t;
dudmuck 0:2ff18de8d48b 763
dudmuck 0:2ff18de8d48b 764 const menu_item_t menu_items[] =
dudmuck 0:2ff18de8d48b 765 { /* after first character, command names must be [A-Za-z] */
dudmuck 0:2ff18de8d48b 766 { "?", cmd_help, "","show available commands"},
dudmuck 0:2ff18de8d48b 767 { ".", cmd_status, "","read status"},
dudmuck 16:67fa19bc6331 768 { "f", cmd_filter, "%x","set dev_addr print filter"},
dudmuck 0:2ff18de8d48b 769 { "b", cmd_beacon_payload, "<%x>","set beacon payload"},
dudmuck 0:2ff18de8d48b 770 { "sb", cmd_skip_beacon, "<%d>","skip beacons"},
dudmuck 0:2ff18de8d48b 771 { "list", cmd_list_motes, "","list active motes"},
dudmuck 0:2ff18de8d48b 772 { "dl", cmd_send_downlink, "[%x %s]","send downlink <mote-hex-dev-addr> <hex-payload>"},
Wayne Roberts 21:1ac5ffad2726 773 //{ "rxr", cmd_rx_restart, "", "restart RX"},
dudmuck 9:a0ce66c18ec0 774 { "brgb", cmd_beacon_rgb, "%u %u %u", "load RGB command into next beacon" },
dudmuck 9:a0ce66c18ec0 775 { "rgb", cmd_downlink_rgb, "%x %u %u %u", "load RGB command to mote"},
dudmuck 9:a0ce66c18ec0 776 { "bgpo", cmd_beacon_gpo, "%d", "load output pin command into next beacon"},
dudmuck 9:a0ce66c18ec0 777 { "gpo", cmd_downlink_gpo, "%x %d", "load output pin command to mote"},
dudmuck 12:9a8c13c4298b 778 { "op", cmd_op, "<dBm>","(TX) get/set TX power"},
dudmuck 14:c6284654d1b0 779 #ifdef TYPE_ABZ
dudmuck 14:c6284654d1b0 780 { "pas", cmd_pa_select, "","(TX) toggle PaSelect"},
dudmuck 14:c6284654d1b0 781 #endif
dudmuck 13:fa2095be01c4 782 { "tz", cmd_set_time, "", "set seconds to zero"},
dudmuck 13:fa2095be01c4 783 { "p", cmd_pwm, "%x %u %u", "send pwm period, duty to dev_addr"},
dudmuck 13:fa2095be01c4 784 { "bp", cmd_beacon_pwm, "%u %u", "send pwm period, duty on beacon"},
dudmuck 14:c6284654d1b0 785 { "ntxp", cmd_endnode_txp, "%x %u", "send txpower index to dev_addr"},
dudmuck 14:c6284654d1b0 786 { "bntxp", cmd_beacon_endnode_txp, "%u", "send txpower index on beacon"},
dudmuck 19:c20591c95746 787 { "hm", cmd_hide_mac, "", "hide mac layer printing "},
dudmuck 19:c20591c95746 788 { "hp", cmd_hide_payload, "", "hide payload printing"},
dudmuck 19:c20591c95746 789 { "sa", cmd_show_all, "", "show both mac and app layers"},
dudmuck 0:2ff18de8d48b 790 { NULL, NULL, NULL, NULL }
dudmuck 0:2ff18de8d48b 791 };
dudmuck 0:2ff18de8d48b 792
dudmuck 0:2ff18de8d48b 793 void cmd_help(uint8_t args_at)
dudmuck 0:2ff18de8d48b 794 {
dudmuck 0:2ff18de8d48b 795 int i;
dudmuck 0:2ff18de8d48b 796
dudmuck 0:2ff18de8d48b 797 for (i = 0; menu_items[i].cmd != NULL ; i++) {
Wayne Roberts 23:801d4bd6dccc 798 pc_printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
dudmuck 0:2ff18de8d48b 799 }
dudmuck 0:2ff18de8d48b 800
dudmuck 0:2ff18de8d48b 801 }
dudmuck 0:2ff18de8d48b 802
dudmuck 0:2ff18de8d48b 803 void
dudmuck 0:2ff18de8d48b 804 console()
dudmuck 0:2ff18de8d48b 805 {
dudmuck 0:2ff18de8d48b 806 int i;
dudmuck 0:2ff18de8d48b 807 uint8_t user_cmd_len;
dudmuck 0:2ff18de8d48b 808
dudmuck 0:2ff18de8d48b 809 if (pcbuf_len < 0) { // ctrl-C
Wayne Roberts 23:801d4bd6dccc 810 //pc_printf("abort\r\n");
dudmuck 0:2ff18de8d48b 811 return;
dudmuck 0:2ff18de8d48b 812 }
dudmuck 0:2ff18de8d48b 813 if (pcbuf_len == 0)
dudmuck 0:2ff18de8d48b 814 return;
dudmuck 0:2ff18de8d48b 815
Wayne Roberts 23:801d4bd6dccc 816 pc_printf("\r\n");
dudmuck 0:2ff18de8d48b 817
dudmuck 0:2ff18de8d48b 818 /* get end of user-entered command */
dudmuck 0:2ff18de8d48b 819 user_cmd_len = 1; // first character can be any character
dudmuck 0:2ff18de8d48b 820 for (i = 1; i <= pcbuf_len; i++) {
dudmuck 0:2ff18de8d48b 821 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') {
dudmuck 0:2ff18de8d48b 822 user_cmd_len = i;
dudmuck 0:2ff18de8d48b 823 break;
dudmuck 0:2ff18de8d48b 824 }
dudmuck 0:2ff18de8d48b 825 }
dudmuck 0:2ff18de8d48b 826
dudmuck 0:2ff18de8d48b 827 for (i = 0; menu_items[i].cmd != NULL ; i++) {
dudmuck 0:2ff18de8d48b 828 int mi_len = strlen(menu_items[i].cmd);
dudmuck 0:2ff18de8d48b 829
dudmuck 0:2ff18de8d48b 830 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) {
dudmuck 0:2ff18de8d48b 831 while (pcbuf[mi_len] == ' ') // skip past spaces
dudmuck 0:2ff18de8d48b 832 mi_len++;
dudmuck 0:2ff18de8d48b 833 menu_items[i].handler(mi_len);
dudmuck 0:2ff18de8d48b 834 break;
dudmuck 0:2ff18de8d48b 835 }
dudmuck 0:2ff18de8d48b 836 }
dudmuck 0:2ff18de8d48b 837
dudmuck 0:2ff18de8d48b 838 pcbuf_len = 0;
Wayne Roberts 23:801d4bd6dccc 839 pc_printf("> ");
dudmuck 0:2ff18de8d48b 840 fflush(stdout);
dudmuck 0:2ff18de8d48b 841 }
dudmuck 0:2ff18de8d48b 842
Wayne Roberts 21:1ac5ffad2726 843 static void OnRadioTxDone()
Wayne Roberts 21:1ac5ffad2726 844 {
Wayne Roberts 22:dd3023aac3b1 845 if (LoRaWan::flags.beacon_test) {
Wayne Roberts 22:dd3023aac3b1 846 LoRaWan::flags.beacon_test = 0;
Wayne Roberts 22:dd3023aac3b1 847 return;
Wayne Roberts 22:dd3023aac3b1 848 }
Wayne Roberts 22:dd3023aac3b1 849
Wayne Roberts 21:1ac5ffad2726 850 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 851 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 21:1ac5ffad2726 852
Wayne Roberts 21:1ac5ffad2726 853 Radio::Rx(0);
Wayne Roberts 21:1ac5ffad2726 854
Wayne Roberts 21:1ac5ffad2726 855 if (LoRaWan::flags.beacon_guard) { // beacon done transmitting
Wayne Roberts 21:1ac5ffad2726 856 measure_ambient();
Wayne Roberts 21:1ac5ffad2726 857 LoRaWan::flags.beacon_guard = false;
Wayne Roberts 21:1ac5ffad2726 858
Wayne Roberts 23:801d4bd6dccc 859 beaconAt += BEACON_INTERVAL_s;
Wayne Roberts 23:801d4bd6dccc 860 beacon_timeout.attach_absolute(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 21:1ac5ffad2726 861 }
Wayne Roberts 21:1ac5ffad2726 862 }
Wayne Roberts 21:1ac5ffad2726 863
Wayne Roberts 21:1ac5ffad2726 864 void tim_init()
Wayne Roberts 21:1ac5ffad2726 865 {
Wayne Roberts 23:801d4bd6dccc 866 beaconAt = HighResClock::now() + BEACON_INTERVAL_s;
Wayne Roberts 23:801d4bd6dccc 867 beacon_timeout.attach_absolute(load_beacon, beaconAt - BEACON_PRELOAD_us);
Wayne Roberts 21:1ac5ffad2726 868 }
Wayne Roberts 21:1ac5ffad2726 869
Wayne Roberts 21:1ac5ffad2726 870
Wayne Roberts 21:1ac5ffad2726 871 const RadioEvents_t rev = {
Wayne Roberts 21:1ac5ffad2726 872 /* Dio0_top_half */ NULL,
Wayne Roberts 21:1ac5ffad2726 873 /* TxDone_topHalf */ NULL,
Wayne Roberts 21:1ac5ffad2726 874 /* TxDone_botHalf */ OnRadioTxDone,
Wayne Roberts 21:1ac5ffad2726 875 /* TxTimeout */ NULL,
Wayne Roberts 21:1ac5ffad2726 876 /* RxDone */ OnRadioRxDone,
Wayne Roberts 21:1ac5ffad2726 877 /* RxTimeout */ NULL,
Wayne Roberts 21:1ac5ffad2726 878 /* RxError */ NULL,
Wayne Roberts 21:1ac5ffad2726 879 /* FhssChangeChannel */NULL,
Wayne Roberts 21:1ac5ffad2726 880 /* CadDone */ NULL
Wayne Roberts 21:1ac5ffad2726 881 };
Wayne Roberts 21:1ac5ffad2726 882
dudmuck 0:2ff18de8d48b 883 int main()
dudmuck 0:2ff18de8d48b 884 {
dudmuck 0:2ff18de8d48b 885 Thread eventThread;
Wayne Roberts 21:1ac5ffad2726 886 pc.baud(115200);
Wayne Roberts 23:801d4bd6dccc 887 pc_printf("\r\nreset\r\n");
dudmuck 11:50d0558a4e37 888 set_time(0);
dudmuck 0:2ff18de8d48b 889
Wayne Roberts 21:1ac5ffad2726 890 Radio::Init(&rev);
dudmuck 0:2ff18de8d48b 891
dudmuck 0:2ff18de8d48b 892 init_radio();
dudmuck 0:2ff18de8d48b 893
Wayne Roberts 22:dd3023aac3b1 894 {
Wayne Roberts 23:801d4bd6dccc 895 long txStartAt;
Wayne Roberts 22:dd3023aac3b1 896 _load_beacon();
Wayne Roberts 22:dd3023aac3b1 897 send_beacon();
Wayne Roberts 23:801d4bd6dccc 898 txStartAt = HighResClock::now().time_since_epoch().count();
Wayne Roberts 22:dd3023aac3b1 899 LoRaWan::flags.beacon_test = 1;
Wayne Roberts 22:dd3023aac3b1 900 while (LoRaWan::flags.beacon_test)
Wayne Roberts 22:dd3023aac3b1 901 Radio::service();
Wayne Roberts 22:dd3023aac3b1 902
Wayne Roberts 23:801d4bd6dccc 903 LoRaWan::beaconDur = HighResClock::now().time_since_epoch().count() - txStartAt;
Wayne Roberts 23:801d4bd6dccc 904 pc_printf("beaconDur:%u, 0x%x\r\n", LoRaWan::beaconDur, LoRaWan::beaconDur);
Wayne Roberts 22:dd3023aac3b1 905 }
Wayne Roberts 22:dd3023aac3b1 906
Wayne Roberts 21:1ac5ffad2726 907 // preambleLen, fixLen, crcOn, invIQ
Wayne Roberts 21:1ac5ffad2726 908 Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
Wayne Roberts 21:1ac5ffad2726 909 Radio::Rx(0);
dudmuck 0:2ff18de8d48b 910
dudmuck 0:2ff18de8d48b 911 LoRaWan::init();
dudmuck 0:2ff18de8d48b 912
dudmuck 0:2ff18de8d48b 913 tim_init();
dudmuck 4:7e743e402681 914
dudmuck 4:7e743e402681 915 pc.attach(&rx_isr);
dudmuck 9:a0ce66c18ec0 916
dudmuck 19:c20591c95746 917 /* default to printing both mac layer and application layer */
dudmuck 19:c20591c95746 918 LoRaWan::flags.show_mac = 1;
dudmuck 19:c20591c95746 919 LoRaWan::flags.show_app = 1;
dudmuck 0:2ff18de8d48b 920
dudmuck 0:2ff18de8d48b 921 for (;;) {
dudmuck 0:2ff18de8d48b 922 console();
Wayne Roberts 21:1ac5ffad2726 923
Wayne Roberts 21:1ac5ffad2726 924 Radio::service();
dudmuck 0:2ff18de8d48b 925 } // ..for(;;)
dudmuck 0:2ff18de8d48b 926 }