The FirmwareUpdater is a mbed firmware update library with HTTP server on cloud.
Dependents: FirmwareUpdater_TestProgram geigercounter04 firm LPC1768_up_frim
Diff: FirmwareUpdater.cpp
- Revision:
- 0:f9bdb06ab672
- Child:
- 1:0305a8120f06
diff -r 000000000000 -r f9bdb06ab672 FirmwareUpdater.cpp --- /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); + } + } +}