wayne roberts
/
CB-LORA-MR_utility
test sending sensor results over lora radio. Accelerometer and temp/pressure.
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 #include "mbed.h" 00002 #include "radio.h" 00003 #include "demo.h" 00004 00005 bool svc_lis2dh12; 00006 //#define MENU_DEBUG 00007 00008 RawSerial pc(USBTX, USBRX); 00009 00010 menuState_t menuState; 00011 00012 typedef enum { 00013 MSG_TYPE_PACKET = 0, 00014 MSG_TYPE_PER, 00015 MSG_TYPE_PINGPONG 00016 } msgType_e; 00017 00018 enum { 00019 CMD_TEMP, 00020 CMD_PRES, 00021 CMD_ACCEL, 00022 CMD_PHOTOS, 00023 CMD_NONE 00024 }; 00025 00026 #define MAX_MENU_ROWS 16 00027 // [row][column] 00028 const menu_t* menu_table[MAX_MENU_ROWS][MAX_MENU_COLUMNS]; 00029 int8_t StopMenuCols[MAX_MENU_ROWS]; 00030 00031 //#define SCROLLING_ROWS 20 00032 #define SCROLLING_ROWS 30 00033 00034 struct _cp_ { 00035 uint8_t row; 00036 uint8_t tableCol; 00037 } curpos; 00038 00039 uint8_t entry_buf_idx; 00040 char entry_buf[64]; 00041 00042 msgType_e msg_type = MSG_TYPE_PACKET; 00043 00044 const uint8_t PingMsg[] = "PING"; 00045 const uint8_t PongMsg[] = "PONG"; 00046 const uint8_t PerMsg[] = "PER"; 00047 00048 volatile struct _flags_ { 00049 uint8_t ping_master : 1; // 0 00050 uint8_t send_ping : 1; // 1 00051 uint8_t send_pong : 1; // 2 00052 uint8_t pingpongEnable : 1; // 3 00053 uint8_t do_next_tx : 1; // 4 00054 uint8_t txBusy : 1; // 5 00055 uint8_t measure_tx : 1; // 5 00056 } flags; 00057 00058 uint8_t botRow; 00059 int regAddr = -1; 00060 00061 #define PHOTOS_PIN PA_0 00062 /* 00063 * available pins PA_0, PA_1, PA_2, PA_3, PA_4, PA_5, PA_6, PA_7, PB_0, PB_1, PC_0, PC_1, PC_2 00064 */ 00065 #ifdef PHOTOS_PIN 00066 AnalogIn photos(PHOTOS_PIN); 00067 #endif /* PHOTOS_PIN */ 00068 00069 #define UART_RX_BUF_LEN 8 00070 uint8_t uart_rx_buf[UART_RX_BUF_LEN]; 00071 volatile uint8_t uart_rx_buf_in; 00072 volatile uint8_t uart_rx_buf_out; 00073 bool accel_tx_en; 00074 00075 #ifdef MENU_DEBUG 00076 char wait_uart_rx() 00077 { 00078 char ret; 00079 unsigned foo = uart_rx_buf_in; 00080 while (uart_rx_buf_in == foo) { 00081 asm("nop"); 00082 } 00083 00084 ret = uart_rx_buf[uart_rx_buf_out++]; 00085 if (uart_rx_buf_out == UART_RX_BUF_LEN) 00086 uart_rx_buf_out = 0; 00087 00088 return ret; 00089 } 00090 #endif /* MENU_DEBUG */ 00091 00092 unsigned lfsr; 00093 #define LFSR_INIT 0x1ff 00094 00095 uint8_t get_pn9_byte() 00096 { 00097 uint8_t ret = 0; 00098 int xor_out; 00099 00100 xor_out = ((lfsr >> 5) & 0xf) ^ (lfsr & 0xf); // four bits at a time 00101 lfsr = (lfsr >> 4) | (xor_out << 5); // four bits at a time 00102 00103 ret |= (lfsr >> 5) & 0x0f; 00104 00105 xor_out = ((lfsr >> 5) & 0xf) ^ (lfsr & 0xf); // four bits at a time 00106 lfsr = (lfsr >> 4) | (xor_out << 5); // four bits at a time 00107 00108 ret |= ((lfsr >> 1) & 0xf0); 00109 00110 return ret; 00111 } 00112 00113 void hw_reset_push() 00114 { 00115 Radio::hw_reset(); 00116 00117 Radio::readChip(); 00118 menuState.mode = MENUMODE_REINIT_MENU; 00119 } 00120 00121 const button_item_t hw_reset_item = { _ITEM_BUTTON, "hw_reset", hw_reset_push }; 00122 00123 void clearIrqs_push() 00124 { 00125 Radio::clearIrqFlags(); 00126 } 00127 00128 const button_item_t clearirqs_item = { _ITEM_BUTTON, "clearIrqs", clearIrqs_push }; 00129 00130 const dropdown_item_t pktType_item = { _ITEM_DROPDOWN, Radio::pktType_strs, Radio::pktType_strs, Radio::pktType_read, Radio::pktType_write}; 00131 00132 00133 unsigned msgType_read(bool fw) 00134 { 00135 return msg_type; 00136 } 00137 00138 menuMode_e msgType_write(unsigned widx) 00139 { 00140 msg_type = (msgType_e)widx; 00141 00142 if (msg_type == MSG_TYPE_PER) { 00143 flags.pingpongEnable = 0; 00144 if (Radio::get_payload_length() < 7) 00145 Radio::set_payload_length(7); 00146 } else if (msg_type == MSG_TYPE_PINGPONG) { 00147 if (Radio::get_payload_length() != 12) 00148 Radio::set_payload_length(12); 00149 } else if (msg_type == MSG_TYPE_PACKET) { 00150 flags.pingpongEnable = 0; 00151 } 00152 00153 return MENUMODE_REINIT_MENU; 00154 } 00155 00156 const char* const msgType_strs[] = { 00157 "PACKET ", 00158 "PER ", 00159 "PINGPONG", 00160 NULL 00161 }; 00162 00163 const dropdown_item_t msgType_item = { _ITEM_DROPDOWN, msgType_strs, msgType_strs, msgType_read, msgType_write}; 00164 00165 #define LAST_CHIP_MENU_ROW (MAX_MENU_ROWS-5) 00166 00167 const value_item_t tx_payload_length_item = { _ITEM_VALUE, 5, Radio::tx_payload_length_print, Radio::tx_payload_length_write}; 00168 00169 void pn9_push() 00170 { 00171 uint8_t i, len = Radio::get_payload_length(); 00172 for (i = 0; i < len; i++) 00173 Radio::radio.tx_buf[i] = get_pn9_byte(); 00174 } 00175 00176 const button_item_t tx_payload_pn9_item = { _ITEM_BUTTON, "PN9", pn9_push }; 00177 00178 void regAddr_print() 00179 { 00180 if (regAddr != -1) 00181 pc.printf("%x", regAddr); 00182 } 00183 00184 bool regAddr_write(const char* txt) 00185 { 00186 sscanf(txt, "%x", ®Addr); 00187 return false; 00188 } 00189 00190 const value_item_t regAddr_item = { _ITEM_VALUE, 5, regAddr_print, regAddr_write}; 00191 00192 void regValue_print() 00193 { 00194 if (regAddr != -1) { 00195 pc.printf("%x", Radio::read_register(regAddr)); 00196 } 00197 } 00198 00199 bool regValue_write(const char* txt) 00200 { 00201 unsigned val; 00202 sscanf(txt, "%x", &val); 00203 if (regAddr != -1) { 00204 Radio::write_register(regAddr, val); 00205 } 00206 return false; 00207 } 00208 00209 const value_item_t regValue_item = { _ITEM_VALUE, 5, regValue_print, regValue_write}; 00210 00211 void tx_payload_print() 00212 { 00213 uint8_t i, len = Radio::get_payload_length(); 00214 for (i = 0; i < len; i++) 00215 pc.printf("%02x ", Radio::radio.tx_buf[i]); 00216 } 00217 00218 bool tx_payload_write(const char* txt) 00219 { 00220 unsigned o, i = 0, pktidx = 0; 00221 while (i < entry_buf_idx) { 00222 sscanf(entry_buf+i, "%02x", &o); 00223 pc.printf("%02x ", o); 00224 i += 2; 00225 Radio::radio.tx_buf[pktidx++] = o; 00226 while (entry_buf[i] == ' ' && i < entry_buf_idx) 00227 i++; 00228 } 00229 log_printf("set payload len %u\r\n", pktidx); 00230 Radio::set_payload_length(pktidx); 00231 return true; 00232 } 00233 00234 const value_item_t tx_payload_item = { _ITEM_VALUE, 80, tx_payload_print, tx_payload_write}; 00235 00236 void txpkt_push() 00237 { 00238 Radio::txPkt(); 00239 } 00240 00241 const button_item_t tx_pkt_item = { _ITEM_BUTTON, "TXPKT", txpkt_push }; 00242 00243 void rxpkt_push() 00244 { 00245 Radio::Rx(); 00246 menuState.mode = MENUMODE_REDRAW; 00247 } 00248 const button_item_t rx_pkt_item = { _ITEM_BUTTON, "RXPKT", rxpkt_push }; 00249 00250 const dropdown_item_t opmode_item = { _ITEM_DROPDOWN, Radio::opmode_status_strs, Radio::opmode_select_strs, Radio::opmode_read, Radio::opmode_write }; 00251 00252 void tx_carrier_push() 00253 { 00254 Radio::tx_carrier(); 00255 } 00256 const button_item_t tx_carrier_item = { _ITEM_BUTTON, "TX_CARRIER", tx_carrier_push }; 00257 00258 void tx_preamble_push() 00259 { 00260 Radio::tx_preamble(); 00261 } 00262 const button_item_t tx_preamble_item = { _ITEM_BUTTON, "TX_PREAMBLE", tx_preamble_push }; 00263 00264 bool accel_en_read() 00265 { 00266 uint8_t status; 00267 accel_is_enabled(&status); 00268 return status; 00269 } 00270 00271 bool accel_tx_en_read() 00272 { 00273 uint8_t status; 00274 accel_is_enabled(&status); 00275 return status && accel_tx_en; 00276 } 00277 00278 00279 bool accel_en_push() 00280 { 00281 uint8_t status; 00282 accel_is_enabled(&status); 00283 00284 accel_tx_en = false; 00285 if (status) 00286 accel_enable(false); 00287 else 00288 accel_enable(true); 00289 00290 accel_is_enabled(&status); 00291 return status; 00292 } 00293 00294 bool accel_tx_en_push() 00295 { 00296 uint8_t status; 00297 accel_is_enabled(&status); 00298 00299 accel_tx_en = true; 00300 if (status) 00301 accel_enable(false); 00302 else 00303 accel_enable(true); 00304 00305 accel_is_enabled(&status); 00306 return status; 00307 } 00308 00309 const toggle_item_t accel_enable_item = { _ITEM_TOGGLE, "enable", NULL, accel_en_read, accel_en_push}; 00310 const toggle_item_t accel_tx_enable_item = { _ITEM_TOGGLE, "tx_enable", NULL, accel_tx_en_read, accel_tx_en_push}; 00311 00312 const menu_t lis12dh12_menu[] = { 00313 { {LAST_CHIP_MENU_ROW-1, 1}, "LIS12DH12 ", &accel_enable_item, FLAG_MSGTYPE_ALL }, 00314 { {LAST_CHIP_MENU_ROW-1, 24}, NULL, &accel_tx_enable_item, FLAG_MSGTYPE_ALL }, 00315 { {0, 0}, NULL, NULL } 00316 }; 00317 00318 00319 #ifdef PHOTOS_PIN 00320 void photos_push() 00321 { 00322 uint16_t val = photos.read_u16(); 00323 log_printf("photos %u\r\n", val); 00324 } 00325 00326 void photos_tx() 00327 { 00328 uint16_t val; 00329 val = photos.read_u16(); 00330 log_printf("Tx photos %u\r\n", val); 00331 Radio::radio.tx_buf[0] = CMD_PHOTOS; 00332 Radio::set_payload_length(sizeof(uint16_t)+1); 00333 memcpy(&Radio::radio.tx_buf[1], &val, sizeof(uint16_t)); 00334 00335 flags.txBusy = true; 00336 Radio::txPkt(); 00337 } 00338 00339 unsigned pollTickerRate; 00340 Ticker pollTicker; 00341 uint8_t enabledSensor = CMD_NONE; 00342 00343 void tx_photos_push() 00344 { 00345 if (pollTickerRate > 0) { 00346 if (enabledSensor != CMD_PHOTOS) 00347 enabledSensor = CMD_PHOTOS; 00348 else { 00349 enabledSensor = CMD_NONE; 00350 } 00351 return; 00352 } 00353 00354 photos_tx(); 00355 } 00356 00357 const button_item_t photos_item = { _ITEM_BUTTON, "photos", photos_push }; 00358 const button_item_t tx_photos_item = { _ITEM_BUTTON, "tx_photos", tx_photos_push }; 00359 00360 const menu_t photos_menu[] = { 00361 { {(LAST_CHIP_MENU_ROW-2), 1}, "PHOTOS ", &photos_item, FLAG_MSGTYPE_ALL }, 00362 { {(LAST_CHIP_MENU_ROW-2), 24}, NULL, &tx_photos_item, FLAG_MSGTYPE_ALL }, 00363 { {0, 0}, NULL, NULL } 00364 }; 00365 #endif /* PHOTOS_PIN */ 00366 00367 void temperature_push() 00368 { 00369 displayFloatToInt_t val; 00370 demo_sample_temp(&val); 00371 } 00372 00373 void pressure_push() 00374 { 00375 displayFloatToInt_t val; 00376 demo_sample_pressure(&val); 00377 } 00378 00379 void temp_tx() 00380 { 00381 displayFloatToInt_t val; 00382 demo_sample_temp(&val); 00383 00384 Radio::set_payload_length(sizeof(displayFloatToInt_t)+1); 00385 00386 Radio::radio.tx_buf[0] = CMD_TEMP; 00387 memcpy(&Radio::radio.tx_buf[1], &val, sizeof(displayFloatToInt_t)); 00388 00389 flags.txBusy = true; 00390 Radio::txPkt(); 00391 } 00392 00393 void tx_temp_push() 00394 { 00395 if (pollTickerRate > 0) { 00396 if (enabledSensor != CMD_TEMP) 00397 enabledSensor = CMD_TEMP; 00398 else { 00399 enabledSensor = CMD_NONE; 00400 } 00401 return; 00402 } 00403 00404 temp_tx(); 00405 } 00406 00407 void pres_tx() 00408 { 00409 displayFloatToInt_t val; 00410 demo_sample_pressure(&val); 00411 00412 Radio::set_payload_length(sizeof(displayFloatToInt_t)+1); 00413 00414 Radio::radio.tx_buf[0] = CMD_PRES; 00415 memcpy(&Radio::radio.tx_buf[1], &val, sizeof(displayFloatToInt_t)); 00416 00417 flags.txBusy = true; 00418 Radio::txPkt(); 00419 } 00420 00421 void tx_pressure_push() 00422 { 00423 if (pollTickerRate > 0) { 00424 if (enabledSensor != CMD_PRES) 00425 enabledSensor = CMD_PRES; 00426 else { 00427 enabledSensor = CMD_NONE; 00428 } 00429 return; 00430 } 00431 00432 pres_tx(); 00433 } 00434 00435 void sensorPoll() 00436 { 00437 if (!flags.txBusy && menuState.mode == MENUMODE_NONE) 00438 flags.measure_tx = 1; 00439 } 00440 00441 void pollRate_print() 00442 { 00443 pc.printf("%ums", pollTickerRate / 1000); 00444 } 00445 00446 bool pollRate_write(const char* str) 00447 { 00448 sscanf(str, "%u", &pollTickerRate); 00449 00450 if (pollTickerRate > 0) { 00451 pollTickerRate *= 1000; 00452 pollTicker.attach_us(sensorPoll, pollTickerRate); 00453 } else 00454 pollTicker.detach(); 00455 00456 log_printf("pollTickerRate %uus\r\n", pollTickerRate); 00457 00458 return false; 00459 } 00460 00461 const button_item_t temperature_item = { _ITEM_BUTTON, "temperature", temperature_push }; 00462 const button_item_t pressure_item = { _ITEM_BUTTON, "pressure", pressure_push }; 00463 const button_item_t tx_temp_item = { _ITEM_BUTTON, "tx_temp", tx_temp_push }; 00464 const button_item_t tx_pressure_item = { _ITEM_BUTTON, "tx_pressure", tx_pressure_push }; 00465 const value_item_t pollRate_item = { _ITEM_VALUE, 8, pollRate_print, pollRate_write }; 00466 00467 const menu_t lps22hh_menu[] = { 00468 { {LAST_CHIP_MENU_ROW, 1}, "LPS22HH ", &temperature_item, FLAG_MSGTYPE_ALL }, 00469 { {LAST_CHIP_MENU_ROW, 22}, NULL, &pressure_item, FLAG_MSGTYPE_ALL }, 00470 { {LAST_CHIP_MENU_ROW, 31}, NULL, &tx_temp_item, FLAG_MSGTYPE_ALL }, 00471 { {LAST_CHIP_MENU_ROW, 40}, NULL, &tx_pressure_item, FLAG_MSGTYPE_ALL }, 00472 { {LAST_CHIP_MENU_ROW, 53}, "poll rate:", &pollRate_item, FLAG_MSGTYPE_ALL }, 00473 { {0, 0}, NULL, NULL } 00474 }; 00475 00476 const menu_t msg_pkt_menu[] = { 00477 { {LAST_CHIP_MENU_ROW+1, 1}, "tx payload length:", &tx_payload_length_item, FLAG_MSGTYPE_PKT }, 00478 { {LAST_CHIP_MENU_ROW+1, 25}, NULL, &tx_payload_pn9_item, FLAG_MSGTYPE_PKT, &tx_payload_item }, 00479 { {LAST_CHIP_MENU_ROW+1, 40}, "regAddr:", ®Addr_item, FLAG_MSGTYPE_PKT, ®Value_item }, 00480 { {LAST_CHIP_MENU_ROW+1, 53}, "regValue:", ®Value_item, FLAG_MSGTYPE_PKT, }, 00481 { {LAST_CHIP_MENU_ROW+2, 1}, NULL, &tx_payload_item, FLAG_MSGTYPE_PKT }, 00482 { {LAST_CHIP_MENU_ROW+3, 1}, NULL, &tx_pkt_item, FLAG_MSGTYPE_PKT, &opmode_item }, 00483 { {LAST_CHIP_MENU_ROW+3, 10}, NULL, &rx_pkt_item, FLAG_MSGTYPE_PKT }, 00484 { {LAST_CHIP_MENU_ROW+3, 20}, NULL, &tx_carrier_item, FLAG_MSGTYPE_PKT, &opmode_item }, 00485 { {LAST_CHIP_MENU_ROW+3, 45}, NULL, &tx_preamble_item, FLAG_MSGTYPE_PKT, &opmode_item }, 00486 00487 { {0, 0}, NULL, NULL } 00488 }; 00489 00490 unsigned tx_ipd_ms; 00491 Timeout mbedTimeout; 00492 unsigned MaxNumPacket; 00493 unsigned CntPacketTx; 00494 unsigned PacketRxSequencePrev; 00495 unsigned CntPacketRxKO; 00496 unsigned CntPacketRxOK; 00497 unsigned RxTimeOutCount; 00498 unsigned receivedCntPacket; 00499 00500 void do_next_tx () 00501 { 00502 Radio::radio.tx_buf[0] = CntPacketTx >> 24; 00503 Radio::radio.tx_buf[1] = CntPacketTx >> 16; 00504 Radio::radio.tx_buf[2] = CntPacketTx >> 8; 00505 Radio::radio.tx_buf[3] = CntPacketTx; 00506 00507 Radio::radio.tx_buf[4] = PerMsg[0]; 00508 Radio::radio.tx_buf[5] = PerMsg[1]; 00509 Radio::radio.tx_buf[6] = PerMsg[2]; 00510 00511 Radio::txPkt(); 00512 } 00513 00514 void next_tx_callback() 00515 { 00516 flags.do_next_tx = 1; 00517 } 00518 00519 00520 void pertx_push() 00521 { 00522 CntPacketTx = 1; // PacketRxSequencePrev initialized to 0 on receiver 00523 00524 log_printf("do perTx\r\n"); 00525 00526 next_tx_callback(); 00527 } 00528 00529 00530 const button_item_t pertx_item = { _ITEM_BUTTON, "PERTX", pertx_push }; 00531 00532 void tx_ipd_print() 00533 { 00534 pc.printf("%u", tx_ipd_ms); 00535 } 00536 00537 bool tx_ipd_write(const char* valStr) 00538 { 00539 sscanf(valStr, "%u", &tx_ipd_ms); 00540 return false; 00541 } 00542 00543 value_item_t per_ipd_item = { _ITEM_VALUE, 4, tx_ipd_print, tx_ipd_write }; 00544 00545 void numpkts_print() 00546 { 00547 pc.printf("%u", MaxNumPacket); 00548 } 00549 00550 bool numpkts_write(const char* valStr) 00551 { 00552 sscanf(valStr, "%u", &MaxNumPacket); 00553 return false; 00554 } 00555 00556 value_item_t per_numpkts_item = { _ITEM_VALUE, 6, numpkts_print, numpkts_write }; 00557 00558 void perrx_push() 00559 { 00560 PacketRxSequencePrev = 0; 00561 CntPacketRxKO = 0; 00562 CntPacketRxOK = 0; 00563 RxTimeOutCount = 0; 00564 00565 Radio::Rx(); 00566 } 00567 00568 const button_item_t perrx_item = { _ITEM_BUTTON, "PERRX", perrx_push }; 00569 00570 void per_reset_push() 00571 { 00572 PacketRxSequencePrev = 0; 00573 CntPacketRxKO = 0; 00574 CntPacketRxOK = 0; 00575 RxTimeOutCount = 0; 00576 } 00577 00578 const button_item_t per_clear_item = { _ITEM_BUTTON, "resetCount", per_reset_push }; 00579 00580 const menu_t msg_per_menu[] = { 00581 { {LAST_CHIP_MENU_ROW+3, 1}, NULL, &pertx_item, FLAG_MSGTYPE_PER }, 00582 { {LAST_CHIP_MENU_ROW+3, 12}, "TX IPD ms:", &per_ipd_item, FLAG_MSGTYPE_PER }, 00583 { {LAST_CHIP_MENU_ROW+3, 26}, "numPkts:", &per_numpkts_item, FLAG_MSGTYPE_PER }, 00584 { {LAST_CHIP_MENU_ROW+3, 40}, NULL, &perrx_item, FLAG_MSGTYPE_PER, &opmode_item }, 00585 { {LAST_CHIP_MENU_ROW+3, 50}, NULL, &per_clear_item, FLAG_MSGTYPE_PER, &opmode_item }, 00586 { {0, 0}, NULL, NULL } 00587 }; 00588 00589 void SendPong() 00590 { 00591 unsigned failCnt = CntPacketRxKO + RxTimeOutCount; 00592 00593 /* ping slave tx */ 00594 log_printf("ACK PKT%u\r\n", receivedCntPacket); 00595 00596 Radio::radio.tx_buf[ 0] = receivedCntPacket >> 24; 00597 Radio::radio.tx_buf[ 1] = receivedCntPacket >> 16; 00598 Radio::radio.tx_buf[ 2] = receivedCntPacket >> 8; 00599 Radio::radio.tx_buf[ 3] = receivedCntPacket; 00600 Radio::radio.tx_buf[ 4] = failCnt >> 24; 00601 Radio::radio.tx_buf[ 5] = failCnt >> 16; 00602 Radio::radio.tx_buf[ 6] = failCnt >> 8; 00603 Radio::radio.tx_buf[ 7] = failCnt; 00604 Radio::radio.tx_buf[ 8] = PongMsg[0]; 00605 Radio::radio.tx_buf[ 9] = PongMsg[1]; 00606 Radio::radio.tx_buf[10] = PongMsg[2]; 00607 Radio::radio.tx_buf[11] = PongMsg[3]; 00608 00609 Radio::txPkt(); 00610 } 00611 00612 void SendPing() 00613 { 00614 /* ping master tx */ 00615 00616 log_printf("MASTER > PING PKT%u\r\n", CntPacketTx); 00617 Radio::radio.tx_buf[0] = CntPacketTx >> 24; 00618 Radio::radio.tx_buf[1] = CntPacketTx >> 16; 00619 Radio::radio.tx_buf[2] = CntPacketTx >> 8; 00620 Radio::radio.tx_buf[3] = CntPacketTx; 00621 Radio::radio.tx_buf[4] = PingMsg[0]; 00622 Radio::radio.tx_buf[5] = PingMsg[1]; 00623 Radio::radio.tx_buf[6] = PingMsg[2]; 00624 Radio::radio.tx_buf[7] = PingMsg[3]; 00625 00626 Radio::txPkt(); 00627 } 00628 00629 void 00630 pingpong_start_push() 00631 { 00632 CntPacketTx = 1; 00633 CntPacketRxKO = 0; 00634 CntPacketRxOK = 0; 00635 RxTimeOutCount = 0; 00636 receivedCntPacket = 0; 00637 00638 flags.send_ping = 1; 00639 00640 flags.ping_master = 1; 00641 00642 flags.pingpongEnable = 1; 00643 log_printf("ping start\r\n"); 00644 } 00645 00646 const button_item_t pingpong_start_item = { _ITEM_BUTTON, "START", pingpong_start_push }; 00647 00648 void 00649 pingpong_stop_push () 00650 { 00651 flags.pingpongEnable = 0; 00652 } 00653 00654 const button_item_t pingpong_stop_item = { _ITEM_BUTTON, "STOP", pingpong_stop_push }; 00655 00656 const menu_t msg_pingpong_menu[] = { 00657 { {LAST_CHIP_MENU_ROW+3, 1}, NULL, &pingpong_start_item, FLAG_MSGTYPE_PING }, 00658 { {LAST_CHIP_MENU_ROW+3, 15}, NULL, &pingpong_stop_item, FLAG_MSGTYPE_PING }, 00659 { {0, 0}, NULL, NULL } 00660 }; 00661 00662 const menu_t* get_msg_menu() 00663 { 00664 switch (msg_type) { 00665 case MSG_TYPE_PACKET: 00666 return msg_pkt_menu; 00667 case MSG_TYPE_PER: 00668 return msg_per_menu; 00669 case MSG_TYPE_PINGPONG: 00670 return msg_pingpong_menu; 00671 } 00672 return NULL; 00673 } 00674 00675 void frf_print() 00676 { 00677 float MHz; 00678 #ifdef SX127x_H 00679 MHz = Radio::radio.get_frf_MHz(); 00680 #else 00681 MHz = Radio::radio.getMHz(); 00682 #endif 00683 pc.printf("%.3fMHz", MHz); 00684 } 00685 00686 bool frf_write(const char* valStr) 00687 { 00688 float MHz; 00689 sscanf(valStr, "%f", &MHz); 00690 #ifdef SX127x_H 00691 Radio::radio.set_frf_MHz(MHz); 00692 #else 00693 Radio::radio.setMHz(MHz); 00694 #endif 00695 return false; 00696 } 00697 00698 const value_item_t frf_item = { _ITEM_VALUE, 14, frf_print, frf_write }; 00699 00700 const value_item_t Radio::tx_dbm_item = { _ITEM_VALUE, 7, Radio::tx_dbm_print, Radio::tx_dbm_write }; 00701 00702 const dropdown_item_t tx_ramp_item = { _ITEM_DROPDOWN, Radio::tx_ramp_strs, Radio::tx_ramp_strs, Radio::tx_ramp_read, Radio::tx_ramp_write }; 00703 00704 const button_item_t chipNum_item = { _ITEM_BUTTON, Radio::chipNum_str, NULL}; 00705 00706 void botrow_print() 00707 { 00708 pc.printf("%u", botRow); 00709 } 00710 00711 bool botrow_write(const char* str) 00712 { 00713 unsigned n; 00714 sscanf(str, "%u", &n); 00715 botRow = n; 00716 00717 pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region 00718 00719 return false; 00720 } 00721 00722 const value_item_t bottomRow_item = { _ITEM_VALUE, 4, botrow_print, botrow_write }; 00723 00724 const menu_t common_menu[] = { 00725 { {1, 1}, NULL, &hw_reset_item, FLAG_MSGTYPE_ALL }, 00726 { {1, 15}, "packetType:", &pktType_item, FLAG_MSGTYPE_ALL }, 00727 { {1, 37}, NULL, &msgType_item, FLAG_MSGTYPE_ALL }, 00728 { {1, 50}, NULL, &chipNum_item, FLAG_MSGTYPE_ALL }, 00729 { {1, 60}, "bottomRow:", &bottomRow_item, FLAG_MSGTYPE_ALL }, 00730 { {2, 1}, NULL, &frf_item, FLAG_MSGTYPE_ALL }, 00731 { {2, 15}, "TX dBm:", &Radio::tx_dbm_item, FLAG_MSGTYPE_ALL }, 00732 { {2, 30}, "ramp us:", &tx_ramp_item, FLAG_MSGTYPE_ALL }, 00733 { {2, 45}, NULL, &clearirqs_item, FLAG_MSGTYPE_ALL }, 00734 { {2, 55}, "opmode:", &opmode_item, FLAG_MSGTYPE_ALL }, 00735 00736 00737 { {0, 0}, NULL, NULL } 00738 }; 00739 00740 bool 00741 is_menu_item_changable(uint8_t table_row, uint8_t table_col) 00742 { 00743 const menu_t* m = menu_table[table_row][table_col]; 00744 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 00745 00746 switch (msg_type) { 00747 case MSG_TYPE_PACKET: 00748 if (m->flags & FLAG_MSGTYPE_PKT) 00749 break; 00750 else 00751 return false; 00752 case MSG_TYPE_PER: 00753 if (m->flags & FLAG_MSGTYPE_PER) 00754 break; 00755 else 00756 return false; 00757 case MSG_TYPE_PINGPONG: 00758 if (m->flags & FLAG_MSGTYPE_PING) 00759 break; 00760 else 00761 return false; 00762 } 00763 00764 if (di->itemType == _ITEM_DROPDOWN) { 00765 if (di->selectable_strs == NULL || di->selectable_strs[0] == NULL) { 00766 log_printf("NULLstrs%u,%u\r\n", table_row, table_col); 00767 return false; 00768 } 00769 } else if (di->itemType == _ITEM_VALUE) { 00770 const value_item_t* vi = (const value_item_t*)m->itemPtr; 00771 if (vi->write == NULL) 00772 return false; 00773 } else if (di->itemType == _ITEM_BUTTON) { 00774 const button_item_t* bi = (const button_item_t*)m->itemPtr; 00775 if (bi->push == NULL) 00776 return false; 00777 } else if (di->itemType == _ITEM_TOGGLE) { 00778 const toggle_item_t * ti = (const toggle_item_t *)m->itemPtr; 00779 if (ti->push == NULL) 00780 return false; 00781 } 00782 00783 return true; 00784 } // ..is_menu_item_changable() 00785 00786 void read_menu_item(const menu_t* m, bool selected) 00787 { 00788 uint8_t valCol; 00789 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 00790 00791 switch (msg_type) { 00792 case MSG_TYPE_PACKET: 00793 if (m->flags & FLAG_MSGTYPE_PKT) 00794 break; 00795 else 00796 return; 00797 case MSG_TYPE_PER: 00798 if (m->flags & FLAG_MSGTYPE_PER) 00799 break; 00800 else 00801 return; 00802 case MSG_TYPE_PINGPONG: 00803 if (m->flags & FLAG_MSGTYPE_PING) 00804 break; 00805 else 00806 return; 00807 } 00808 00809 pc.printf("\e[%u;%uf", m->pos.row, m->pos.col); // set (force) cursor to row;column 00810 valCol = m->pos.col; 00811 if (m->label) { 00812 pc.printf(m->label); 00813 valCol += strlen(m->label); 00814 } 00815 if (di->itemType == _ITEM_DROPDOWN) { 00816 if (di->read && di->printed_strs) { 00817 uint8_t ridx = di->read(false); 00818 if (selected) 00819 pc.printf("\e[7m"); 00820 pc.printf(di->printed_strs[ridx]); 00821 if (selected) 00822 pc.printf("\e[0m"); 00823 } else if (di->printed_strs) { 00824 pc.printf(di->printed_strs[0]); 00825 } 00826 } else if (di->itemType == _ITEM_VALUE) { 00827 const value_item_t* vi = (const value_item_t*)m->itemPtr; 00828 if (vi->print) { 00829 for (unsigned n = 0; n < vi->width; n++) 00830 pc.putc(' '); 00831 00832 pc.printf("\e[%u;%uf", m->pos.row, valCol); // set (force) cursor to row;column 00833 if (selected) 00834 pc.printf("\e[7m"); 00835 vi->print(); 00836 if (selected) 00837 pc.printf("\e[0m"); 00838 } 00839 } else if (di->itemType == _ITEM_BUTTON) { 00840 const button_item_t* bi = (const button_item_t*)m->itemPtr; 00841 if (bi->label) { 00842 if (selected) 00843 pc.printf("\e[7m%s\e[0m", bi->label); 00844 else 00845 pc.printf("%s", bi->label); 00846 } 00847 } else if (di->itemType == _ITEM_TOGGLE) { 00848 const toggle_item_t* ti = (const toggle_item_t *)m->itemPtr; 00849 bool on = ti->read(); 00850 if (ti->label1) { 00851 const char* const cptr = on ? ti->label1 : ti->label0; 00852 if (selected) 00853 pc.printf("\e[7m%s\e[0m", cptr); 00854 else 00855 pc.printf("%s", cptr); 00856 } else { 00857 if (on) 00858 pc.printf("\e[1m"); 00859 if (selected) 00860 pc.printf("\e[7m"); 00861 00862 pc.printf("%s", ti->label0); 00863 00864 if (selected || on) 00865 pc.printf("\e[0m"); 00866 } 00867 } 00868 } // ..read_menu_item() 00869 00870 void draw_menu() 00871 { 00872 unsigned table_row; 00873 00874 for (table_row = 0; table_row < MAX_MENU_ROWS; table_row++) { 00875 int table_col; 00876 for (table_col = 0; table_col < StopMenuCols[table_row]; table_col++) { 00877 read_menu_item(menu_table[table_row][table_col], false); 00878 } // ..table column iterator 00879 } // ..table row iterator 00880 00881 read_menu_item(menu_table[curpos.row][curpos.tableCol], true); 00882 00883 } // ..draw_menu() 00884 00885 typedef struct { 00886 int row; 00887 int col; 00888 } tablexy_t; 00889 00890 void 00891 menu_init_(const menu_t* in, tablexy_t* tc) 00892 { 00893 unsigned n; 00894 00895 for (n = 0; in[n].pos.row > 0; n++) { 00896 const menu_t* m = &in[n]; 00897 if (tc->row != m->pos.row - 1) { 00898 tc->row = m->pos.row - 1; 00899 tc->col = 0; 00900 } else 00901 tc->col++; 00902 00903 menu_table[tc->row][tc->col] = m; 00904 #ifdef MENU_DEBUG 00905 pc.printf("table:%u,%u ", tc->row, tc->col); 00906 pc.printf(" %d<%d? ", StopMenuCols[tc->row], tc->col); 00907 #endif /* MENU_DEBUG */ 00908 if (StopMenuCols[tc->row] < tc->col) 00909 StopMenuCols[tc->row] = tc->col; 00910 #ifdef MENU_DEBUG 00911 pc.printf("{%u %u}", tc->row, tc->col); 00912 pc.printf("in:%p[%u] screen:%u,%u ", in, n, m->pos.row, m->pos.col); 00913 //pc.printf(" loc:%p ", &in[n].itemPtr); 00914 if (in[n].itemPtr) { 00915 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 00916 pc.printf(" itemPtr:%p type:%02x ", di, di->itemType); 00917 } 00918 pc.printf("stopMenuCols[%u]: %d ", tc->row, StopMenuCols[tc->row]); 00919 if (m->label) 00920 pc.printf("label:%s", m->label); 00921 else 00922 pc.printf("noLabel"); 00923 pc.printf("\r\n"); 00924 #endif /* MENU_DEBUG */ 00925 00926 00927 } 00928 #ifdef MENU_DEBUG 00929 pc.printf("hit key:"); 00930 wait_uart_rx(); //pc.getc(); 00931 00932 #endif /* MENU_DEBUG */ 00933 } 00934 00935 void navigate_dropdown(uint8_t ch) 00936 { 00937 unsigned n; 00938 const menu_t* m = menuState.sm; 00939 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 00940 00941 switch (ch) { 00942 case 'A': // cursor UP 00943 if (menuState.sel_idx > 0) { 00944 menuState.sel_idx--; 00945 } 00946 break; 00947 case 'B': // cursor DOWN 00948 if (di->selectable_strs[menuState.sel_idx+1] != NULL) 00949 menuState.sel_idx++; 00950 break; 00951 } // ..switch (ch) 00952 00953 for (n = 0; di->selectable_strs[n] != NULL; n++) { 00954 pc.printf("\e[%u;%uf", m->pos.row+n, menuState.dropdown_col); 00955 if (n == menuState.sel_idx) 00956 pc.printf("\e[7m"); 00957 pc.printf(di->selectable_strs[n]); 00958 if (n == menuState.sel_idx) 00959 pc.printf("\e[0m"); 00960 } 00961 pc.printf("\e[%u;%uf", m->pos.row + menuState.sel_idx, menuState.dropdown_col + strlen(di->selectable_strs[menuState.sel_idx])); 00962 } 00963 00964 bool is_item_selectable(const menu_t* m) 00965 { 00966 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 00967 00968 if (di->itemType == _ITEM_BUTTON) { 00969 const button_item_t* bi = (const button_item_t*)m->itemPtr; 00970 if (bi->push == NULL) 00971 return false; 00972 } else if (di->itemType == _ITEM_TOGGLE) { 00973 const toggle_item_t* ti = (const toggle_item_t*)m->itemPtr; 00974 if (ti->push == NULL) 00975 return false; 00976 } 00977 00978 return true; 00979 } 00980 00981 void navigate_menu(uint8_t ch) 00982 { 00983 read_menu_item(menu_table[curpos.row][curpos.tableCol], false); 00984 00985 switch (ch) { 00986 case 'A': // cursor UP 00987 if (curpos.row == 0) 00988 break; 00989 00990 { // find previous row up with column 00991 int8_t row; 00992 for (row = curpos.row - 1; row >= 0; row--) { 00993 if (StopMenuCols[row] > -1) { 00994 curpos.row = row; 00995 break; 00996 } 00997 } 00998 if (row == 0 && StopMenuCols[0] < 0) 00999 break; // nothing found 01000 } 01001 01002 if (curpos.tableCol >= StopMenuCols[curpos.row]) { 01003 curpos.tableCol = StopMenuCols[curpos.row]-1; 01004 } 01005 01006 break; 01007 case 'B': // cursor DOWN 01008 if (curpos.row >= MAX_MENU_ROWS) 01009 break; 01010 01011 { // find next row down with column 01012 uint8_t row; 01013 for (row = curpos.row + 1; row < MAX_MENU_ROWS; row++) { 01014 if (StopMenuCols[row] != -1) { 01015 curpos.row = row; 01016 break; 01017 } 01018 } 01019 if (row == MAX_MENU_ROWS-1 && StopMenuCols[row] == -1) 01020 break; // nothing found 01021 } 01022 01023 if (curpos.tableCol >= StopMenuCols[curpos.row]) { 01024 curpos.tableCol = StopMenuCols[curpos.row]-1; 01025 } 01026 01027 01028 break; 01029 case 'C': // cursor LEFT 01030 if (curpos.tableCol >= StopMenuCols[curpos.row]-1) 01031 break; 01032 01033 { // find next row left with editable 01034 uint8_t tcol; 01035 for (tcol = curpos.tableCol + 1; tcol < StopMenuCols[curpos.row]; tcol++) { 01036 if (is_menu_item_changable(curpos.row, tcol)) { 01037 curpos.tableCol = tcol; 01038 break; 01039 } 01040 } 01041 } 01042 01043 break; 01044 case 'D': // cursor RIGHT 01045 if (curpos.tableCol == 0) 01046 break; 01047 01048 { 01049 int8_t tcol; 01050 for (tcol = curpos.tableCol - 1; tcol >= 0; tcol--) { 01051 if (is_menu_item_changable(curpos.row, tcol)) { 01052 curpos.tableCol = tcol; 01053 break; 01054 } 01055 } 01056 } 01057 01058 break; 01059 default: 01060 //pc.printf("unhancled-csi:%02x\eE", ch); 01061 break; 01062 } // ..switch (ch) 01063 01064 if (!is_item_selectable(menu_table[curpos.row][curpos.tableCol])) { 01065 int c; 01066 for (c = 0; c < StopMenuCols[curpos.row]; c++) { 01067 if (is_item_selectable(menu_table[curpos.row][c])) { 01068 curpos.tableCol = c; 01069 break; 01070 } 01071 } 01072 if (c == StopMenuCols[curpos.row]) 01073 return; 01074 } 01075 01076 #ifdef MENU_DEBUG 01077 log_printf("table:%u,%u screen:%u,%u \r\n", curpos.row, curpos.tableCol, 01078 menu_table[curpos.row][curpos.tableCol]->pos.row, 01079 menu_table[curpos.row][curpos.tableCol]->pos.col 01080 ); 01081 #endif /* MENU_DEBUG */ 01082 01083 read_menu_item(menu_table[curpos.row][curpos.tableCol], true); 01084 } // ..navigate_menu 01085 01086 void commit_menu_item_change() 01087 { 01088 const menu_t* m = menu_table[curpos.row][curpos.tableCol]; 01089 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 01090 01091 if (di->itemType == _ITEM_DROPDOWN) { 01092 menuState.mode = di->write(menuState.sel_idx); 01093 01094 pc.printf("\e[%u;%uf", m->pos.row, m->pos.col-2); 01095 } else if (di->itemType == _ITEM_VALUE) { 01096 const value_item_t* vi = (const value_item_t*)m->itemPtr; 01097 /* commit value entry */ 01098 if (vi->write) { 01099 if (vi->write(entry_buf)) 01100 menuState.mode = MENUMODE_REDRAW; 01101 else 01102 menuState.mode = MENUMODE_NONE; 01103 } else 01104 menuState.mode = MENUMODE_NONE; 01105 01106 if (menuState.mode == MENUMODE_NONE) { 01107 read_menu_item(menu_table[curpos.row][curpos.tableCol], true); 01108 } 01109 } 01110 } // ..commit_menu_item_change() 01111 01112 void refresh_item_in_table(const void* item) 01113 { 01114 unsigned table_row; 01115 01116 if (item == NULL) 01117 return; 01118 01119 for (table_row = 0; table_row < MAX_MENU_ROWS; table_row++) { 01120 int table_col; 01121 for (table_col = 0; table_col < StopMenuCols[table_row]; table_col++) { 01122 //log_printf("%u %u %p\r\n", table_row, table_col, menu_table[table_row][table_col]->itemPtr); 01123 if (item == menu_table[table_row][table_col]->itemPtr) { 01124 read_menu_item(menu_table[table_row][table_col], false); 01125 return; 01126 } 01127 } 01128 } 01129 } 01130 01131 void 01132 start_value_entry(const menu_t* m) 01133 { 01134 const value_item_t* vi = (const value_item_t*)m->itemPtr; 01135 uint8_t col = m->pos.col; 01136 01137 if (m->label) 01138 col += strlen(m->label); 01139 01140 pc.printf("\e[%u;%uf", m->pos.row, col); 01141 for (unsigned i = 0; i < vi->width; i++) 01142 pc.putc(' '); // clear displayed value for user entry 01143 01144 pc.printf("\e[%u;%uf", m->pos.row, col); 01145 menuState.mode = MENUMODE_ENTRY; 01146 entry_buf_idx = 0; 01147 } 01148 01149 void start_menu_item_change() 01150 { 01151 const menu_t* m = menu_table[curpos.row][curpos.tableCol]; 01152 const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr; 01153 bool checkRefresh = false; 01154 01155 if (di->itemType == _ITEM_DROPDOWN && di->selectable_strs) { 01156 menuState.dropdown_col = m->pos.col; 01157 unsigned n, sidx = 0; 01158 /* start dropdown */ 01159 if (di->read) 01160 sidx = di->read(true); 01161 01162 if (m->label) 01163 menuState.dropdown_col += strlen(m->label); 01164 01165 for (n = 0; di->selectable_strs[n] != NULL; n++) { 01166 uint8_t col = menuState.dropdown_col; 01167 bool leftPad = false; 01168 if (col > 3 && n > 0) { // dropdown left side padding 01169 col -= 2; 01170 leftPad = true; 01171 } 01172 pc.printf("\e[%u;%uf", m->pos.row+n, col); 01173 if (leftPad ) { 01174 pc.putc(' '); 01175 pc.putc(' '); 01176 } 01177 if (n == sidx) 01178 pc.printf("\e[7m"); 01179 pc.printf(di->selectable_strs[n]); 01180 if (n == sidx) 01181 pc.printf("\e[0m"); 01182 pc.putc(' '); // right side padding 01183 pc.putc(' '); 01184 } 01185 pc.printf("\e[%u;%uf", m->pos.row, menuState.dropdown_col-2); 01186 01187 menuState.mode = MENUMODE_DROPDOWN; 01188 menuState.sel_idx = sidx; 01189 menuState.sm = m; 01190 } else if (di->itemType == _ITEM_VALUE) { 01191 /* start value entry */ 01192 start_value_entry(m); 01193 } else if (di->itemType == _ITEM_BUTTON) { 01194 const button_item_t* bi = (const button_item_t*)m->itemPtr; 01195 if (bi->push) { 01196 bi->push(); 01197 checkRefresh = true; 01198 } 01199 } else if (di->itemType == _ITEM_TOGGLE) { 01200 const toggle_item_t* ti = (const toggle_item_t*)m->itemPtr; 01201 if (ti->push) { 01202 bool on = ti->push(); 01203 uint8_t col = m->pos.col; 01204 01205 if (m->label) 01206 col += strlen(m->label); 01207 01208 pc.printf("\e[%u;%uf", m->pos.row, col); 01209 if (ti->label1) { 01210 pc.printf("\e[7m%s\e[0m", on ? ti->label1 : ti->label0); 01211 } else { 01212 if (on) 01213 pc.printf("\e[1;7m%s\e[0m", ti->label0); 01214 else 01215 pc.printf("\e[7m%s\e[0m", ti->label0); 01216 } 01217 checkRefresh = true; 01218 } 01219 } 01220 01221 if (checkRefresh) { 01222 if (m->refreshReadItem) { 01223 refresh_item_in_table(m->refreshReadItem); // read associated 01224 read_menu_item(m, true); // restore cursor 01225 } 01226 } 01227 } // ..start_menu_item_change() 01228 01229 void full_menu_init() 01230 { 01231 unsigned n; 01232 const menu_t *m; 01233 tablexy_t txy; 01234 01235 txy.row = INT_MAX; 01236 txy.col = 0; 01237 01238 for (n = 0; n < MAX_MENU_ROWS; n++) { 01239 StopMenuCols[n] = -1; 01240 } 01241 01242 menu_init_(common_menu, &txy); 01243 01244 menu_init_(Radio::common_menu, &txy); 01245 01246 m = Radio::get_modem_menu(); 01247 if (m == NULL) { 01248 log_printf("NULL-modemMenu\r\n"); 01249 for (;;) asm("nop"); 01250 } 01251 #ifdef MENU_DEBUG 01252 pc.printf("modemmenuInit\r\n"); 01253 #endif 01254 menu_init_(m, &txy); 01255 01256 m = Radio::get_modem_sub_menu(); 01257 if (m) { 01258 #ifdef MENU_DEBUG 01259 pc.printf("modemsubmenuInit\r\n"); 01260 #endif 01261 menu_init_(m, &txy); 01262 } 01263 #ifdef MENU_DEBUG 01264 else 01265 pc.printf("no-modemsubmenu\r\n"); 01266 #endif 01267 01268 #ifdef PHOTOS_PIN 01269 menu_init_(photos_menu, &txy); 01270 #endif /* PHOTOS_PIN */ 01271 menu_init_(lis12dh12_menu, &txy); // accel 01272 menu_init_(lps22hh_menu, &txy); // temp, pressure 01273 01274 m = get_msg_menu(); 01275 if (m == NULL) { 01276 log_printf("NULL-msgMenu %d\r\n", msg_type); 01277 for (;;) asm("nop"); 01278 } 01279 menu_init_(m, &txy); 01280 01281 for (n = 0; n < MAX_MENU_ROWS; n++) { 01282 if (StopMenuCols[n] != -1) 01283 StopMenuCols[n]++; 01284 } 01285 } 01286 01287 bool ishexchar(char ch) 01288 { 01289 if (((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) || (ch >= '0' && ch <= '9')) 01290 return true; 01291 else 01292 return false; 01293 } 01294 01295 enum _urx_ { 01296 URX_STATE_NONE = 0, 01297 URX_STATE_ESCAPE, 01298 URX_STATE_CSI, 01299 } uart_rx_state; 01300 01301 Timeout uartRxTimeout; 01302 01303 void uart_rx_timeout() 01304 { 01305 /* escape by itself: abort change on item */ 01306 menuState.mode = MENUMODE_REDRAW; 01307 01308 uart_rx_state = URX_STATE_NONE; 01309 } 01310 01311 void serial_callback(char ch) 01312 { 01313 switch (uart_rx_state) { 01314 case URX_STATE_NONE: 01315 if (ch == 0x1b) { 01316 if (menuState.mode == MENUMODE_ENTRY) { 01317 /* abort entry mode */ 01318 menuState.mode = MENUMODE_NONE; 01319 read_menu_item(menu_table[curpos.row][curpos.tableCol], true); 01320 } else { 01321 uart_rx_state = URX_STATE_ESCAPE; 01322 if (menuState.mode != MENUMODE_NONE) { 01323 /* is this escape by itself, user wants to abort? */ 01324 uartRxTimeout.attach(uart_rx_timeout, 0.03); 01325 } 01326 } 01327 } else if (ch == 2) { // ctrl-B 01328 log_printf("--------------\r\n"); 01329 } else if (ch == '\r') { 01330 if (menuState.mode == MENUMODE_NONE) { 01331 start_menu_item_change(); 01332 } else { 01333 entry_buf[entry_buf_idx] = 0; 01334 commit_menu_item_change(); 01335 } 01336 } else if (menuState.mode == MENUMODE_ENTRY) { 01337 if (ch == 8) { 01338 if (entry_buf_idx > 0) { 01339 pc.putc(8); 01340 pc.putc(' '); 01341 pc.putc(8); 01342 entry_buf_idx--; 01343 } 01344 } else if (ch == 3) { // ctrl-C 01345 menuState.mode = MENUMODE_NONE; 01346 } else if (entry_buf_idx < sizeof(entry_buf)) { 01347 entry_buf[entry_buf_idx++] = ch; 01348 pc.putc(ch); 01349 } 01350 } else if (menuState.mode == MENUMODE_NONE) { 01351 if (ishexchar(ch) || ch == '-') { // characters which start entry 01352 const value_item_t* vi = (const value_item_t*)menu_table[curpos.row][curpos.tableCol]->itemPtr; 01353 if (vi->itemType == _ITEM_VALUE) { 01354 start_value_entry(menu_table[curpos.row][curpos.tableCol]); 01355 entry_buf[entry_buf_idx++] = ch; 01356 pc.putc(ch); 01357 } 01358 } else if (ch == 'r') { 01359 menuState.mode = MENUMODE_REDRAW; 01360 } else if (ch == '.') { 01361 Radio::test(); 01362 } 01363 01364 } 01365 break; 01366 case URX_STATE_ESCAPE: 01367 uartRxTimeout.detach(); 01368 if (ch == '[') 01369 uart_rx_state = URX_STATE_CSI; 01370 else { 01371 #ifdef MENU_DEBUG 01372 log_printf("unhancled-esc:%02x\r\n", ch); 01373 #endif /* MENU_DEBUG */ 01374 uart_rx_state = URX_STATE_NONE; 01375 } 01376 break; 01377 case URX_STATE_CSI: 01378 if (menuState.mode == MENUMODE_NONE) 01379 navigate_menu(ch); 01380 else if (menuState.mode == MENUMODE_DROPDOWN) 01381 navigate_dropdown(ch); 01382 01383 uart_rx_state = URX_STATE_NONE; 01384 //pc.printf("\e[18;1f"); // set (force) cursor to row;column 01385 break; 01386 } // ..switch (uart_rx_state) 01387 } 01388 01389 void ev_uart_rx() 01390 { 01391 log_printf("ev_uart_rx %u %u\r\n", uart_rx_buf_in, uart_rx_buf_out); 01392 while (uart_rx_buf_in != uart_rx_buf_out) { 01393 log_printf("X ev_uart_rx %u %u\r\n", uart_rx_buf_in, uart_rx_buf_out); 01394 serial_callback(uart_rx_buf[uart_rx_buf_out++]); 01395 if (uart_rx_buf_out == UART_RX_BUF_LEN) 01396 uart_rx_buf_out = 0; 01397 } 01398 } 01399 01400 //volatile unsigned rxCnt = 0; 01401 void rx_isr() 01402 { 01403 //rxCnt++; 01404 uart_rx_buf[uart_rx_buf_in++] = pc.getc(); 01405 if (uart_rx_buf_in == UART_RX_BUF_LEN) 01406 uart_rx_buf_in = 0; 01407 01408 //queue.call(ev_uart_rx); 01409 } 01410 01411 01412 void txDone() 01413 { 01414 if (msg_type == MSG_TYPE_PER) { 01415 log_printf("CntPacketTx%u, max:%u ipd%u\r\n", CntPacketTx, MaxNumPacket, tx_ipd_ms); 01416 if (++CntPacketTx <= MaxNumPacket) 01417 mbedTimeout.attach_us(next_tx_callback, tx_ipd_ms * 1000); 01418 } else if (msg_type == MSG_TYPE_PINGPONG) { 01419 if (flags.ping_master) { 01420 ++CntPacketTx; 01421 } 01422 01423 Radio::Rx(); 01424 } 01425 01426 flags.txBusy = false; 01427 } 01428 01429 static void 01430 printRxPkt(uint8_t size) 01431 { 01432 char str[80]; 01433 char *ptr, *endPtr; 01434 unsigned n = 0; 01435 endPtr = str + sizeof(str); 01436 ptr = str; 01437 while (ptr < endPtr) { 01438 sprintf(ptr, "%02x ", Radio::radio.rx_buf[n]); 01439 ptr += 3; 01440 if (++n >= size) 01441 break; 01442 } 01443 log_printf("%s\r\n", str); 01444 } 01445 01446 void rxDone(uint8_t size, float rssi, float snr) 01447 { 01448 log_printf("rxDone %u, %.1fdBm %.1fdB\r\n", size, rssi, snr); 01449 if (msg_type == MSG_TYPE_PACKET) { 01450 switch (Radio::radio.rx_buf[0]) { 01451 displayFloatToInt_t val; 01452 case CMD_TEMP: 01453 memcpy(&val, &Radio::radio.rx_buf[1], sizeof(displayFloatToInt_t)); 01454 log_printf("TEMP: %c%d.%02d\r\n", ((val.sign) ? '-' : '+'), 01455 (int)val.out_int, (int)val.out_dec); 01456 break; 01457 case CMD_PRES: 01458 memcpy(&val, &Radio::radio.rx_buf[1], sizeof(displayFloatToInt_t)); 01459 log_printf("PRESS: %c%d.%02d\r\n", ((val.sign) ? '-' : '+'), 01460 (int)val.out_int, (int)val.out_dec); 01461 break; 01462 case CMD_ACCEL: 01463 SensorAxes_t acc; 01464 memcpy(&acc, &Radio::radio.rx_buf[1], sizeof(SensorAxes_t)); 01465 log_printf("ACC %5ld %5ld %5ld\r\n", acc.AXIS_X, acc.AXIS_Y, acc.AXIS_Z); 01466 break; 01467 case CMD_PHOTOS: 01468 uint16_t pv; 01469 memcpy(&pv, &Radio::radio.rx_buf[1], sizeof(uint16_t)); 01470 log_printf("photos: %u\r\n", pv); 01471 break; 01472 default: 01473 printRxPkt(size); 01474 break; 01475 } 01476 } else if (msg_type == MSG_TYPE_PER) { 01477 if (memcmp(Radio::radio.rx_buf+4, PerMsg, 3) == 0) { 01478 unsigned i, PacketRxSequence = Radio::radio.rx_buf[0]; 01479 PacketRxSequence <<= 8; 01480 PacketRxSequence += Radio::radio.rx_buf[1]; 01481 PacketRxSequence <<= 8; 01482 PacketRxSequence += Radio::radio.rx_buf[2]; 01483 PacketRxSequence <<= 8; 01484 PacketRxSequence += Radio::radio.rx_buf[3]; 01485 01486 CntPacketRxOK++; 01487 01488 if (PacketRxSequence <= PacketRxSequencePrev || PacketRxSequencePrev == 0) 01489 i = 0; // sequence reset to resync, dont count missed packets this time 01490 else 01491 i = PacketRxSequence - PacketRxSequencePrev - 1; 01492 01493 01494 CntPacketRxKO += i; 01495 RxTimeOutCount = 0; 01496 log_printf("PER rx%u ok%u ko%u\r\n", PacketRxSequence , CntPacketRxOK, CntPacketRxKO); 01497 01498 PacketRxSequencePrev = PacketRxSequence; 01499 } // ..if PerMsg 01500 else { 01501 log_printf("per?\r\n"); 01502 printRxPkt(size); 01503 } 01504 } else if (msg_type == MSG_TYPE_PINGPONG) { 01505 if (memcmp(Radio::radio.rx_buf+4, PingMsg, 4) == 0) { 01506 /* ping slave rx */ 01507 Radio::setFS(); 01508 receivedCntPacket = Radio::radio.rx_buf[0]; 01509 receivedCntPacket <<= 8; 01510 receivedCntPacket += Radio::radio.rx_buf[1]; 01511 receivedCntPacket <<= 8; 01512 receivedCntPacket += Radio::radio.rx_buf[2]; 01513 receivedCntPacket <<= 8; 01514 receivedCntPacket += Radio::radio.rx_buf[3]; 01515 log_printf("%u rxPing->txPong\r\n", receivedCntPacket); 01516 01517 flags.ping_master = 0; 01518 flags.send_pong = 1; 01519 01520 } else if (memcmp(Radio::radio.rx_buf+8, PongMsg, 4) == 0) { 01521 unsigned cnt; 01522 /* ping master rx */ 01523 Radio::setFS(); 01524 cnt = Radio::radio.rx_buf[0]; 01525 cnt <<= 8; 01526 cnt += Radio::radio.rx_buf[1]; 01527 cnt <<= 8; 01528 cnt += Radio::radio.rx_buf[2]; 01529 cnt <<= 8; 01530 cnt += Radio::radio.rx_buf[3]; 01531 log_printf("%u rxPong->txPing\r\n", cnt); 01532 flags.send_ping = 1; 01533 } else { 01534 log_printf("pingpong?\r\n"); 01535 printRxPkt(size); 01536 } 01537 } else { 01538 /*for (unsigned n = 0; n < size; n++) 01539 log_printf("%02x\r\n", Radio::radio.rx_buf[n]);*/ 01540 log_printf("msg_type %u\r\n", msg_type); 01541 } 01542 01543 } 01544 01545 const RadioEvents_t rev = { 01546 txDone, 01547 rxDone 01548 }; 01549 01550 static DrvStatusTypeDef LIS2DH12_Read_Single_FIFO_Data(uint16_t sampleIndex, SensorAxes_t* acceleration) 01551 { 01552 //SensorAxes_t acceleration; 01553 01554 /* Read single FIFO data (acceleration in 3 axes) */ 01555 if (lis2dh12_get_axes(acceleration) == COMPONENT_ERROR) 01556 { 01557 return COMPONENT_ERROR; 01558 } 01559 01560 if (sampleIndex < SAMPLE_LIST_MAX) 01561 { 01562 log_printf("[DATA %02d] %5ld %5ld %5ld\r\n", sampleIndex + 1, acceleration->AXIS_X, 01563 acceleration->AXIS_Y, 01564 acceleration->AXIS_Z); 01565 } 01566 01567 return COMPONENT_OK; 01568 } 01569 01570 void uart_rx_service() 01571 { 01572 while (uart_rx_buf_in != uart_rx_buf_out) { 01573 serial_callback(uart_rx_buf[uart_rx_buf_out++]); 01574 if (uart_rx_buf_out == UART_RX_BUF_LEN) 01575 uart_rx_buf_out = 0; 01576 } 01577 } 01578 01579 static DrvStatusTypeDef LIS2DH12_Read_All_FIFO_Data(void) 01580 { 01581 uint16_t samplesToRead = accel_get_num_samples(); 01582 SensorAxes_t acc; 01583 01584 /* 'samplesToRead' actually contains number of words in FIFO but each FIFO sample (data set) consists of 3 words 01585 so the 'samplesToRead' has to be divided by 3 */ 01586 samplesToRead /= 3; 01587 01588 log_printf("\r\n%d samples in FIFO.\r\n\r\nStarted downloading data from FIFO ...\r\n", samplesToRead); 01589 01590 log_printf("\r\n[DATA ##] ACC_X ACC_Y ACC_Z [mg]\r\n"); 01591 01592 for (int i = 0; i < samplesToRead; i++) 01593 { 01594 uart_rx_service(); 01595 01596 if (LIS2DH12_Read_Single_FIFO_Data(i, &acc) == COMPONENT_ERROR) 01597 { 01598 return COMPONENT_ERROR; 01599 } else { 01600 } 01601 } 01602 01603 if (accel_tx_en) { 01604 Radio::radio.tx_buf[0] = CMD_ACCEL; 01605 Radio::set_payload_length(sizeof(SensorAxes_t)+1); 01606 memcpy(&Radio::radio.tx_buf[1], &acc, sizeof(SensorAxes_t)); 01607 Radio::txPkt(); 01608 } 01609 01610 if (samplesToRead > SAMPLE_LIST_MAX) 01611 { 01612 log_printf("\r\nSample list limited to: %d\r\n", SAMPLE_LIST_MAX); 01613 } 01614 01615 return COMPONENT_OK; 01616 } 01617 01618 01619 int main() 01620 { 01621 01622 lfsr = LFSR_INIT; 01623 msg_type = MSG_TYPE_PACKET; 01624 01625 uart_rx_state = URX_STATE_NONE; 01626 pc.attach(rx_isr); 01627 01628 Radio::boardInit(&rev); 01629 01630 { 01631 unsigned n; 01632 for (n = 0; n < MAX_MENU_ROWS; n++) 01633 StopMenuCols[n] = -1; 01634 } 01635 01636 botRow = MAX_MENU_ROWS + SCROLLING_ROWS; 01637 01638 pc.baud(115200); 01639 pc.printf("\e[7h"); // enable line wrapping 01640 pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region 01641 pc.printf("\e[2J"); // erase entire screen 01642 01643 full_menu_init(); 01644 //wait_uart_rx(); //pc.getc(); 01645 01646 pc.printf("\e[2J"); // erase entire screen 01647 01648 menuState.mode = MENUMODE_NONE; 01649 01650 draw_menu(); 01651 01652 curpos.row = 0; 01653 curpos.tableCol = 0; 01654 01655 tx_ipd_ms = 100; 01656 01657 if (demo_start()) { 01658 log_printf("demo_start-Failed\r\n"); 01659 for (;;) { asm("nop"); } 01660 } else 01661 log_printf("demo_start-OK\r\n"); 01662 01663 01664 svc_lis2dh12 = true; 01665 01666 for (;;) { 01667 int ret; 01668 01669 uart_rx_service(); 01670 01671 if (flags.send_ping) { 01672 if (flags.pingpongEnable) 01673 SendPing(); 01674 flags.send_ping = 0; 01675 } 01676 01677 if (flags.send_pong) { 01678 if (flags.pingpongEnable) 01679 SendPong(); 01680 flags.send_pong = 0; 01681 } 01682 01683 if (flags.do_next_tx) { 01684 do_next_tx(); 01685 flags.do_next_tx = 0; 01686 } 01687 01688 if (menuState.mode == MENUMODE_REINIT_MENU) { 01689 full_menu_init(); 01690 menuState.mode = MENUMODE_REDRAW; 01691 } 01692 01693 if (menuState.mode == MENUMODE_REDRAW) { 01694 // erase entire screen, some dropdowns extend to scrolling area 01695 pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region, if terminal started after 01696 pc.printf("\e[2J"); 01697 //pc.printf("\e[%u;1f\e[1J", MAX_MENU_ROWS); // erase menu area 01698 01699 menuState.mode = MENUMODE_NONE; 01700 draw_menu(); 01701 } 01702 01703 if (Radio::service(menuState.mode == MENUMODE_NONE ? LAST_CHIP_MENU_ROW : -1)) { 01704 read_menu_item(menu_table[curpos.row][curpos.tableCol], true); 01705 } 01706 01707 if (svc_lis2dh12) { 01708 ret = lis2dh_mainloop(); 01709 switch (ret) { 01710 case LIS2DH_FAIL_STATE: 01711 log_printf("lis2dh-stateFail\r\n"); 01712 break; 01713 case LIS2DH_FAIL: 01714 log_printf("lis2dh-Fail\r\n"); 01715 break; 01716 case LIS2DH_BSP_FAIL: 01717 log_printf("lis2dh bsp-fail\r\n"); 01718 wait(0.05); 01719 break; 01720 case LIS2DH_MAIN_SLEEP: 01721 lis2dh_set_fifo_mode(); 01722 01723 log_printf("lis2dh fifo-mode-sleep\r\n"); 01724 svc_lis2dh12 = false; 01725 break; 01726 case LIS2DH_MAIN_READ_FIFO: 01727 if (LIS2DH12_Read_All_FIFO_Data() == COMPONENT_ERROR) 01728 { 01729 return LIS2DH_FAIL; 01730 } 01731 01732 /* Reset FIFO by setting FIFO mode to Bypass */ 01733 if (lis2dh_set_fifo_bypass() < 0) { 01734 log_printf("fifo-bypass-fail\r\n"); 01735 } 01736 break; 01737 default: 01738 break; 01739 } 01740 } // ..if (svc_lis2dh12) 01741 else { 01742 } 01743 01744 if (flags.measure_tx) { 01745 switch (enabledSensor) { 01746 case CMD_PHOTOS: 01747 photos_tx(); 01748 break; 01749 case CMD_PRES: 01750 pres_tx(); 01751 break; 01752 case CMD_TEMP: 01753 temp_tx(); 01754 break; 01755 } 01756 flags.measure_tx = 0; 01757 } 01758 01759 } // ..for (;;) 01760 } 01761 01762 void lis2dh_int1() 01763 { 01764 log_printf("\r\nReceived FIFO Threshold Interrupt on INT1 pin ...\r\n" 01765 "\r\nNucleo processor is waking up ...\r\n" 01766 ); 01767 01768 svc_lis2dh12 = true; 01769 } 01770 01771 char strbuf[255]; 01772 01773 void c_log_printf(const char* format, ...) 01774 { 01775 va_list arglist; 01776 01777 // put cursor at last scrolling-area line 01778 pc.printf("\e[%u;1f", botRow); 01779 va_start(arglist, format); 01780 vsnprintf(strbuf, sizeof(strbuf), format, arglist); 01781 va_end(arglist); 01782 01783 pc.printf(strbuf); 01784 } 01785 01786 void log_printf(const char* format, ...) 01787 { 01788 va_list arglist; 01789 01790 // put cursor at last scrolling-area line 01791 pc.printf("\e[%u;1f", botRow); 01792 va_start(arglist, format); 01793 vsnprintf(strbuf, sizeof(strbuf), format, arglist); 01794 va_end(arglist); 01795 01796 pc.printf(strbuf); 01797 } 01798
Generated on Tue Jul 12 2022 16:29:49 by 1.7.2