wayne roberts
/
lora_mesh
star-mesh LoRa network
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 #include "main.h" 00002 00003 #ifdef TARGET_STM32L0 00004 #include "stm32l0xx_ll_utils.h" 00005 #elif defined(TARGET_STM32L1) 00006 #include "stm32l1xx_ll_utils.h" 00007 #elif defined(TARGET_STM32L4) 00008 #include "stm32l4xx_ll_utils.h" 00009 #endif 00010 00011 #ifdef TARGET_DISCO_L072CZ_LRWAN1 00012 DigitalOut rxdbg(PB_8); 00013 #elif defined(TARGET_FF_ARDUINO) 00014 DigitalOut rxdbg(PC_3); 00015 #endif 00016 00017 RawSerial pc(USBTX, USBRX); 00018 00019 EventQueue queue(32 * EVENTS_EVENT_SIZE); 00020 00021 char pcbuf[64]; /* local user terminal */ 00022 int pcbuf_len; 00023 00024 unsigned discovery_ans_time_step_us; 00025 unsigned discovery_ans_time_total_us; 00026 00027 uint32_t my_id; 00028 00029 #ifdef GATEWAY 00030 const uint8_t hops_from_gateway = 0; 00031 #else 00032 uint8_t hops_from_gateway; 00033 #endif 00034 00035 volatile flags_t flags; 00036 00037 static uint8_t attemptCnt; 00038 static int req_timeout_id; 00039 reqflags_t reqFlags; 00040 volatile unsigned channelVacantCount; 00041 00042 uint8_t txBuf[255]; 00043 uint8_t txBuf_idx; 00044 uint32_t tx_dest_id; 00045 00046 bool remove_directlyAttached_device(uint32_t id) 00047 { 00048 bool removed = false; 00049 lid_list_t* L; 00050 for (L = attachedDevices; L != NULL; L = L->next) { 00051 if (L->id == id) { 00052 /* remove/clear all child devices also */ 00053 cid_list_t* children; 00054 for (children = L->attachedList; children != NULL; children = children->next) 00055 children->id = ID_NONE; 00056 00057 removed = true; 00058 L->id = ID_NONE; 00059 } 00060 } 00061 return removed; 00062 } 00063 00064 void remove_childDevice(uint32_t id, uint32_t* attachedTo) 00065 { 00066 lid_list_t* L; 00067 *attachedTo = ID_NONE; 00068 for (L = attachedDevices; L != NULL; L = L->next) { 00069 cid_list_t* children; 00070 for (children = L->attachedList; children != NULL; children = children->next) { 00071 if (children->id == id) { 00072 *attachedTo = L->id; 00073 children->id = ID_NONE; 00074 } 00075 } 00076 } 00077 } 00078 00079 void setPreambleSize(bool wakesize, uint8_t by) 00080 { 00081 if (wakesize) { 00082 Radio::LoRaPacketConfig(N_PRE_SYMB, false, true, false); // preambleLen, fixLen, crcOn, invIQ 00083 if (flags.discoverAnswering) { 00084 Mdbg_printf("\e[41mLPDA%02x\e[0m ", by); 00085 } 00086 } else { 00087 Radio::LoRaPacketConfig(8, false, true, false); // preambleLen, fixLen, crcOn, invIQ 00088 } 00089 } 00090 00091 static void rxSingle() 00092 { 00093 if (flags.CallTXRequest) { 00094 txBuf_send(true); 00095 flags.CallTXRequest = 0; 00096 } else if (reqFlags.octet == 0 || flags.deferred_send) { 00097 flags.vacantCheck = 1; 00098 /* rx single: auto-timeout */ 00099 Radio::Rx(999); 00100 } 00101 } 00102 00103 void start_periodic_rxing(uint8_t by) // definition 00104 { 00105 setPreambleSize(true, by | 3); 00106 Radio::SetLoRaSymbolTimeout(8); 00107 queue.call_in(WAKEUP_INTERVAL_MS, rxSingle); 00108 } 00109 00110 const char* const cmdStrs[] = { 00111 "unused", /* 0 CMD_UNUSED */ 00112 "Ans", /* 1 CMD_ANS, */ 00113 "discoverReq", /* 2 CMD_DISCOVERY_REQ, */ 00114 "discoverAns", /* 3 CMD_DISCOVERY_ANS, */ 00115 "attachReq", /* 4 CMD_ATTACH_REQ, */ 00116 "userPayReqUp", /* 5 CMD_USER_PAYLOAD_UP_REQ, */ 00117 "userPayReqDn", /* 6 CMD_USER_PAYLOAD_DN_REQ, */ 00118 "newDev", /* 7 CMD_NEW_DEVICE_ATTACHED_REQ, */ 00119 "removeDev", /* 8 CMD_REMOVE_DEVICE_REQ, */ 00120 "downstreamNotResponding", /* 9 CMD_DOWNSTREAM_NOT_RESPONDING, */ 00121 }; 00122 00123 00124 uint8_t tx_len; 00125 00126 static void _send_(void) 00127 { 00128 if (flags.sending_req) 00129 setPreambleSize(true, 2); // sending request 00130 00131 Radio::Send(tx_len, 0, 0, 0); /* begin transmission */ 00132 if (flags.discoverAnswering) { 00133 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]]); 00134 } else { 00135 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]]); 00136 } 00137 Mdbg_printf(":"); 00138 #ifdef MESH_DEBUG 00139 /*{ 00140 unsigned n; 00141 for (n = 0; n < tx_len; n++) 00142 pc.printf("%02x ", Radio::radio.tx_buf[n]); 00143 }*/ 00144 #endif /* MESH_DEBUG */ 00145 00146 if (flags.sending_req) { 00147 attemptCnt++; 00148 flags.getAns = 1; 00149 } else 00150 flags.getAns = 0; 00151 00152 channelVacantCount = 0; 00153 } // .._send_() 00154 00155 void txBuf_send(bool sendingReq) 00156 { 00157 uint16_t crc; 00158 00159 if (txBuf_idx == 0) { 00160 return; 00161 } 00162 00163 Radio::Standby(); 00164 00165 if (sendingReq) { 00166 if (attemptCnt > RETRY_LIMIT) { 00167 /* give up trying */ 00168 txBuf_idx = 0; 00169 attemptCnt = 0; 00170 #ifdef GATEWAY 00171 reqFlags.octet = 0; // TODO dropping request 00172 start_periodic_rxing(0x80); // retry give-up 00173 return; 00174 #else 00175 if (tx_dest_id == attUp.id) { 00176 /* find new upstream device */ 00177 queue.call_in(1000, upstream_init); 00178 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) 00179 app_uplink_complete(); // TODO report failure to application layer 00180 return; 00181 } else { 00182 txBuf[txBuf_idx++] = CMD_DOWNSTREAM_NOT_RESPONDING; 00183 putu32ToBuf(&txBuf[txBuf_idx], my_id); // ID of reporting device 00184 txBuf_idx += 4; 00185 putu32ToBuf(&txBuf[txBuf_idx], tx_dest_id); // ID of failed downstream device 00186 txBuf_idx += 4; 00187 tx_dest_id = attUp.id; 00188 reqFlags.bits.currentOp = CMD_DOWNSTREAM_NOT_RESPONDING; 00189 } 00190 #endif /* !GATEWAY */ 00191 } 00192 } // ..if (sendingReq) 00193 00194 Radio::radio.tx_buf[0] = hops_from_gateway; 00195 putu32ToBuf(&Radio::radio.tx_buf[1], my_id); 00196 putu32ToBuf(&Radio::radio.tx_buf[5], tx_dest_id); 00197 00198 tx_len = txBuf_idx; 00199 memcpy(&Radio::radio.tx_buf[9], txBuf, tx_len); 00200 tx_len += 9; 00201 crc = crc16(Radio::radio.tx_buf, tx_len); 00202 putu16ToBuf(&Radio::radio.tx_buf[tx_len], crc); 00203 tx_len += 2; 00204 00205 flags.sending_req = sendingReq; 00206 if (sendingReq) { 00207 if (channelVacantCount > CHANNEL_VACANT_REQUIRED_COUNT) 00208 _send_(); 00209 else { 00210 flags.deferred_send = 1; 00211 start_periodic_rxing(0x70); // deferred send 00212 } 00213 } else 00214 _send_(); 00215 00216 } // ..txBuf_send() 00217 00218 #ifdef MESH_DEBUG 00219 bool rx_log_disable; 00220 char rx_log[768]; 00221 volatile unsigned rx_log_buf_idx; 00222 int _rx_log_printf(const char *format, ...) 00223 { 00224 va_list aptr; 00225 int ret = -1; 00226 00227 va_start(aptr, format); 00228 if (!rx_log_disable) { 00229 ret = vsprintf(rx_log + rx_log_buf_idx , format, aptr); 00230 rx_log_buf_idx += ret; 00231 if (rx_log_buf_idx >= sizeof(rx_log)-1) { 00232 pc.printf("\e[31mrx_log_overrun\e[0m "); 00233 rx_log_disable = true; 00234 } 00235 } 00236 va_end(aptr); 00237 00238 00239 return ret; 00240 } 00241 00242 void rx_log_print() 00243 { 00244 rx_log[rx_log_buf_idx+1] = 0; 00245 pc.printf(rx_log); 00246 rx_log_buf_idx = 0; 00247 } 00248 #endif /* MESH_DEBUG */ 00249 00250 static void txAns(unsigned sending_id) 00251 { 00252 unsigned elapsedAlready; 00253 int pad_us; 00254 txBuf_idx = 0; // previously sent request no longer needed 00255 txBuf[txBuf_idx++] = CMD_ANS; 00256 txBuf[txBuf_idx++] = reqFlags.bits.txAns; 00257 setPreambleSize(false, 6); // sending answer 00258 tx_dest_id = sending_id; 00259 elapsedAlready = Radio::lpt.read_us() - Radio::irqAt; 00260 pad_us = (ANS_PAD_MS * 1000) - elapsedAlready; 00261 if (pad_us > 100) { 00262 wait_us(pad_us); // short wait time more accurate in busy-loop 00263 } 00264 txBuf_send(false); 00265 if (pad_us <= 0) { 00266 pc.printf("\e[41mLATE:%d ", pad_us); 00267 pc.printf("\e[0m "); 00268 } 00269 00270 #ifdef MESH_DEBUG 00271 // printing of rx_log was deferred until this answer sent 00272 rx_log_print(); 00273 #endif /* MESH_DEBUG */ 00274 } 00275 00276 uint16_t getu16FromBuf(const uint8_t* in) 00277 { 00278 uint16_t ret; 00279 00280 ret = in[1]; 00281 ret <<= 8; 00282 ret |= in[0]; 00283 00284 return ret; 00285 } 00286 00287 void putu16ToBuf(uint8_t* out, uint16_t v) 00288 { 00289 *out++ = v & 0xff; 00290 v >>= 8; 00291 *out = v & 0xff; 00292 } 00293 00294 void putu32ToBuf(uint8_t* out, uint32_t v) 00295 { 00296 /* most significant last */ 00297 /* least significant first */ 00298 *out++ = v & 0xff; 00299 v >>= 8; 00300 *out++ = v & 0xff; 00301 v >>= 8; 00302 *out++ = v & 0xff; 00303 v >>= 8; 00304 *out = v & 0xff; 00305 } 00306 00307 uint32_t getu32FromBuf(const uint8_t* in) 00308 { 00309 uint32_t ret; 00310 00311 ret = in[3]; 00312 ret <<= 8; 00313 ret |= in[2]; 00314 ret <<= 8; 00315 ret |= in[1]; 00316 ret <<= 8; 00317 ret |= in[0]; 00318 00319 return ret; 00320 } 00321 00322 00323 00324 struct _fwd_ fwd; 00325 struct _nr_ notResponding; 00326 00327 void txDoneCB() 00328 { 00329 if (flags.getAns) { 00330 unsigned toms; 00331 setPreambleSize(false, 5); // getting answer 00332 Radio::Rx(0); 00333 #ifndef GATEWAY 00334 if (reqFlags.bits.currentOp == CMD_DISCOVERY_REQ) { 00335 /* discovering: listen for answers from any upstream devices */ 00336 toms = discovery_ans_time_total_us / 1000; 00337 queue.call_in(toms, discovery_rx_end); 00338 } else 00339 #endif /* !GATEWAY */ 00340 { 00341 unsigned target_us; 00342 target_us = Radio::lora_toa_us(ANS_SIZE_BYTE) * 4; // four packet length's worth 00343 toms = (ANS_PAD_MS + ANS_PAD_MS) + (target_us / 1000); // microseconds to milliseconds 00344 req_timeout_id = queue.call_in(toms, txBuf_send, true); 00345 } 00346 } else if (reqFlags.bits.txAns != NOT_ANSWERING) { // txDone callback answer-tx-complete 00347 /* we just sent answer: restore to idle condition waiting for wakeup packet */ 00348 reqFlags.bits.txAns = NOT_ANSWERING; 00349 txBuf_idx = 0; 00350 00351 #ifndef GATEWAY 00352 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ || reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { 00353 int n; 00354 if (fwd.len >= 0) { 00355 tx_dest_id = fwd.tx_dest_id; 00356 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { 00357 /* forward upstream */ 00358 txBuf[txBuf_idx++] = CMD_USER_PAYLOAD_UP_REQ; 00359 putu32ToBuf(&txBuf[txBuf_idx], fwd.B_id); // originating_src_id 00360 txBuf_idx += 4; 00361 } else if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { 00362 /* forward downstream */ 00363 txBuf[txBuf_idx++] = CMD_USER_PAYLOAD_DN_REQ; 00364 putu32ToBuf(&txBuf[txBuf_idx], fwd.A_id); // final_dest_id 00365 txBuf_idx += 4; 00366 } 00367 txBuf[txBuf_idx++] = fwd.len; 00368 for (n = 0; n < fwd.len; n++) 00369 txBuf[txBuf_idx++] = fwd.buf[n]; 00370 00371 queue.call_in(500, txBuf_send, true); 00372 fwd.len = -1; 00373 } // ..if (fwd.len >= 0) 00374 else { 00375 /* uplink/downlink not forwarding */ 00376 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) 00377 app_uplink_complete(); 00378 reqFlags.bits.currentOp = CMD_UNUSED; 00379 } 00380 } 00381 00382 if (attUp.id == ID_NONE) { 00383 /* disconnected from upstream, rediscover */ 00384 queue.call_in(1000, upstream_init); 00385 } else if (id_newDeviceNotification != ID_NONE) { 00386 upstream_new_device_notify(); 00387 } else if (reqFlags.bits.currentOp == CMD_DOWNSTREAM_NOT_RESPONDING) { 00388 tx_dest_id = attUp.id; 00389 txBuf[txBuf_idx++] = CMD_DOWNSTREAM_NOT_RESPONDING; 00390 putu32ToBuf(&txBuf[txBuf_idx], notResponding.reporting_id); 00391 txBuf_idx += 4; 00392 putu32ToBuf(&txBuf[txBuf_idx], notResponding.device_not_respoding_id); 00393 txBuf_idx += 4; 00394 queue.call_in(500, txBuf_send, true); 00395 } else 00396 #endif /* !GATEWAY */ 00397 if (downRemove.destID != ID_NONE) { 00398 request_remove_device(); 00399 } 00400 start_periodic_rxing(0x60); // reqFlags.bits.txAns != NOT_ANSWERING 00401 } else if (reqFlags.bits.currentOp == CMD_DISCOVERY_ANS) { 00402 if (flags.firstDiscoverAns) { 00403 unsigned rnd = Radio::Random() % N_HALF_DISCOVERY_ANS; 00404 queue.call_in((discovery_ans_time_step_us * rnd) / 1000, txBuf_send, false); 00405 flags.firstDiscoverAns = 0; 00406 } else { 00407 reqFlags.bits.currentOp = CMD_UNUSED; 00408 txBuf_idx = 0; 00409 //start_periodic_rxing(0x50); // 2nd discoverAns 00410 } 00411 } else { 00412 /* ? wtf did we just transmit ? */ 00413 pc.printf("\e[31mnoTxAns_or_STATE_GET_ANS\e[0m "); 00414 } 00415 } // ..txDoneCB() 00416 00417 00418 uint16_t crc16( uint8_t *buffer, uint16_t length ) 00419 { 00420 uint16_t i; 00421 // The CRC calculation follows CCITT 00422 const uint16_t polynom = 0x1021; 00423 // CRC initial value 00424 uint16_t crc = 0x0000; 00425 00426 if( buffer == NULL ) 00427 { 00428 return 0; 00429 } 00430 00431 for( i = 0; i < length; ++i ) 00432 { 00433 uint16_t j; 00434 crc ^= ( uint16_t ) buffer[i] << 8; 00435 for( j = 0; j < 8; ++j ) 00436 { 00437 crc = ( crc & 0x8000 ) ? ( crc << 1 ) ^ polynom : ( crc << 1 ); 00438 } 00439 } 00440 00441 return crc; 00442 } 00443 00444 00445 void rxDoneCB(uint8_t size, float rssi, float snr) 00446 { 00447 uint8_t rx_buf_idx; 00448 uint16_t calc, rxCrc; 00449 uint8_t rx_hfg = Radio::radio.rx_buf[0]; 00450 uint32_t sending_id = getu32FromBuf(&Radio::radio.rx_buf[1]); 00451 uint32_t dest_id = getu32FromBuf(&Radio::radio.rx_buf[5]); 00452 #ifdef GATEWAY 00453 upInfo_t up_info; 00454 up_info.originating_src_id = ID_NONE; 00455 #endif /* GATEWAY */ 00456 00457 #ifdef MESH_DEBUG 00458 bool print_log_here = true; 00459 rx_log_buf_idx = 0; 00460 rx_log[0] = 0; 00461 rx_log_disable = false; 00462 #endif /* MESH_DEBUG */ 00463 00464 if (flags.vacantCheck) { 00465 channelVacantCount = 0; 00466 flags.vacantCheck = 0; 00467 } 00468 00469 Rx_log_printf("\e[32mrxDone %ubytes %.1fdBm %.1fdB\e[0m ", size, rssi, snr); 00470 Rx_log_printf("from:%lx_to_%lx ", sending_id, dest_id); 00471 00472 if (dest_id != my_id && dest_id != ANY_ID) { 00473 #ifndef GATEWAY 00474 /* check if upstream device were attached to is re-attaching */ 00475 upstream_attached_check(sending_id); 00476 #endif /* !GATEWAY */ 00477 if (!flags.discoverAnswering) 00478 start_periodic_rxing(0x40); // rxDone notForMe 00479 goto done; 00480 } 00481 00482 calc = crc16(Radio::radio.rx_buf, size-2); 00483 rxCrc = getu16FromBuf(&Radio::radio.rx_buf[size-2]); 00484 if (calc != rxCrc) { 00485 Rx_log_printf("%04x != %04x\r\n", calc, rxCrc); 00486 if (!flags.discoverAnswering) 00487 start_periodic_rxing(0x30); // rxDone crcfail 00488 goto done; 00489 } 00490 00491 size -= 2; // take off trailing crc 00492 for (rx_buf_idx = 9; rx_buf_idx < size; ) { 00493 cmd_e cmd = (cmd_e)Radio::radio.rx_buf[rx_buf_idx++]; 00494 00495 Rx_log_printf(" curOp:%u_", reqFlags.bits.currentOp); 00496 Rx_log_printf(" \e[7mRxCmd:%s\e[0m", cmdStrs[cmd]); 00497 Rx_log_printf(" "); 00498 00499 switch (cmd) { 00500 ans_e ans; 00501 case CMD_ANS: 00502 ans = (ans_e)Radio::radio.rx_buf[rx_buf_idx++]; 00503 /* request as been answered successfully */ 00504 Rx_log_printf("\e[35mrxAns\e[0m "); 00505 if (flags.getAns) { 00506 if (ans == ANSWER_OK) { 00507 txBuf_idx = 0; 00508 queue.cancel(req_timeout_id); 00509 attemptCnt = 0; 00510 downstream_ans_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); 00511 #ifndef GATEWAY 00512 upstream_ans_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); 00513 #endif /* !GATEWAY */ 00514 00515 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_UP_REQ) { 00516 fwd.len = -1; 00517 reqFlags.bits.currentOp = CMD_UNUSED; 00518 } 00519 00520 if (reqFlags.bits.currentOp == CMD_USER_PAYLOAD_DN_REQ) { 00521 fwd.len = -1; 00522 reqFlags.bits.currentOp = CMD_UNUSED; 00523 } 00524 } 00525 } 00526 00527 break; 00528 case CMD_UNUSED: 00529 break; 00530 case CMD_DISCOVERY_REQ: 00531 case CMD_ATTACH_REQ: 00532 case CMD_NEW_DEVICE_ATTACHED_REQ: 00533 case CMD_USER_PAYLOAD_UP_REQ: 00534 case CMD_DOWNSTREAM_NOT_RESPONDING: 00535 #ifdef GATEWAY 00536 downstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd, &up_info); 00537 #else 00538 downstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); 00539 #endif 00540 break; 00541 case CMD_REMOVE_DEVICE_REQ: 00542 case CMD_DISCOVERY_ANS: 00543 case CMD_USER_PAYLOAD_DN_REQ: 00544 upstream_req_rxDoneCB(rssi, snr, &rx_buf_idx, sending_id, cmd); 00545 break; 00546 } // ..switch (cmd) 00547 00548 } // ..for (rx_buf_idx = 9; rx_buf_idx < size; ) 00549 00550 if (reqFlags.bits.currentOp != CMD_DISCOVERY_ANS && reqFlags.bits.currentOp != CMD_DISCOVERY_REQ) { 00551 if (reqFlags.bits.txAns != NOT_ANSWERING) { 00552 queue.call(txAns, sending_id); // must return from this function prior to transmitting 00553 #ifdef MESH_DEBUG 00554 print_log_here = false; 00555 #endif /* MESH_DEBUG */ 00556 } else { 00557 Radio::Sleep(); 00558 start_periodic_rxing(0x20); // rxDone 00559 } 00560 } 00561 00562 done: 00563 #ifdef GATEWAY 00564 if (rx_hfg == 0) { 00565 Rx_log_printf("\e[31mrx_hfg:%u\e[0m ", rx_hfg); /* another gateway */ 00566 } else { 00567 Rx_log_printf("rx_hfg:%u ", rx_hfg); 00568 } 00569 #else 00570 Rx_log_printf("rx_hfg:%u ", rx_hfg); 00571 /* compare against attached upstream */ 00572 if (hops_from_gateway != HFG_UNATTACHED) 00573 upstream_signal_check(rssi, snr, rx_hfg, sending_id); 00574 #endif 00575 00576 #ifdef MESH_DEBUG 00577 if (print_log_here) 00578 queue.call_in(10, rx_log_print); 00579 // else txAns must be completed first, will be called from txAns 00580 #endif /* MESH_DEBUG */ 00581 00582 #ifdef GATEWAY 00583 if (up_info.originating_src_id != ID_NONE) { 00584 /* txAns takes priority over application layer */ 00585 queue.call(gateway_uplink, up_info.len, up_info.originating_src_id, &Radio::radio.rx_buf[up_info.rxBufIdx]); 00586 } 00587 #endif /* GATEWAY */ 00588 } // ..rxDoneCB() 00589 00590 void txTimeoutCB() 00591 { 00592 pc.printf("\e[41mTxTimeout\e[0m\r\n"); 00593 } 00594 00595 void rxTimeoutCB() 00596 { 00597 Radio::Sleep(); 00598 queue.call_in(WAKEUP_INTERVAL_MS, rxSingle); 00599 00600 if (flags.vacantCheck) { 00601 channelVacantCount++; 00602 if (flags.deferred_send) { 00603 uint8_t vc_thresh = CHANNEL_VACANT_REQUIRED_COUNT; 00604 if (attemptCnt > 1) { 00605 /* retry backoff */ 00606 vc_thresh += Radio::Random() % CHANNEL_VACANT_REQUIRED_COUNT; 00607 } 00608 if (channelVacantCount > vc_thresh) { 00609 _send_(); 00610 flags.deferred_send = 0; 00611 } 00612 } 00613 flags.vacantCheck = 0; 00614 } 00615 } 00616 00617 uint32_t find_dest_id(uint32_t reqid) 00618 { 00619 lid_list_t* L; 00620 for (L = attachedDevices; L != NULL; L = L->next) { 00621 if (L->id == reqid) 00622 return L->id; // is locally attached 00623 } 00624 00625 for (L = attachedDevices; L != NULL; L = L->next) { 00626 if (L->attachedList != NULL) { 00627 cid_list_t* children; 00628 for (children = L->attachedList; children != NULL; children = children->next) { 00629 if (children->id == reqid) 00630 return L->id; 00631 } 00632 } 00633 } 00634 return ID_NONE; 00635 } 00636 00637 void cmd_tx(uint8_t argsAt) 00638 { 00639 unsigned symbs; 00640 if (sscanf(pcbuf+argsAt, "%u", &symbs) == 1) { 00641 Radio::LoRaPacketConfig(symbs, false, true, false); // preambleLen, fixLen, crcOn, invIQ 00642 pc.printf("txing %u symbols\r\n", symbs); 00643 } 00644 00645 txBuf[txBuf_idx++] = CMD_UNUSED; 00646 tx_dest_id = ANY_ID; 00647 txBuf_send(false); 00648 } 00649 00650 void cmd_list_devices(uint8_t argsAt) 00651 { 00652 lid_list_t* L; 00653 pc.printf("my_id:%lx hops_from_gateway:%u\r\n", my_id, hops_from_gateway); 00654 for (L = attachedDevices; L != NULL; L = L->next) { 00655 pc.printf("%lx", L->id); 00656 if (L->attachedList != NULL) { 00657 cid_list_t* children; 00658 pc.printf(": "); 00659 for (children = L->attachedList; children != NULL; children = children->next) 00660 pc.printf("%lx ", children->id); 00661 } 00662 pc.printf("\r\n"); 00663 } 00664 } 00665 00666 void cmd_print_status(uint8_t idx) 00667 { 00668 radio_print_status(); 00669 00670 pc.printf("my_id:%lx hops_from_gateway:%u\r\n", my_id, hops_from_gateway); 00671 pc.printf("ClearChan%u reqFlags:%02x ", channelVacantCount, reqFlags.octet); 00672 #ifndef GATEWAY 00673 upstream_print_status(); 00674 #endif /* GATEWAY */ 00675 pc.printf("\r\n"); 00676 } 00677 00678 typedef struct { 00679 const char* const cmd; 00680 void (*handler)(uint8_t args_at); 00681 const char* const arg_descr; 00682 const char* const description; 00683 } menu_item_t; 00684 00685 void cmd_help(uint8_t); 00686 00687 const menu_item_t menu_items[] = { 00688 { ".", cmd_print_status, "","print status"}, 00689 { "op", cmd_op, "%u","get/set tx power"}, 00690 #ifdef GATEWAY 00691 { "dl", cmd_downlink, "%x %x...","send downlink <destIDhex> <payload bytes hex>"}, 00692 #endif /* GATEWAY */ 00693 { "ls", cmd_list_devices, "%u","list seen downstream devices"}, 00694 { "tx", cmd_tx, "%u","tx test preamble length"}, 00695 { "?", cmd_help, "","this list of commands"}, 00696 { NULL, NULL, NULL, NULL } 00697 }; 00698 00699 void cmd_help(uint8_t args_at) 00700 { 00701 int i; 00702 00703 for (i = 0; menu_items[i].cmd != NULL ; i++) { 00704 printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description); 00705 } 00706 } 00707 00708 void console() 00709 { 00710 uint8_t i, user_cmd_len; 00711 00712 if (pcbuf_len == 0) 00713 return; 00714 00715 printf("\r\n"); 00716 00717 /* get end of user-entered command */ 00718 user_cmd_len = 1; // first character can be any character 00719 for (i = 1; i <= pcbuf_len; i++) { 00720 if (pcbuf[i] < 'A' || (pcbuf[i] > 'Z' && pcbuf[i] < 'a') || pcbuf[i] > 'z') { 00721 user_cmd_len = i; 00722 break; 00723 } 00724 } 00725 00726 for (i = 0; menu_items[i].cmd != NULL ; i++) { 00727 int mi_len = strlen(menu_items[i].cmd); 00728 if (menu_items[i].handler && user_cmd_len == mi_len && (strncmp(pcbuf, menu_items[i].cmd, mi_len) == 0)) { 00729 while (pcbuf[mi_len] == ' ') // skip past spaces 00730 mi_len++; 00731 menu_items[i].handler(mi_len); 00732 break; 00733 } 00734 } 00735 00736 pcbuf_len = 0; 00737 printf("> "); 00738 fflush(stdout); 00739 } 00740 00741 void radio_irq_topHalf() 00742 { 00743 /* isr context -> main loop context */ 00744 queue.call(Radio::service); 00745 } 00746 00747 const RadioEvents_t rev = { 00748 /* DioPin_top_half */ radio_irq_topHalf, 00749 /* TxDone_topHalf */ NULL, 00750 /* TxDone_botHalf */ txDoneCB, 00751 /* TxTimeout */ txTimeoutCB, 00752 /* RxDone */ rxDoneCB, 00753 /* RxTimeout */ rxTimeoutCB, 00754 /* RxError */ NULL, 00755 /* FhssChangeChannel */NULL, 00756 /* CadDone */ NULL 00757 }; 00758 00759 void rx_callback() 00760 { 00761 static uint8_t pcbuf_idx = 0; 00762 static uint8_t prev_len = 0; 00763 char c = pc.getc(); 00764 if (c == 8) { 00765 if (pcbuf_idx > 0) { 00766 pc.putc(8); 00767 pc.putc(' '); 00768 pc.putc(8); 00769 pcbuf_idx--; 00770 } 00771 } else if (c == 3) { // ctrl-C 00772 pcbuf_len = -1; 00773 } else if (c == '\r') { 00774 if (pcbuf_idx == 0) { 00775 pcbuf_len = prev_len; 00776 } else { 00777 pcbuf[pcbuf_idx] = 0; // null terminate 00778 prev_len = pcbuf_idx; 00779 pcbuf_idx = 0; 00780 pcbuf_len = prev_len; 00781 } 00782 queue.call(console); 00783 } else if (pcbuf_idx < sizeof(pcbuf)) { 00784 pcbuf[pcbuf_idx++] = c; 00785 pc.putc(c); 00786 } 00787 } 00788 00789 int main() 00790 { 00791 pc.baud(115200); 00792 pc.printf("\r\nreset\r\n"); 00793 pc.attach(rx_callback); 00794 00795 { 00796 uint32_t u32; 00797 #ifdef TARGET_FAMILY_STM32 00798 u32 = LL_GetUID_Word0(); 00799 u32 <<= 2; 00800 u32 ^= LL_GetUID_Word1(); 00801 u32 ^= LL_GetUID_Word2(); 00802 #else 00803 #error TODO_nSTM32 00804 #endif 00805 my_id = u32; 00806 pc.printf("my_id %lx\r\n", my_id); 00807 } 00808 00809 wait_ms(200); // power stabilization from cold-reset 00810 Radio::Init(&rev); 00811 00812 rxdbg = 0; 00813 Radio::Standby(); 00814 Radio::LoRaModemConfig(BW_KHZ, SPREADING_FACTOR, 1); 00815 Radio::SetChannel(CF_MHZ * 1000000); 00816 Radio::set_tx_dbm(TX_DBM); 00817 #ifdef SX126x_H 00818 { 00819 status_t status; 00820 uint8_t stopOnPreamble = 1; 00821 00822 Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet); 00823 wait_ms(20); 00824 Radio::radio.xfer(OPCODE_STOP_TIMER_ON_PREAMBLE, 1, 0, &stopOnPreamble); 00825 } 00826 #endif /* SX126x_H */ 00827 00828 setPreambleSize(false, 4); //init 00829 { 00830 unsigned daDur = Radio::lora_toa_us(DISCOVERY_ANS_LENGTH); 00831 discovery_ans_time_step_us = daDur + (ANS_PAD_MS * 1000); // + padding for receiver handling 00832 discovery_ans_time_total_us = discovery_ans_time_step_us * N_DISCOVERY_ANS; 00833 } 00834 00835 #ifdef SX128x_H 00836 /* C preprocess doesnt do floating point */ 00837 if (N_PRE_SYMB > 255) { 00838 pc.printf("\e[41mlong preamble oversized %.1f\e[0m\r\n", N_PRE_SYMB); 00839 } 00840 #endif /* ..SX128x_H */ 00841 00842 #ifdef GATEWAY 00843 start_periodic_rxing(0x10); // gateway startup 00844 #else 00845 init_attached_upstream(); 00846 hops_from_gateway = HFG_UNATTACHED; 00847 upstream_init(); 00848 #endif 00849 00850 app_init(); 00851 fwd.len = -1; 00852 00853 /* if (!sleep_manager_can_deep_sleep()) { 00854 sleep_manager_unlock_deep_sleep(); 00855 pc.printf("unLockDeepSleep\r\n"); 00856 }*/ 00857 00858 queue.dispatch(); 00859 } // ..main() 00860
Generated on Fri Jul 15 2022 20:28:20 by 1.7.2