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 12:57:51 2010 +0000
Child:
1:0305a8120f06
Commit message:
Initial version.

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
--- /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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FirmwareUpdater.h	Wed Nov 03 12:57:51 2010 +0000
@@ -0,0 +1,152 @@
+/**
+ * =============================================================================
+ * 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.
+ * =============================================================================
+ */
+
+#ifndef FIRMWARE_UPDATER_H
+#define FIRMWARE_UPDATER_H
+
+#include "mbed.h"
+#include "HTTPClient.h"
+#include "LocalFileSystem.h"
+#include <string>
+
+/**
+ * @code
+ * #include "mbed.h"
+ * #include "FirmwareUpdater.h"
+ * #include "EthernetNetIf.h"
+ *
+ * EthernetNetIf eth;
+ * FirmwareUpdater fwup("http://mbed.org/media/uploads/shintamainjp/", "firmware", true); 
+ *
+ * // There are 2 files for the firmware.
+ * //  1. firmware.txt : firmware version file.
+ * //  2. firmware.bin : firmware binary file.
+ *
+ * int main() {
+ *     eth.setup();
+ *     if (fwup.exist() == 0) {
+ *         printf("Found a new firmware.\n");
+ *         if (fwup.execute() == 0) {
+ *             printf("Update succeed.\n");
+ *             printf("Resetting this system...\n\n\n\n\n");
+ *             fwup.reset();
+ *         } else {
+ *             printf("Update failed!\n");
+ *         }
+ *     }
+ * }
+ * @endcode
+ */
+class FirmwareUpdater {
+public:
+    /**
+     * 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(std::string url, std::string name, bool log = false);
+
+    /**
+     * Dispose.
+     */
+    ~FirmwareUpdater();
+
+    /**
+     * Get a URL.
+     *
+     * @return URL.
+     */
+    const std::string getURL() const;
+
+    /**
+     * Get a name.
+     *
+     * @return name.
+     */
+    const std::string getName() const;
+
+    /**
+     * 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 exist();
+
+    /**
+     * Execute update.
+     *
+     * @return Return 0 if it succeed.
+     */
+    int execute();
+
+    /**
+     * Reset system.
+     */
+    void reset();
+private:
+    static const std::string EXT_BIN;
+    static const std::string EXT_BINTMP;
+    static const std::string EXT_TXT;
+    static const std::string EXT_TXTTMP;
+    const std::string url;
+    const std::string name;
+    const bool log;
+    LocalFileSystem local;
+    HTTPClient client;
+
+    /**
+     * Fetch a file.
+     *
+     * @param src_url URL of a source file.
+     * @param local_file Local file name.
+     *
+     * @return Return 0 if it succeed.
+     */
+    int fetch(std::string src_url, std::string local_file);
+
+    /**
+     * Copy a file.
+     *
+     * @param local_file1 Source file.
+     * @param local_file2 Destination file.
+     *
+     * @return Return 0 if it succeed.
+     */
+    int copy(std::string local_file1, std::string local_file2);
+
+    /**
+     * Output a message to a log file.
+     *
+     * @param format ...
+     */
+    void LOG(const char* format, ...);
+
+};
+
+#endif