SWUpdate library to be used with RPC.
Fork of SWUpdate by
Diff: SWUpdate.cpp
- Revision:
- 9:73067ef14c30
- Parent:
- 8:8e840a036116
- Child:
- 14:0e012d53c6df
--- a/SWUpdate.cpp Sun Jun 15 20:01:58 2014 +0000 +++ b/SWUpdate.cpp Sat Jun 21 19:13:30 2014 +0000 @@ -30,6 +30,7 @@ int newCksum = 0; int newFSize = 0; FILE *fh = fopen(fname, "rb"); + INFO("IntegrityCheck(%s,%d,%d)", fname, cksum, fsize); if (fh) { char buf; @@ -47,17 +48,96 @@ return res; } -bool SoftwareUpdate(const char *url, const char * name, Reboot_T reboot) { +/// mytolower exists because not all compiler libraries have this function +/// +/// This takes a character and if it is upper-case, it converts it to +/// lower-case and returns it. +/// +/// @param a is the character to convert +/// @returns the lower case equivalent to a +/// +static char mytolower(char a) { + if (a >= 'A' && a <= 'Z') + return (a - 'A' + 'a'); + else + return a; +} + +/// mystrnicmp exists because not all compiler libraries have this function. +/// +/// Some have strnicmp, others _strnicmp, and others have C++ methods, which +/// is outside the scope of this C-portable set of functions. +/// +/// @param l is a pointer to the string on the left +/// @param r is a pointer to the string on the right +/// @param n is the number of characters to compare +/// @returns -1 if l < r +/// @returns 0 if l == r +/// @returns +1 if l > r +/// +static int mystrnicmp(const char *l, const char *r, size_t n) { + int result = 0; + + if (n != 0) { + do { + result = mytolower(*l++) - mytolower(*r++); + } while ((result == 0) && (*l != '\0') && (--n > 0)); + } + if (result < -1) + result = -1; + else if (result > 1) + result = 1; + return result; +} + + +// Scan the local file system for any .bin files and +// if they don't match the current one, remove them. +// +static bool RemoveOtherBinFiles(const char * name, int ver) +{ + char curbin[SW_MAX_FQFN]; + DIR *d; + struct dirent *p; + bool noFailed = true; + + snprintf(curbin, SW_MAX_FQFN, "%s%03d.bin", name, ver); + INFO("Remove bin files excluding {%s}", curbin); + d = opendir("/local/"); + // Get a directory handle + if ( d != NULL ) { + // Walk the directory + while ( (p = readdir(d)) != NULL ) { + INFO(" check {%s}", p->d_name); + // if the file is .bin and not curbin + if (0 == mystrnicmp(p->d_name + strlen(p->d_name) - 4, ".bin", 4) + && (0 != mystrnicmp(p->d_name, curbin, strlen(curbin)))) { + // remove the file + char toremove[SW_MAX_FQFN]; + snprintf(toremove, SW_MAX_FQFN, "/local/%s", p->d_name); + INFO(" removing %s.", toremove); + if (remove(toremove)) { + // set flag if it could not be removed + noFailed = false; + } + } + } + closedir(d); + } + return noFailed; +} + +SWUpdate_T SoftwareUpdate(const char *url, const char * name, Reboot_T action) { HTTPClient http; //http.setTimeout( 15000 ); - char fqurl[150]; // fully qualified url - char verfn[32]; // local version file - char fwfn[32]; - bool result = false; // many things can go wrong, assume failure - char buf[50]; + char fqurl[SW_MAX_URL]; // fully qualified url + char verfn[SW_MAX_FQFN]; // local version file + char fwfn[SW_MAX_FQFN]; + uint16_t result = SWUP_OK; // starting out quite optimistic, for all the things that can go wrong + char buf[50]; // long enough for 3 comma separated numbers... INFO("SoftwareUpdate(%s,%s)", url, name); - snprintf(verfn, 32, "/local/%s.ver", name); + snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", name); /* Read installed version string */ int inst_ver = -1; @@ -70,7 +150,7 @@ /* Download latest version string */ HTTPText server_ver("test message"); - snprintf(fqurl, 150, "%s/%s.txt", url, name); + snprintf(fqurl, SW_MAX_URL, "%s/%s.txt", url, name); HTTPResult r = http.get(fqurl, buf, sizeof(buf)); if (r == HTTP_OK) { int latest_ver = -1; @@ -79,25 +159,21 @@ int parseCount; parseCount = sscanf(buf, "%d,%d,%d", &latest_ver, &cksum, &fsize); if (parseCount == 3) { - INFO(" web version: %d", latest_ver); - INFO(" checksum: %d", cksum); - INFO(" file size: %d", fsize); + INFO(" web version: %d", latest_ver); + INFO(" checksum: %d", cksum); + INFO(" file size: %d", fsize); if (inst_ver != latest_ver) { INFO(" Downloading firmware ver %d ...", latest_ver); - sprintf(fwfn, "/local/%s%d.BIN", name, latest_ver); + sprintf(fwfn, "/local/%s%03d.BIN", name, latest_ver); snprintf(fqurl, 150, "%s/%s.bin", url, name); HTTPFile latest(fwfn); r = http.get(fqurl, &latest); if (r == HTTP_OK) { - // Check the integrity of the freshly downloaded file, - // before swapping out the old version. - // ... to appear here ... if (PassesIntegrityCheck(fwfn, cksum, fsize)) { - sprintf(fwfn, "/local/%s%d.BIN", name, inst_ver); - INFO(" Firmware downloaded, removing old version (%s).", fwfn); - if (remove(fwfn)) { - ERR(" *** Failed to remove old version. ***"); + if (!RemoveOtherBinFiles(name, latest_ver)) { + ERR(" *** Failed to remove old version(s). ***"); + result |= SWUP_OLD_STUCK; } INFO("Updating stored version number."); fv = fopen(verfn, "w"); @@ -106,30 +182,35 @@ if (fr < 0) { ERR("Failed (%d) to update stored version number.", fr); fclose( fv ); + result |= SWUP_VER_STUCK; } else { fclose( fv ); - if (reboot == AUTO_REBOOT) { + if (action == AUTO_REBOOT) { WARN("Resetting...\n"); wait_ms(200); mbed_reset(); } - result = true; } } else { WARN("Failed to update local version info in %s.", verfn); + result |= SWUP_VWRITE_FAILED; } } else { WARN("New file {%s} did not pass integrity check.", fwfn); + result |= SWUP_INTEGRITY_FAILED; } } else { WARN("Failed to download lastest firmware."); + result |= SWUP_BAD_URL; } } else { - INFO("Online version is same as installed version.", parseCount); + INFO("Online version is same as installed version."); + result |= SWUP_SAME_VER; } } } else { WARN("Failed to download online firmware version number."); + result |= SWUP_HTTP_ERR; } - return result; + return (SWUpdate_T)result; }