SWUpdate library to be used with RPC.
Fork of SWUpdate by
Embed:
(wiki syntax)
Show/hide line numbers
SWUpdate.cpp
00001 00002 // Software Update via Ethernet from forum - 00003 // http://mbed.org/forum/mbed/topic/1183/ 00004 // 00005 #include "mbed.h" 00006 #include "SWUpdate.h" 00007 //#include "HTTPClient.h" 00008 #include "HTTPText.h" 00009 #include "HTTPFile.h" 00010 #include <stdio.h> 00011 00012 extern "C" void mbed_reset(); 00013 00014 //#define DEBUG "SWup" 00015 #include <cstdio> 00016 #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) 00017 #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00018 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00019 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00020 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00021 #else 00022 #define DBG(x, ...) 00023 #define WARN(x, ...) 00024 #define ERR(x, ...) 00025 #define INFO(x, ...) 00026 #endif 00027 00028 static HTTPResult HTTPErrorCode; 00029 00030 typedef enum { 00031 ok, 00032 no_file, 00033 bad_crc 00034 } Integrity_t; 00035 00036 static Integrity_t PassesIntegrityCheck(const char * fname, int cksum, int fsize) 00037 { 00038 Integrity_t res = bad_crc; // assume things go wrong... 00039 int newCksum = 0; 00040 int newFSize = 0; 00041 FILE *fh = fopen(fname, "rb"); 00042 00043 INFO("IntegrityCheck(%s,%d,%d)", fname, cksum, fsize); 00044 if (fh) { 00045 char buf; 00046 while (fread(&buf, 1, 1, fh)) { 00047 newCksum = (newCksum + buf) & 0xFFFF; 00048 newFSize++; 00049 } 00050 fclose(fh); 00051 INFO(" Check(...,%d,%d)", newCksum, newFSize); 00052 if (newCksum == cksum && newFSize == fsize) 00053 res = ok; 00054 } else { 00055 WARN("failed to open %s.", fname); 00056 res = no_file; 00057 } 00058 return res; 00059 } 00060 00061 /// mytolower exists because not all compiler libraries have this function 00062 /// 00063 /// This takes a character and if it is upper-case, it converts it to 00064 /// lower-case and returns it. 00065 /// 00066 /// @note this only works for characters in the range 'A' - 'Z'. 00067 /// 00068 /// a is the character to convert 00069 /// returns the lower case equivalent to the supplied character. 00070 /// 00071 static char mytolower(char a) 00072 { 00073 if (a >= 'A' && a <= 'Z') 00074 return (a - 'A' + 'a'); 00075 else 00076 return a; 00077 } 00078 00079 /// mystrnicmp exists because not all compiler libraries have this function. 00080 /// 00081 /// Some have strnicmp, others _strnicmp, and others have C++ methods, which 00082 /// is outside the scope of this C-portable set of functions. 00083 /// 00084 /// l is a pointer to the string on the left 00085 /// r is a pointer to the string on the right 00086 /// n is the number of characters to compare 00087 /// returns -1 if l < r 00088 /// returns 0 if l == r 00089 /// returns +1 if l > r 00090 /// 00091 static int mystrnicmp(const char *l, const char *r, size_t n) 00092 { 00093 int result = 0; 00094 00095 if (n != 0) { 00096 do { 00097 result = mytolower(*l++) - mytolower(*r++); 00098 } while ((result == 0) && (*l != '\0') && (--n > 0)); 00099 } 00100 if (result < -1) 00101 result = -1; 00102 else if (result > 1) 00103 result = 1; 00104 return result; 00105 } 00106 00107 00108 // Scan the local file system for any .bin files and 00109 // if they don't match the current one, remove them. 00110 // 00111 static bool RemoveOtherBinFiles(const char * name, int ver) 00112 { 00113 char curbin[SW_MAX_FQFN]; 00114 DIR *d; 00115 struct dirent *p; 00116 bool noFailed = true; 00117 00118 snprintf(curbin, SW_MAX_FQFN, "%s%02d.bin", name, (ver % 100)); 00119 INFO("Remove bin files excluding {%s}", curbin); 00120 d = opendir("/local/"); 00121 // Get a directory handle 00122 if ( d != NULL ) { 00123 // Walk the directory 00124 while ( (p = readdir(d)) != NULL ) { 00125 INFO(" check {%s}", p->d_name); 00126 // if the file is .bin and not curbin 00127 if (0 == mystrnicmp(p->d_name + strlen(p->d_name) - 4, ".bin", 4) 00128 && (0 != mystrnicmp(p->d_name, curbin, strlen(curbin)))) { 00129 // remove the file 00130 char toremove[SW_MAX_FQFN]; 00131 snprintf(toremove, SW_MAX_FQFN, "/local/%s", p->d_name); 00132 INFO(" removing %s.", toremove); 00133 if (remove(toremove)) { 00134 // set flag if it could not be removed 00135 noFailed = false; 00136 } 00137 } 00138 } 00139 closedir(d); 00140 } 00141 return noFailed; 00142 } 00143 00144 HTTPResult SoftwareUpdateGetHTTPErrorCode(void) 00145 { 00146 return HTTPErrorCode; 00147 } 00148 00149 SWUpdate_T SoftwareUpdate(const char *url, const char * name, Reboot_T action) 00150 { 00151 HTTPClient http; 00152 //http.setTimeout( 15000 ); 00153 char fqurl[SW_MAX_URL]; // fully qualified url 00154 char verfn[SW_MAX_FQFN]; // local version file 00155 char fwfn[SW_MAX_FQFN]; 00156 char nameroot[7]; 00157 uint16_t result = SWUP_OK; // starting out quite optimistic, for all the things that can go wrong 00158 char buf[50]; // long enough for 3 comma separated numbers... 00159 00160 INFO("SoftwareUpdate(%s,%s)", url, name); 00161 strncpy(nameroot, name, 6); 00162 nameroot[6] = '\0'; 00163 snprintf(verfn, SW_MAX_FQFN, "/local/%s.ver", nameroot); 00164 00165 /* Read installed version string */ 00166 int inst_ver = -1; 00167 FILE *fv = fopen(verfn, "r"); 00168 if (fv) { 00169 fscanf(fv, "%d", &inst_ver); 00170 fclose(fv); 00171 } 00172 INFO(" Installed version: %d", inst_ver); 00173 00174 /* Download latest version string */ 00175 HTTPText server_ver("test message"); 00176 snprintf(fqurl, SW_MAX_URL, "%s/%s.txt", url, name); 00177 HTTPErrorCode = http.get(fqurl, buf, sizeof(buf)); 00178 if (HTTPErrorCode == HTTP_OK) { 00179 int latest_ver = -1; 00180 int cksum = 0; 00181 int fsize = 0; 00182 int parseCount; 00183 parseCount = sscanf(buf, "%d,%d,%d", &latest_ver, &cksum, &fsize); 00184 if (parseCount == 3) { 00185 INFO(" web version: %d", latest_ver); 00186 INFO(" checksum: %d", cksum); 00187 INFO(" file size: %d", fsize); 00188 if (inst_ver != latest_ver) { 00189 INFO(" Downloading firmware ver %d ...", latest_ver); 00190 sprintf(fwfn, "/local/%s%02d.BIN", nameroot, (latest_ver % 100)); 00191 snprintf(fqurl, 150, "%s/%s.bin", url, name); 00192 00193 HTTPFile latest(fwfn); 00194 HTTPErrorCode = http.get(fqurl, &latest); 00195 if (HTTPErrorCode == HTTP_OK) { 00196 Integrity_t t = PassesIntegrityCheck(fwfn, cksum, fsize); 00197 if (t == no_file) { 00198 ERR(" *** No space on file system. ***"); 00199 result |= SWUP_NO_SPACE; 00200 } else if (t == ok) { 00201 if (!RemoveOtherBinFiles(nameroot, latest_ver)) { 00202 ERR(" *** Failed to remove old version(s). ***"); 00203 result |= SWUP_OLD_STUCK; 00204 } 00205 INFO("Updating stored version number."); 00206 fv = fopen(verfn, "w"); 00207 if (fv) { 00208 int fr = fputs(buf, fv); 00209 if (fr < 0) { 00210 ERR("Failed (%d) to update stored version number.", fr); 00211 fclose( fv ); 00212 result |= SWUP_VER_STUCK; 00213 } else { 00214 fclose( fv ); 00215 if (action == AUTO_REBOOT) { 00216 WARN("Resetting...\n"); 00217 wait_ms(200); 00218 mbed_reset(); 00219 } 00220 } 00221 } else { 00222 WARN("Failed to update local version info in %s.", verfn); 00223 result |= SWUP_VWRITE_FAILED; 00224 } 00225 } else /* t == bad_crc */ { 00226 WARN("New file {%s} did not pass integrity check.", fwfn); 00227 result |= SWUP_INTEGRITY_FAILED; 00228 } 00229 } else { 00230 WARN("Failed to download lastest firmware."); 00231 result |= SWUP_HTTP_BIN; 00232 } 00233 } else { 00234 INFO("Online version is same as installed version."); 00235 result |= SWUP_SAME_VER; 00236 } 00237 } 00238 } else { 00239 WARN("Failed accessing server. Extended Error Code = %d", HTTPErrorCode); 00240 result |= SWUP_HTTP_VER; 00241 } 00242 return (SWUpdate_T)result; 00243 }
Generated on Wed Jul 13 2022 02:19:41 by 1.7.2