liubin | 281ac46 | 2023-07-19 14:22:54 +0800 | [diff] [blame^] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include <unistd.h> |
| 5 | #include <sys/types.h> |
| 6 | #include <errno.h> |
| 7 | #include <fcntl.h> |
| 8 | #include <pthread.h> |
| 9 | #include <libubox/blobmsg_json.h> |
| 10 | #include "libubus.h" |
| 11 | #include "ql/ql_fota.h" |
| 12 | |
| 13 | // #define DEBUG 1 |
| 14 | |
| 15 | #ifdef DEBUG |
| 16 | #define fota_log(...) printf(__VA_ARGS__) |
| 17 | #else |
| 18 | #define fota_log(...) |
| 19 | #endif |
| 20 | |
| 21 | #define UNUSEDPARAM(param) (void)param; |
| 22 | #define OTA_MAX_STRING_LEN 128 |
| 23 | |
| 24 | static struct ubus_context *fota_ubus_ctx = NULL; |
| 25 | static uint32_t fota_request_id; |
| 26 | static struct ubus_subscriber notification_event; |
| 27 | static pthread_t fota_status_pthread; |
| 28 | static struct blob_buf b; |
| 29 | static fota_callback fota_cb = NULL; |
| 30 | |
| 31 | enum { |
| 32 | ATTR_SMSGPS, |
| 33 | ATTR_SMSGPS_MAX, |
| 34 | }; |
| 35 | |
| 36 | static const struct blobmsg_policy ota_info_attr_policy[] = { |
| 37 | [ATTR_SMSGPS] ={.name = "notification", .type = BLOBMSG_TYPE_STRING,}, |
| 38 | }; |
| 39 | |
| 40 | /** |
| 41 | * \brief strstr_n |
| 42 | * |
| 43 | * find string return number |
| 44 | * |
| 45 | * \param param |
| 46 | * \return return type |
| 47 | */ |
| 48 | static int strstr_n(const char *s1, const char *s2) |
| 49 | { |
| 50 | int n; |
| 51 | int strlen = 0; |
| 52 | |
| 53 | if(*s2) { |
| 54 | while(*s1) { |
| 55 | for(n = 0; *(s1+n) == *(s2 + n); n++) { |
| 56 | if(!*(s2 + n + 1)) { |
| 57 | strlen++; |
| 58 | return strlen; |
| 59 | } |
| 60 | } |
| 61 | s1++; |
| 62 | strlen++; |
| 63 | } |
| 64 | return 0; |
| 65 | } |
| 66 | else |
| 67 | return 0; |
| 68 | } |
| 69 | |
| 70 | static int otad_notify(struct ubus_context* ctx, struct ubus_object* obj, |
| 71 | struct ubus_request_data* req, const char* method, |
| 72 | struct blob_attr* msg) |
| 73 | { |
| 74 | UNUSEDPARAM(ctx); |
| 75 | UNUSEDPARAM(obj); |
| 76 | UNUSEDPARAM(req); |
| 77 | UNUSEDPARAM(method); |
| 78 | // User can get downloading process information from here |
| 79 | int ret, len; |
| 80 | char progress[4] = {0}; |
| 81 | char *notify_str; |
| 82 | |
| 83 | struct blob_attr *tb[ATTR_SMSGPS_MAX]; |
| 84 | ret = blobmsg_parse(ota_info_attr_policy, ARRAY_SIZE(ota_info_attr_policy), tb, |
| 85 | blob_data(msg), blob_len(msg)); |
| 86 | |
| 87 | if (ret || !tb[ATTR_SMSGPS]) { |
| 88 | printf("invalid SMS\n"); |
| 89 | return -1; |
| 90 | } |
| 91 | |
| 92 | notify_str = blobmsg_get_string(tb[ATTR_SMSGPS]); |
| 93 | len = strlen(notify_str); |
| 94 | fota_log("%s : %s\r\n", __FUNCTION__, notify_str); |
| 95 | if (strstr_n(notify_str, "start")) { |
| 96 | fota_cb(0, 0); |
| 97 | } else if (strstr_n(notify_str, "end[1]")) { |
| 98 | fota_cb(0, 100); |
| 99 | printf("download firmware success!\r\n"); |
| 100 | } else if (strstr_n(notify_str, "end[0]")) { |
| 101 | fota_cb(1, 100); |
| 102 | } |
| 103 | ret = strstr_n(notify_str, "progress"); |
| 104 | if (ret) { |
| 105 | memcpy(progress, ¬ify_str[ret + 8], len - ret - 9); |
| 106 | fota_cb(0, atoi(progress)); |
| 107 | } |
| 108 | return 0; |
| 109 | } |
| 110 | |
| 111 | static void otad_subscriber_remove_cb(struct ubus_context* ctx, |
| 112 | struct ubus_subscriber* obj, uint32_t id) |
| 113 | { |
| 114 | UNUSEDPARAM(ctx); |
| 115 | UNUSEDPARAM(obj); |
| 116 | UNUSEDPARAM(id); |
| 117 | fota_log("%s,%d\n", __FUNCTION__, __LINE__); |
| 118 | } |
| 119 | |
| 120 | |
| 121 | /*******************************************************************************\ |
| 122 | * Function: main |
| 123 | \*******************************************************************************/ |
| 124 | void* fota_main(void* argc) |
| 125 | { |
| 126 | int ret, retries = 0; |
| 127 | UNUSEDPARAM(argc); |
| 128 | |
| 129 | //register for ril indication |
| 130 | ret = ubus_register_subscriber(fota_ubus_ctx, ¬ification_event); |
| 131 | if (ret) { |
| 132 | fota_log("%s,%d\n", __FUNCTION__, __LINE__); |
| 133 | pthread_exit(NULL); |
| 134 | } |
| 135 | notification_event.cb = otad_notify; |
| 136 | notification_event.remove_cb = otad_subscriber_remove_cb; |
| 137 | |
| 138 | ubus_subscribe(fota_ubus_ctx, ¬ification_event, fota_request_id); |
| 139 | uloop_run(); |
| 140 | ubus_unsubscribe(fota_ubus_ctx, ¬ification_event, fota_request_id); |
| 141 | pthread_exit(NULL); |
| 142 | |
| 143 | return NULL; |
| 144 | } |
| 145 | |
| 146 | int ql_fota_init(fota_callback cb) |
| 147 | { |
| 148 | int id; |
| 149 | int retries = 0; |
| 150 | |
| 151 | /*create ubus loop to listen to RIL event*/ |
| 152 | uloop_init(); |
| 153 | fota_ubus_ctx = ubus_connect(NULL); |
| 154 | if (!fota_ubus_ctx) { |
| 155 | fota_log("%s,%d\n", __FUNCTION__, __LINE__); |
| 156 | uloop_done(); |
| 157 | return 0; |
| 158 | } |
| 159 | |
| 160 | ubus_add_uloop(fota_ubus_ctx); |
| 161 | |
| 162 | do { |
| 163 | //register for ril request |
| 164 | retries = 0; |
| 165 | if (ubus_lookup_id(fota_ubus_ctx, "ota", &fota_request_id)) { |
| 166 | fota_log("%s,%d\n", __FUNCTION__, __LINE__); |
| 167 | sleep(1); |
| 168 | } else { |
| 169 | break; |
| 170 | } |
| 171 | } while (retries++ < 20); |
| 172 | if (retries >= 20) { |
| 173 | printf("%s,%d\n", __FUNCTION__, __LINE__); |
| 174 | goto fail1; |
| 175 | } |
| 176 | pthread_create(&fota_status_pthread, NULL, (void*)fota_main, NULL); |
| 177 | fota_cb = cb; |
| 178 | fail1: |
| 179 | return 0; |
| 180 | } |
| 181 | |
| 182 | static void sync_prog_cb(struct ubus_request *req, int type, struct blob_attr *msg) |
| 183 | { |
| 184 | char *str; |
| 185 | if (!msg) |
| 186 | return; |
| 187 | |
| 188 | /* |
| 189 | 在这里处理返回的消息。 |
| 190 | 本例子只是将返回的消息打印出来。 |
| 191 | */ |
| 192 | str = blobmsg_format_json_indent(msg, true, 0); |
| 193 | printf("%s\n", str); |
| 194 | |
| 195 | if (strstr_n(str, "end[1]")) { |
| 196 | fota_cb(0, 100); |
| 197 | printf("download firmware success!\r\n"); |
| 198 | } else if (strstr_n(str, "end[0]") || strstr_n(str, "failed")) { |
| 199 | fota_cb(1, 0); |
| 200 | } |
| 201 | free(str); |
| 202 | } |
| 203 | /******************************************************************************* |
| 204 | * @brief write firmware package, the firmware package is written in segments. |
| 205 | and The result of the write is output by calling the callback function. |
| 206 | the firmware package size must less than 32MB |
| 207 | @param |
| 208 | fname: firmware package file |
| 209 | segment_size: the length of once write, recommending 3*1024*1024 bytes |
| 210 | @return |
| 211 | if success return 0, else return -1 |
| 212 | *******************************************************************************/ |
| 213 | int ql_fota_fw_write(char* fname, int segment_size) |
| 214 | { |
| 215 | static struct ubus_request req; |
| 216 | int _segment_size; |
| 217 | blob_buf_init(&b, 0); |
| 218 | blobmsg_add_string(&b, "url", fname); |
| 219 | blobmsg_add_u32(&b, "type", 2); |
| 220 | blobmsg_add_u32(&b, "sync", 1); |
| 221 | _segment_size = segment_size; |
| 222 | if (_segment_size > 1024) { |
| 223 | blobmsg_add_u32(&b, "segment_size", _segment_size); |
| 224 | } |
| 225 | // blobmsg_add_u32(&b, "segment_size", segment_size); |
| 226 | /* 调用"ota"对象的"download"方法 */ |
| 227 | ubus_invoke(fota_ubus_ctx, fota_request_id, |
| 228 | "download", b.head, sync_prog_cb, NULL, 30 * 1000); |
| 229 | |
| 230 | return 0; |
| 231 | } |
| 232 | |
| 233 | |
| 234 | /******************************************************************************* |
| 235 | * @brief download firmware by url, and write firmware package, the firmware |
| 236 | package is written in segments. The result of the write is output by |
| 237 | calling the callback function. the firmware package size must less than |
| 238 | 32MB |
| 239 | @param |
| 240 | url: [IN] the address of download firmware package file, the url |
| 241 | support http or https protocol. |
| 242 | segment_size: [IN] the length of once write, recommending 3*1024*1024 bytes |
| 243 | conn_timeout: [IN] timeout to connect to the server, if set 0 that means |
| 244 | switch to the default build-in connection timeout(300s) |
| 245 | download_timeout: [IN] timeout for download the firmware file. if set 0 that means |
| 246 | it never time out |
| 247 | @return |
| 248 | if success return 0, else return -1 |
| 249 | *******************************************************************************/ |
| 250 | int ql_fota_fw_write_by_url(char* url, int segment_size, |
| 251 | int conn_timeout, int download_timeout) |
| 252 | { |
| 253 | static struct ubus_request req; |
| 254 | int _segment_size; |
| 255 | blob_buf_init(&b, 0); |
| 256 | blobmsg_add_string(&b, "url", url); |
| 257 | blobmsg_add_string(&b, "username", "user name"); |
| 258 | blobmsg_add_u32(&b, "type", 0); |
| 259 | blobmsg_add_u32(&b, "sync", 1); |
| 260 | _segment_size = segment_size; |
| 261 | if (_segment_size > 1024) { |
| 262 | blobmsg_add_u32(&b, "segment_size", _segment_size); |
| 263 | } |
| 264 | blobmsg_add_u32(&b, "sync", 1); |
| 265 | ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req); |
| 266 | ubus_complete_request_async(fota_ubus_ctx, &req); |
| 267 | return 0; |
| 268 | } |
| 269 | /******************************************************************************* |
| 270 | * @brief reboot system and clear env |
| 271 | @param |
| 272 | is_reboot: if set 1, after fota success, reboot system |
| 273 | @return |
| 274 | if success return 0, else return -1 |
| 275 | *******************************************************************************/ |
| 276 | int ql_fota_done(int is_reboot) |
| 277 | { |
| 278 | int ret; |
| 279 | |
| 280 | ret = pthread_cancel(fota_status_pthread); |
| 281 | fota_log("kill pthread : %d \n", ret); |
| 282 | pthread_join(fota_status_pthread, NULL); |
| 283 | do { |
| 284 | ret = pthread_kill(fota_status_pthread, 0); |
| 285 | fota_log("kill pthread: %d \n", ret); |
| 286 | if (ret == ESRCH) { |
| 287 | fota_log("The specified thread does not exist or has terminated\n"); |
| 288 | } else if (ret == EINVAL) { |
| 289 | fota_log("Useless signal\n"); |
| 290 | } else { |
| 291 | fota_log("The thread exists\n"); |
| 292 | } |
| 293 | usleep(100000); |
| 294 | } while (0 == ret); |
| 295 | |
| 296 | |
| 297 | ubus_free(fota_ubus_ctx); |
| 298 | uloop_done(); |
| 299 | |
| 300 | fota_cb = NULL; |
| 301 | |
| 302 | if (is_reboot) { |
| 303 | system("reboot"); |
| 304 | } |
| 305 | return 0; |
| 306 | } |