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