Example for updating the MTi-1's firmware. Uses a platform independent, retargetable pure C implementation of the firmware updater protocol.
fwupdate.c
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
Generated on Wed Jul 13 2022 07:56:15 by
1.7.2

