Example for updating the MTi-1's firmware. Uses a platform independent, retargetable pure C implementation of the firmware updater protocol.

Dependencies:   mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fwupdate.c Source File

fwupdate.c

Go to the documentation of this file.
00001 /*!
00002  * \file
00003  * \copyright Copyright (C) Xsens Technologies B.V., 2015.
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00006  * use this file except in compliance with the License. You may obtain a copy
00007  * of the License at
00008  *
00009  * http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00014  * License for the specific language governing permissions and limitations
00015  * under the License.
00016  */
00017 #include "fwupdate.h "
00018 #include "string.h"
00019 
00020 #ifndef LOG
00021 static void defaultLogFunction(char const* format, ...) { }
00022 #define LOG defaultLogFunction
00023 #endif
00024 
00025 #define XMID_FIRMWARE_UPDATE (0xF2)
00026 
00027 #define FWUP_DEFAULT_SLICE_SIZE (64)
00028 
00029 
00030 /*! \brief Firmware updater commands
00031 */
00032 #define FWUP_READY          (unsigned char)0x52 //'R'
00033 #define FWUP_OK             (unsigned char)0x53 //'S'
00034 #define FWUP_CSERROR        (unsigned char)0x45 //'E'
00035 #define FWUP_CRITICAL       (unsigned char)0x46 //'F'
00036 #define FWUP_FINISHED       (unsigned char)0x46 //'F'
00037 #define FWUP_PAGE           (unsigned char)0x50 //'P'
00038 #define FWUP_HEADER         (unsigned char)0x53 //'S'
00039 #define FWUP_PAGESLICE      (unsigned char)0x54 //'T'
00040 #define FWUP_STARTED        (unsigned char)0x41 //'A'
00041 #define FWUP_OTHER          (unsigned char)0x4F //'O'
00042 
00043 
00044 /*! \brief Helper function for converting a firmware updater command to a string
00045 */
00046 const char *commandToString(uint8_t command)
00047 {
00048     switch (command)
00049     {
00050         case FWUP_READY:        return("FWUP_READY");
00051         case FWUP_HEADER:       return("FWUP_HEADER");
00052         case FWUP_FINISHED:     return("FWUP_FINISHED");
00053         case FWUP_PAGE:         return("FWUP_PAGE");
00054         case FWUP_PAGESLICE:    return("FWUP_PAGESLICE");
00055         case FWUP_STARTED:      return("FWUP_STARTED");
00056         case FWUP_OTHER:        return("FWUP_OTHER");
00057         default:                return("unknown");
00058     }
00059 }
00060 
00061 
00062 /*! \brief Helper function for converting a firmware updater command acknowledge to a string
00063 */
00064 const char *ackToString(uint8_t command)
00065 {
00066     switch (command)
00067     {
00068         case FWUP_READY:        return "FWUP_READY";
00069         case FWUP_OK:           return "FWUP_OK";
00070         case FWUP_CSERROR:      return "FWUP_CSERROR";
00071         case FWUP_CRITICAL:     return "FWUP_CRITICAL";
00072         case FWUP_PAGE:         return "FWUP_PAGE";
00073         case FWUP_PAGESLICE:    return "FWUP_PAGESLICE";
00074         case FWUP_STARTED:      return "FWUP_STARTED";
00075         case FWUP_OTHER:        return "FWUP_OTHER";
00076         default:                return "unknown";
00077     }
00078 }
00079 
00080 
00081 /*! \brief Read a uint32_t from the current position in the xff
00082 */
00083 uint32_t readUint32(FwUpdate *thisPtr)
00084 {
00085     uint32_t result;
00086     uint8_t buffer[4];
00087     int n = thisPtr->m_readXffData(buffer, thisPtr->m_readIndex, 4);
00088     thisPtr->m_readIndex += n;
00089     if (n == 4)
00090     {
00091         result = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
00092     }
00093     else
00094     {
00095         thisPtr->m_endOfFile = 1;
00096         result = 0;
00097     }
00098     return result;
00099 }
00100 
00101 
00102 /*! \brief Read a uint16_t from the current position in the xff
00103 */
00104 uint16_t readUint16(FwUpdate *thisPtr)
00105 {
00106     uint16_t result;
00107     uint8_t buffer[2];
00108     int n = thisPtr->m_readXffData(buffer, thisPtr->m_readIndex, 2);
00109     thisPtr->m_readIndex += n;
00110     if (n == 2)
00111     {
00112         result = buffer[0] << 8 | buffer[1];
00113     }
00114     else
00115     {
00116         thisPtr->m_endOfFile = 1;
00117         result = 0;
00118     }
00119     return result;
00120 }
00121 
00122 
00123 /*! \brief Read a uint8_t from the current position in the xff
00124 */
00125 uint8_t readUint8(FwUpdate *thisPtr)
00126 {
00127     uint8_t result;
00128     uint8_t buffer[1];
00129     int n = thisPtr->m_readXffData(buffer, thisPtr->m_readIndex, 1);
00130     thisPtr->m_readIndex += n;
00131     if (n == 1)
00132     {
00133         result = buffer[0];
00134     }
00135     else
00136     {
00137         thisPtr->m_endOfFile = 1;
00138         result = 0;
00139     }
00140     return result;
00141 }
00142 
00143 
00144 /*! \brief Read an Xff header from the current position in the xff
00145 */
00146 static void readXffHeader(FwUpdate *thisPtr)
00147 {
00148     LOG("Fwu: readXffHeader()\n");
00149 
00150     thisPtr->m_xffHeader.m_globalId = readUint32(thisPtr);
00151     thisPtr->m_xffHeader.m_sectionSize = readUint32(thisPtr);
00152     thisPtr->m_xffHeader.m_firmwareRevision[0] = readUint8(thisPtr);
00153     thisPtr->m_xffHeader.m_firmwareRevision[1] = readUint8(thisPtr);
00154     thisPtr->m_xffHeader.m_firmwareRevision[2] = readUint8(thisPtr);
00155     thisPtr->m_xffHeader.m_xffVersion[0] = readUint8(thisPtr);
00156     thisPtr->m_xffHeader.m_xffVersion[1] = readUint8(thisPtr);
00157     thisPtr->m_xffHeader.m_chipId = readUint8(thisPtr);
00158     thisPtr->m_xffHeader.m_numberOfSections = readUint8(thisPtr);
00159     thisPtr->m_xffHeader.m_addressLength = readUint8(thisPtr);
00160     thisPtr->m_xffHeader.m_pageSize = readUint16(thisPtr);
00161     if (thisPtr->m_xffHeader.m_xffVersion[0] >= 2)
00162         thisPtr->m_xffHeader.m_sliceSize = readUint16(thisPtr);
00163     else
00164         thisPtr->m_xffHeader.m_sliceSize = FWUP_DEFAULT_SLICE_SIZE;
00165 }
00166 
00167 
00168 /*! \brief Send an XMID_FIRMWARE_UPDATE xbus message
00169     \param data Pointer to the xbus message payload data
00170     \param length Number of payload bytes
00171 */
00172 static void sendFirmwareUpdateCommand(FwUpdate *thisPtr, uint8_t *data, uint16_t length)
00173 {
00174     struct XbusMessage xbusMessage;
00175     xbusMessage.m_mid = XMID_FIRMWARE_UPDATE;
00176     xbusMessage.m_length = length;
00177     xbusMessage.m_data = data;
00178     thisPtr->m_sendXbusMessage(&xbusMessage);
00179 }
00180 
00181 
00182 /*! \brief Send a FWUP_READY command
00183 */
00184 static void sendReady(FwUpdate *thisPtr)
00185 {
00186     thisPtr->m_txBuffer[0] = FWUP_READY;
00187     sendFirmwareUpdateCommand(thisPtr, thisPtr->m_txBuffer, 1);
00188 }
00189 
00190 
00191 /*! \brief Send a FWUP_HEADER command
00192 */
00193 static void sendHeader(FwUpdate *thisPtr)
00194 {
00195     int n;
00196     thisPtr->m_txBuffer[0] = FWUP_HEADER;
00197     n = thisPtr->m_readXffData(&thisPtr->m_txBuffer[1], thisPtr->m_readIndex, thisPtr->m_xffHeader.m_addressLength);
00198     thisPtr->m_readIndex += n;
00199     if (n == thisPtr->m_xffHeader.m_addressLength)
00200     {
00201         memcpy(&thisPtr->m_txBuffer[1 + thisPtr->m_xffHeader.m_addressLength], &thisPtr->m_nofSlicesPerPage, 2);
00202         sendFirmwareUpdateCommand(thisPtr, thisPtr->m_txBuffer, 1 + thisPtr->m_xffHeader.m_addressLength + 2);
00203     }
00204     else
00205     {
00206         thisPtr->m_endOfFile = 1;
00207     }
00208 }
00209 
00210 
00211 /*! \brief Send a page slice
00212 */
00213 static void sendSlice(FwUpdate *thisPtr)
00214 {
00215     int n;
00216     thisPtr->m_txBuffer[0] = FWUP_PAGESLICE;
00217     n = thisPtr->m_readXffData(&thisPtr->m_txBuffer[1], thisPtr->m_readIndex, thisPtr->m_xffHeader.m_sliceSize);
00218     thisPtr->m_readIndex += n;
00219     if (n == thisPtr->m_xffHeader.m_sliceSize)
00220     {
00221         sendFirmwareUpdateCommand(thisPtr, thisPtr->m_txBuffer, 1 + thisPtr->m_xffHeader.m_sliceSize);
00222     }
00223     else
00224     {
00225         thisPtr->m_endOfFile = 1;
00226     }
00227 }
00228 
00229 
00230 /*! \brief Send a FWUP_OTHER command
00231 */
00232 static void sendOther(FwUpdate *thisPtr)
00233 {
00234     thisPtr->m_txBuffer[0] = FWUP_OTHER;
00235     thisPtr->m_txBuffer[1] = thisPtr->m_xffHeader.m_chipId;
00236     LOG("Fwu: Send FWUP_OTHER\n");
00237     sendFirmwareUpdateCommand(thisPtr, thisPtr->m_txBuffer, 2);
00238 }
00239 
00240 
00241 /*! \brief Send a FWUP_FINISHED command
00242 */
00243 static void sendFinished(FwUpdate *thisPtr)
00244 {
00245     thisPtr->m_txBuffer[0] = FWUP_FINISHED;
00246     LOG("Fwu: Send FWUP_FINISHED\n");
00247     sendFirmwareUpdateCommand(thisPtr, thisPtr->m_txBuffer, 1);
00248 }
00249 
00250 
00251 /*! \brief Enter the next section of the xff file
00252 */
00253 static void enterNewSection(FwUpdate *thisPtr)
00254 {
00255     LOG("\nFwu: enterNewSection()\n");
00256     readXffHeader(thisPtr);
00257     thisPtr->m_nofPages = thisPtr->m_xffHeader.m_sectionSize / (thisPtr->m_xffHeader.m_pageSize + thisPtr->m_xffHeader.m_addressLength);
00258     thisPtr->m_nofSlicesPerPage = thisPtr->m_xffHeader.m_pageSize / thisPtr->m_xffHeader.m_sliceSize;
00259     thisPtr->m_pageCounter = 0;
00260     thisPtr->m_sliceCounter = 0;
00261     sendOther(thisPtr);
00262 }
00263 
00264 
00265 /*  \brief Public interface of the firmware updater:
00266 */
00267 
00268 /*! \brief Initialize a FwUpdate instance
00269 */
00270 void FwUpdate_init(FwUpdate *thisPtr)
00271 {
00272     LOG("Fwu: init()\n");
00273     thisPtr->m_state = STATE_Idle;
00274 }
00275 
00276 
00277 /*! \brief Start a firmware update
00278 */
00279 void FwUpdate_start(FwUpdate *thisPtr)
00280 {
00281     if (thisPtr->m_state == STATE_Idle)
00282     {
00283         LOG("Fwu: start() --> Send FWUP_READY\n");
00284         thisPtr->m_readIndex = 0;
00285         thisPtr->m_endOfFile = 0;
00286         thisPtr->m_state = STATE_Start;
00287         sendReady(thisPtr);
00288     }
00289     else
00290     {
00291         thisPtr->m_readyHandler(FWU_Failed);
00292         LOG("Fwu: start() failed\n");
00293     }
00294 }
00295 
00296 
00297 /*! \brief Handle xbus message coming from the module
00298     \param xbusMessage The xbus message from the module to be handled
00299 */
00300 void FwUpdate_handleXbus(FwUpdate* thisPtr, struct XbusMessage* xbusMessage)
00301 {
00302     uint8_t ack;
00303     if (xbusMessage->m_mid != XMID_FIRMWARE_UPDATE)
00304     {
00305         LOG("Fwu: Got unhandled xbus message 0x%02X (ignored)\n", xbusMessage->m_mid);
00306         return;
00307     }
00308 
00309     ack = xbusMessage->m_data[0];
00310 
00311     switch (thisPtr->m_state)
00312     {
00313         case STATE_Idle:
00314         {
00315             LOG("Fwu: Got %s in STATE_Idle (ignored)\n", ackToString(ack));
00316         } break;
00317 
00318         case STATE_Start:
00319         {
00320             if (ack == FWUP_READY)
00321             {
00322                 LOG("Fwu: FWUP_READY in STATE_Start --> Enter new section\n");
00323                 enterNewSection(thisPtr);
00324                 thisPtr->m_state = STATE_WaitReady;
00325             }
00326             else
00327             {
00328                 LOG("Fwu: Got %s in STATE_Start (ignored)\n", ackToString(ack));
00329             }
00330         } break;
00331 
00332         case STATE_WaitReady:
00333         {
00334             if (ack == FWUP_READY)
00335             {
00336                 LOG("Fwu: FWUP_READY in STATE_WaitReady --> Send header\n");
00337                 sendHeader(thisPtr);
00338                 thisPtr->m_state = STATE_WaitHeaderResult;
00339             }
00340             else
00341             {
00342                 LOG("Fwu: Got %s in STATE_WaitReady --> Failed\n", ackToString(ack));
00343                 thisPtr->m_readyHandler(FWU_Failed);
00344                 thisPtr->m_state = STATE_Idle;
00345             }
00346         } break;
00347 
00348         case STATE_WaitHeaderResult:
00349         {
00350             if (ack == FWUP_READY)
00351             {
00352                 LOG("Fwu: FWUP_READY in STATE_WaitHeaderResult --> Send first slice\n");
00353                 sendSlice(thisPtr);
00354                 thisPtr->m_sliceCounter = 1;
00355                 thisPtr->m_state = STATE_WaitSliceReady;
00356             }
00357             else
00358             {
00359                 LOG("Fwu: Got %s in STATE_WaitHeaderResult --> Failed\n", ackToString(ack));
00360                 thisPtr->m_readyHandler(FWU_Failed);
00361                 thisPtr->m_state = STATE_Idle;
00362             }
00363         } break;
00364 
00365         case STATE_WaitSliceReady:
00366         {
00367             if (ack == FWUP_READY)
00368             {
00369                 if (thisPtr->m_sliceCounter < thisPtr->m_nofSlicesPerPage)
00370                 {
00371                     LOG("Fwu: FWUP_READY in STATE_WaitSliceReady --> Send slice %d\n", thisPtr->m_sliceCounter);
00372                     sendSlice(thisPtr);
00373                     thisPtr->m_sliceCounter++;
00374                 }
00375                 else
00376                 {
00377                     LOG("Fwu: All slices sent --> STATE_WaitPageOk\n");
00378                     thisPtr->m_state = STATE_WaitPageOk;
00379                 }
00380             }
00381             else
00382             {
00383                 LOG("Fwu: Got %s in STATE_WaitSliceReady --> Failed\n", ackToString(ack));
00384                 thisPtr->m_readyHandler(FWU_Failed);
00385                 thisPtr->m_state = STATE_Idle;
00386             }
00387         } break;
00388 
00389         case STATE_WaitPageOk:
00390         {
00391             if (ack == FWUP_OK)
00392             {
00393                 LOG("Fwu: FWUP_OK in STATE_WaitPageOk --> STATE_WaitPageReady\n");
00394                 thisPtr->m_state = STATE_WaitPageReady;
00395             }
00396             else
00397             {
00398                 LOG("Fwu: Got %s in STATE_WaitPageOk --> Failed\n", ackToString(ack));
00399                 thisPtr->m_readyHandler(FWU_Failed);
00400                 thisPtr->m_state = STATE_Idle;
00401             }
00402         } break;
00403 
00404         case STATE_WaitPageReady:
00405         {
00406             if (ack == FWUP_READY)
00407             {
00408                 thisPtr->m_pageCounter++;
00409                 if (thisPtr->m_nofPages != 0 && thisPtr->m_pageCounter == thisPtr->m_nofPages)
00410                 {
00411                     LOG("Fwu: All pages sent --> Enter new section\n");
00412                     enterNewSection(thisPtr);
00413                     thisPtr->m_state = STATE_WaitReady;
00414                 }
00415                 else
00416                 {
00417                     sendHeader(thisPtr);
00418                     if (thisPtr->m_endOfFile)
00419                     {
00420                         LOG("Fwu: End of file --> Firmware update done\n");
00421                         sendFinished(thisPtr);
00422                         thisPtr->m_readyHandler(FWU_Success);
00423                         thisPtr->m_state = STATE_Idle;
00424                     }
00425                     else
00426                     {
00427                         LOG("Fwu: FWUP_READY in STATE_WaitPageReady --> Send header\n");
00428                         thisPtr->m_state = STATE_WaitHeaderResult;
00429                     }
00430                 }
00431             }
00432             else
00433             {
00434                 LOG("Fwu: Got %s in STATE_WaitPageReady --> Failed\n", ackToString(ack));
00435                 thisPtr->m_readyHandler(FWU_Failed);
00436                 thisPtr->m_state = STATE_Idle;
00437             }
00438         } break;
00439 
00440         default:
00441         {
00442         }
00443     }
00444 }
00445 
00446