Software Update via Ethernet - the mbed application can pull down an updated application binary from a web server and activate that binary. This library works only with the LPC1768, as it relies on the magic-chip boot-loader mechanism.
Dependents: WattEye X10Svr PUB_SWUpdate
SWUpdate.cpp
00001 00002 // Software Update via Ethernet from forum - 00003 // http://mbed.org/forum/mbed/topic/1183/ 00004 // 00005 #include "mbed.h" 00006 #include "SWUpdate.h" 00007 #include "HTTPFile.h" 00008 #include <stdio.h> 00009 00010 extern "C" void mbed_reset(); 00011 00012 //#define DEBUG "SWup" 00013 #include <cstdio> 00014 #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) 00015 #define DBG(x, ...) std::printf("[DBG %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00016 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00017 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00018 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00019 #else 00020 #define DBG(x, ...) 00021 #define WARN(x, ...) 00022 #define ERR(x, ...) 00023 #define INFO(x, ...) 00024 #endif 00025 00026 static HTTPResult HTTPErrorCode; 00027 00028 typedef enum { 00029 ok, 00030 no_file, 00031 bad_crc 00032 } Integrity_t; 00033 00034 00035 const char * SWErrorMsg[] = { 00036 "OK", // SWUP_OK = 0x00, ///< Software Update succeeded as planned. 00037 "Same version", // SWUP_SAME_VER = 0x01, ///< Online version is the same as the installed version. 00038 "Get bin error", // SWUP_HTTP_BIN = 0x02, ///< HTTP get returned an error while trying to fetch the bin file. 00039 "Old file stuck", // SWUP_OLD_STUCK = 0x03, ///< Old file could not be removed. 00040 "Old vers stuck", // SWUP_VER_STUCK = 0x04, ///< Old version number could not be updated. 00041 "Ver write fail", // SWUP_VWRITE_FAILED = 0x05, ///< Can't open for write the version tracking file. 00042 "Integrity fail", // SWUP_INTEGRITY_FAILED = 0x06, ///< Integrity check of downloaded file failed. 00043 "Get ver fail", // SWUP_HTTP_VER = 0x07, ///< HTTP get returned an error while trying to fetch the version file. 00044 "Filesys full", // SWUP_NO_SPACE = 0x08, ///< No space on file system for new version. 00045 "Does not exist", // SWUP_NO_FILE = 0x09, ///< Specified file does not exist 00046 }; 00047 00048 const char * SoftwareUpdateGetHTTPErrorMsg(SWUpdate_T r) 00049 { 00050 const char * p = "invalid result code"; 00051 if (r <= SWUP_NO_FILE) 00052 p = SWErrorMsg[r]; 00053 return p; 00054 } 00055 00056 HTTPResult SoftwareUpdateGetHTTPErrorCode(void) 00057 { 00058 return HTTPErrorCode; 00059 } 00060 00061 00062 static Integrity_t PassesIntegrityCheck(const char * fname, int cksum, int fsize) 00063 { 00064 Integrity_t res = bad_crc; // assume things go wrong... 00065 int newCksum = 0; 00066 int newFSize = 0; 00067 FILE *fh = fopen(fname, "rb"); 00068 00069 INFO("IntegrityCheck(%s,%d,%d)", fname, cksum, fsize); 00070 if (fh) { 00071 char buf; 00072 while (fread(&buf, 1, 1, fh)) { 00073 newCksum = (newCksum + buf) & 0xFFFF; 00074 newFSize++; 00075 } 00076 fclose(fh); 00077 INFO(" Check(...,%d,%d)", newCksum, newFSize); 00078 if (newCksum == cksum && newFSize == fsize) 00079 res = ok; 00080 } else { 00081 WARN("failed to open %s.", fname); 00082 res = no_file; 00083 } 00084 return res; 00085 } 00086 00087 /// mytolower exists because not all compiler libraries have this function 00088 /// 00089 /// This takes a character and if it is upper-case, it converts it to 00090 /// lower-case and returns it. 00091 /// 00092 /// @note this only works for characters in the range 'A' - 'Z'. 00093 /// 00094 /// a is the character to convert 00095 /// returns the lower case equivalent to the supplied character. 00096 /// 00097 static char mytolower(char a) 00098 { 00099 if (a >= 'A' && a <= 'Z') 00100 return (a - 'A' + 'a'); 00101 else 00102 return a; 00103 } 00104 00105 /// mystrnicmp exists because not all compiler libraries have this function. 00106 /// 00107 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which 00108 /// is outside the scope of this C-portable set of functions. 00109 /// 00110 /// l is a pointer to the string on the left 00111 /// r is a pointer to the string on the right 00112 /// n is the number of characters to compare 00113 /// returns -1 if l < r 00114 /// returns 0 if l == r 00115 /// returns +1 if l > r 00116 /// 00117 static int mystrnicmp(const char *l, const char *r, size_t n) 00118 { 00119 int result = 0; 00120 00121 if (n != 0) { 00122 do { 00123 result = mytolower(*l++) - mytolower(*r++); 00124 } while ((result == 0) && (*l != '\0') && (--n > 0)); 00125 } 00126 if (result < -1) 00127 result = -1; 00128 else if (result > 1) 00129 result = 1; 00130 return result; 00131 } 00132 00133 00134 // Scan the local file system for any .bin files and 00135 // if they don't match the current one, remove them. 00136 // 00137 static bool RemoveOtherBinFiles(const char * name, int ver) 00138 { 00139 char curbin[SW_MAX_FQFN]; 00140 DIR *d; 00141 struct dirent *p; 00142 bool noFailed = true; 00143 00144 snprintf(curbin, SW_MAX_FQFN, "%s%02d.bin", name, (ver % 100)); 00145 INFO("Remove bin files excluding {%s}", curbin); 00146 d = opendir("/local/"); 00147 // Get a directory handle 00148 if ( d != NULL ) { 00149 // Walk the directory 00150 while ( (p = readdir(d)) != NULL ) { 00151 INFO(" check {%s}", p->d_name); 00152 // if the file is .bin and not curbin 00153 if (0 == mystrnicmp(p->d_name + strlen(p->d_name) - 4, ".bin", 4) 00154 && (0 != mystrnicmp(p->d_name, curbin, strlen(curbin)))) { 00155 // remove the file 00156 char toremove[SW_MAX_FQFN]; 00157 snprintf(toremove, SW_MAX_FQFN, "/local/%s", p->d_name); 00158 INFO(" removing %s.", toremove); 00159 if (remove(toremove)) { 00160 // set flag if it could not be removed 00161 noFailed = false; 00162 } 00163 } 00164 } 00165 closedir(d); 00166 } 00167 return noFailed; 00168 } 00169 00170 00171 int GetSoftwareVersionNumber(const char * name) 00172 { 00173 char nameroot[7]; 00174 char verfn[SW_MAX_FQFN]; // local version file 00175 00176 strncpy(nameroot, name, 6); 00177 nameroot[6] = '\0'; 00178 snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", nameroot); 00179 00180 /* Read installed version string */ 00181 int inst_ver = -1; 00182 FILE *fv = fopen(verfn, "r"); 00183 if (fv) { 00184 fscanf(fv, "%d", &inst_ver); 00185 fclose(fv); 00186 } else { 00187 inst_ver = -1; 00188 } 00189 INFO(" Installed version: %d", inst_ver); 00190 return inst_ver; 00191 } 00192 00193 bool SetSoftwareVersionNumber(const char * name, int ver, int cksum, int filesize) 00194 { 00195 char nameroot[7]; 00196 char verfn[SW_MAX_FQFN]; // local version file 00197 char buf[40]; 00198 00199 strncpy(nameroot, name, 6); 00200 nameroot[6] = '\0'; 00201 snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", nameroot); 00202 snprintf(buf, 40, "%d,%d,%d", ver, cksum, filesize); 00203 FILE *fv = fopen(verfn, "w"); 00204 if (fv) { 00205 int fr = fputs(buf, fv); 00206 fclose( fv ); 00207 if (fr >= 0) { 00208 return true; 00209 } else { 00210 ERR("Failed (%d) to update stored version number.", fr); 00211 } 00212 } else { 00213 WARN("Failed to update local version info in %s.", verfn); 00214 } 00215 return false; 00216 } 00217 00218 SWUpdate_T SoftwareUpdate(const char *url, const char * name, Reboot_T action) 00219 { 00220 HTTPClient http; 00221 //http.setTimeout( 15000 ); 00222 char fqurl[SW_MAX_URL]; // fully qualified url 00223 char fwfn[SW_MAX_FQFN]; 00224 char nameroot[7]; 00225 SWUpdate_T result = SWUP_OK; // starting out quite optimistic, for all the things that can go wrong 00226 char buf[50]; // long enough for 3 comma separated numbers... 00227 00228 INFO("SoftwareUpdate(%s , %s)", url, name); 00229 strncpy(nameroot, name, 6); 00230 nameroot[6] = '\0'; 00231 int inst_ver = GetSoftwareVersionNumber(name); 00232 /* Download latest version string */ 00233 //HTTPText server_ver("test message"); 00234 snprintf(fqurl, SW_MAX_URL, "%s/%s.txt", url, name); 00235 INFO("Query %s", fqurl); 00236 HTTPErrorCode = http.get(fqurl, buf, sizeof(buf)); 00237 if (HTTPErrorCode == HTTP_OK) { 00238 int latest_ver = -1; 00239 int cksum = 0; 00240 int fsize = 0; 00241 int parseCount; 00242 parseCount = sscanf(buf, "%d,%d,%d", &latest_ver, &cksum, &fsize); 00243 if (parseCount == 3) { 00244 INFO(" web version: %d", latest_ver); 00245 INFO(" checksum: %d", cksum); 00246 INFO(" file size: %d", fsize); 00247 if (inst_ver != latest_ver) { 00248 INFO(" Downloading firmware ver %d ...", latest_ver); 00249 snprintf(fwfn, SW_MAX_FQFN, "/local/%s%02d.BIN", nameroot, (latest_ver % 100)); 00250 snprintf(fqurl, SW_MAX_URL, "%s/%s.bin", url, name); 00251 00252 HTTPFile latest(fwfn); 00253 INFO("Fetch %s", fqurl); 00254 HTTPErrorCode = http.get(fqurl, &latest); 00255 if (HTTPErrorCode == HTTP_OK) { 00256 Integrity_t t = PassesIntegrityCheck(fwfn, cksum, fsize); 00257 if (t == no_file) { 00258 ERR(" *** No space on file system. ***"); 00259 result = SWUP_NO_SPACE; 00260 } else if (t == ok) { 00261 if (!RemoveOtherBinFiles(nameroot, latest_ver)) { 00262 ERR(" *** Failed to remove old version(s). ***"); 00263 result = SWUP_OLD_STUCK; 00264 } 00265 INFO("Updating stored version number."); 00266 if (SetSoftwareVersionNumber(name, latest_ver, cksum, fsize)) { 00267 // ok 00268 if (action == AUTO_REBOOT) { 00269 WARN("Resetting...\n"); 00270 wait_ms(200); 00271 mbed_reset(); 00272 } 00273 } else { 00274 // failed 00275 ERR("Failed to update stored version number."); 00276 result = SWUP_VWRITE_FAILED; 00277 } 00278 } else /* t == bad_crc */ { 00279 WARN("New file {%s} did not pass integrity check.", fwfn); 00280 result = SWUP_INTEGRITY_FAILED; 00281 } 00282 } else { 00283 WARN("Failed to download lastest firmware."); 00284 result = SWUP_HTTP_BIN; 00285 } 00286 } else { 00287 INFO("Online version is same as installed version."); 00288 result = SWUP_SAME_VER; 00289 } 00290 } 00291 } else { 00292 int ec = http.getHTTPResponseCode(); 00293 WARN("Failed accessing {%s}. Extended Error Code = %d", fqurl, HTTPErrorCode); 00294 WARN(" HTTP Response Code %d", ec); 00295 if (ec == 404) 00296 result = SWUP_NO_FILE; 00297 else 00298 result = SWUP_HTTP_VER; 00299 } 00300 return result; 00301 }
Generated on Wed Jul 13 2022 03:23:45 by 1.7.2