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.
upstream_interface.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 | /* upstream: interface towards gateway 36m cyan */ |
Wayne Roberts |
0:6015834e4279 | 2 | #include "main.h" |
Wayne Roberts |
0:6015834e4279 | 3 | |
Wayne Roberts |
0:6015834e4279 | 4 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 5 | struct { |
Wayne Roberts |
0:6015834e4279 | 6 | int preference; |
Wayne Roberts |
0:6015834e4279 | 7 | uint32_t id; |
Wayne Roberts |
0:6015834e4279 | 8 | uint8_t hfg; |
Wayne Roberts |
0:6015834e4279 | 9 | } best_upstream; |
Wayne Roberts |
0:6015834e4279 | 10 | |
Wayne Roberts |
0:6015834e4279 | 11 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 12 | |
Wayne Roberts |
0:6015834e4279 | 13 | |
Wayne Roberts |
0:6015834e4279 | 14 | /* packets received from upstream */ |
Wayne Roberts |
0:6015834e4279 | 15 | void upstream_req_rxDoneCB(float rssi, float snr, uint8_t* Idx, uint32_t sendingID, uint8_t cmd) |
Wayne Roberts |
0:6015834e4279 | 16 | { |
Wayne Roberts |
0:6015834e4279 | 17 | if (cmd == CMD_REMOVE_DEVICE_REQ) { |
Wayne Roberts |
0:6015834e4279 | 18 | uint32_t remove_id = getu32FromBuf(&Radio::radio.rx_buf[*Idx]); |
Wayne Roberts |
0:6015834e4279 | 19 | *Idx += 4; |
Wayne Roberts |
0:6015834e4279 | 20 | if (!remove_directlyAttached_device(remove_id)) { |
Wayne Roberts |
0:6015834e4279 | 21 | /* wasnt found locally, check child devices */ |
Wayne Roberts |
0:6015834e4279 | 22 | uint32_t removedFrom; |
Wayne Roberts |
0:6015834e4279 | 23 | remove_childDevice(remove_id, &removedFrom); |
Wayne Roberts |
0:6015834e4279 | 24 | if (removedFrom != ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 25 | /* forward this remove down */ |
Wayne Roberts |
0:6015834e4279 | 26 | downRemove.destID = removedFrom; |
Wayne Roberts |
0:6015834e4279 | 27 | downRemove.removeID = remove_id; |
Wayne Roberts |
0:6015834e4279 | 28 | reqFlags.bits.txAns = ANSWER_OK; |
Wayne Roberts |
0:6015834e4279 | 29 | } else |
Wayne Roberts |
0:6015834e4279 | 30 | reqFlags.bits.txAns = ANSWER_BUSY; |
Wayne Roberts |
0:6015834e4279 | 31 | } else |
Wayne Roberts |
0:6015834e4279 | 32 | reqFlags.bits.txAns = ANSWER_OK; |
Wayne Roberts |
0:6015834e4279 | 33 | |
Wayne Roberts |
0:6015834e4279 | 34 | } else if (cmd == CMD_DISCOVERY_ANS) { |
Wayne Roberts |
0:6015834e4279 | 35 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 36 | *Idx += 6; |
Wayne Roberts |
0:6015834e4279 | 37 | #else |
Wayne Roberts |
0:6015834e4279 | 38 | int my_sq, peer_sq; |
Wayne Roberts |
0:6015834e4279 | 39 | uint8_t idxCpy = *Idx; |
Wayne Roberts |
0:6015834e4279 | 40 | uint8_t hfg; |
Wayne Roberts |
0:6015834e4279 | 41 | float signal_preference; |
Wayne Roberts |
0:6015834e4279 | 42 | int hops_preference, preference; |
Wayne Roberts |
0:6015834e4279 | 43 | /* everything is upstream when we arent associated on network */ |
Wayne Roberts |
0:6015834e4279 | 44 | |
Wayne Roberts |
0:6015834e4279 | 45 | // signal quality is negative: rss + snr |
Wayne Roberts |
0:6015834e4279 | 46 | peer_sq = Radio::radio.rx_buf[idxCpy++] - 0x100; |
Wayne Roberts |
0:6015834e4279 | 47 | my_sq = rssi + snr; |
Wayne Roberts |
0:6015834e4279 | 48 | signal_preference = (peer_sq + my_sq) / 2; // round-trip signal quality |
Wayne Roberts |
0:6015834e4279 | 49 | hfg = Radio::radio.rx_buf[idxCpy++]; |
Wayne Roberts |
0:6015834e4279 | 50 | if (hfg != HFG_UNATTACHED) { |
Wayne Roberts |
0:6015834e4279 | 51 | hops_preference = 1 - hfg; // lower number preferable |
Wayne Roberts |
0:6015834e4279 | 52 | preference = signal_preference + (hops_preference * 10); |
Wayne Roberts |
0:6015834e4279 | 53 | if (preference > best_upstream.preference) { |
Wayne Roberts |
0:6015834e4279 | 54 | best_upstream.preference = preference; |
Wayne Roberts |
0:6015834e4279 | 55 | best_upstream.id = sendingID; |
Wayne Roberts |
0:6015834e4279 | 56 | best_upstream.hfg = hfg; |
Wayne Roberts |
0:6015834e4279 | 57 | } |
Wayne Roberts |
0:6015834e4279 | 58 | } |
Wayne Roberts |
0:6015834e4279 | 59 | |
Wayne Roberts |
0:6015834e4279 | 60 | *Idx += 2; |
Wayne Roberts |
0:6015834e4279 | 61 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 62 | } else if (cmd == CMD_USER_PAYLOAD_DN_REQ) { // rxDone callback, pkt from upstream |
Wayne Roberts |
0:6015834e4279 | 63 | uint8_t len; |
Wayne Roberts |
0:6015834e4279 | 64 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 65 | uint32_t final_dest_id = getu32FromBuf(&Radio::radio.rx_buf[*Idx]); |
Wayne Roberts |
0:6015834e4279 | 66 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 67 | *Idx += 4; |
Wayne Roberts |
0:6015834e4279 | 68 | len = Radio::radio.rx_buf[*Idx]; |
Wayne Roberts |
0:6015834e4279 | 69 | (*Idx)++; |
Wayne Roberts |
0:6015834e4279 | 70 | #ifdef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 71 | reqFlags.bits.txAns = ANSWER_OK; |
Wayne Roberts |
0:6015834e4279 | 72 | #else |
Wayne Roberts |
0:6015834e4279 | 73 | if (final_dest_id == my_id) { |
Wayne Roberts |
0:6015834e4279 | 74 | app_downlink(len, &Radio::radio.rx_buf[*Idx]); |
Wayne Roberts |
0:6015834e4279 | 75 | reqFlags.bits.txAns = ANSWER_OK; |
Wayne Roberts |
0:6015834e4279 | 76 | } else { |
Wayne Roberts |
0:6015834e4279 | 77 | if (attUp.id == ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 78 | reqFlags.bits.txAns = ANSWER_UNATTACHED; |
Wayne Roberts |
0:6015834e4279 | 79 | } else { |
Wayne Roberts |
0:6015834e4279 | 80 | if (fwd.len == -1) { |
Wayne Roberts |
0:6015834e4279 | 81 | fwd.len = len; |
Wayne Roberts |
0:6015834e4279 | 82 | fwd.A_id = final_dest_id; |
Wayne Roberts |
0:6015834e4279 | 83 | fwd.tx_dest_id = find_dest_id(final_dest_id); |
Wayne Roberts |
0:6015834e4279 | 84 | memcpy(fwd.buf, &Radio::radio.rx_buf[*Idx], len); |
Wayne Roberts |
0:6015834e4279 | 85 | reqFlags.bits.currentOp = CMD_USER_PAYLOAD_DN_REQ; // this is downlink |
Wayne Roberts |
0:6015834e4279 | 86 | reqFlags.bits.txAns = ANSWER_OK; |
Wayne Roberts |
0:6015834e4279 | 87 | } else |
Wayne Roberts |
0:6015834e4279 | 88 | reqFlags.bits.txAns = ANSWER_BUSY; |
Wayne Roberts |
0:6015834e4279 | 89 | } |
Wayne Roberts |
0:6015834e4279 | 90 | } |
Wayne Roberts |
0:6015834e4279 | 91 | #endif /* !GATEWAY */ |
Wayne Roberts |
0:6015834e4279 | 92 | (*Idx) += len; |
Wayne Roberts |
0:6015834e4279 | 93 | } |
Wayne Roberts |
0:6015834e4279 | 94 | |
Wayne Roberts |
0:6015834e4279 | 95 | } // ..upstream_req_rxDoneCB() |
Wayne Roberts |
0:6015834e4279 | 96 | |
Wayne Roberts |
0:6015834e4279 | 97 | #ifndef GATEWAY |
Wayne Roberts |
0:6015834e4279 | 98 | |
Wayne Roberts |
0:6015834e4279 | 99 | upstream_t attUp; |
Wayne Roberts |
0:6015834e4279 | 100 | upstream_t prospect; |
Wayne Roberts |
0:6015834e4279 | 101 | uint32_t id_newDeviceNotification; |
Wayne Roberts |
0:6015834e4279 | 102 | |
Wayne Roberts |
0:6015834e4279 | 103 | void upstream_ans_rxDoneCB(float rssi, float snr, uint8_t* Idx, uint32_t sendingID, uint8_t cmd) |
Wayne Roberts |
0:6015834e4279 | 104 | { |
Wayne Roberts |
0:6015834e4279 | 105 | if (reqFlags.bits.currentOp == CMD_ATTACH_REQ) { |
Wayne Roberts |
0:6015834e4279 | 106 | if (sendingID == best_upstream.id) { |
Wayne Roberts |
0:6015834e4279 | 107 | attUp.id = best_upstream.id; |
Wayne Roberts |
0:6015834e4279 | 108 | attUp.preference = best_upstream.preference; |
Wayne Roberts |
0:6015834e4279 | 109 | attUp.hfg = best_upstream.hfg; |
Wayne Roberts |
0:6015834e4279 | 110 | hops_from_gateway = best_upstream.hfg + 1; |
Wayne Roberts |
0:6015834e4279 | 111 | prospect.id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 112 | } |
Wayne Roberts |
0:6015834e4279 | 113 | |
Wayne Roberts |
0:6015834e4279 | 114 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 115 | } else if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { |
Wayne Roberts |
0:6015834e4279 | 116 | app_uplink_complete(); |
Wayne Roberts |
0:6015834e4279 | 117 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 118 | } else if (reqFlags.bits.currentOp == CMD_NEW_DEVICE_ATTACHED_REQ) { |
Wayne Roberts |
0:6015834e4279 | 119 | id_newDeviceNotification = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 120 | reqFlags.bits.currentOp = CMD_UNUSED; |
Wayne Roberts |
0:6015834e4279 | 121 | } |
Wayne Roberts |
0:6015834e4279 | 122 | |
Wayne Roberts |
0:6015834e4279 | 123 | } // ..upstream_ans_rxDoneCB() |
Wayne Roberts |
0:6015834e4279 | 124 | |
Wayne Roberts |
0:6015834e4279 | 125 | void upstream_print_status() |
Wayne Roberts |
0:6015834e4279 | 126 | { |
Wayne Roberts |
0:6015834e4279 | 127 | pc.printf("attUp.id:%lx ", attUp.id); |
Wayne Roberts |
0:6015834e4279 | 128 | if (hops_from_gateway == HFG_UNATTACHED) { |
Wayne Roberts |
0:6015834e4279 | 129 | pc.printf("best_upstream %lx, %d hfg:%u\r\n", best_upstream.id, best_upstream.preference, best_upstream.hfg); |
Wayne Roberts |
0:6015834e4279 | 130 | } |
Wayne Roberts |
0:6015834e4279 | 131 | } |
Wayne Roberts |
0:6015834e4279 | 132 | |
Wayne Roberts |
0:6015834e4279 | 133 | void upstream_new_device_notify() /* called from txDone */ |
Wayne Roberts |
0:6015834e4279 | 134 | { |
Wayne Roberts |
0:6015834e4279 | 135 | txBuf[txBuf_idx++] = CMD_NEW_DEVICE_ATTACHED_REQ; |
Wayne Roberts |
0:6015834e4279 | 136 | putu32ToBuf(&txBuf[txBuf_idx], id_newDeviceNotification); |
Wayne Roberts |
0:6015834e4279 | 137 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 138 | tx_dest_id = attUp.id; |
Wayne Roberts |
0:6015834e4279 | 139 | queue.call_in(500, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 140 | reqFlags.bits.currentOp = CMD_NEW_DEVICE_ATTACHED_REQ; |
Wayne Roberts |
0:6015834e4279 | 141 | //mdbg_printf("newDeviceNotify_tx "); |
Wayne Roberts |
0:6015834e4279 | 142 | } |
Wayne Roberts |
0:6015834e4279 | 143 | |
Wayne Roberts |
0:6015834e4279 | 144 | void discovery_rx_end() |
Wayne Roberts |
0:6015834e4279 | 145 | { |
Wayne Roberts |
0:6015834e4279 | 146 | Radio::Sleep(); |
Wayne Roberts |
0:6015834e4279 | 147 | //mdbg_printf("discoveryAnsRxEnd "); |
Wayne Roberts |
0:6015834e4279 | 148 | |
Wayne Roberts |
0:6015834e4279 | 149 | if (best_upstream.preference == INT_MIN) { |
Wayne Roberts |
0:6015834e4279 | 150 | /* nothing received, try discoverying again */ |
Wayne Roberts |
0:6015834e4279 | 151 | queue.call_in(1000, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 152 | pc.printf("discoveredNothing\r\n"); |
Wayne Roberts |
0:6015834e4279 | 153 | } else { |
Wayne Roberts |
0:6015834e4279 | 154 | /* best gateway heard, attach to it */ |
Wayne Roberts |
0:6015834e4279 | 155 | txBuf_idx = 0; // squash discovery request, no longer needed |
Wayne Roberts |
0:6015834e4279 | 156 | txBuf[txBuf_idx++] = CMD_ATTACH_REQ; |
Wayne Roberts |
0:6015834e4279 | 157 | tx_dest_id = best_upstream.id; |
Wayne Roberts |
0:6015834e4279 | 158 | queue.call_in(500, txBuf_send, true); |
Wayne Roberts |
0:6015834e4279 | 159 | pc.printf("attach-to-%lx\r\n", best_upstream.id); |
Wayne Roberts |
0:6015834e4279 | 160 | reqFlags.bits.currentOp = CMD_ATTACH_REQ; |
Wayne Roberts |
0:6015834e4279 | 161 | } |
Wayne Roberts |
0:6015834e4279 | 162 | } // ..discovery_rx_end() |
Wayne Roberts |
0:6015834e4279 | 163 | |
Wayne Roberts |
0:6015834e4279 | 164 | void upstream_init() |
Wayne Roberts |
0:6015834e4279 | 165 | { |
Wayne Roberts |
0:6015834e4279 | 166 | pc.printf("txDiscoverReq:%u ", txBuf_idx); |
Wayne Roberts |
0:6015834e4279 | 167 | txBuf[txBuf_idx++] = CMD_DISCOVERY_REQ; |
Wayne Roberts |
0:6015834e4279 | 168 | tx_dest_id = ANY_ID; |
Wayne Roberts |
0:6015834e4279 | 169 | txBuf_send(true); |
Wayne Roberts |
0:6015834e4279 | 170 | |
Wayne Roberts |
0:6015834e4279 | 171 | best_upstream.preference = INT_MIN; |
Wayne Roberts |
0:6015834e4279 | 172 | init_attached_upstream(); |
Wayne Roberts |
0:6015834e4279 | 173 | hops_from_gateway = HFG_UNATTACHED; |
Wayne Roberts |
0:6015834e4279 | 174 | reqFlags.bits.currentOp = CMD_DISCOVERY_REQ; |
Wayne Roberts |
0:6015834e4279 | 175 | } |
Wayne Roberts |
0:6015834e4279 | 176 | |
Wayne Roberts |
0:6015834e4279 | 177 | int uplink(const uint8_t* userPayload, uint8_t userPayloadSize) |
Wayne Roberts |
0:6015834e4279 | 178 | { |
Wayne Roberts |
0:6015834e4279 | 179 | unsigned n; |
Wayne Roberts |
0:6015834e4279 | 180 | //mdbg_printf("uplink_tx%u ", userPayloadSize); |
Wayne Roberts |
0:6015834e4279 | 181 | if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { |
Wayne Roberts |
0:6015834e4279 | 182 | //mdbg_printf("busy\r\n"); |
Wayne Roberts |
0:6015834e4279 | 183 | return -1; |
Wayne Roberts |
0:6015834e4279 | 184 | } |
Wayne Roberts |
0:6015834e4279 | 185 | |
Wayne Roberts |
0:6015834e4279 | 186 | reqFlags.bits.currentOp = CMD_USER_PAYLOAD_UP_REQ; |
Wayne Roberts |
0:6015834e4279 | 187 | |
Wayne Roberts |
0:6015834e4279 | 188 | txBuf[txBuf_idx++] = CMD_USER_PAYLOAD_UP_REQ; |
Wayne Roberts |
0:6015834e4279 | 189 | |
Wayne Roberts |
0:6015834e4279 | 190 | // originating ID, to be preserved all the way up to gateway |
Wayne Roberts |
0:6015834e4279 | 191 | putu32ToBuf(&txBuf[txBuf_idx], my_id); |
Wayne Roberts |
0:6015834e4279 | 192 | txBuf_idx += 4; |
Wayne Roberts |
0:6015834e4279 | 193 | |
Wayne Roberts |
0:6015834e4279 | 194 | txBuf[txBuf_idx++] = userPayloadSize; |
Wayne Roberts |
0:6015834e4279 | 195 | for (n = 0; n < userPayloadSize; n++) |
Wayne Roberts |
0:6015834e4279 | 196 | txBuf[txBuf_idx++] = userPayload[n]; |
Wayne Roberts |
0:6015834e4279 | 197 | |
Wayne Roberts |
0:6015834e4279 | 198 | tx_dest_id = attUp.id; |
Wayne Roberts |
0:6015834e4279 | 199 | flags.CallTXRequest = 1; // transmit will occur in idle-rxsingle cycle |
Wayne Roberts |
0:6015834e4279 | 200 | |
Wayne Roberts |
0:6015834e4279 | 201 | return 0; |
Wayne Roberts |
0:6015834e4279 | 202 | } |
Wayne Roberts |
0:6015834e4279 | 203 | |
Wayne Roberts |
0:6015834e4279 | 204 | void upstream_attached_check(uint32_t sending_id) |
Wayne Roberts |
0:6015834e4279 | 205 | { |
Wayne Roberts |
0:6015834e4279 | 206 | if (sending_id != attUp.id) |
Wayne Roberts |
0:6015834e4279 | 207 | return; |
Wayne Roberts |
0:6015834e4279 | 208 | |
Wayne Roberts |
0:6015834e4279 | 209 | cmd_e cmd = (cmd_e)Radio::radio.rx_buf[9]; |
Wayne Roberts |
0:6015834e4279 | 210 | Mdbg_printf("upAttCmd:%s? ", cmdStrs[cmd]); |
Wayne Roberts |
0:6015834e4279 | 211 | if (cmd == CMD_ATTACH_REQ) { |
Wayne Roberts |
0:6015834e4279 | 212 | pc.printf("\e[31muppreattach\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 213 | /* TODO appropriate action when upstream path changes */ |
Wayne Roberts |
0:6015834e4279 | 214 | } |
Wayne Roberts |
0:6015834e4279 | 215 | } |
Wayne Roberts |
0:6015834e4279 | 216 | |
Wayne Roberts |
0:6015834e4279 | 217 | void init_attached_upstream() |
Wayne Roberts |
0:6015834e4279 | 218 | { |
Wayne Roberts |
0:6015834e4279 | 219 | attUp.id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 220 | attUp.cnt = 0; |
Wayne Roberts |
0:6015834e4279 | 221 | attUp.preference = INT_MIN; |
Wayne Roberts |
0:6015834e4279 | 222 | |
Wayne Roberts |
0:6015834e4279 | 223 | prospect.id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 224 | prospect.cnt = 0; |
Wayne Roberts |
0:6015834e4279 | 225 | prospect.preference = INT_MIN; |
Wayne Roberts |
0:6015834e4279 | 226 | } |
Wayne Roberts |
0:6015834e4279 | 227 | |
Wayne Roberts |
0:6015834e4279 | 228 | void upstream_signal_check(float rssi, float snr, uint8_t rx_hfg, uint32_t rx_id) |
Wayne Roberts |
0:6015834e4279 | 229 | { |
Wayne Roberts |
0:6015834e4279 | 230 | float signal_preference; |
Wayne Roberts |
0:6015834e4279 | 231 | int this_preference, my_sq, hops_preference = 1 - rx_hfg; |
Wayne Roberts |
0:6015834e4279 | 232 | my_sq = rssi + snr; |
Wayne Roberts |
0:6015834e4279 | 233 | signal_preference = my_sq; |
Wayne Roberts |
0:6015834e4279 | 234 | this_preference = signal_preference + (hops_preference * 10); |
Wayne Roberts |
0:6015834e4279 | 235 | if (rx_id == attUp.id) { |
Wayne Roberts |
0:6015834e4279 | 236 | /* how much has path to upstream changed ? */ |
Wayne Roberts |
0:6015834e4279 | 237 | Rx_log_printf("attachedChange initial:%d vs this:%d ", attUp.preference, this_preference); |
Wayne Roberts |
0:6015834e4279 | 238 | if (attUp.preference > this_preference) { |
Wayne Roberts |
0:6015834e4279 | 239 | attUp.cnt++; |
Wayne Roberts |
0:6015834e4279 | 240 | } else |
Wayne Roberts |
0:6015834e4279 | 241 | attUp.cnt = 0; |
Wayne Roberts |
0:6015834e4279 | 242 | } else { |
Wayne Roberts |
0:6015834e4279 | 243 | /* check for better upstream */ |
Wayne Roberts |
0:6015834e4279 | 244 | Rx_log_printf("attached:%d vs this:%d ", attUp.preference, this_preference); |
Wayne Roberts |
0:6015834e4279 | 245 | if ((this_preference-10) > attUp.preference) { // -10: significantly better |
Wayne Roberts |
0:6015834e4279 | 246 | Rx_log_printf("better"); |
Wayne Roberts |
0:6015834e4279 | 247 | if (prospect.id == ID_NONE) { |
Wayne Roberts |
0:6015834e4279 | 248 | prospect.cnt = 1; |
Wayne Roberts |
0:6015834e4279 | 249 | prospect.id = rx_id; |
Wayne Roberts |
0:6015834e4279 | 250 | Rx_log_printf("Init"); |
Wayne Roberts |
0:6015834e4279 | 251 | } else { |
Wayne Roberts |
0:6015834e4279 | 252 | prospect.cnt++; |
Wayne Roberts |
0:6015834e4279 | 253 | Rx_log_printf("Inc%u", prospect.cnt); |
Wayne Roberts |
0:6015834e4279 | 254 | if (prospect.cnt > 3) { |
Wayne Roberts |
0:6015834e4279 | 255 | init_attached_upstream(); |
Wayne Roberts |
0:6015834e4279 | 256 | hops_from_gateway = HFG_UNATTACHED; |
Wayne Roberts |
0:6015834e4279 | 257 | queue.call_in(2000, upstream_init); |
Wayne Roberts |
0:6015834e4279 | 258 | Rx_log_printf("\e[33mreattach\e[0m "); |
Wayne Roberts |
0:6015834e4279 | 259 | } |
Wayne Roberts |
0:6015834e4279 | 260 | } |
Wayne Roberts |
0:6015834e4279 | 261 | } else if (this_preference < attUp.preference) { |
Wayne Roberts |
0:6015834e4279 | 262 | Rx_log_printf("worse"); |
Wayne Roberts |
0:6015834e4279 | 263 | if (prospect.id == rx_id) { |
Wayne Roberts |
0:6015834e4279 | 264 | prospect.id = ID_NONE; |
Wayne Roberts |
0:6015834e4279 | 265 | prospect.cnt = 0; |
Wayne Roberts |
0:6015834e4279 | 266 | Rx_log_printf("Clear"); |
Wayne Roberts |
0:6015834e4279 | 267 | } |
Wayne Roberts |
0:6015834e4279 | 268 | } |
Wayne Roberts |
0:6015834e4279 | 269 | |
Wayne Roberts |
0:6015834e4279 | 270 | Rx_log_printf(" "); |
Wayne Roberts |
0:6015834e4279 | 271 | } // ..rx from other-than-attached |
Wayne Roberts |
0:6015834e4279 | 272 | } |
Wayne Roberts |
0:6015834e4279 | 273 | |
Wayne Roberts |
0:6015834e4279 | 274 | #endif /* !GATEWAY */ |