blob: 58942725dea26b5528f652bc7afdd2a20bb53954 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001#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
24static struct ubus_context *fota_ubus_ctx = NULL;
25static uint32_t fota_request_id;
26static struct ubus_subscriber notification_event;
27static pthread_t fota_status_pthread;
28static struct blob_buf b;
29static fota_callback fota_cb = NULL;
30
31enum {
32 ATTR_SMSGPS,
33 ATTR_SMSGPS_MAX,
34};
35
36static 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 */
48static 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
70static 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, &notify_str[ret + 8], len - ret - 9);
106 fota_cb(0, atoi(progress));
107 }
108 return 0;
109}
110
111static 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\*******************************************************************************/
124void* 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, &notification_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, &notification_event, fota_request_id);
139 uloop_run();
140 ubus_unsubscribe(fota_ubus_ctx, &notification_event, fota_request_id);
141 pthread_exit(NULL);
142
143 return NULL;
144}
145
146int 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;
178fail1:
179 return 0;
180}
181
182static 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 *******************************************************************************/
213int 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 *******************************************************************************/
250int 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 *******************************************************************************/
276int 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}