SWUpdate library to be used with RPC.
Fork of SWUpdate by
SWUpdate.cpp@22:2a010efe00da, 2016-12-29 (annotated)
- Committer:
- WiredHome
- Date:
- Thu Dec 29 20:16:46 2016 +0000
- Revision:
- 22:2a010efe00da
- Parent:
- 21:253e7da56ff9
- Child:
- 23:cfe84db2b2cb
Minor change from sprintf to snprintf
Who changed what in which revision?
User | Revision | Line number | New 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 | 21:253e7da56ff9 | 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 | 19:169aab9047bd | 30 | typedef enum { |
WiredHome | 19:169aab9047bd | 31 | ok, |
WiredHome | 19:169aab9047bd | 32 | no_file, |
WiredHome | 19:169aab9047bd | 33 | bad_crc |
WiredHome | 19:169aab9047bd | 34 | } Integrity_t; |
WiredHome | 19:169aab9047bd | 35 | |
WiredHome | 19:169aab9047bd | 36 | static Integrity_t PassesIntegrityCheck(const char * fname, int cksum, int fsize) |
WiredHome | 17:1d318666246c | 37 | { |
WiredHome | 19:169aab9047bd | 38 | Integrity_t res = bad_crc; // assume things go wrong... |
WiredHome | 3:c69fff55fc60 | 39 | int newCksum = 0; |
WiredHome | 3:c69fff55fc60 | 40 | int newFSize = 0; |
WiredHome | 3:c69fff55fc60 | 41 | FILE *fh = fopen(fname, "rb"); |
WiredHome | 17:1d318666246c | 42 | |
WiredHome | 3:c69fff55fc60 | 43 | INFO("IntegrityCheck(%s,%d,%d)", fname, cksum, fsize); |
WiredHome | 3:c69fff55fc60 | 44 | if (fh) { |
WiredHome | 3:c69fff55fc60 | 45 | char buf; |
WiredHome | 3:c69fff55fc60 | 46 | while (fread(&buf, 1, 1, fh)) { |
WiredHome | 3:c69fff55fc60 | 47 | newCksum = (newCksum + buf) & 0xFFFF; |
WiredHome | 3:c69fff55fc60 | 48 | newFSize++; |
WiredHome | 3:c69fff55fc60 | 49 | } |
WiredHome | 3:c69fff55fc60 | 50 | fclose(fh); |
WiredHome | 3:c69fff55fc60 | 51 | INFO(" Check(...,%d,%d)", newCksum, newFSize); |
WiredHome | 3:c69fff55fc60 | 52 | if (newCksum == cksum && newFSize == fsize) |
WiredHome | 19:169aab9047bd | 53 | res = ok; |
WiredHome | 3:c69fff55fc60 | 54 | } else { |
WiredHome | 3:c69fff55fc60 | 55 | WARN("failed to open %s.", fname); |
WiredHome | 19:169aab9047bd | 56 | res = no_file; |
WiredHome | 3:c69fff55fc60 | 57 | } |
WiredHome | 3:c69fff55fc60 | 58 | return res; |
WiredHome | 1:208de08b1a19 | 59 | } |
WiredHome | 1:208de08b1a19 | 60 | |
WiredHome | 9:73067ef14c30 | 61 | /// mytolower exists because not all compiler libraries have this function |
WiredHome | 9:73067ef14c30 | 62 | /// |
WiredHome | 9:73067ef14c30 | 63 | /// This takes a character and if it is upper-case, it converts it to |
WiredHome | 9:73067ef14c30 | 64 | /// lower-case and returns it. |
WiredHome | 9:73067ef14c30 | 65 | /// |
WiredHome | 17:1d318666246c | 66 | /// @note this only works for characters in the range 'A' - 'Z'. |
WiredHome | 17:1d318666246c | 67 | /// |
WiredHome | 18:5f7667d63a27 | 68 | /// a is the character to convert |
WiredHome | 18:5f7667d63a27 | 69 | /// returns the lower case equivalent to the supplied character. |
WiredHome | 9:73067ef14c30 | 70 | /// |
WiredHome | 17:1d318666246c | 71 | static char mytolower(char a) |
WiredHome | 17:1d318666246c | 72 | { |
WiredHome | 9:73067ef14c30 | 73 | if (a >= 'A' && a <= 'Z') |
WiredHome | 9:73067ef14c30 | 74 | return (a - 'A' + 'a'); |
WiredHome | 9:73067ef14c30 | 75 | else |
WiredHome | 9:73067ef14c30 | 76 | return a; |
WiredHome | 9:73067ef14c30 | 77 | } |
WiredHome | 9:73067ef14c30 | 78 | |
WiredHome | 9:73067ef14c30 | 79 | /// mystrnicmp exists because not all compiler libraries have this function. |
WiredHome | 9:73067ef14c30 | 80 | /// |
WiredHome | 9:73067ef14c30 | 81 | /// Some have strnicmp, others _strnicmp, and others have C++ methods, which |
WiredHome | 9:73067ef14c30 | 82 | /// is outside the scope of this C-portable set of functions. |
WiredHome | 9:73067ef14c30 | 83 | /// |
WiredHome | 18:5f7667d63a27 | 84 | /// l is a pointer to the string on the left |
WiredHome | 18:5f7667d63a27 | 85 | /// r is a pointer to the string on the right |
WiredHome | 18:5f7667d63a27 | 86 | /// n is the number of characters to compare |
WiredHome | 18:5f7667d63a27 | 87 | /// returns -1 if l < r |
WiredHome | 18:5f7667d63a27 | 88 | /// returns 0 if l == r |
WiredHome | 18:5f7667d63a27 | 89 | /// returns +1 if l > r |
WiredHome | 9:73067ef14c30 | 90 | /// |
WiredHome | 17:1d318666246c | 91 | static int mystrnicmp(const char *l, const char *r, size_t n) |
WiredHome | 17:1d318666246c | 92 | { |
WiredHome | 9:73067ef14c30 | 93 | int result = 0; |
WiredHome | 9:73067ef14c30 | 94 | |
WiredHome | 9:73067ef14c30 | 95 | if (n != 0) { |
WiredHome | 9:73067ef14c30 | 96 | do { |
WiredHome | 9:73067ef14c30 | 97 | result = mytolower(*l++) - mytolower(*r++); |
WiredHome | 9:73067ef14c30 | 98 | } while ((result == 0) && (*l != '\0') && (--n > 0)); |
WiredHome | 9:73067ef14c30 | 99 | } |
WiredHome | 9:73067ef14c30 | 100 | if (result < -1) |
WiredHome | 9:73067ef14c30 | 101 | result = -1; |
WiredHome | 9:73067ef14c30 | 102 | else if (result > 1) |
WiredHome | 9:73067ef14c30 | 103 | result = 1; |
WiredHome | 9:73067ef14c30 | 104 | return result; |
WiredHome | 9:73067ef14c30 | 105 | } |
WiredHome | 9:73067ef14c30 | 106 | |
WiredHome | 9:73067ef14c30 | 107 | |
WiredHome | 17:1d318666246c | 108 | // Scan the local file system for any .bin files and |
WiredHome | 9:73067ef14c30 | 109 | // if they don't match the current one, remove them. |
WiredHome | 9:73067ef14c30 | 110 | // |
WiredHome | 9:73067ef14c30 | 111 | static bool RemoveOtherBinFiles(const char * name, int ver) |
WiredHome | 9:73067ef14c30 | 112 | { |
WiredHome | 9:73067ef14c30 | 113 | char curbin[SW_MAX_FQFN]; |
WiredHome | 9:73067ef14c30 | 114 | DIR *d; |
WiredHome | 9:73067ef14c30 | 115 | struct dirent *p; |
WiredHome | 9:73067ef14c30 | 116 | bool noFailed = true; |
WiredHome | 17:1d318666246c | 117 | |
WiredHome | 17:1d318666246c | 118 | snprintf(curbin, SW_MAX_FQFN, "%s%02d.bin", name, (ver % 100)); |
WiredHome | 9:73067ef14c30 | 119 | INFO("Remove bin files excluding {%s}", curbin); |
WiredHome | 9:73067ef14c30 | 120 | d = opendir("/local/"); |
WiredHome | 9:73067ef14c30 | 121 | // Get a directory handle |
WiredHome | 9:73067ef14c30 | 122 | if ( d != NULL ) { |
WiredHome | 9:73067ef14c30 | 123 | // Walk the directory |
WiredHome | 9:73067ef14c30 | 124 | while ( (p = readdir(d)) != NULL ) { |
WiredHome | 9:73067ef14c30 | 125 | INFO(" check {%s}", p->d_name); |
WiredHome | 9:73067ef14c30 | 126 | // if the file is .bin and not curbin |
WiredHome | 9:73067ef14c30 | 127 | if (0 == mystrnicmp(p->d_name + strlen(p->d_name) - 4, ".bin", 4) |
WiredHome | 17:1d318666246c | 128 | && (0 != mystrnicmp(p->d_name, curbin, strlen(curbin)))) { |
WiredHome | 9:73067ef14c30 | 129 | // remove the file |
WiredHome | 9:73067ef14c30 | 130 | char toremove[SW_MAX_FQFN]; |
WiredHome | 9:73067ef14c30 | 131 | snprintf(toremove, SW_MAX_FQFN, "/local/%s", p->d_name); |
WiredHome | 9:73067ef14c30 | 132 | INFO(" removing %s.", toremove); |
WiredHome | 9:73067ef14c30 | 133 | if (remove(toremove)) { |
WiredHome | 9:73067ef14c30 | 134 | // set flag if it could not be removed |
WiredHome | 9:73067ef14c30 | 135 | noFailed = false; |
WiredHome | 9:73067ef14c30 | 136 | } |
WiredHome | 9:73067ef14c30 | 137 | } |
WiredHome | 9:73067ef14c30 | 138 | } |
WiredHome | 9:73067ef14c30 | 139 | closedir(d); |
WiredHome | 9:73067ef14c30 | 140 | } |
WiredHome | 9:73067ef14c30 | 141 | return noFailed; |
WiredHome | 9:73067ef14c30 | 142 | } |
WiredHome | 9:73067ef14c30 | 143 | |
WiredHome | 17:1d318666246c | 144 | HTTPResult SoftwareUpdateGetHTTPErrorCode(void) |
WiredHome | 17:1d318666246c | 145 | { |
WiredHome | 17:1d318666246c | 146 | return HTTPErrorCode; |
WiredHome | 17:1d318666246c | 147 | } |
WiredHome | 17:1d318666246c | 148 | |
WiredHome | 17:1d318666246c | 149 | SWUpdate_T SoftwareUpdate(const char *url, const char * name, Reboot_T action) |
WiredHome | 17:1d318666246c | 150 | { |
WiredHome | 0:e221363f7942 | 151 | HTTPClient http; |
WiredHome | 17:1d318666246c | 152 | //http.setTimeout( 15000 ); |
WiredHome | 9:73067ef14c30 | 153 | char fqurl[SW_MAX_URL]; // fully qualified url |
WiredHome | 9:73067ef14c30 | 154 | char verfn[SW_MAX_FQFN]; // local version file |
WiredHome | 9:73067ef14c30 | 155 | char fwfn[SW_MAX_FQFN]; |
WiredHome | 16:de99e872fc9d | 156 | char nameroot[7]; |
WiredHome | 9:73067ef14c30 | 157 | uint16_t result = SWUP_OK; // starting out quite optimistic, for all the things that can go wrong |
WiredHome | 9:73067ef14c30 | 158 | char buf[50]; // long enough for 3 comma separated numbers... |
WiredHome | 17:1d318666246c | 159 | |
WiredHome | 22:2a010efe00da | 160 | INFO("SoftwareUpdate(%s , %s)", url, name); |
WiredHome | 16:de99e872fc9d | 161 | strncpy(nameroot, name, 6); |
WiredHome | 16:de99e872fc9d | 162 | nameroot[6] = '\0'; |
WiredHome | 16:de99e872fc9d | 163 | snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", nameroot); |
WiredHome | 0:e221363f7942 | 164 | |
WiredHome | 0:e221363f7942 | 165 | /* Read installed version string */ |
WiredHome | 0:e221363f7942 | 166 | int inst_ver = -1; |
WiredHome | 0:e221363f7942 | 167 | FILE *fv = fopen(verfn, "r"); |
WiredHome | 0:e221363f7942 | 168 | if (fv) { |
WiredHome | 0:e221363f7942 | 169 | fscanf(fv, "%d", &inst_ver); |
WiredHome | 0:e221363f7942 | 170 | fclose(fv); |
WiredHome | 0:e221363f7942 | 171 | } |
WiredHome | 0:e221363f7942 | 172 | INFO(" Installed version: %d", inst_ver); |
WiredHome | 17:1d318666246c | 173 | |
WiredHome | 0:e221363f7942 | 174 | /* Download latest version string */ |
WiredHome | 21:253e7da56ff9 | 175 | //HTTPText server_ver("test message"); |
WiredHome | 9:73067ef14c30 | 176 | snprintf(fqurl, SW_MAX_URL, "%s/%s.txt", url, name); |
WiredHome | 17:1d318666246c | 177 | HTTPErrorCode = http.get(fqurl, buf, sizeof(buf)); |
WiredHome | 17:1d318666246c | 178 | if (HTTPErrorCode == HTTP_OK) { |
WiredHome | 0:e221363f7942 | 179 | int latest_ver = -1; |
WiredHome | 3:c69fff55fc60 | 180 | int cksum = 0; |
WiredHome | 3:c69fff55fc60 | 181 | int fsize = 0; |
WiredHome | 3:c69fff55fc60 | 182 | int parseCount; |
WiredHome | 3:c69fff55fc60 | 183 | parseCount = sscanf(buf, "%d,%d,%d", &latest_ver, &cksum, &fsize); |
WiredHome | 3:c69fff55fc60 | 184 | if (parseCount == 3) { |
WiredHome | 9:73067ef14c30 | 185 | INFO(" web version: %d", latest_ver); |
WiredHome | 9:73067ef14c30 | 186 | INFO(" checksum: %d", cksum); |
WiredHome | 9:73067ef14c30 | 187 | INFO(" file size: %d", fsize); |
WiredHome | 3:c69fff55fc60 | 188 | if (inst_ver != latest_ver) { |
WiredHome | 3:c69fff55fc60 | 189 | INFO(" Downloading firmware ver %d ...", latest_ver); |
WiredHome | 22:2a010efe00da | 190 | snprintf(fwfn, SW_MAX_FQFN, "/local/%s%02d.BIN", nameroot, (latest_ver % 100)); |
WiredHome | 22:2a010efe00da | 191 | snprintf(fqurl, SW_MAX_URL, "%s/%s.bin", url, name); |
WiredHome | 17:1d318666246c | 192 | |
WiredHome | 3:c69fff55fc60 | 193 | HTTPFile latest(fwfn); |
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 | } |