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:
Thu Jun 01 11:35:49 2017 +0000
Revision:
23:cfe84db2b2cb
Parent:
22:2a010efe00da
Child:
24:e400edb8d2ee
Cleanup remove unnecessary include files.

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