Fork to see if I can get working
Dependencies: BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated
Fork of xDotBridge_update_test20180823 by
SerialTermMgr.cpp
00001 /* 00002 * SerialTermMgr.cpp 00003 * 00004 * Created on: May 8, 2017 00005 * Author: mbriggs 00006 */ 00007 00008 #include "SerialTermMgr.h" 00009 #include "UserInterface.h" 00010 00011 extern Serial pc; 00012 const char ACK = 0x06; 00013 const char NAK = 0x15; 00014 const char SOH = 0x01; 00015 const char EOT = 0x04; 00016 const char SUB = 0x1A; 00017 00018 SerialTermMgr::SerialTermMgr(BaseboardIO *bbio, WinbondSPIFlash *flash, float fwVersion) 00019 { 00020 mPc = NULL; 00021 mFwVersion = fwVersion; 00022 mCurrScreen = mainScreenId; 00023 mBbio = bbio; 00024 mFlash = flash; 00025 } 00026 void SerialTermMgr::printScreen() 00027 { 00028 switch (mCurrScreen) { 00029 case mainScreenId: 00030 printMainScreen(); 00031 break; 00032 case genInfoScreenId: 00033 printGenInfo(); 00034 break; 00035 case settingsScreenId: 00036 printSettings(); 00037 break; 00038 case statsScreenId: 00039 case errorLogScreenId: 00040 case liveLogScreenId: 00041 case enterSerialBridgeScreenId: 00042 printMainScreen(); 00043 break; 00044 case enterProgModeScreenId: 00045 printEnterProgMode(); 00046 } 00047 } 00048 bool SerialTermMgr::input() 00049 { 00050 if (mPc == NULL) { 00051 return true; 00052 } 00053 bool quit = false; 00054 char c = 10; 00055 if (mPc->readable()) { 00056 c = mPc->getc(); 00057 } 00058 else { 00059 return false; // Do nothing if there is no input 00060 } 00061 switch (mCurrScreen) { 00062 case mainScreenId: 00063 quit = inputMainPage(c); 00064 break; 00065 case genInfoScreenId: 00066 inputGenInfo(c); 00067 break; 00068 case settingsScreenId: 00069 inputSettings(c); 00070 break; 00071 case statsScreenId: 00072 case errorLogScreenId: 00073 case liveLogScreenId: 00074 case enterSerialBridgeScreenId: 00075 inputMainPage(c); 00076 break; 00077 case enterProgModeScreenId: 00078 inputEnterProgMode(c); 00079 } 00080 return quit; 00081 } 00082 00083 // private methods 00084 bool SerialTermMgr::inputMainPage (char in) { 00085 bool quit = false; 00086 switch (in) { 00087 case '1': 00088 mCurrScreen = genInfoScreenId; 00089 break; 00090 case '2': 00091 mCurrScreen = enterProgModeScreenId; 00092 break; 00093 case '3': 00094 seedSaveSettings(); 00095 mCurrScreen = settingsScreenId; 00096 break; 00097 // Future 00098 // case '4': 00099 // mPc->printf("\r\nNot implemented yet.\r\n"); 00100 //// mCurrScreen = statsScreenId; 00101 // break; 00102 // case '5': 00103 // mPc->printf("\r\nNot implemented yet.\r\n"); 00104 //// mCurrScreen = errorLogScreenId; 00105 // break; 00106 // case '6': 00107 // mPc->printf("\r\nNot implemented yet.\r\n"); 00108 //// mCurrScreen = liveLogScreenId; 00109 // break; 00110 // case '7': 00111 // mPc->printf("\r\nNot implemented yet.\r\n"); 00112 //// mCurrScreen = enterSerialBridgeScreenId; 00113 // break; 00114 case 0x11: // ctrl-q 00115 quit=true; 00116 break; 00117 default: 00118 mCurrScreen = mainScreenId; 00119 } 00120 if (!quit) { 00121 printScreen(); 00122 } 00123 return quit; 00124 } 00125 00126 void SerialTermMgr::printMainScreen() 00127 { 00128 if (mPc == NULL) { 00129 return; 00130 } 00131 mPc->printf("\r\n\r\n"); 00132 mPc->printf("===============================================\r\n"); 00133 mPc->printf("= Wireless Bridge Terminal (Firmware: v%0.2f) =\r\n", mFwVersion); 00134 mPc->printf("===============================================\r\n"); 00135 mPc->printf("===============================================\r\n"); 00136 mPc->printf("= Selection Options =\r\n"); 00137 mPc->printf("===============================================\r\n"); 00138 mPc->printf("= 0: Refresh (Enter and space also work) =\r\n"); 00139 mPc->printf("= 1: General information =\r\n"); 00140 mPc->printf("= 2: Enter programming mode =\r\n"); 00141 mPc->printf("= 3: Settings =\r\n"); 00142 // Future 00143 // mPc->printf("= 4: Statistics =\r\n"); 00144 // mPc->printf("= 5: Error log =\r\n"); 00145 // mPc->printf("= 6: Live log =\r\n"); 00146 // mPc->printf("= 7: Enter serial bridge mode =\r\n"); 00147 mPc->printf("= <ctrl>-q: Exit terminal =\r\n"); 00148 mPc->printf("===============================================\r\n"); 00149 } 00150 00151 void SerialTermMgr::inputGenInfo (char in) { 00152 if (mPc == NULL) { 00153 return; 00154 } 00155 switch (in) { 00156 case 0x1B: // esc 00157 mCurrScreen = mainScreenId; 00158 break; 00159 case 'r': 00160 mBbio->sampleUserSwitches(); 00161 mPc->printf("User switches sampled.\r\n"); 00162 break; 00163 default: 00164 mPc->printf("Invalid key.\r\n"); 00165 } 00166 printScreen(); 00167 } 00168 00169 void SerialTermMgr::printGenInfo() 00170 { 00171 if (mPc == NULL) { 00172 return; 00173 } 00174 mPc->printf("\r\n\r\n"); 00175 mPc->printf("===============================================\r\n"); 00176 mPc->printf("= General Info (ESC to return to main menu) =\r\n"); 00177 mPc->printf("===============================================\r\n"); 00178 mPc->printf("= Press r to sample user switch values =\r\n"); 00179 mPc->printf("===============================================\r\n"); 00180 mPc->printf("===============================================\r\n"); 00181 mPc->printf("= Firmware version: v%0.2f =\r\n", mFwVersion); 00182 //TODO 00183 // mPc->printf("= Radio EUI: %s =\r\n", mts::Text::bin2hexString(dot->getDeviceId()).c_str()); 00184 mPc->printf("= Contact closure: %s =\r\n", mBbio->isCCNO() ? "Normally open " : 00185 "Normally closed"); 00186 mPc->printf("= WB Mode: %s =\r\n", mBbio->isTx() ? "Transmitter" : 00187 "Receiver "); 00188 // mPc->printf("= Comm Mode: %s =\r\n", mBbio->isLoRaWANMode() ? "LoRaWAN " : 00189 // "Peer-to-peer"); 00190 // mPc->printf("= Serial Mode: %s =\r\n", mBbio->isSerialEnabled() ? "Enabled " : 00191 // "Disabled"); 00192 if (mBbio->isTx()) { 00193 mPc->printf("= Currently no rotary switches apply for TX =\r\n"); 00194 } 00195 else { 00196 mPc->printf("= Rotary 1 hold setting is %05.1f seconds =\r\n", 00197 HoldTimeSetting::rotVal2Sec(mBbio->rotarySwitch1())); 00198 mPc->printf("= Rotary 2 currently does not apply for RX =\r\n"); 00199 } 00200 mPc->printf("===============================================\r\n"); 00201 } 00202 00203 void SerialTermMgr::inputSettings (char in) { 00204 if (mPc == NULL) { 00205 return; 00206 } 00207 switch (in) { 00208 case 0x1B: // esc 00209 mCurrScreen = mainScreenId; 00210 break; 00211 case 0x13: // ctrl-s 00212 applySaveSettings(); 00213 mPc->printf("Settings saved \r\n"); 00214 mCurrScreen = mainScreenId; 00215 break; 00216 case 'r': 00217 mBbio->sampleUserSwitches(); 00218 mPc->printf("User switches sampled.\r\n"); 00219 break; 00220 case '1': 00221 mSaveIsCCNO = !mSaveIsCCNO; 00222 break; 00223 case '2': 00224 mSaveIsTx = !mSaveIsTx; 00225 break; 00226 case '3': 00227 if (!mSaveIsTx) { 00228 mSaveRot1 = (++mSaveRot1) % 10; 00229 } 00230 break; 00231 default: 00232 mPc->printf("Invalid key.\r\n"); 00233 } 00234 printScreen(); 00235 } 00236 00237 void SerialTermMgr::printSettings() 00238 { 00239 if (mPc == NULL) { 00240 return; 00241 } 00242 mPc->printf("\r\n\r\n"); 00243 mPc->printf("===============================================\r\n"); 00244 mPc->printf("= Settings (ESC to return to main menu) =\r\n"); 00245 mPc->printf("===============================================\r\n"); 00246 mPc->printf("= Press r to sample user switch values =\r\n"); 00247 mPc->printf("= Press <ctrl>-s to save values =\r\n"); 00248 mPc->printf("===============================================\r\n"); 00249 mPc->printf("===============================================\r\n"); 00250 mPc->printf("= Setting [Mod Key]: curr value, save value =\r\n"); 00251 mPc->printf("= Contact closure [1]: %s, %s =\r\n", 00252 mBbio->isCCNO() ? "NO" : "NC", 00253 mSaveIsCCNO ? "NO" : "NC"); 00254 mPc->printf("= WB Mode [2]: %s, %s =\r\n", 00255 mBbio->isTx() ? "TX" : "RX", 00256 mSaveIsTx ? "TX" : "RX"); 00257 if (mSaveIsTx) { 00258 mPc->printf("= Currently no rotary switches apply for TX =\r\n"); 00259 } 00260 else { 00261 mPc->printf("= Rotary 1 hold setting [3]: %05.1fs, %05.1fs =\r\n", 00262 HoldTimeSetting::rotVal2Sec(mBbio->rotarySwitch1()), 00263 HoldTimeSetting::rotVal2Sec(mSaveRot1)); 00264 mPc->printf("= Rotary 2 currently does not apply for RX =\r\n"); 00265 } 00266 mPc->printf("===============================================\r\n"); 00267 } 00268 00269 void SerialTermMgr::seedSaveSettings() 00270 { 00271 mSaveIsCCNO = mBbio->isCCNO(); 00272 mSaveIsTx = mBbio->isTx(); 00273 mSaveRot1 = mBbio->rotarySwitch1(); 00274 } 00275 00276 void SerialTermMgr::applySaveSettings() 00277 { 00278 mBbio->setIsCCNO(mSaveIsCCNO); 00279 mBbio->setIsTx(mSaveIsTx); 00280 mBbio->setRotarySwitch1(mSaveRot1); 00281 } 00282 00283 void SerialTermMgr::printEnterProgMode() 00284 { 00285 if (mPc == NULL) { 00286 return; 00287 } 00288 mPc->printf("\r\n\r\n"); 00289 mPc->printf("===============================================\r\n"); 00290 mPc->printf("= Serial Firmware Prog Mode (Esc to return) =\r\n"); 00291 mPc->printf("===============================================\r\n"); 00292 mPc->printf("===============================================\r\n"); 00293 mPc->printf("= To program firmware: \r\n"); 00294 mPc->printf("= 1: Have bin file ready =\r\n"); 00295 mPc->printf("= 2: Hit <ctrl>-d to enter XMODEM mode =\r\n"); 00296 mPc->printf("= 3: In terminal program (such as teraterm) =\r\n"); 00297 mPc->printf("= select transfer via XMODEM =\r\n"); 00298 mPc->printf("= 4: Programming may take up to a minute =\r\n"); 00299 mPc->printf("= 5: If successful terminal prints \"Success\" =\r\n"); 00300 mPc->printf("= 6: Wireless Bridge will then automatically =\r\n"); 00301 mPc->printf("= reboot with new firmware. =\r\n"); 00302 mPc->printf("===============================================\r\n"); 00303 } 00304 00305 void SerialTermMgr::inputEnterProgMode (char in) { 00306 if (mPc == NULL) { 00307 return; 00308 } 00309 switch (in) { 00310 case 0x1B: // esc: 00311 mCurrScreen = mainScreenId; 00312 break; 00313 case 0x04: 00314 xmodem2Flash(); 00315 break; 00316 default: 00317 mPc->printf("Invalid key.\r\n"); 00318 } 00319 printScreen(); 00320 } 00321 00322 bool SerialTermMgr::xmodem2Flash () 00323 { 00324 mPc->printf("Ready to receive file\r\n"); 00325 mFlash->releaseFromPowerDown(); 00326 mFlash->chipErase(); 00327 char packetBuf[132]; 00328 uint16_t packetNum = 1; 00329 uint8_t csum = 0; 00330 unsigned char pktIdx = 0; 00331 time_t lastValidInput = 0; 00332 unsigned char nTimeouts = 0; 00333 while (1) { 00334 // Send a NAK if a packet is not received within timeout period 00335 if ((time(NULL)-lastValidInput) > XMODEM_TIMEOUT){ 00336 pc.printf("Total chars: %d\r\n", pktIdx); 00337 pktIdx = 0; 00338 mPc->printf("%c", NAK); // Send NAK 00339 lastValidInput = time(NULL); 00340 nTimeouts++; 00341 if (nTimeouts >= MAX_TIMEOUTS) { 00342 mPc->printf("Programming timed out.\r\n"); 00343 pc.printf("Programming timed out.\r\n"); 00344 break; 00345 } 00346 } 00347 if (mPc->readable()) { 00348 packetBuf[pktIdx++] = mPc->getc(); 00349 if (pktIdx == 1 && packetBuf[0] == EOT) { 00350 lastValidInput = time(NULL); 00351 mPc->printf("%c", ACK); // Last ACK 00352 00353 // Check for update string in last packet 00354 bool foundKey; 00355 for (int packetIdx=3;packetIdx<sizeof(packetBuf)-sizeof(VORTEX_UPDATE_KEY);packetIdx++) { 00356 foundKey = true; 00357 for (int i=0;i<sizeof(VORTEX_UPDATE_KEY)-1;i++) { 00358 if (packetBuf[packetIdx+i] != VORTEX_UPDATE_KEY[i]) { 00359 foundKey = false; 00360 break; 00361 } 00362 } 00363 if (foundKey) { 00364 break; 00365 } 00366 } 00367 if (foundKey) { 00368 mPc->printf("Success.\r\n"); 00369 pc.printf("Success on xmodem. Reset in progress.\r\n"); 00370 writeBootloaderCtrlPage(packetNum*XMODEM_PACKET_SIZE); 00371 } 00372 else { 00373 mPc->printf("Failed update key validation.\r\n"); 00374 pc.printf("Failed update key validation\r\n"); 00375 } 00376 00377 wait(0.01); 00378 mFlash->powerDown(); 00379 if (foundKey) { 00380 NVIC_SystemReset(); 00381 } 00382 break; 00383 } 00384 else if (pktIdx >= 132) { 00385 lastValidInput = time(NULL); 00386 nTimeouts = 0; // Clear n timeouts with new packet 00387 csum = 0; 00388 for (int i=3; i<131; i++) { 00389 csum += packetBuf[i]; 00390 } 00391 pktIdx = 0; 00392 if ((csum == packetBuf[131]) && (packetBuf[0] == SOH) && 00393 (packetBuf[1] == ((uint8_t)packetNum)) && (((uint8_t)~packetBuf[2]) == ((uint8_t)packetNum))) { 00394 mFlash->writeStream(FLASH_BIN_OFFSET+(packetNum-1)*XMODEM_PACKET_SIZE, packetBuf+3, 00395 XMODEM_PACKET_SIZE); 00396 mPc->printf("%c", ACK); 00397 packetNum++; 00398 } 00399 else { 00400 mPc->printf("%c", NAK); 00401 } 00402 } 00403 } 00404 } 00405 mCurrScreen = mainScreenId; // Just return to main screen for now 00406 mFlash->powerDown(); 00407 00408 return true; 00409 } 00410 00411 void SerialTermMgr::writeBootloaderCtrlPage(uint32_t nBytes) 00412 { 00413 // This should always be less than 256 bytes 00414 00415 // Zero updates the bootloader version so that is cleared until the bootloader adds its back 00416 const uint32_t zeroBootloaderVersion = 0; 00417 const unsigned int ctrlSize = sizeof(NEW_CODE)+sizeof(nBytes)+sizeof(zeroBootloaderVersion); 00418 char buf[ctrlSize]; 00419 std::memcpy(buf, NEW_CODE, sizeof(NEW_CODE)); 00420 std::memcpy(buf+sizeof(NEW_CODE), &nBytes, sizeof(nBytes)); 00421 std::memcpy(buf+sizeof(NEW_CODE)+sizeof(nBytes), 00422 &zeroBootloaderVersion, sizeof(zeroBootloaderVersion)); 00423 // TODO add reprogram counter or other functions 00424 00425 // Copy to first page of flash 00426 mFlash->writeStream(0, buf, sizeof(buf)); 00427 }
Generated on Fri Jul 15 2022 14:36:45 by 1.7.2