Software Update via Ethernet - the mbed application can pull down an updated application binary from a web server and activate that binary. This library works only with the LPC1768, as it relies on the magic-chip boot-loader mechanism.

Dependents:   WattEye X10Svr PUB_SWUpdate

Success!! With this library, a network connection, and a web server hosting a new binary image, you can update the mbed firmware over the air (FOTA) - well, at least via Ethernet so far.

As of March 2015, it has been tested with the following mbed official libraries:

And a custom derivation:

  • HTTPClient v33, v32, which includes a custom HTTPFile.

Part of the update process involves checking the integrity of the downloaded binary file, for both a checksum and the program (file) size. To create this additional information, a small perl script is used (the important part is only 20 lines of code). See the documentation in the header file.

After the new binary is successfully downloaded, the checksum and the size are evaluated and if correct, then the old binary file is removed (this is the only way to cause the new binary to activate).

The mbed can then be automatically reset to activate the new image, or this may be deferred in case there is some other process necessary for an orderly restart.

Details are in the SWUpdate header file, and PUB_SWUpdate is a publicly accessible demonstration program for this library.

Committer:
WiredHome
Date:
Sat Jul 05 22:27:09 2014 +0000
Revision:
17:1d318666246c
Parent:
16:de99e872fc9d
Child:
18:5f7667d63a27
The cleanup function was not properly forming the current version filename, so could delete it on some circumstances.

Who changed what in which revision?

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