SWUpdate library to be used with RPC.

Fork of SWUpdate by David Smart

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;
 }