Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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