Fork to see if I can get working

Dependencies:   BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated

Fork of xDotBridge_update_test20180823 by Matt Briggs

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SerialTermMgr.cpp Source File

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 }