star-mesh LoRa network
radio chip selection
Radio chip driver is not included, because options are available.
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 NAmote72 or Murata discovery, then you must import only sx127x driver.
In this network, devices repeat messages to/from devices out of range of central gateway device. Appropriate for use when slightly larger batteries cost less than extra LoRaWAN gateways. This network uses LoRa transceiver directly and is not LoRaWAN. This network is appropriate for use where extra latency added from store-and-forward is of minimal consequence.
network implementation
Network achieves low-power operation by device waking up at regular intervals to check if LoRa preamble exists. If so, packet is received, otherwise devices sleeps. In this type of operation, trade-off is made between transmitter sending long preamble, and receiver waking up to receive this preamble along with associate message at the end of preamble. This long preamble is only used for request packets: the reply packet will have normal 8-symbol preamble length. This is known as asynchronous low-power operation, permitting an arbitrary number of devices to operate.
Devices start operation on the network by sending a discovery request to any devices that can hear it. Any devices which hears this discovery request will then send a discovery reply at randomized time offset relative to the request. After a pre-established time limit, the discovering device will decide which device to attach to depending on signal quality and how many hops away from the central gateway the device resides.
After device has attached to network, downlinks and uplinks can be sent to/from device. To facilitate downlinks, the devices closer to central gateway will be sent a new-device-notification to inform all devices between the central gateway and the newly attached device, which devices the new device can be reached via.
All devices have two logical interfaces to the network: An upstream interface, and a downstream interface. However, the central gateway device only has a downstream interface, because the "upstream" is only a UART interface to the user handling the user payloads on central gateway.
All devices on network are programmed with same firmware, except for gateway. In main.h #define GATEWAY
is commented-out for devices on network, or is defined for central gateway device. Only one central gateway must exist on this network. The unique identifying address of device is derived from CPU unique ID registers, of which 4 byte ID number is used on this network. Using this CPU serial number permits the same binary file to be programmed into any number of devices.
network configuration
Network is configured in main.h
define in main.h | ||
spreading factor | SPREADING_FACTOR | |
bandwidth | BW_KHZ | |
operating radio frequency | CF_MHZ | |
gateway or device | GATEWAY | |
transmit power | TX_DBM |
MAC layer timing scales according to LoRa symbol period. When spreading factor and/or bandwidth is changed, all network timing is scaled accordingly by MAC layer.
The transceivers used with the project operate at one datarate. This datarate is fixed, and must be defined at compile time for all devices and gateway.
low power operation
This MAC layer uses mbed eventqueue for scheduling. To enable low power operation, events.use-lowpower-timer-ticker
is defined in mbed_app.json
. This requires bare-metal operation to have eventqueue use low power timer, permitting deep sleep. LoRa applications such as this do not require RTOS: bare-metal mode is preferred for typical LoRa use.
application layer
User payloads are handled in app_endDevice.cpp
.
Uplinks are send from application layer by calling uplink(uint8_t *buffer_ptr, uint8_t length)
Downlinks are handled in callback function app_downlink()
For gateway, app_gateway.cpp
handles user payloads.
For downlinks, an example is provided in cmd_downlink()
where destination and payload is entered on serial port.
All uplinks are handled in callback function gateway_uplink()
.
Header file app.h
contains definitions common to application layer on both network central control and end device.
Note
This page describes how to use the network, for more detailed description of implementation, see details page.
serial terminal user interface
The STDIO UART is used to send and receive user-payload on the gateway, but is also available on end-devices. This serial port is configured at 115200 : 8,N,1.
command | arguments | description |
---|---|---|
? | list commands | |
dl | destID byte0 byte1 etc | send downlink to device (from gateway) |
ls | list downstream devices attached | |
op | dBm | manually change transmit power |
For the list of downstream devices, on start each row is printed directly attached device. If devices are attached further downstream, they will be subsequently printed on the same row.
testing / evaluation
Use 3 devices for testing: one gateway and two devices.
Three devices required for checking message repeating (relaying) function.
The gateway device must be installed at some distance to prevent both devices from connecting directly to gateway.
Gateway needs to be located far enough away, so signal strength preference overrides hop count from gateway.
main.cpp@1:fcd4c56fc56c, 2019-12-03 (annotated)
- Committer:
- Wayne Roberts
- Date:
- Tue Dec 03 09:50:00 2019 -0800
- Revision:
- 1:fcd4c56fc56c
- Parent:
- 0:6015834e4279
remove radio driver
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Wayne Roberts |
0:6015834e4279 | 1 | #include "main.h" |
Wayne Roberts |
0:6015834e4279 | 2 | |
Wayne Roberts |
0:6015834e4279 | 3 | #ifdef TARGET_STM32L0 |
Wayne Roberts |
0:6015834e4279 | 4 | #include "stm32l0xx_ll_utils.h" |
Wayne Roberts |
0:6015834e4279 | 5 | #elif defined(TARGET_STM32L1) |
Wayne Roberts |
0:6015834e4279 | 6 | #include "stm32l1xx_ll_utils.h" |
Wayne Roberts |
0:6015834e4279 | 7 | #elif defined(TARGET_STM32L4) |
Wayne Roberts |
0:6015834e4279 | 8 | #include "stm32l4xx_ll_utils.h" |
Wayne Roberts |
0:6015834e4279 | 9 | #endif |
Wayne Roberts |
0:6015834e4279 | 10 | |
Wayne Roberts |
0:6015834e4279 | 11 | #ifdef TARGET_DISCO_L072CZ_LRWAN1 |
Wayne Roberts |
0:6015834e4279 | 12 | DigitalOut rxdbg(PB_8); |
Wayne Roberts |
0:6015834e4279 | 13 | #elif defined(TARGET_FF_ARDUINO) |
Wayne Roberts |
0:6015834e4279 | 14 | DigitalOut rxdbg(PC_3); |
Wayne Roberts |
0:6015834e4279 | 15 | #endif |
Wayne Roberts |
0:6015834e4279 | 16 | |
Wayne Roberts |
0:6015834e4279 | 17 | RawSerial pc(USBTX, USBRX); |
Wayne Roberts |
0:6015834e4279 | 18 | |
Wayne Roberts |
0:6015834e4279 | 19 | EventQueue queue(32 * EVENTS_EVENT_SIZE); |
Wayne Roberts |
0:6015834e4279 | 20 | |
Wayne Roberts |
0:6015834e4279 | 21 | char pcbuf[64]; /* local user terminal */ |
Wayne Roberts |
0:6015834e4279 | 22 | int pcbuf_len; |
Wayne Roberts |
0:6015834e4279 | 23 | |
Wayne Roberts |
0:6015834e4279 | 24 | unsigned discovery_ans_time_step_us; |
Wayne Roberts |
0:6015834e4279 | 25 | unsigned discovery_ans_time_total_us; |
Wayne Roberts |
0:6015834e4279 | 26 | |
Wayne Roberts |
0:6015834e4279 | 27 | uint32_t my_id; |
Wayne Roberts |
0:6015834e4279 | 28 | |
Wayne Roberts |
0:6015834e4279 | 29 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 30 | const uint8_t hops_from_gateway = 0; |
Wayne Roberts |
0:6015834e4279 | 31 | #else |
Wayne Roberts |
0:6015834e4279 | 32 | uint8_t hops_from_gateway; |
Wayne Roberts |
0:6015834e4279 | 33 | #endif |
Wayne Roberts |
0:6015834e4279 | 34 | |
Wayne Roberts |
0:6015834e4279 | 35 | volatile flags_t flags; |
Wayne Roberts |
0:6015834e4279 | 36 | |
Wayne Roberts |
0:6015834e4279 | 37 | static uint8_t attemptCnt; |
Wayne Roberts |
0:6015834e4279 | 38 | static int req_timeout_id; |
Wayne Roberts |
0:6015834e4279 | 39 | reqflags_t reqFlags; |
Wayne Roberts |
0:6015834e4279 | 40 | volatile unsigned channelVacantCount; |
Wayne Roberts |
0:6015834e4279 | 41 | |
Wayne Roberts |
0:6015834e4279 | 42 | uint8_t txBuf[255]; |
Wayne Roberts |
0:6015834e4279 | 43 | uint8_t txBuf_idx; |
Wayne Roberts |
0:6015834e4279 | 44 | uint32_t tx_dest_id; |
Wayne Roberts |
0:6015834e4279 | 45 | |
Wayne Roberts |
0:6015834e4279 | 46 | bool remove_directlyAttached_device(uint32_t id) |
Wayne Roberts |
0:6015834e4279 | 47 | { |
Wayne Roberts |
0:6015834e4279 | 48 | bool removed = false; |
Wayne Roberts |
0:6015834e4279 | 49 | lid_list_t* L; |
Wayne Roberts |
0:6015834e4279 | 50 | for (L = attachedDevices; L != NULL; L = L->next) { |
Wayne Roberts |
0:6015834e4279 | 51 | if (L->id == id) { |
Wayne Roberts |
0:6015834e4279 | 52 | /* remove/clear all child devices also */ |
Wayne Roberts |
0:6015834e4279 | 53 | cid_list_t* children; |
Wayne Roberts |
0:6015834e4279 | 54 | for (children = L->attachedList; children != NULL; children = children->next) |
Wayne Roberts |
0:6015834e4279 | 55 | children->id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 56 | |
Wayne Roberts |
0:6015834e4279 | 57 | removed = true; |
Wayne Roberts |
0:6015834e4279 | 58 | L->id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 59 | } |
Wayne Roberts |
0:6015834e4279 | 60 | } |
Wayne Roberts |
0:6015834e4279 | 61 | return removed; |
Wayne Roberts |
0:6015834e4279 | 62 | } |
Wayne Roberts |
0:6015834e4279 | 63 | |
Wayne Roberts |
0:6015834e4279 | 64 | void remove_childDevice(uint32_t id, uint32_t* attachedTo) |
Wayne Roberts |
0:6015834e4279 | 65 | { |
Wayne Roberts |
0:6015834e4279 | 66 | lid_list_t* L; |
Wayne Roberts |
0:6015834e4279 | 67 | *attachedTo = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 68 | for (L = attachedDevices; L != NULL; L = L->next) { |
Wayne Roberts |
0:6015834e4279 | 69 | cid_list_t* children; |
Wayne Roberts |
0:6015834e4279 | 70 | for (children = L->attachedList; children != NULL; children = children->next) { |
Wayne Roberts |
0:6015834e4279 | 71 | if (children->id == id) { |
Wayne Roberts |
0:6015834e4279 | 72 | *attachedTo = L->id; |
Wayne Roberts |
0:6015834e4279 | 73 | children->id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 74 | } |
Wayne Roberts |
0:6015834e4279 | 75 | } |
Wayne Roberts |
0:6015834e4279 | 76 | } |
Wayne Roberts |
0:6015834e4279 | 77 | } |
Wayne Roberts |
0:6015834e4279 | 78 | |
Wayne Roberts |
0:6015834e4279 | 79 | void setPreambleSize(bool wakesize, uint8_t by) |
Wayne Roberts |
0:6015834e4279 | 80 | { |
Wayne Roberts |
0:6015834e4279 | 81 | if (wakesize) { |
Wayne Roberts |
0:6015834e4279 | 82 | Radio::LoRaPacketConfig(N_PRE_SYMB, false, true, false); // preambleLen, fixLen, crcOn, invIQ |
Wayne Roberts |
0:6015834e4279 | 83 | if (flags.discoverAnswering) { |
Wayne Roberts |
0:6015834e4279 | 84 | Mdbg_printf("\e[41mLPDA%02x\e[0m ", by); |
Wayne Roberts |
0:6015834e4279 | 85 | } |
Wayne Roberts |
0:6015834e4279 | 86 | } else { |
Wayne Roberts |
0:6015834e4279 | 87 | Radio::LoRaPacketConfig(8, false, true, false); // preambleLen, fixLen, crcOn, invIQ |
Wayne Roberts |
0:6015834e4279 | 88 | } |
Wayne Roberts |
0:6015834e4279 | 89 | } |
Wayne Roberts |
0:6015834e4279 | 90 | |
Wayne Roberts |
0:6015834e4279 | 91 | static void rxSingle() |
Wayne Roberts |
0:6015834e4279 | 92 | { |
Wayne Roberts |
0:6015834e4279 | 93 | if (flags.CallTXRequest) { |
Wayne Roberts |
0:6015834e4279 | 94 | txBuf_send(true); |
Wayne Roberts |
0:6015834e4279 | 95 | flags.CallTXRequest = 0; |
Wayne Roberts |
0:6015834e4279 | 96 | } else if (reqFlags.octet == 0 || flags.deferred_send) { |
Wayne Roberts |
0:6015834e4279 | 97 | flags.vacantCheck = 1; |
Wayne Roberts |
0:6015834e4279 | 98 | /* rx single: auto-timeout */ |
Wayne Roberts |
0:6015834e4279 | 99 | Radio::Rx(999); |
Wayne Roberts |
0:6015834e4279 | 100 | } |
Wayne Roberts |
0:6015834e4279 | 101 | } |
Wayne Roberts |
0:6015834e4279 | 102 | |
Wayne Roberts |
0:6015834e4279 | 103 | void start_periodic_rxing(uint8_t by) // definition |
Wayne Roberts |
0:6015834e4279 | 104 | { |
Wayne Roberts |
0:6015834e4279 | 105 | setPreambleSize(true, by | 3); |
Wayne Roberts |
0:6015834e4279 | 106 | Radio::SetLoRaSymbolTimeout(8); |
Wayne Roberts |
0:6015834e4279 | 107 | queue.call_in(WAKEUP_INTERVAL_MS, rxSingle); |
Wayne Roberts |
0:6015834e4279 | 108 | } |
Wayne Roberts |
0:6015834e4279 | 109 | |
Wayne Roberts |
0:6015834e4279 | 110 | const char* const cmdStrs[] = { |
Wayne Roberts |
0:6015834e4279 | 111 | "unused", /* 0 CMD_UNUSED */ |
Wayne Roberts |
0:6015834e4279 | 112 | "Ans", /* 1 CMD_ANS, */ |
Wayne Roberts |
0:6015834e4279 | 113 | "discoverReq", /* 2 CMD_DISCOVERY_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 114 | "discoverAns", /* 3 CMD_DISCOVERY_ANS, */ |
Wayne Roberts |
0:6015834e4279 | 115 | "attachReq", /* 4 CMD_ATTACH_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 116 | "userPayReqUp", /* 5 CMD_USER_PAYLOAD_UP_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 117 | "userPayReqDn", /* 6 CMD_USER_PAYLOAD_DN_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 118 | "newDev", /* 7 CMD_NEW_DEVICE_ATTACHED_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 119 | "removeDev", /* 8 CMD_REMOVE_DEVICE_REQ, */ |
Wayne Roberts |
0:6015834e4279 | 120 | "downstreamNotResponding", /* 9 CMD_DOWNSTREAM_NOT_RESPONDING, */ |
Wayne Roberts |
0:6015834e4279 | 121 | }; |
Wayne Roberts |
0:6015834e4279 | 122 | |
Wayne Roberts |
0:6015834e4279 | 123 | |
Wayne Roberts |
0:6015834e4279 | 124 | uint8_t tx_len; |
Wayne Roberts |
0:6015834e4279 | 125 | |
Wayne Roberts |
0:6015834e4279 | 126 | static void _send_(void) |
Wayne Roberts |
0:6015834e4279 | 127 | { |
Wayne Roberts |
0:6015834e4279 | 128 | if (flags.sending_req) |
Wayne Roberts |
0:6015834e4279 | 129 | setPreambleSize(true, 2); // sending request |
Wayne Roberts |
0:6015834e4279 | 130 | |
Wayne Roberts |
0:6015834e4279 | 131 | Radio::Send(tx_len, 0, 0, 0); /* begin transmission */ |
Wayne Roberts |
0:6015834e4279 | 132 | if (flags.discoverAnswering) { |
Wayne Roberts |
0:6015834e4279 | 133 | Mdbg_printf("\e[36m%u->txing%u_to:%lx_%s\e[0m", txBuf_idx, tx_len, tx_dest_id, cmdStrs[Radio::radio.tx_buf[9]]); |
Wayne Roberts |
0:6015834e4279 | 134 | } else { |
Wayne Roberts |
0:6015834e4279 | 135 | Mdbg_printf("%u->\e[31mtxing\e[0m%u_to:%lx_\e[7m%s\e[0m", txBuf_idx, tx_len, tx_dest_id, cmdStrs[Radio::radio.tx_buf[9]]); |
Wayne Roberts |
0:6015834e4279 | 136 | } |
Wayne Roberts |
0:6015834e4279 | 137 | Mdbg_printf(":"); |
Wayne Roberts |
0:6015834e4279 | 138 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 139 | /*{ |
Wayne Roberts |
0:6015834e4279 | 140 | unsigned n; |
Wayne Roberts |
0:6015834e4279 | 141 | for (n = 0; n < tx_len; n++) |
Wayne Roberts |
0:6015834e4279 | 142 | pc.printf("%02x ", Radio::radio.tx_buf[n]); |
Wayne Roberts |
0:6015834e4279 | 143 | }*/ |
Wayne Roberts |
0:6015834e4279 | 144 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 145 | |
Wayne Roberts |
0:6015834e4279 | 146 | if (flags.sending_req) { |
Wayne Roberts |
0:6015834e4279 | 147 | attemptCnt++; |
Wayne Roberts |
0:6015834e4279 | 148 | flags.getAns = 1; |
Wayne Roberts |
0:6015834e4279 | 149 | } else |
Wayne Roberts |
0:6015834e4279 | 150 | flags.getAns = 0; |
Wayne Roberts |
0:6015834e4279 | 151 | |
Wayne Roberts |
0:6015834e4279 | 152 | channelVacantCount = 0; |
Wayne Roberts |
0:6015834e4279 | 153 | } // .._send_() |
Wayne Roberts |
0:6015834e4279 | 154 | |
Wayne Roberts |
0:6015834e4279 | 155 | void txBuf_send(bool sendingReq) |
Wayne Roberts |
0:6015834e4279 | 156 | { |
Wayne Roberts |
0:6015834e4279 | 157 | uint16_t crc; |
Wayne Roberts |
0:6015834e4279 | 158 | |
Wayne Roberts |
0:6015834e4279 | 159 | if (txBuf_idx == 0) { |
Wayne Roberts |
0:6015834e4279 | 160 | return; |
Wayne Roberts |
0:6015834e4279 | 161 | } |
Wayne Roberts |
0:6015834e4279 | 162 | |
Wayne Roberts |
0:6015834e4279 | 163 | Radio::Standby(); |
Wayne Roberts |
0:6015834e4279 | 164 | |
Wayne Roberts |
0:6015834e4279 | 165 | if (sendingReq) { |
Wayne Roberts |
0:6015834e4279 | 166 | if (attemptCnt > RETRY_LIMIT) { |
Wayne Roberts |
0:6015834e4279 | 167 | /* give up trying */ |
Wayne Roberts |
0:6015834e4279 | 168 | txBuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 169 | attemptCnt = 0; |
Wayne Roberts |
0:6015834e4279 | 170 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 171 | reqFlags.octet = 0; // TODO dropping request |
Wayne Roberts |
0:6015834e4279 | 172 | start_periodic_rxing(0x80); // retry give-up |
Wayne Roberts |
0:6015834e4279 | 173 | return; |
Wayne Roberts |
0:6015834e4279 | 174 | #else |
Wayne Roberts |
0:6015834e4279 | 175 | if (tx_dest_id == attUp.id) { |
Wayne Roberts |
0:6015834e4279 | 176 | /* find new upstream device */ |
Wayne Roberts |
0:6015834e4279 | 177 | queue.call_in(1000, upstream_init); |
Wayne Roberts |
0:6015834e4279 | 178 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) |
Wayne Roberts |
0:6015834e4279 | 179 | app_uplink_complete(); // TODO report failure to application layer |
Wayne Roberts |
0:6015834e4279 | 180 | return; |
Wayne Roberts |
0:6015834e4279 | 181 | } else { |
Wayne Roberts |
0:6015834e4279 | 182 | txBuf[txBuf_idx++] = CMD_DOWNSTREAM_NOT_RESPONDING; |
Wayne Roberts |
0:6015834e4279 | 183 | putu32ToBuf(&txBuf[txBuf_idx], my_id); // ID of reporting device |
Wayne Roberts |
0:6015834e4279 | 184 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 185 | putu32ToBuf(&txBuf[txBuf_idx], tx_dest_id); // ID of failed downstream device |
Wayne Roberts |
0:6015834e4279 | 186 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 187 | tx_dest_id = attUp.id; |
Wayne Roberts |
0:6015834e4279 | 188 | reqFlags.bits.currentOp = CMD_DOWNSTREAM_NOT_RESPONDING; |
Wayne Roberts |
0:6015834e4279 | 189 | } |
Wayne Roberts |
0:6015834e4279 | 190 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 191 | } |
Wayne Roberts |
0:6015834e4279 | 192 | } // ..if (sendingReq) |
Wayne Roberts |
0:6015834e4279 | 193 | |
Wayne Roberts |
0:6015834e4279 | 194 | Radio::radio.tx_buf[0] = hops_from_gateway; |
Wayne Roberts |
0:6015834e4279 | 195 | putu32ToBuf(&Radio::radio.tx_buf[1], my_id); |
Wayne Roberts |
0:6015834e4279 | 196 | putu32ToBuf(&Radio::radio.tx_buf[5], tx_dest_id); |
Wayne Roberts |
0:6015834e4279 | 197 | |
Wayne Roberts |
0:6015834e4279 | 198 | tx_len = txBuf_idx; |
Wayne Roberts |
0:6015834e4279 | 199 | memcpy(&Radio::radio.tx_buf[9], txBuf, tx_len); |
Wayne Roberts |
0:6015834e4279 | 200 | tx_len += 9; |
Wayne Roberts |
0:6015834e4279 | 201 | crc = crc16(Radio::radio.tx_buf, tx_len); |
Wayne Roberts |
0:6015834e4279 | 202 | putu16ToBuf(&Radio::radio.tx_buf[tx_len], crc); |
Wayne Roberts |
0:6015834e4279 | 203 | tx_len += 2; |
Wayne Roberts |
0:6015834e4279 | 204 | |
Wayne Roberts |
0:6015834e4279 | 205 | flags.sending_req = sendingReq; |
Wayne Roberts |
0:6015834e4279 | 206 | if (sendingReq) { |
Wayne Roberts |
0:6015834e4279 | 207 | if (channelVacantCount > CHANNEL_VACANT_REQUIRED_COUNT) |
Wayne Roberts |
0:6015834e4279 | 208 | _send_(); |
Wayne Roberts |
0:6015834e4279 | 209 | else { |
Wayne Roberts |
0:6015834e4279 | 210 | flags.deferred_send = 1; |
Wayne Roberts |
0:6015834e4279 | 211 | start_periodic_rxing(0x70); // deferred send |
Wayne Roberts |
0:6015834e4279 | 212 | } |
Wayne Roberts |
0:6015834e4279 | 213 | } else |
Wayne Roberts |
0:6015834e4279 | 214 | _send_(); |
Wayne Roberts |
0:6015834e4279 | 215 | |
Wayne Roberts |
0:6015834e4279 | 216 | } // ..txBuf_send() |
Wayne Roberts |
0:6015834e4279 | 217 | |
Wayne Roberts |
0:6015834e4279 | 218 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 219 | bool rx_log_disable; |
Wayne Roberts |
0:6015834e4279 | 220 | char rx_log[768]; |
Wayne Roberts |
0:6015834e4279 | 221 | volatile unsigned rx_log_buf_idx; |
Wayne Roberts |
0:6015834e4279 | 222 | int _rx_log_printf(const char *format, ...) |
Wayne Roberts |
0:6015834e4279 | 223 | { |
Wayne Roberts |
0:6015834e4279 | 224 | va_list aptr; |
Wayne Roberts |
0:6015834e4279 | 225 | int ret = -1; |
Wayne Roberts |
0:6015834e4279 | 226 | |
Wayne Roberts |
0:6015834e4279 | 227 | va_start(aptr, format); |
Wayne Roberts |
0:6015834e4279 | 228 | if (!rx_log_disable) { |
Wayne Roberts |
0:6015834e4279 | 229 | ret = vsprintf(rx_log + rx_log_buf_idx , format, aptr); |
Wayne Roberts |
0:6015834e4279 | 230 | rx_log_buf_idx += ret; |
Wayne Roberts |
0:6015834e4279 | 231 | if (rx_log_buf_idx >= sizeof(rx_log)-1) { |
Wayne Roberts |
0:6015834e4279 | 232 | pc.printf("\e[31mrx_log_overrun\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 233 | rx_log_disable = true; |
Wayne Roberts |
0:6015834e4279 | 234 | } |
Wayne Roberts |
0:6015834e4279 | 235 | } |
Wayne Roberts |
0:6015834e4279 | 236 | va_end(aptr); |
Wayne Roberts |
0:6015834e4279 | 237 | |
Wayne Roberts |
0:6015834e4279 | 238 | |
Wayne Roberts |
0:6015834e4279 | 239 | return ret; |
Wayne Roberts |
0:6015834e4279 | 240 | } |
Wayne Roberts |
0:6015834e4279 | 241 | |
Wayne Roberts |
0:6015834e4279 | 242 | void rx_log_print() |
Wayne Roberts |
0:6015834e4279 | 243 | { |
Wayne Roberts |
0:6015834e4279 | 244 | rx_log[rx_log_buf_idx+1] = 0; |
Wayne Roberts |
0:6015834e4279 | 245 | pc.printf(rx_log); |
Wayne Roberts |
0:6015834e4279 | 246 | rx_log_buf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 247 | } |
Wayne Roberts |
0:6015834e4279 | 248 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 249 | |
Wayne Roberts |
0:6015834e4279 | 250 | static void txAns(unsigned sending_id) |
Wayne Roberts |
0:6015834e4279 | 251 | { |
Wayne Roberts |
0:6015834e4279 | 252 | unsigned elapsedAlready; |
Wayne Roberts |
0:6015834e4279 | 253 | int pad_us; |
Wayne Roberts |
0:6015834e4279 | 254 | txBuf_idx = 0; // previously sent request no longer needed |
Wayne Roberts |
0:6015834e4279 | 255 | txBuf[txBuf_idx++] = CMD_ANS; |
Wayne Roberts |
0:6015834e4279 | 256 | txBuf[txBuf_idx++] = reqFlags.bits.txAns; |
Wayne Roberts |
0:6015834e4279 | 257 | setPreambleSize(false, 6); // sending answer |
Wayne Roberts |
0:6015834e4279 | 258 | tx_dest_id = sending_id; |
Wayne Roberts |
0:6015834e4279 | 259 | elapsedAlready = Radio::lpt.read_us() - Radio::irqAt; |
Wayne Roberts |
0:6015834e4279 | 260 | pad_us = (ANS_PAD_MS * 1000) - elapsedAlready; |
Wayne Roberts |
0:6015834e4279 | 261 | if (pad_us > 100) { |
Wayne Roberts |
0:6015834e4279 | 262 | wait_us(pad_us); // short wait time more accurate in busy-loop |
Wayne Roberts |
0:6015834e4279 | 263 | } |
Wayne Roberts |
0:6015834e4279 | 264 | txBuf_send(false); |
Wayne Roberts |
0:6015834e4279 | 265 | if (pad_us <= 0) { |
Wayne Roberts |
0:6015834e4279 | 266 | pc.printf("\e[41mLATE:%d ", pad_us); |
Wayne Roberts |
0:6015834e4279 | 267 | pc.printf("\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 268 | } |
Wayne Roberts |
0:6015834e4279 | 269 | |
Wayne Roberts |
0:6015834e4279 | 270 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 271 | // printing of rx_log was deferred until this answer sent |
Wayne Roberts |
0:6015834e4279 | 272 | rx_log_print(); |
Wayne Roberts |
0:6015834e4279 | 273 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 274 | } |
Wayne Roberts |
0:6015834e4279 | 275 | |
Wayne Roberts |
0:6015834e4279 | 276 | uint16_t getu16FromBuf(const uint8_t* in) |
Wayne Roberts |
0:6015834e4279 | 277 | { |
Wayne Roberts |
0:6015834e4279 | 278 | uint16_t ret; |
Wayne Roberts |
0:6015834e4279 | 279 | |
Wayne Roberts |
0:6015834e4279 | 280 | ret = in[1]; |
Wayne Roberts |
0:6015834e4279 | 281 | ret <<= 8; |
Wayne Roberts |
0:6015834e4279 | 282 | ret |= in[0]; |
Wayne Roberts |
0:6015834e4279 | 283 | |
Wayne Roberts |
0:6015834e4279 | 284 | return ret; |
Wayne Roberts |
0:6015834e4279 | 285 | } |
Wayne Roberts |
0:6015834e4279 | 286 | |
Wayne Roberts |
0:6015834e4279 | 287 | void putu16ToBuf(uint8_t* out, uint16_t v) |
Wayne Roberts |
0:6015834e4279 | 288 | { |
Wayne Roberts |
0:6015834e4279 | 289 | *out++ = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 290 | v >>= 8; |
Wayne Roberts |
0:6015834e4279 | 291 | *out = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 292 | } |
Wayne Roberts |
0:6015834e4279 | 293 | |
Wayne Roberts |
0:6015834e4279 | 294 | void putu32ToBuf(uint8_t* out, uint32_t v) |
Wayne Roberts |
0:6015834e4279 | 295 | { |
Wayne Roberts |
0:6015834e4279 | 296 | /* most significant last */ |
Wayne Roberts |
0:6015834e4279 | 297 | /* least significant first */ |
Wayne Roberts |
0:6015834e4279 | 298 | *out++ = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 299 | v >>= 8; |
Wayne Roberts |
0:6015834e4279 | 300 | *out++ = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 301 | v >>= 8; |
Wayne Roberts |
0:6015834e4279 | 302 | *out++ = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 303 | v >>= 8; |
Wayne Roberts |
0:6015834e4279 | 304 | *out = v & 0xff; |
Wayne Roberts |
0:6015834e4279 | 305 | } |
Wayne Roberts |
0:6015834e4279 | 306 | |
Wayne Roberts |
0:6015834e4279 | 307 | uint32_t getu32FromBuf(const uint8_t* in) |
Wayne Roberts |
0:6015834e4279 | 308 | { |
Wayne Roberts |
0:6015834e4279 | 309 | uint32_t ret; |
Wayne Roberts |
0:6015834e4279 | 310 | |
Wayne Roberts |
0:6015834e4279 | 311 | ret = in[3]; |
Wayne Roberts |
0:6015834e4279 | 312 | ret <<= 8; |
Wayne Roberts |
0:6015834e4279 | 313 | ret |= in[2]; |
Wayne Roberts |
0:6015834e4279 | 314 | ret <<= 8; |
Wayne Roberts |
0:6015834e4279 | 315 | ret |= in[1]; |
Wayne Roberts |
0:6015834e4279 | 316 | ret <<= 8; |
Wayne Roberts |
0:6015834e4279 | 317 | ret |= in[0]; |
Wayne Roberts |
0:6015834e4279 | 318 | |
Wayne Roberts |
0:6015834e4279 | 319 | return ret; |
Wayne Roberts |
0:6015834e4279 | 320 | } |
Wayne Roberts |
0:6015834e4279 | 321 | |
Wayne Roberts |
0:6015834e4279 | 322 | |
Wayne Roberts |
0:6015834e4279 | 323 | |
Wayne Roberts |
0:6015834e4279 | 324 | struct _fwd_ fwd; |
Wayne Roberts |
0:6015834e4279 | 325 | struct _nr_ notResponding; |
Wayne Roberts |
0:6015834e4279 | 326 | |
Wayne Roberts |
0:6015834e4279 | 327 | void txDoneCB() |
Wayne Roberts |
0:6015834e4279 | 328 | { |
Wayne Roberts |
0:6015834e4279 | 329 | if (flags.getAns) { |
Wayne Roberts |
0:6015834e4279 | 330 | unsigned toms; |
Wayne Roberts |
0:6015834e4279 | 331 | setPreambleSize(false, 5); // getting answer |
Wayne Roberts |
0:6015834e4279 | 332 | Radio::Rx(0); |
Wayne Roberts |
0:6015834e4279 | 333 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 334 | if (reqFlags.bits.currentOp == CMD_DISCOVERY_REQ) { |
Wayne Roberts |
0:6015834e4279 | 335 | /* discovering: listen for answers from any upstream devices */ |
Wayne Roberts |
0:6015834e4279 | 336 | toms = discovery_ans_time_total_us / 1000; |
Wayne Roberts |
0:6015834e4279 | 337 | queue.call_in(toms, discovery_rx_end); |
Wayne Roberts |
0:6015834e4279 | 338 | } else |
Wayne Roberts |
0:6015834e4279 | 339 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 340 | { |
Wayne Roberts |
0:6015834e4279 | 341 | unsigned target_us; |
Wayne Roberts |
0:6015834e4279 | 342 | target_us = Radio::lora_toa_us(ANS_SIZE_BYTE) * 4; // four packet length's worth |
Wayne Roberts |
0:6015834e4279 | 343 | toms = (ANS_PAD_MS + ANS_PAD_MS) + (target_us / 1000); // microseconds to milliseconds |
Wayne Roberts |
0:6015834e4279 | 344 | req_timeout_id = queue.call_in(toms, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 345 | } |
Wayne Roberts |
0:6015834e4279 | 346 | } else if (reqFlags.bits.txAns != NOT_ANSWERING) { // txDone callback answer-tx-complete |
Wayne Roberts |
0:6015834e4279 | 347 | /* we just sent answer: restore to idle condition waiting for wakeup packet */ |
Wayne Roberts |
0:6015834e4279 | 348 | reqFlags.bits.txAns = NOT_ANSWERING; |
Wayne Roberts |
0:6015834e4279 | 349 | txBuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 350 | |
Wayne Roberts |
0:6015834e4279 | 351 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 352 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ || reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { |
Wayne Roberts |
0:6015834e4279 | 353 | int n; |
Wayne Roberts |
0:6015834e4279 | 354 | if (fwd.len >= 0) { |
Wayne Roberts |
0:6015834e4279 | 355 | tx_dest_id = fwd.tx_dest_id; |
Wayne Roberts |
0:6015834e4279 | 356 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { |
Wayne Roberts |
0:6015834e4279 | 357 | /* forward upstream */ |
Wayne Roberts |
0:6015834e4279 | 358 | txBuf[txBuf_idx++] = CMD_USER_PAYLOAD_UP_REQ; |
Wayne Roberts |
0:6015834e4279 | 359 | putu32ToBuf(&txBuf[txBuf_idx], fwd.B_id); // originating_src_id |
Wayne Roberts |
0:6015834e4279 | 360 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 361 | } else if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { |
Wayne Roberts |
0:6015834e4279 | 362 | /* forward downstream */ |
Wayne Roberts |
0:6015834e4279 | 363 | txBuf[txBuf_idx++] = CMD_USER_PAYLOAD_DN_REQ; |
Wayne Roberts |
0:6015834e4279 | 364 | putu32ToBuf(&txBuf[txBuf_idx], fwd.A_id); // final_dest_id |
Wayne Roberts |
0:6015834e4279 | 365 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 366 | } |
Wayne Roberts |
0:6015834e4279 | 367 | txBuf[txBuf_idx++] = fwd.len; |
Wayne Roberts |
0:6015834e4279 | 368 | for (n = 0; n < fwd.len; n++) |
Wayne Roberts |
0:6015834e4279 | 369 | txBuf[txBuf_idx++] = fwd.buf[n]; |
Wayne Roberts |
0:6015834e4279 | 370 | |
Wayne Roberts |
0:6015834e4279 | 371 | queue.call_in(500, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 372 | fwd.len = -1; |
Wayne Roberts |
0:6015834e4279 | 373 | } // ..if (fwd.len >= 0) |
Wayne Roberts |
0:6015834e4279 | 374 | else { |
Wayne Roberts |
0:6015834e4279 | 375 | /* uplink/downlink not forwarding */ |
Wayne Roberts |
0:6015834e4279 | 376 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) |
Wayne Roberts |
0:6015834e4279 | 377 | app_uplink_complete(); |
Wayne Roberts |
0:6015834e4279 | 378 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 379 | } |
Wayne Roberts |
0:6015834e4279 | 380 | } |
Wayne Roberts |
0:6015834e4279 | 381 | |
Wayne Roberts |
0:6015834e4279 | 382 | if (attUp.id == ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 383 | /* disconnected from upstream, rediscover */ |
Wayne Roberts |
0:6015834e4279 | 384 | queue.call_in(1000, upstream_init); |
Wayne Roberts |
0:6015834e4279 | 385 | } else if (id_newDeviceNotification != ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 386 | upstream_new_device_notify(); |
Wayne Roberts |
0:6015834e4279 | 387 | } else if (reqFlags.bits.currentOp == CMD_DOWNSTREAM_NOT_RESPONDING) { |
Wayne Roberts |
0:6015834e4279 | 388 | tx_dest_id = attUp.id; |
Wayne Roberts |
0:6015834e4279 | 389 | txBuf[txBuf_idx++] = CMD_DOWNSTREAM_NOT_RESPONDING; |
Wayne Roberts |
0:6015834e4279 | 390 | putu32ToBuf(&txBuf[txBuf_idx], notResponding.reporting_id); |
Wayne Roberts |
0:6015834e4279 | 391 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 392 | putu32ToBuf(&txBuf[txBuf_idx], notResponding.device_not_respoding_id); |
Wayne Roberts |
0:6015834e4279 | 393 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 394 | queue.call_in(500, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 395 | } else |
Wayne Roberts |
0:6015834e4279 | 396 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 397 | if (downRemove.destID != ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 398 | request_remove_device(); |
Wayne Roberts |
0:6015834e4279 | 399 | } |
Wayne Roberts |
0:6015834e4279 | 400 | start_periodic_rxing(0x60); // reqFlags.bits.txAns != NOT_ANSWERING |
Wayne Roberts |
0:6015834e4279 | 401 | } else if (reqFlags.bits.currentOp == CMD_DISCOVERY_ANS) { |
Wayne Roberts |
0:6015834e4279 | 402 | if (flags.firstDiscoverAns) { |
Wayne Roberts |
0:6015834e4279 | 403 | unsigned rnd = Radio::Random() % N_HALF_DISCOVERY_ANS; |
Wayne Roberts |
0:6015834e4279 | 404 | queue.call_in((discovery_ans_time_step_us * rnd) / 1000, txBuf_send, false); |
Wayne Roberts |
0:6015834e4279 | 405 | flags.firstDiscoverAns = 0; |
Wayne Roberts |
0:6015834e4279 | 406 | } else { |
Wayne Roberts |
0:6015834e4279 | 407 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 408 | txBuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 409 | //start_periodic_rxing(0x50); // 2nd discoverAns |
Wayne Roberts |
0:6015834e4279 | 410 | } |
Wayne Roberts |
0:6015834e4279 | 411 | } else { |
Wayne Roberts |
0:6015834e4279 | 412 | /* ? wtf did we just transmit ? */ |
Wayne Roberts |
0:6015834e4279 | 413 | pc.printf("\e[31mnoTxAns_or_STATE_GET_ANS\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 414 | } |
Wayne Roberts |
0:6015834e4279 | 415 | } // ..txDoneCB() |
Wayne Roberts |
0:6015834e4279 | 416 | |
Wayne Roberts |
0:6015834e4279 | 417 | |
Wayne Roberts |
0:6015834e4279 | 418 | uint16_t crc16( uint8_t *buffer, uint16_t length ) |
Wayne Roberts |
0:6015834e4279 | 419 | { |
Wayne Roberts |
0:6015834e4279 | 420 | uint16_t i; |
Wayne Roberts |
0:6015834e4279 | 421 | // The CRC calculation follows CCITT |
Wayne Roberts |
0:6015834e4279 | 422 | const uint16_t polynom = 0x1021; |
Wayne Roberts |
0:6015834e4279 | 423 | // CRC initial value |
Wayne Roberts |
0:6015834e4279 | 424 | uint16_t crc = 0x0000; |
Wayne Roberts |
0:6015834e4279 | 425 | |
Wayne Roberts |
0:6015834e4279 | 426 | if( buffer == NULL ) |
Wayne Roberts |
0:6015834e4279 | 427 | { |
Wayne Roberts |
0:6015834e4279 | 428 | return 0; |
Wayne Roberts |
0:6015834e4279 | 429 | } |
Wayne Roberts |
0:6015834e4279 | 430 | |
Wayne Roberts |
0:6015834e4279 | 431 | for( i = 0; i < length; ++i ) |
Wayne Roberts |
0:6015834e4279 | 432 | { |
Wayne Roberts |
0:6015834e4279 | 433 | uint16_t j; |
Wayne Roberts |
0:6015834e4279 | 434 | crc ^= ( uint16_t ) buffer[i] << 8; |
Wayne Roberts |
0:6015834e4279 | 435 | for( j = 0; j < 8; ++j ) |
Wayne Roberts |
0:6015834e4279 | 436 | { |
Wayne Roberts |
0:6015834e4279 | 437 | crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 ); |
Wayne Roberts |
0:6015834e4279 | 438 | } |
Wayne Roberts |
0:6015834e4279 | 439 | } |
Wayne Roberts |
0:6015834e4279 | 440 | |
Wayne Roberts |
0:6015834e4279 | 441 | return crc; |
Wayne Roberts |
0:6015834e4279 | 442 | } |
Wayne Roberts |
0:6015834e4279 | 443 | |
Wayne Roberts |
0:6015834e4279 | 444 | |
Wayne Roberts |
0:6015834e4279 | 445 | void rxDoneCB(uint8_t size, float rssi, float snr) |
Wayne Roberts |
0:6015834e4279 | 446 | { |
Wayne Roberts |
0:6015834e4279 | 447 | uint8_t rx_buf_idx; |
Wayne Roberts |
0:6015834e4279 | 448 | uint16_t calc, rxCrc; |
Wayne Roberts |
0:6015834e4279 | 449 | uint8_t rx_hfg = Radio::radio.rx_buf[0]; |
Wayne Roberts |
0:6015834e4279 | 450 | uint32_t sending_id = getu32FromBuf(&Radio::radio.rx_buf[1]); |
Wayne Roberts |
0:6015834e4279 | 451 | uint32_t dest_id = getu32FromBuf(&Radio::radio.rx_buf[5]); |
Wayne Roberts |
0:6015834e4279 | 452 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 453 | upInfo_t up_info; |
Wayne Roberts |
0:6015834e4279 | 454 | up_info.originating_src_id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 455 | #endif /* GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 456 | |
Wayne Roberts |
0:6015834e4279 | 457 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 458 | bool print_log_here = true; |
Wayne Roberts |
0:6015834e4279 | 459 | rx_log_buf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 460 | rx_log[0] = 0; |
Wayne Roberts |
0:6015834e4279 | 461 | rx_log_disable = false; |
Wayne Roberts |
0:6015834e4279 | 462 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 463 | |
Wayne Roberts |
0:6015834e4279 | 464 | if (flags.vacantCheck) { |
Wayne Roberts |
0:6015834e4279 | 465 | channelVacantCount = 0; |
Wayne Roberts |
0:6015834e4279 | 466 | flags.vacantCheck = 0; |
Wayne Roberts |
0:6015834e4279 | 467 | } |
Wayne Roberts |
0:6015834e4279 | 468 | |
Wayne Roberts |
0:6015834e4279 | 469 | Rx_log_printf("\e[32mrxDone %ubytes %.1fdBm %.1fdB\e[0m ", size, rssi, snr); |
Wayne Roberts |
0:6015834e4279 | 470 | Rx_log_printf("from:%lx_to_%lx ", sending_id, dest_id); |
Wayne Roberts |
0:6015834e4279 | 471 | |
Wayne Roberts |
0:6015834e4279 | 472 | if (dest_id != my_id && dest_id != ANY_ID) { |
Wayne Roberts |
0:6015834e4279 | 473 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 474 | /* check if upstream device were attached to is re-attaching */ |
Wayne Roberts |
0:6015834e4279 | 475 | upstream_attached_check(sending_id); |
Wayne Roberts |
0:6015834e4279 | 476 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 477 | if (!flags.discoverAnswering) |
Wayne Roberts |
0:6015834e4279 | 478 | start_periodic_rxing(0x40); // rxDone notForMe |
Wayne Roberts |
0:6015834e4279 | 479 | goto done; |
Wayne Roberts |
0:6015834e4279 | 480 | } |
Wayne Roberts |
0:6015834e4279 | 481 | |
Wayne Roberts |
0:6015834e4279 | 482 | calc = crc16(Radio::radio.rx_buf, size-2); |
Wayne Roberts |
0:6015834e4279 | 483 | rxCrc = getu16FromBuf(&Radio::radio.rx_buf[size-2]); |
Wayne Roberts |
0:6015834e4279 | 484 | if (calc != rxCrc) { |
Wayne Roberts |
0:6015834e4279 | 485 | Rx_log_printf("%04x != %04x\r\n", calc, rxCrc); |
Wayne Roberts |
0:6015834e4279 | 486 | if (!flags.discoverAnswering) |
Wayne Roberts |
0:6015834e4279 | 487 | start_periodic_rxing(0x30); // rxDone crcfail |
Wayne Roberts |
0:6015834e4279 | 488 | goto done; |
Wayne Roberts |
0:6015834e4279 | 489 | } |
Wayne Roberts |
0:6015834e4279 | 490 | |
Wayne Roberts |
0:6015834e4279 | 491 | size -= 2; // take off trailing crc |
Wayne Roberts |
0:6015834e4279 | 492 | for (rx_buf_idx = 9; rx_buf_idx < size; ) { |
Wayne Roberts |
0:6015834e4279 | 493 | cmd_e cmd = (cmd_e)Radio::radio.rx_buf[rx_buf_idx++]; |
Wayne Roberts |
0:6015834e4279 | 494 | |
Wayne Roberts |
0:6015834e4279 | 495 | Rx_log_printf(" curOp:%u_", reqFlags.bits.currentOp); |
Wayne Roberts |
0:6015834e4279 | 496 | Rx_log_printf(" \e[7mRxCmd:%s\e[0m", cmdStrs[cmd]); |
Wayne Roberts |
0:6015834e4279 | 497 | Rx_log_printf(" "); |
Wayne Roberts |
0:6015834e4279 | 498 | |
Wayne Roberts |
0:6015834e4279 | 499 | switch (cmd) { |
Wayne Roberts |
0:6015834e4279 | 500 | ans_e ans; |
Wayne Roberts |
0:6015834e4279 | 501 | case CMD_ANS: |
Wayne Roberts |
0:6015834e4279 | 502 | ans = (ans_e)Radio::radio.rx_buf[rx_buf_idx++]; |
Wayne Roberts |
0:6015834e4279 | 503 | /* request as been answered successfully */ |
Wayne Roberts |
0:6015834e4279 | 504 | Rx_log_printf("\e[35mrxAns\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 505 | if (flags.getAns) { |
Wayne Roberts |
0:6015834e4279 | 506 | if (ans == ANSWER_OK) { |
Wayne Roberts |
0:6015834e4279 | 507 | txBuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 508 | queue.cancel(req_timeout_id); |
Wayne Roberts |
0:6015834e4279 | 509 | attemptCnt = 0; |
Wayne Roberts |
0:6015834e4279 | 510 | downstream_ans_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); |
Wayne Roberts |
0:6015834e4279 | 511 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 512 | upstream_ans_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); |
Wayne Roberts |
0:6015834e4279 | 513 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 514 | |
Wayne Roberts |
0:6015834e4279 | 515 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { |
Wayne Roberts |
0:6015834e4279 | 516 | fwd.len = -1; |
Wayne Roberts |
0:6015834e4279 | 517 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 518 | } |
Wayne Roberts |
0:6015834e4279 | 519 | |
Wayne Roberts |
0:6015834e4279 | 520 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { |
Wayne Roberts |
0:6015834e4279 | 521 | fwd.len = -1; |
Wayne Roberts |
0:6015834e4279 | 522 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 523 | } |
Wayne Roberts |
0:6015834e4279 | 524 | } |
Wayne Roberts |
0:6015834e4279 | 525 | } |
Wayne Roberts |
0:6015834e4279 | 526 | |
Wayne Roberts |
0:6015834e4279 | 527 | break; |
Wayne Roberts |
0:6015834e4279 | 528 | case CMD_UNUSED: |
Wayne Roberts |
0:6015834e4279 | 529 | break; |
Wayne Roberts |
0:6015834e4279 | 530 | case CMD_DISCOVERY_REQ: |
Wayne Roberts |
0:6015834e4279 | 531 | case CMD_ATTACH_REQ: |
Wayne Roberts |
0:6015834e4279 | 532 | case CMD_NEW_DEVICE_ATTACHED_REQ: |
Wayne Roberts |
0:6015834e4279 | 533 | case CMD_USER_PAYLOAD_UP_REQ: |
Wayne Roberts |
0:6015834e4279 | 534 | case CMD_DOWNSTREAM_NOT_RESPONDING: |
Wayne Roberts |
0:6015834e4279 | 535 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 536 | downstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd, &up_info); |
Wayne Roberts |
0:6015834e4279 | 537 | #else |
Wayne Roberts |
0:6015834e4279 | 538 | downstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); |
Wayne Roberts |
0:6015834e4279 | 539 | #endif |
Wayne Roberts |
0:6015834e4279 | 540 | break; |
Wayne Roberts |
0:6015834e4279 | 541 | case CMD_REMOVE_DEVICE_REQ: |
Wayne Roberts |
0:6015834e4279 | 542 | case CMD_DISCOVERY_ANS: |
Wayne Roberts |
0:6015834e4279 | 543 | case CMD_USER_PAYLOAD_DN_REQ: |
Wayne Roberts |
0:6015834e4279 | 544 | upstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); |
Wayne Roberts |
0:6015834e4279 | 545 | break; |
Wayne Roberts |
0:6015834e4279 | 546 | } // ..switch (cmd) |
Wayne Roberts |
0:6015834e4279 | 547 | |
Wayne Roberts |
0:6015834e4279 | 548 | } // ..for (rx_buf_idx = 9; rx_buf_idx < size; ) |
Wayne Roberts |
0:6015834e4279 | 549 | |
Wayne Roberts |
0:6015834e4279 | 550 | if (reqFlags.bits.currentOp != CMD_DISCOVERY_ANS && reqFlags.bits.currentOp != CMD_DISCOVERY_REQ) { |
Wayne Roberts |
0:6015834e4279 | 551 | if (reqFlags.bits.txAns != NOT_ANSWERING) { |
Wayne Roberts |
0:6015834e4279 | 552 | queue.call(txAns, sending_id); // must return from this function prior to transmitting |
Wayne Roberts |
0:6015834e4279 | 553 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 554 | print_log_here = false; |
Wayne Roberts |
0:6015834e4279 | 555 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 556 | } else { |
Wayne Roberts |
0:6015834e4279 | 557 | Radio::Sleep(); |
Wayne Roberts |
0:6015834e4279 | 558 | start_periodic_rxing(0x20); // rxDone |
Wayne Roberts |
0:6015834e4279 | 559 | } |
Wayne Roberts |
0:6015834e4279 | 560 | } |
Wayne Roberts |
0:6015834e4279 | 561 | |
Wayne Roberts |
0:6015834e4279 | 562 | done: |
Wayne Roberts |
0:6015834e4279 | 563 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 564 | if (rx_hfg == 0) { |
Wayne Roberts |
0:6015834e4279 | 565 | Rx_log_printf("\e[31mrx_hfg:%u\e[0m ", rx_hfg); /* another gateway */ |
Wayne Roberts |
0:6015834e4279 | 566 | } else { |
Wayne Roberts |
0:6015834e4279 | 567 | Rx_log_printf("rx_hfg:%u ", rx_hfg); |
Wayne Roberts |
0:6015834e4279 | 568 | } |
Wayne Roberts |
0:6015834e4279 | 569 | #else |
Wayne Roberts |
0:6015834e4279 | 570 | Rx_log_printf("rx_hfg:%u ", rx_hfg); |
Wayne Roberts |
0:6015834e4279 | 571 | /* compare against attached upstream */ |
Wayne Roberts |
0:6015834e4279 | 572 | if (hops_from_gateway != HFG_UNATTACHED) |
Wayne Roberts |
0:6015834e4279 | 573 | upstream_signal_check(rssi, snr, rx_hfg, sending_id); |
Wayne Roberts |
0:6015834e4279 | 574 | #endif |
Wayne Roberts |
0:6015834e4279 | 575 | |
Wayne Roberts |
0:6015834e4279 | 576 | #ifdef MESH_DEBUG |
Wayne Roberts |
0:6015834e4279 | 577 | if (print_log_here) |
Wayne Roberts |
0:6015834e4279 | 578 | queue.call_in(10, rx_log_print); |
Wayne Roberts |
0:6015834e4279 | 579 | // else txAns must be completed first, will be called from txAns |
Wayne Roberts |
0:6015834e4279 | 580 | #endif /* MESH_DEBUG */ |
Wayne Roberts |
0:6015834e4279 | 581 | |
Wayne Roberts |
0:6015834e4279 | 582 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 583 | if (up_info.originating_src_id != ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 584 | /* txAns takes priority over application layer */ |
Wayne Roberts |
0:6015834e4279 | 585 | queue.call(gateway_uplink, up_info.len, up_info.originating_src_id, &Radio::radio.rx_buf[up_info.rxBufIdx]); |
Wayne Roberts |
0:6015834e4279 | 586 | } |
Wayne Roberts |
0:6015834e4279 | 587 | #endif /* GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 588 | } // ..rxDoneCB() |
Wayne Roberts |
0:6015834e4279 | 589 | |
Wayne Roberts |
0:6015834e4279 | 590 | void txTimeoutCB() |
Wayne Roberts |
0:6015834e4279 | 591 | { |
Wayne Roberts |
0:6015834e4279 | 592 | pc.printf("\e[41mTxTimeout\e[0m\r\n"); |
Wayne Roberts |
0:6015834e4279 | 593 | } |
Wayne Roberts |
0:6015834e4279 | 594 | |
Wayne Roberts |
0:6015834e4279 | 595 | void rxTimeoutCB() |
Wayne Roberts |
0:6015834e4279 | 596 | { |
Wayne Roberts |
0:6015834e4279 | 597 | Radio::Sleep(); |
Wayne Roberts |
0:6015834e4279 | 598 | queue.call_in(WAKEUP_INTERVAL_MS, rxSingle); |
Wayne Roberts |
0:6015834e4279 | 599 | |
Wayne Roberts |
0:6015834e4279 | 600 | if (flags.vacantCheck) { |
Wayne Roberts |
0:6015834e4279 | 601 | channelVacantCount++; |
Wayne Roberts |
0:6015834e4279 | 602 | if (flags.deferred_send) { |
Wayne Roberts |
0:6015834e4279 | 603 | uint8_t vc_thresh = CHANNEL_VACANT_REQUIRED_COUNT; |
Wayne Roberts |
0:6015834e4279 | 604 | if (attemptCnt > 1) { |
Wayne Roberts |
0:6015834e4279 | 605 | /* retry backoff */ |
Wayne Roberts |
0:6015834e4279 | 606 | vc_thresh += Radio::Random() % CHANNEL_VACANT_REQUIRED_COUNT; |
Wayne Roberts |
0:6015834e4279 | 607 | } |
Wayne Roberts |
0:6015834e4279 | 608 | if (channelVacantCount > vc_thresh) { |
Wayne Roberts |
0:6015834e4279 | 609 | _send_(); |
Wayne Roberts |
0:6015834e4279 | 610 | flags.deferred_send = 0; |
Wayne Roberts |
0:6015834e4279 | 611 | } |
Wayne Roberts |
0:6015834e4279 | 612 | } |
Wayne Roberts |
0:6015834e4279 | 613 | flags.vacantCheck = 0; |
Wayne Roberts |
0:6015834e4279 | 614 | } |
Wayne Roberts |
0:6015834e4279 | 615 | } |
Wayne Roberts |
0:6015834e4279 | 616 | |
Wayne Roberts |
0:6015834e4279 | 617 | uint32_t find_dest_id(uint32_t reqid) |
Wayne Roberts |
0:6015834e4279 | 618 | { |
Wayne Roberts |
0:6015834e4279 | 619 | lid_list_t* L; |
Wayne Roberts |
0:6015834e4279 | 620 | for (L = attachedDevices; L != NULL; L = L->next) { |
Wayne Roberts |
0:6015834e4279 | 621 | if (L->id == reqid) |
Wayne Roberts |
0:6015834e4279 | 622 | return L->id; // is locally attached |
Wayne Roberts |
0:6015834e4279 | 623 | } |
Wayne Roberts |
0:6015834e4279 | 624 | |
Wayne Roberts |
0:6015834e4279 | 625 | for (L = attachedDevices; L != NULL; L = L->next) { |
Wayne Roberts |
0:6015834e4279 | 626 | if (L->attachedList != NULL) { |
Wayne Roberts |
0:6015834e4279 | 627 | cid_list_t* children; |
Wayne Roberts |
0:6015834e4279 | 628 | for (children = L->attachedList; children != NULL; children = children->next) { |
Wayne Roberts |
0:6015834e4279 | 629 | if (children->id == reqid) |
Wayne Roberts |
0:6015834e4279 | 630 | return L->id; |
Wayne Roberts |
0:6015834e4279 | 631 | } |
Wayne Roberts |
0:6015834e4279 | 632 | } |
Wayne Roberts |
0:6015834e4279 | 633 | } |
Wayne Roberts |
0:6015834e4279 | 634 | return ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 635 | } |
Wayne Roberts |
0:6015834e4279 | 636 | |
Wayne Roberts |
0:6015834e4279 | 637 | void cmd_tx(uint8_t argsAt) |
Wayne Roberts |
0:6015834e4279 | 638 | { |
Wayne Roberts |
0:6015834e4279 | 639 | unsigned symbs; |
Wayne Roberts |
0:6015834e4279 | 640 | if (sscanf(pcbuf+argsAt, "%u", &symbs) == 1) { |
Wayne Roberts |
0:6015834e4279 | 641 | Radio::LoRaPacketConfig(symbs, false, true, false); // preambleLen, fixLen, crcOn, invIQ |
Wayne Roberts |
0:6015834e4279 | 642 | pc.printf("txing %u symbols\r\n", symbs); |
Wayne Roberts |
0:6015834e4279 | 643 | } |
Wayne Roberts |
0:6015834e4279 | 644 | |
Wayne Roberts |
0:6015834e4279 | 645 | txBuf[txBuf_idx++] = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 646 | tx_dest_id = ANY_ID; |
Wayne Roberts |
0:6015834e4279 | 647 | txBuf_send(false); |
Wayne Roberts |
0:6015834e4279 | 648 | } |
Wayne Roberts |
0:6015834e4279 | 649 | |
Wayne Roberts |
0:6015834e4279 | 650 | void cmd_list_devices(uint8_t argsAt) |
Wayne Roberts |
0:6015834e4279 | 651 | { |
Wayne Roberts |
0:6015834e4279 | 652 | lid_list_t* L; |
Wayne Roberts |
0:6015834e4279 | 653 | pc.printf("my_id:%lx hops_from_gateway:%u\r\n", my_id, hops_from_gateway); |
Wayne Roberts |
0:6015834e4279 | 654 | for (L = attachedDevices; L != NULL; L = L->next) { |
Wayne Roberts |
0:6015834e4279 | 655 | pc.printf("%lx", L->id); |
Wayne Roberts |
0:6015834e4279 | 656 | if (L->attachedList != NULL) { |
Wayne Roberts |
0:6015834e4279 | 657 | cid_list_t* children; |
Wayne Roberts |
0:6015834e4279 | 658 | pc.printf(": "); |
Wayne Roberts |
0:6015834e4279 | 659 | for (children = L->attachedList; children != NULL; children = children->next) |
Wayne Roberts |
0:6015834e4279 | 660 | pc.printf("%lx ", children->id); |
Wayne Roberts |
0:6015834e4279 | 661 | } |
Wayne Roberts |
0:6015834e4279 | 662 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 663 | } |
Wayne Roberts |
0:6015834e4279 | 664 | } |
Wayne Roberts |
0:6015834e4279 | 665 | |
Wayne Roberts |
0:6015834e4279 | 666 | void cmd_print_status(uint8_t idx) |
Wayne Roberts |
0:6015834e4279 | 667 | { |
Wayne Roberts |
0:6015834e4279 | 668 | radio_print_status(); |
Wayne Roberts |
0:6015834e4279 | 669 | |
Wayne Roberts |
0:6015834e4279 | 670 | pc.printf("my_id:%lx hops_from_gateway:%u\r\n", my_id, hops_from_gateway); |
Wayne Roberts |
0:6015834e4279 | 671 | pc.printf("ClearChan%u reqFlags:%02x ", channelVacantCount, reqFlags.octet); |
Wayne Roberts |
0:6015834e4279 | 672 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 673 | upstream_print_status(); |
Wayne Roberts |
0:6015834e4279 | 674 | #endif /* GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 675 | pc.printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 676 | } |
Wayne Roberts |
0:6015834e4279 | 677 | |
Wayne Roberts |
0:6015834e4279 | 678 | typedef struct { |
Wayne Roberts |
0:6015834e4279 | 679 | const char* const cmd; |
Wayne Roberts |
0:6015834e4279 | 680 | void (*handler)(uint8_t args_at); |
Wayne Roberts |
0:6015834e4279 | 681 | const char* const arg_descr; |
Wayne Roberts |
0:6015834e4279 | 682 | const char* const description; |
Wayne Roberts |
0:6015834e4279 | 683 | } menu_item_t; |
Wayne Roberts |
0:6015834e4279 | 684 | |
Wayne Roberts |
0:6015834e4279 | 685 | void cmd_help(uint8_t); |
Wayne Roberts |
0:6015834e4279 | 686 | |
Wayne Roberts |
0:6015834e4279 | 687 | const menu_item_t menu_items[] = { |
Wayne Roberts |
0:6015834e4279 | 688 | { ".", cmd_print_status, "","print status"}, |
Wayne Roberts |
0:6015834e4279 | 689 | { "op", cmd_op, "%u","get/set tx power"}, |
Wayne Roberts |
0:6015834e4279 | 690 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 691 | { "dl", cmd_downlink, "%x %x...","send downlink <destIDhex> <payload bytes hex>"}, |
Wayne Roberts |
0:6015834e4279 | 692 | #endif /* GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 693 | { "ls", cmd_list_devices, "%u","list seen downstream devices"}, |
Wayne Roberts |
0:6015834e4279 | 694 | { "tx", cmd_tx, "%u","tx test preamble length"}, |
Wayne Roberts |
0:6015834e4279 | 695 | { "?", cmd_help, "","this list of commands"}, |
Wayne Roberts |
0:6015834e4279 | 696 | { NULL, NULL, NULL, NULL } |
Wayne Roberts |
0:6015834e4279 | 697 | }; |
Wayne Roberts |
0:6015834e4279 | 698 | |
Wayne Roberts |
0:6015834e4279 | 699 | void cmd_help(uint8_t args_at) |
Wayne Roberts |
0:6015834e4279 | 700 | { |
Wayne Roberts |
0:6015834e4279 | 701 | int i; |
Wayne Roberts |
0:6015834e4279 | 702 | |
Wayne Roberts |
0:6015834e4279 | 703 | for (i = 0; menu_items[i].cmd != NULL ; i++) { |
Wayne Roberts |
0:6015834e4279 | 704 | printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description); |
Wayne Roberts |
0:6015834e4279 | 705 | } |
Wayne Roberts |
0:6015834e4279 | 706 | } |
Wayne Roberts |
0:6015834e4279 | 707 | |
Wayne Roberts |
0:6015834e4279 | 708 | void console() |
Wayne Roberts |
0:6015834e4279 | 709 | { |
Wayne Roberts |
0:6015834e4279 | 710 | uint8_t i, user_cmd_len; |
Wayne Roberts |
0:6015834e4279 | 711 | |
Wayne Roberts |
0:6015834e4279 | 712 | if (pcbuf_len == 0) |
Wayne Roberts |
0:6015834e4279 | 713 | return; |
Wayne Roberts |
0:6015834e4279 | 714 | |
Wayne Roberts |
0:6015834e4279 | 715 | printf("\r\n"); |
Wayne Roberts |
0:6015834e4279 | 716 | |
Wayne Roberts |
0:6015834e4279 | 717 | /* get end of user-entered command */ |
Wayne Roberts |
0:6015834e4279 | 718 | user_cmd_len = 1; // first character can be any character |
Wayne Roberts |
0:6015834e4279 | 719 | for (i = 1; i <= pcbuf_len; i++) { |
Wayne Roberts |
0:6015834e4279 | 720 | if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') { |
Wayne Roberts |
0:6015834e4279 | 721 | user_cmd_len = i; |
Wayne Roberts |
0:6015834e4279 | 722 | break; |
Wayne Roberts |
0:6015834e4279 | 723 | } |
Wayne Roberts |
0:6015834e4279 | 724 | } |
Wayne Roberts |
0:6015834e4279 | 725 | |
Wayne Roberts |
0:6015834e4279 | 726 | for (i = 0; menu_items[i].cmd != NULL ; i++) { |
Wayne Roberts |
0:6015834e4279 | 727 | int mi_len = strlen(menu_items[i].cmd); |
Wayne Roberts |
0:6015834e4279 | 728 | if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) { |
Wayne Roberts |
0:6015834e4279 | 729 | while (pcbuf[mi_len] == ' ') // skip past spaces |
Wayne Roberts |
0:6015834e4279 | 730 | mi_len++; |
Wayne Roberts |
0:6015834e4279 | 731 | menu_items[i].handler(mi_len); |
Wayne Roberts |
0:6015834e4279 | 732 | break; |
Wayne Roberts |
0:6015834e4279 | 733 | } |
Wayne Roberts |
0:6015834e4279 | 734 | } |
Wayne Roberts |
0:6015834e4279 | 735 | |
Wayne Roberts |
0:6015834e4279 | 736 | pcbuf_len = 0; |
Wayne Roberts |
0:6015834e4279 | 737 | printf("> "); |
Wayne Roberts |
0:6015834e4279 | 738 | fflush(stdout); |
Wayne Roberts |
0:6015834e4279 | 739 | } |
Wayne Roberts |
0:6015834e4279 | 740 | |
Wayne Roberts |
0:6015834e4279 | 741 | void radio_irq_topHalf() |
Wayne Roberts |
0:6015834e4279 | 742 | { |
Wayne Roberts |
0:6015834e4279 | 743 | /* isr context -> main loop context */ |
Wayne Roberts |
0:6015834e4279 | 744 | queue.call(Radio::service); |
Wayne Roberts |
0:6015834e4279 | 745 | } |
Wayne Roberts |
0:6015834e4279 | 746 | |
Wayne Roberts |
0:6015834e4279 | 747 | const RadioEvents_t rev = { |
Wayne Roberts |
0:6015834e4279 | 748 | /* DioPin_top_half */ radio_irq_topHalf, |
Wayne Roberts |
0:6015834e4279 | 749 | /* TxDone_topHalf */ NULL, |
Wayne Roberts |
0:6015834e4279 | 750 | /* TxDone_botHalf */ txDoneCB, |
Wayne Roberts |
0:6015834e4279 | 751 | /* TxTimeout */ txTimeoutCB, |
Wayne Roberts |
0:6015834e4279 | 752 | /* RxDone */ rxDoneCB, |
Wayne Roberts |
0:6015834e4279 | 753 | /* RxTimeout */ rxTimeoutCB, |
Wayne Roberts |
0:6015834e4279 | 754 | /* RxError */ NULL, |
Wayne Roberts |
0:6015834e4279 | 755 | /* FhssChangeChannel */NULL, |
Wayne Roberts |
0:6015834e4279 | 756 | /* CadDone */ NULL |
Wayne Roberts |
0:6015834e4279 | 757 | }; |
Wayne Roberts |
0:6015834e4279 | 758 | |
Wayne Roberts |
0:6015834e4279 | 759 | void rx_callback() |
Wayne Roberts |
0:6015834e4279 | 760 | { |
Wayne Roberts |
0:6015834e4279 | 761 | static uint8_t pcbuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 762 | static uint8_t prev_len = 0; |
Wayne Roberts |
0:6015834e4279 | 763 | char c = pc.getc(); |
Wayne Roberts |
0:6015834e4279 | 764 | if (c == 8) { |
Wayne Roberts |
0:6015834e4279 | 765 | if (pcbuf_idx > 0) { |
Wayne Roberts |
0:6015834e4279 | 766 | pc.putc(8); |
Wayne Roberts |
0:6015834e4279 | 767 | pc.putc(' '); |
Wayne Roberts |
0:6015834e4279 | 768 | pc.putc(8); |
Wayne Roberts |
0:6015834e4279 | 769 | pcbuf_idx--; |
Wayne Roberts |
0:6015834e4279 | 770 | } |
Wayne Roberts |
0:6015834e4279 | 771 | } else if (c == 3) { // ctrl-C |
Wayne Roberts |
0:6015834e4279 | 772 | pcbuf_len = -1; |
Wayne Roberts |
0:6015834e4279 | 773 | } else if (c == '\r') { |
Wayne Roberts |
0:6015834e4279 | 774 | if (pcbuf_idx == 0) { |
Wayne Roberts |
0:6015834e4279 | 775 | pcbuf_len = prev_len; |
Wayne Roberts |
0:6015834e4279 | 776 | } else { |
Wayne Roberts |
0:6015834e4279 | 777 | pcbuf[pcbuf_idx] = 0; // null terminate |
Wayne Roberts |
0:6015834e4279 | 778 | prev_len = pcbuf_idx; |
Wayne Roberts |
0:6015834e4279 | 779 | pcbuf_idx = 0; |
Wayne Roberts |
0:6015834e4279 | 780 | pcbuf_len = prev_len; |
Wayne Roberts |
0:6015834e4279 | 781 | } |
Wayne Roberts |
0:6015834e4279 | 782 | queue.call(console); |
Wayne Roberts |
0:6015834e4279 | 783 | } else if (pcbuf_idx < sizeof(pcbuf)) { |
Wayne Roberts |
0:6015834e4279 | 784 | pcbuf[pcbuf_idx++] = c; |
Wayne Roberts |
0:6015834e4279 | 785 | pc.putc(c); |
Wayne Roberts |
0:6015834e4279 | 786 | } |
Wayne Roberts |
0:6015834e4279 | 787 | } |
Wayne Roberts |
0:6015834e4279 | 788 | |
Wayne Roberts |
0:6015834e4279 | 789 | int main() |
Wayne Roberts |
0:6015834e4279 | 790 | { |
Wayne Roberts |
0:6015834e4279 | 791 | pc.baud(115200); |
Wayne Roberts |
0:6015834e4279 | 792 | pc.printf("\r\nreset\r\n"); |
Wayne Roberts |
0:6015834e4279 | 793 | pc.attach(rx_callback); |
Wayne Roberts |
0:6015834e4279 | 794 | |
Wayne Roberts |
0:6015834e4279 | 795 | { |
Wayne Roberts |
0:6015834e4279 | 796 | uint32_t u32; |
Wayne Roberts |
0:6015834e4279 | 797 | #ifdef TARGET_FAMILY_STM32 |
Wayne Roberts |
0:6015834e4279 | 798 | u32 = LL_GetUID_Word0(); |
Wayne Roberts |
0:6015834e4279 | 799 | u32 <<= 2; |
Wayne Roberts |
0:6015834e4279 | 800 | u32 ^= LL_GetUID_Word1(); |
Wayne Roberts |
0:6015834e4279 | 801 | u32 ^= LL_GetUID_Word2(); |
Wayne Roberts |
0:6015834e4279 | 802 | #else |
Wayne Roberts |
0:6015834e4279 | 803 | #error TODO_nSTM32 |
Wayne Roberts |
0:6015834e4279 | 804 | #endif |
Wayne Roberts |
0:6015834e4279 | 805 | my_id = u32; |
Wayne Roberts |
0:6015834e4279 | 806 | pc.printf("my_id %lx\r\n", my_id); |
Wayne Roberts |
0:6015834e4279 | 807 | } |
Wayne Roberts |
0:6015834e4279 | 808 | |
Wayne Roberts |
0:6015834e4279 | 809 | wait_ms(200); // power stabilization from cold-reset |
Wayne Roberts |
0:6015834e4279 | 810 | Radio::Init(&rev); |
Wayne Roberts |
0:6015834e4279 | 811 | |
Wayne Roberts |
0:6015834e4279 | 812 | rxdbg = 0; |
Wayne Roberts |
0:6015834e4279 | 813 | Radio::Standby(); |
Wayne Roberts |
0:6015834e4279 | 814 | Radio::LoRaModemConfig(BW_KHZ, SPREADING_FACTOR, 1); |
Wayne Roberts |
0:6015834e4279 | 815 | Radio::SetChannel(CF_MHZ * 1000000); |
Wayne Roberts |
0:6015834e4279 | 816 | Radio::set_tx_dbm(TX_DBM); |
Wayne Roberts |
0:6015834e4279 | 817 | #ifdef SX126x_H |
Wayne Roberts |
0:6015834e4279 | 818 | { |
Wayne Roberts |
0:6015834e4279 | 819 | status_t status; |
Wayne Roberts |
0:6015834e4279 | 820 | uint8_t stopOnPreamble = 1; |
Wayne Roberts |
0:6015834e4279 | 821 | |
Wayne Roberts |
0:6015834e4279 | 822 | Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet); |
Wayne Roberts |
0:6015834e4279 | 823 | wait_ms(20); |
Wayne Roberts |
0:6015834e4279 | 824 | Radio::radio.xfer(OPCODE_STOP_TIMER_ON_PREAMBLE, 1, 0, &stopOnPreamble); |
Wayne Roberts |
0:6015834e4279 | 825 | } |
Wayne Roberts |
0:6015834e4279 | 826 | #endif /* SX126x_H */ |
Wayne Roberts |
0:6015834e4279 | 827 | |
Wayne Roberts |
0:6015834e4279 | 828 | setPreambleSize(false, 4); //init |
Wayne Roberts |
0:6015834e4279 | 829 | { |
Wayne Roberts |
0:6015834e4279 | 830 | unsigned daDur = Radio::lora_toa_us(DISCOVERY_ANS_LENGTH); |
Wayne Roberts |
0:6015834e4279 | 831 | discovery_ans_time_step_us = daDur + (ANS_PAD_MS * 1000); // + padding for receiver handling |
Wayne Roberts |
0:6015834e4279 | 832 | discovery_ans_time_total_us = discovery_ans_time_step_us * N_DISCOVERY_ANS; |
Wayne Roberts |
0:6015834e4279 | 833 | } |
Wayne Roberts |
0:6015834e4279 | 834 | |
Wayne Roberts |
0:6015834e4279 | 835 | #ifdef SX128x_H |
Wayne Roberts |
0:6015834e4279 | 836 | /* C preprocess doesnt do floating point */ |
Wayne Roberts |
0:6015834e4279 | 837 | if (N_PRE_SYMB > 255) { |
Wayne Roberts |
0:6015834e4279 | 838 | pc.printf("\e[41mlong preamble oversized %.1f\e[0m\r\n", N_PRE_SYMB); |
Wayne Roberts |
0:6015834e4279 | 839 | } |
Wayne Roberts |
0:6015834e4279 | 840 | #endif /* ..SX128x_H */ |
Wayne Roberts |
0:6015834e4279 | 841 | |
Wayne Roberts |
0:6015834e4279 | 842 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 843 | start_periodic_rxing(0x10); // gateway startup |
Wayne Roberts |
0:6015834e4279 | 844 | #else |
Wayne Roberts |
0:6015834e4279 | 845 | init_attached_upstream(); |
Wayne Roberts |
0:6015834e4279 | 846 | hops_from_gateway = HFG_UNATTACHED; |
Wayne Roberts |
0:6015834e4279 | 847 | upstream_init(); |
Wayne Roberts |
0:6015834e4279 | 848 | #endif |
Wayne Roberts |
0:6015834e4279 | 849 | |
Wayne Roberts |
0:6015834e4279 | 850 | app_init(); |
Wayne Roberts |
0:6015834e4279 | 851 | fwd.len = -1; |
Wayne Roberts |
0:6015834e4279 | 852 | |
Wayne Roberts |
0:6015834e4279 | 853 | /* if (!sleep_manager_can_deep_sleep()) { |
Wayne Roberts |
0:6015834e4279 | 854 | sleep_manager_unlock_deep_sleep(); |
Wayne Roberts |
0:6015834e4279 | 855 | pc.printf("unLockDeepSleep\r\n"); |
Wayne Roberts |
0:6015834e4279 | 856 | }*/ |
Wayne Roberts |
0:6015834e4279 | 857 | |
Wayne Roberts |
0:6015834e4279 | 858 | queue.dispatch(); |
Wayne Roberts |
0:6015834e4279 | 859 | } // ..main() |
Wayne Roberts |
0:6015834e4279 | 860 |