SWUpdate library to be used with RPC.

Fork of SWUpdate by David Smart

Committer:
WiredHome
Date:
Sat Jul 05 16:06:55 2014 +0000
Revision:
16:de99e872fc9d
Parent:
15:49cc43dcbbf6
Child:
17:1d318666246c
Permit reference to "long file" name on server, but truncate binary file name on local file system to 6 chars, allowing 2 for version number => staying at final of 8.3.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:e221363f7942 1
WiredHome 0:e221363f7942 2 // Software Update via Ethernet from forum -
WiredHome 0:e221363f7942 3 // http://mbed.org/forum/mbed/topic/1183/
WiredHome 1:208de08b1a19 4 //
WiredHome 0:e221363f7942 5 #include "mbed.h"
WiredHome 0:e221363f7942 6 #include "SWUpdate.h"
WiredHome 0:e221363f7942 7 #include "HTTPClient.h"
WiredHome 0:e221363f7942 8 #include "HTTPText.h"
WiredHome 0:e221363f7942 9 #include "HTTPFile.h"
WiredHome 0:e221363f7942 10 #include <stdio.h>
WiredHome 0:e221363f7942 11
WiredHome 0:e221363f7942 12 extern "C" void mbed_reset();
WiredHome 0:e221363f7942 13
WiredHome 15:49cc43dcbbf6 14 //#define DEBUG "SWup"
WiredHome 0:e221363f7942 15 #include <cstdio>
WiredHome 0:e221363f7942 16 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 0:e221363f7942 17 #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:e221363f7942 18 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:e221363f7942 19 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:e221363f7942 20 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:e221363f7942 21 #else
WiredHome 0:e221363f7942 22 #define DBG(x, ...)
WiredHome 0:e221363f7942 23 #define WARN(x, ...)
WiredHome 0:e221363f7942 24 #define ERR(x, ...)
WiredHome 0:e221363f7942 25 #define INFO(x, ...)
WiredHome 0:e221363f7942 26 #endif
WiredHome 0:e221363f7942 27
WiredHome 3:c69fff55fc60 28 static bool PassesIntegrityCheck(const char * fname, int cksum, int fsize) {
WiredHome 3:c69fff55fc60 29 int res = false; // assume things go wrong...
WiredHome 3:c69fff55fc60 30 int newCksum = 0;
WiredHome 3:c69fff55fc60 31 int newFSize = 0;
WiredHome 3:c69fff55fc60 32 FILE *fh = fopen(fname, "rb");
WiredHome 9:73067ef14c30 33
WiredHome 3:c69fff55fc60 34 INFO("IntegrityCheck(%s,%d,%d)", fname, cksum, fsize);
WiredHome 3:c69fff55fc60 35 if (fh) {
WiredHome 3:c69fff55fc60 36 char buf;
WiredHome 3:c69fff55fc60 37 while (fread(&buf, 1, 1, fh)) {
WiredHome 3:c69fff55fc60 38 newCksum = (newCksum + buf) & 0xFFFF;
WiredHome 3:c69fff55fc60 39 newFSize++;
WiredHome 3:c69fff55fc60 40 }
WiredHome 3:c69fff55fc60 41 fclose(fh);
WiredHome 3:c69fff55fc60 42 INFO(" Check(...,%d,%d)", newCksum, newFSize);
WiredHome 3:c69fff55fc60 43 if (newCksum == cksum && newFSize == fsize)
WiredHome 3:c69fff55fc60 44 res = true;
WiredHome 3:c69fff55fc60 45 } else {
WiredHome 3:c69fff55fc60 46 WARN("failed to open %s.", fname);
WiredHome 3:c69fff55fc60 47 }
WiredHome 3:c69fff55fc60 48 return res;
WiredHome 1:208de08b1a19 49 }
WiredHome 1:208de08b1a19 50
WiredHome 9:73067ef14c30 51 /// mytolower exists because not all compiler libraries have this function
WiredHome 9:73067ef14c30 52 ///
WiredHome 9:73067ef14c30 53 /// This takes a character and if it is upper-case, it converts it to
WiredHome 9:73067ef14c30 54 /// lower-case and returns it.
WiredHome 9:73067ef14c30 55 ///
WiredHome 9:73067ef14c30 56 /// @param a is the character to convert
WiredHome 9:73067ef14c30 57 /// @returns the lower case equivalent to a
WiredHome 9:73067ef14c30 58 ///
WiredHome 9:73067ef14c30 59 static char mytolower(char a) {
WiredHome 9:73067ef14c30 60 if (a >= 'A' && a <= 'Z')
WiredHome 9:73067ef14c30 61 return (a - 'A' + 'a');
WiredHome 9:73067ef14c30 62 else
WiredHome 9:73067ef14c30 63 return a;
WiredHome 9:73067ef14c30 64 }
WiredHome 9:73067ef14c30 65
WiredHome 9:73067ef14c30 66 /// mystrnicmp exists because not all compiler libraries have this function.
WiredHome 9:73067ef14c30 67 ///
WiredHome 9:73067ef14c30 68 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which
WiredHome 9:73067ef14c30 69 /// is outside the scope of this C-portable set of functions.
WiredHome 9:73067ef14c30 70 ///
WiredHome 9:73067ef14c30 71 /// @param l is a pointer to the string on the left
WiredHome 9:73067ef14c30 72 /// @param r is a pointer to the string on the right
WiredHome 9:73067ef14c30 73 /// @param n is the number of characters to compare
WiredHome 9:73067ef14c30 74 /// @returns -1 if l < r
WiredHome 9:73067ef14c30 75 /// @returns 0 if l == r
WiredHome 9:73067ef14c30 76 /// @returns +1 if l > r
WiredHome 9:73067ef14c30 77 ///
WiredHome 9:73067ef14c30 78 static int mystrnicmp(const char *l, const char *r, size_t n) {
WiredHome 9:73067ef14c30 79 int result = 0;
WiredHome 9:73067ef14c30 80
WiredHome 9:73067ef14c30 81 if (n != 0) {
WiredHome 9:73067ef14c30 82 do {
WiredHome 9:73067ef14c30 83 result = mytolower(*l++) - mytolower(*r++);
WiredHome 9:73067ef14c30 84 } while ((result == 0) && (*l != '\0') && (--n > 0));
WiredHome 9:73067ef14c30 85 }
WiredHome 9:73067ef14c30 86 if (result < -1)
WiredHome 9:73067ef14c30 87 result = -1;
WiredHome 9:73067ef14c30 88 else if (result > 1)
WiredHome 9:73067ef14c30 89 result = 1;
WiredHome 9:73067ef14c30 90 return result;
WiredHome 9:73067ef14c30 91 }
WiredHome 9:73067ef14c30 92
WiredHome 9:73067ef14c30 93
WiredHome 9:73067ef14c30 94 // Scan the local file system for any .bin files and
WiredHome 9:73067ef14c30 95 // if they don't match the current one, remove them.
WiredHome 9:73067ef14c30 96 //
WiredHome 9:73067ef14c30 97 static bool RemoveOtherBinFiles(const char * name, int ver)
WiredHome 9:73067ef14c30 98 {
WiredHome 9:73067ef14c30 99 char curbin[SW_MAX_FQFN];
WiredHome 9:73067ef14c30 100 DIR *d;
WiredHome 9:73067ef14c30 101 struct dirent *p;
WiredHome 9:73067ef14c30 102 bool noFailed = true;
WiredHome 9:73067ef14c30 103
WiredHome 14:0e012d53c6df 104 snprintf(curbin, SW_MAX_FQFN, "%s%02d.bin", name, ver);
WiredHome 9:73067ef14c30 105 INFO("Remove bin files excluding {%s}", curbin);
WiredHome 9:73067ef14c30 106 d = opendir("/local/");
WiredHome 9:73067ef14c30 107 // Get a directory handle
WiredHome 9:73067ef14c30 108 if ( d != NULL ) {
WiredHome 9:73067ef14c30 109 // Walk the directory
WiredHome 9:73067ef14c30 110 while ( (p = readdir(d)) != NULL ) {
WiredHome 9:73067ef14c30 111 INFO(" check {%s}", p->d_name);
WiredHome 9:73067ef14c30 112 // if the file is .bin and not curbin
WiredHome 9:73067ef14c30 113 if (0 == mystrnicmp(p->d_name + strlen(p->d_name) - 4, ".bin", 4)
WiredHome 9:73067ef14c30 114 && (0 != mystrnicmp(p->d_name, curbin, strlen(curbin)))) {
WiredHome 9:73067ef14c30 115 // remove the file
WiredHome 9:73067ef14c30 116 char toremove[SW_MAX_FQFN];
WiredHome 9:73067ef14c30 117 snprintf(toremove, SW_MAX_FQFN, "/local/%s", p->d_name);
WiredHome 9:73067ef14c30 118 INFO(" removing %s.", toremove);
WiredHome 9:73067ef14c30 119 if (remove(toremove)) {
WiredHome 9:73067ef14c30 120 // set flag if it could not be removed
WiredHome 9:73067ef14c30 121 noFailed = false;
WiredHome 9:73067ef14c30 122 }
WiredHome 9:73067ef14c30 123 }
WiredHome 9:73067ef14c30 124 }
WiredHome 9:73067ef14c30 125 closedir(d);
WiredHome 9:73067ef14c30 126 }
WiredHome 9:73067ef14c30 127 return noFailed;
WiredHome 9:73067ef14c30 128 }
WiredHome 9:73067ef14c30 129
WiredHome 9:73067ef14c30 130 SWUpdate_T SoftwareUpdate(const char *url, const char * name, Reboot_T action) {
WiredHome 0:e221363f7942 131 HTTPClient http;
WiredHome 0:e221363f7942 132 //http.setTimeout( 15000 );
WiredHome 9:73067ef14c30 133 char fqurl[SW_MAX_URL]; // fully qualified url
WiredHome 9:73067ef14c30 134 char verfn[SW_MAX_FQFN]; // local version file
WiredHome 9:73067ef14c30 135 char fwfn[SW_MAX_FQFN];
WiredHome 16:de99e872fc9d 136 char nameroot[7];
WiredHome 9:73067ef14c30 137 uint16_t result = SWUP_OK; // starting out quite optimistic, for all the things that can go wrong
WiredHome 9:73067ef14c30 138 char buf[50]; // long enough for 3 comma separated numbers...
WiredHome 0:e221363f7942 139
WiredHome 0:e221363f7942 140 INFO("SoftwareUpdate(%s,%s)", url, name);
WiredHome 16:de99e872fc9d 141 strncpy(nameroot, name, 6);
WiredHome 16:de99e872fc9d 142 nameroot[6] = '\0';
WiredHome 16:de99e872fc9d 143 snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", nameroot);
WiredHome 0:e221363f7942 144
WiredHome 0:e221363f7942 145 /* Read installed version string */
WiredHome 0:e221363f7942 146 int inst_ver = -1;
WiredHome 0:e221363f7942 147 FILE *fv = fopen(verfn, "r");
WiredHome 0:e221363f7942 148 if (fv) {
WiredHome 0:e221363f7942 149 fscanf(fv, "%d", &inst_ver);
WiredHome 0:e221363f7942 150 fclose(fv);
WiredHome 0:e221363f7942 151 }
WiredHome 0:e221363f7942 152 INFO(" Installed version: %d", inst_ver);
WiredHome 0:e221363f7942 153
WiredHome 0:e221363f7942 154 /* Download latest version string */
WiredHome 0:e221363f7942 155 HTTPText server_ver("test message");
WiredHome 9:73067ef14c30 156 snprintf(fqurl, SW_MAX_URL, "%s/%s.txt", url, name);
WiredHome 0:e221363f7942 157 HTTPResult r = http.get(fqurl, buf, sizeof(buf));
WiredHome 0:e221363f7942 158 if (r == HTTP_OK) {
WiredHome 0:e221363f7942 159 int latest_ver = -1;
WiredHome 3:c69fff55fc60 160 int cksum = 0;
WiredHome 3:c69fff55fc60 161 int fsize = 0;
WiredHome 3:c69fff55fc60 162 int parseCount;
WiredHome 3:c69fff55fc60 163 parseCount = sscanf(buf, "%d,%d,%d", &latest_ver, &cksum, &fsize);
WiredHome 3:c69fff55fc60 164 if (parseCount == 3) {
WiredHome 9:73067ef14c30 165 INFO(" web version: %d", latest_ver);
WiredHome 9:73067ef14c30 166 INFO(" checksum: %d", cksum);
WiredHome 9:73067ef14c30 167 INFO(" file size: %d", fsize);
WiredHome 3:c69fff55fc60 168 if (inst_ver != latest_ver) {
WiredHome 3:c69fff55fc60 169 INFO(" Downloading firmware ver %d ...", latest_ver);
WiredHome 16:de99e872fc9d 170 sprintf(fwfn, "/local/%s%02d.BIN", nameroot, (latest_ver % 100));
WiredHome 3:c69fff55fc60 171 snprintf(fqurl, 150, "%s/%s.bin", url, name);
WiredHome 3:c69fff55fc60 172
WiredHome 3:c69fff55fc60 173 HTTPFile latest(fwfn);
WiredHome 3:c69fff55fc60 174 r = http.get(fqurl, &latest);
WiredHome 3:c69fff55fc60 175 if (r == HTTP_OK) {
WiredHome 3:c69fff55fc60 176 if (PassesIntegrityCheck(fwfn, cksum, fsize)) {
WiredHome 16:de99e872fc9d 177 if (!RemoveOtherBinFiles(nameroot, latest_ver)) {
WiredHome 9:73067ef14c30 178 ERR(" *** Failed to remove old version(s). ***");
WiredHome 9:73067ef14c30 179 result |= SWUP_OLD_STUCK;
WiredHome 3:c69fff55fc60 180 }
WiredHome 3:c69fff55fc60 181 INFO("Updating stored version number.");
WiredHome 3:c69fff55fc60 182 fv = fopen(verfn, "w");
WiredHome 3:c69fff55fc60 183 if (fv) {
WiredHome 3:c69fff55fc60 184 int fr = fputs(buf, fv);
WiredHome 3:c69fff55fc60 185 if (fr < 0) {
WiredHome 3:c69fff55fc60 186 ERR("Failed (%d) to update stored version number.", fr);
WiredHome 3:c69fff55fc60 187 fclose( fv );
WiredHome 9:73067ef14c30 188 result |= SWUP_VER_STUCK;
WiredHome 3:c69fff55fc60 189 } else {
WiredHome 3:c69fff55fc60 190 fclose( fv );
WiredHome 9:73067ef14c30 191 if (action == AUTO_REBOOT) {
WiredHome 3:c69fff55fc60 192 WARN("Resetting...\n");
WiredHome 3:c69fff55fc60 193 wait_ms(200);
WiredHome 3:c69fff55fc60 194 mbed_reset();
WiredHome 3:c69fff55fc60 195 }
WiredHome 3:c69fff55fc60 196 }
WiredHome 1:208de08b1a19 197 } else {
WiredHome 3:c69fff55fc60 198 WARN("Failed to update local version info in %s.", verfn);
WiredHome 9:73067ef14c30 199 result |= SWUP_VWRITE_FAILED;
WiredHome 1:208de08b1a19 200 }
WiredHome 0:e221363f7942 201 } else {
WiredHome 3:c69fff55fc60 202 WARN("New file {%s} did not pass integrity check.", fwfn);
WiredHome 9:73067ef14c30 203 result |= SWUP_INTEGRITY_FAILED;
WiredHome 0:e221363f7942 204 }
WiredHome 1:208de08b1a19 205 } else {
WiredHome 3:c69fff55fc60 206 WARN("Failed to download lastest firmware.");
WiredHome 9:73067ef14c30 207 result |= SWUP_BAD_URL;
WiredHome 0:e221363f7942 208 }
WiredHome 0:e221363f7942 209 } else {
WiredHome 9:73067ef14c30 210 INFO("Online version is same as installed version.");
WiredHome 9:73067ef14c30 211 result |= SWUP_SAME_VER;
WiredHome 0:e221363f7942 212 }
WiredHome 0:e221363f7942 213 }
WiredHome 0:e221363f7942 214 } else {
WiredHome 16:de99e872fc9d 215 WARN("Failed to download online firmware version number. r= %d", r);
WiredHome 9:73067ef14c30 216 result |= SWUP_HTTP_ERR;
WiredHome 0:e221363f7942 217 }
WiredHome 9:73067ef14c30 218 return (SWUpdate_T)result;
WiredHome 0:e221363f7942 219 }