The FirmwareUpdater is a mbed firmware update library with HTTP server on cloud.

Dependents:   FirmwareUpdater_TestProgram geigercounter04 firm LPC1768_up_frim

Files at this revision

API Documentation at this revision

Comitter:
shintamainjp
Date:
Wed Nov 03 22:03:18 2010 +0000
Parent:
0:f9bdb06ab672
Child:
2:a9a32355af69
Commit message:
Bug fixed. mbed can not sense a new firmware binary. Because there is no time stamp for the binary. So I decided to change a specification of my library.

Changed in this revision

FirmwareUpdater.cpp Show annotated file Show diff for this revision Revisions of this file
FirmwareUpdater.h Show annotated file Show diff for this revision Revisions of this file
--- a/FirmwareUpdater.cpp	Wed Nov 03 12:57:51 2010 +0000
+++ b/FirmwareUpdater.cpp	Wed Nov 03 22:03:18 2010 +0000
@@ -1,6 +1,6 @@
 /**
  * =============================================================================
- * Firmware updater (Version 0.0.1)
+ * Firmware updater (Version 0.0.2)
  * =============================================================================
  * Copyright (c) 2010 Shinichiro Nakamura (CuBeatSystems)
  *
@@ -10,7 +10,7 @@
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
@@ -50,9 +50,10 @@
     /*
      * A file name on the mbed local file system should keep '8 + 3' types of name.
      */
-    if (name.length() > 8) {
-        printf("Invalid firmware name '%s' found. The maximum length is 8.\n", name.c_str());
-        LOG("Invalid firmware name '%s' found. The maximum length is 8.\n", name.c_str());
+    const int PREFIX_MAXLEN = 4;
+    if (name.length() > PREFIX_MAXLEN) {
+        LOG("ERR : Invalid firmware name '%s' found. The maximum length is PREFIX_MAXLEN.\n", name.c_str());
+        error("ERR : Invalid firmware name '%s' found. The maximum length is PREFIX_MAXLEN.\n", name.c_str());
     }
 }
 
@@ -92,36 +93,19 @@
     /*
      * Fetch the version from a local.
      */
-    {
-        std::string file_local = "/local/" + name + EXT_TXT;
-        FILE *fp = fopen(file_local.c_str(), "rb");
-        if (fp == NULL) {
-            LOG("Local firmware version file '%s' open failed.\n", file_local.c_str());
-            return -1;
-        }
-        if (fscanf(fp, "%d", &ver_local) != 1) {
-            LOG("Local firmware version file '%s' is invalid.\n", file_local.c_str());
-            return -2;
-        }
-        fclose(fp);
-        LOG("Local firmware version is %d. (%s)\n", ver_local, file_local.c_str());
+    std::string file_local = "/local/" + name + EXT_TXT;
+    ver_local = readVersionFromFile(file_local.c_str());
+    if (ver_local < 0) {
+        return -1;
     }
+
     /*
      * Fetch the version from a server.
      */
-    {
-        std::string file_server = url + "/" + name + EXT_TXT;
-        HTTPText text;
-        HTTPResult r = client.get(file_server.c_str(), &text);
-        if (r != HTTP_OK) {
-            LOG("Server firmware version file '%s' open failed.\n", file_server.c_str());
-            return -3;
-        }
-        if (sscanf(text.gets(), "%d", &ver_server) != 1) {
-            LOG("Server firmware version file '%s' is invalid.\n", file_server.c_str());
-            return -4;
-        }
-        LOG("Server firmware version is %d. (%s)\n", ver_server, file_server.c_str());
+    std::string file_server = url + "/" + name + EXT_TXT;
+    ver_server = readVersionFromURL(file_server.c_str());
+    if (ver_server < 0) {
+        return -2;
     }
 
     return (ver_local < ver_server) ? 0 : 1;
@@ -137,25 +121,65 @@
      * Fetch the files.
      */
     std::string serv_txt = url + "/" + name + EXT_TXT;
-    std::string serv_bin = url + "/" + name + EXT_BIN;
     std::string file_txttmp = "/local/" + name + EXT_TXTTMP;
-    std::string file_bintmp = "/local/" + name + EXT_BINTMP;
     if (fetch(serv_txt, file_txttmp) != 0) {
+        LOG("ERR : Aborted...\n");
         return -1;
     }
+    std::string serv_bin = url + "/" + name + EXT_BIN;
+    std::string file_bintmp = "/local/" + name + EXT_BINTMP;
     if (fetch(serv_bin, file_bintmp) != 0) {
+        LOG("ERR : Aborted...\n");
         return -2;
     }
+
+    /*
+     * Check the firmware versions.
+     */
+    std::string file_txt = "/local/" + name + EXT_TXT;
+    int ver_old = readVersionFromFile(file_txt.c_str());
+    int ver_new = readVersionFromFile(file_txttmp.c_str());
+    if (ver_old < 0) {
+        LOG("ERR : Could not read the previous firmware version.\n");
+        LOG("ERR : Aborted...\n");
+        return -3;
+    }
+    if (ver_new < 0) {
+        LOG("ERR : Could not read the new firmware version.\n");
+        LOG("ERR : Aborted...\n");
+        return -4;
+    }
+    if (ver_new < ver_old) {
+        LOG("ERR : Ignore the new firmware. (old=%d, new=%d)\n", ver_old, ver_new);
+        LOG("ERR : Aborted...\n");
+        return -5;
+    }
+    LOG("INFO: Firmware updating... (%d -> %d)\n", ver_old, ver_new);
+
+    /*
+     * Cleanup the previous versions.
+     *
+     * Note:
+     *  A file time stamp on mbed is always '12:00 01/01/2008'.
+     *  mbed can't sense updated firmware when the file name is same as previous version.
+     *
+     *  So I decided to cleanup all bin files.
+     *  And the new firmware name is 'name-VERSION.bin'.
+     *  To remove previous versions at first means 'start critical section on the system'.
+     */
+    cleanupAllBinFiles();
+
     /*
      * Copy it.
      */
-    std::string file_txt = "/local/" + name + EXT_TXT;
-    std::string file_bin = "/local/" + name + EXT_BIN;
+    char nbuf[32];
+    snprintf(nbuf, sizeof(nbuf) - 1, "-%d", ver_new);
+    std::string file_bin = "/local/" + name + std::string(nbuf) + EXT_BIN;
     if (copy(file_txttmp, file_txt) != 0) {
-        return -3;
+        return -6;
     }
     if (copy(file_bintmp, file_bin) != 0) {
-        return -4;
+        return -7;
     }
     /*
      * Delete the temporary files.
@@ -187,10 +211,10 @@
     HTTPFile file(local_file.c_str());
     int r = client.get(src_url.c_str(), &file);
     if (r != HTTP_OK) {
-        LOG("Fetch '%s' from '%s' failed.\n", local_file.c_str(), src_url.c_str());
+        LOG("ERR : Fetch '%s' to '%s'.\n", src_url.c_str(), local_file.c_str());
         return -1;
     }
-    LOG("Fetch '%s' from '%s' succeed.\n", local_file.c_str(), src_url.c_str());
+    LOG("INFO: Fetch '%s' to '%s'.\n", src_url.c_str(), local_file.c_str());
     return 0;
 }
 
@@ -203,18 +227,16 @@
  * @return Return 0 if it succeed.
  */
 int FirmwareUpdater::copy(std::string local_file1, std::string local_file2) {
-
-    LOG("File copying... (%s->%s)\n", local_file1.c_str(), local_file2.c_str());
-
+    LOG("INFO: File copying... (%s->%s)\n", local_file1.c_str(), local_file2.c_str());
     FILE *rp = fopen(local_file1.c_str(), "rb");
     if (rp == NULL) {
-        LOG("File '%s' open failed.\n", local_file1.c_str());
+        LOG("ERR : File '%s' open failed.\n", local_file1.c_str());
         return -1;
     }
     remove(local_file2.c_str());
     FILE *wp = fopen(local_file2.c_str(), "wb");
     if (wp == NULL) {
-        LOG("File '%s' open failed.\n", local_file2.c_str());
+        LOG("ERR : File '%s' open failed.\n", local_file2.c_str());
         fclose(rp);
         return -2;
     }
@@ -224,7 +246,7 @@
     }
     fclose(rp);
     fclose(wp);
-    LOG("File copied. (%s->%s)\n", local_file1.c_str(), local_file2.c_str());
+    LOG("INFO: File copied. (%s->%s)\n", local_file1.c_str(), local_file2.c_str());
     return 0;
 }
 
@@ -242,8 +264,80 @@
             va_start(p, format);
             vsnprintf(buf, sizeof(buf) - 1, format, p);
             fprintf(fplog, "%s", buf);
+
+            printf("%s", buf);
+
             va_end(p);
             fclose(fplog);
         }
     }
 }
+
+/**
+ * Cleanup all bin files.
+ */
+int FirmwareUpdater::cleanupAllBinFiles(void) {
+    struct dirent *p;
+    DIR *dir = opendir("/local");
+    if (dir == NULL) {
+        return -1;
+    }
+    while ((p = readdir(dir)) != NULL) {
+        char *str = p->d_name;
+        if ((strstr(str, ".bin") != NULL) || (strstr(str, ".BIN") != NULL)) {
+            char buf[BUFSIZ];
+            snprintf(buf, sizeof(buf) - 1, "/local/%s", str);
+            if (remove(buf) == 0) {
+                LOG("INFO: Deleted '%s'.\n", buf);
+            } else {
+                LOG("ERR : Delete '%s' failed.\n", buf);
+            }
+        }
+    }
+    closedir(dir);
+    return 0;
+}
+
+/**
+ * Read a version from a file.
+ *
+ * @param filename file name.
+ * @return A version.
+ */
+int FirmwareUpdater::readVersionFromFile(const char *filename) {
+    int ver;
+    FILE *fp = fopen(filename, "rb");
+    if (fp == NULL) {
+        LOG("ERR : Version file '%s' open failed.\n", filename);
+        return -1;
+    }
+    if (fscanf(fp, "%d", &ver) != 1) {
+        LOG("ERR : Version file '%s' is invalid.\n", filename);
+        return -2;
+    }
+    fclose(fp);
+    LOG("INFO: Version file '%s': Version %d.\n", filename, ver);
+    return ver;
+}
+
+/**
+ * Read a version from a URL.
+ *
+ * @param url URL.
+ * @return A version.
+ */
+int FirmwareUpdater::readVersionFromURL(const char *url) {
+    int ver;
+    HTTPText text;
+    HTTPResult r = client.get(url, &text);
+    if (r != HTTP_OK) {
+        LOG("ERR : Version file '%s' open failed.\n", url);
+        return -1;
+    }
+    if (sscanf(text.gets(), "%d", &ver) != 1) {
+        LOG("ERR : Version file '%s' is invalid.\n", url);
+        return -2;
+    }
+    LOG("INFO: Version file '%s': Version %d.\n", url, ver);
+    return ver;
+}
--- a/FirmwareUpdater.h	Wed Nov 03 12:57:51 2010 +0000
+++ b/FirmwareUpdater.h	Wed Nov 03 22:03:18 2010 +0000
@@ -1,6 +1,6 @@
 /**
  * =============================================================================
- * Firmware updater (Version 0.0.1)
+ * Firmware updater (Version 0.0.2)
  * =============================================================================
  * Copyright (c) 2010 Shinichiro Nakamura (CuBeatSystems)
  *
@@ -10,7 +10,7 @@
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
@@ -39,7 +39,7 @@
  * #include "EthernetNetIf.h"
  *
  * EthernetNetIf eth;
- * FirmwareUpdater fwup("http://mbed.org/media/uploads/shintamainjp/", "firmware", true); 
+ * FirmwareUpdater fwup("http://mbed.org/media/uploads/shintamainjp/", "firmware", true);
  *
  * // There are 2 files for the firmware.
  * //  1. firmware.txt : firmware version file.
@@ -147,6 +147,26 @@
      */
     void LOG(const char* format, ...);
 
+    /**
+     * Cleanup all bin files.
+     */
+    int cleanupAllBinFiles(void);
+
+    /**
+     * Read a version from a file.
+     *
+     * @param filename file name.
+     * @return A version.
+     */
+    int readVersionFromFile(const char *filename);
+
+    /**
+     * Read a version from a URL.
+     *
+     * @param url URL.
+     * @return A version.
+     */
+    int readVersionFromURL(const char *url);
 };
 
 #endif