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

Dependents:   FirmwareUpdater_TestProgram geigercounter04 firm LPC1768_up_frim

Revision:
0:f9bdb06ab672
Child:
1:0305a8120f06
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FirmwareUpdater.cpp	Wed Nov 03 12:57:51 2010 +0000
@@ -0,0 +1,249 @@
+/**
+ * =============================================================================
+ * Firmware updater (Version 0.0.1)
+ * =============================================================================
+ * Copyright (c) 2010 Shinichiro Nakamura (CuBeatSystems)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * =============================================================================
+ */
+
+#include "FirmwareUpdater.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+extern "C" void mbed_reset();
+
+const std::string FirmwareUpdater::EXT_BIN = ".bin";
+const std::string FirmwareUpdater::EXT_BINTMP = ".b__";
+const std::string FirmwareUpdater::EXT_TXT = ".txt";
+const std::string FirmwareUpdater::EXT_TXTTMP = ".t__";
+
+/**
+ * Create.
+ *
+ * @param url URL for firmware. Do not include a target file name.
+ * @param name An application name. Do not include a extention.
+ * @param log True if logging.
+ */
+FirmwareUpdater::FirmwareUpdater(std::string url, std::string name, bool log)
+        : url(url), name(name), log(log), local("local") {
+    client.setTimeout(10000);
+
+    /*
+     * 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());
+    }
+}
+
+/**
+ * Dispose.
+ */
+FirmwareUpdater::~FirmwareUpdater() {
+}
+
+/**
+ * Get a URL.
+ *
+ * @return URL.
+ */
+const std::string FirmwareUpdater:: getURL() const {
+    return url;
+}
+
+/**
+ * Get a name.
+ *
+ * @return name.
+ */
+const std::string FirmwareUpdater:: getName() const {
+    return name;
+}
+
+/**
+ * Checking a new firmware.
+ * Compare versions of the software between local storage on mbed and on webserver.
+ *
+ * @return Return 0 if a new firmware exists.
+ */
+int FirmwareUpdater::exist() {
+    int ver_local, ver_server;
+
+    /*
+     * 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());
+    }
+    /*
+     * 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());
+    }
+
+    return (ver_local < ver_server) ? 0 : 1;
+}
+
+/**
+ * Execute update.
+ *
+ * @return Return 0 if it succeed.
+ */
+int FirmwareUpdater::execute() {
+    /*
+     * 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) {
+        return -1;
+    }
+    if (fetch(serv_bin, file_bintmp) != 0) {
+        return -2;
+    }
+    /*
+     * Copy it.
+     */
+    std::string file_txt = "/local/" + name + EXT_TXT;
+    std::string file_bin = "/local/" + name + EXT_BIN;
+    if (copy(file_txttmp, file_txt) != 0) {
+        return -3;
+    }
+    if (copy(file_bintmp, file_bin) != 0) {
+        return -4;
+    }
+    /*
+     * Delete the temporary files.
+     */
+    remove(file_txttmp.c_str());
+    remove(file_bintmp.c_str());
+    return 0;
+}
+
+/**
+ * Reset system.
+ */
+void FirmwareUpdater::reset() {
+    mbed_reset();
+}
+
+/**
+ * Fetch a file.
+ *
+ * @param src_url URL of a source file.
+ * @param local_file Local file name.
+ *
+ * @return Return 0 if it succeed.
+ */
+int FirmwareUpdater::fetch(std::string src_url, std::string local_file) {
+    /*
+     * Fetch the source file from URL to a temporary file on local.
+     */
+    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());
+        return -1;
+    }
+    LOG("Fetch '%s' from '%s' succeed.\n", local_file.c_str(), src_url.c_str());
+    return 0;
+}
+
+/**
+ * Copy a file.
+ *
+ * @param local_file1 Source file.
+ * @param local_file2 Destination file.
+ *
+ * @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());
+
+    FILE *rp = fopen(local_file1.c_str(), "rb");
+    if (rp == NULL) {
+        LOG("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());
+        fclose(rp);
+        return -2;
+    }
+    int c;
+    while ((c = fgetc(rp)) != EOF) {
+        fputc(c, wp);
+    }
+    fclose(rp);
+    fclose(wp);
+    LOG("File copied. (%s->%s)\n", local_file1.c_str(), local_file2.c_str());
+    return 0;
+}
+
+/**
+ * Output a message to a log file.
+ *
+ * @param format ...
+ */
+void FirmwareUpdater::LOG(const char* format, ...) {
+    if (log) {
+        FILE *fplog = fopen("/local/update.log", "a");
+        if (fplog != NULL) {
+            char buf[BUFSIZ];
+            va_list p;
+            va_start(p, format);
+            vsnprintf(buf, sizeof(buf) - 1, format, p);
+            fprintf(fplog, "%s", buf);
+            va_end(p);
+            fclose(fplog);
+        }
+    }
+}