NVM: Remove unused static function and duplicated declarations
[platform/core/telephony/tel-plugin-imc.git] / src / s_modem.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Harish Bishnoi <hbishnoi@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <glib.h>
27
28 #include <tcore.h>
29 #include <hal.h>
30 #include <core_object.h>
31 #include <plugin.h>
32 #include <user_request.h>
33 #include <queue.h>
34 #include <co_modem.h>
35 #include <storage.h>
36 #include <server.h>
37 #include <at.h>
38 #include <mux.h>
39
40 #include "s_common.h"
41 #include "s_modem.h"
42 #include "nvm/nvm.h"
43
44
45 #define ID_RESERVED_AT 0x0229
46
47 #define MAX_VERSION_LEN 32
48 #define TAPI_MISC_ME_SN_LEN_MAX             32
49 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX      32
50 #define TAPI_MISC_MODEL_ID_LEN_MAX          17
51 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX       17
52
53 #define CPAS_RES_READY          0
54 #define CPAS_RES_UNAVAIL            1
55 #define CPAS_RES_UNKNOWN            2
56 #define CPAS_RES_RINGING            3
57 #define CPAS_RES_CALL_PROGRESS  4
58 #define CPAS_RES_ASLEEP           5
59 #define AT_VER_LEN 20
60
61
62 enum cp_state {
63         CP_STATE_OFFLINE,
64         CP_STATE_CRASH_RESET,
65         CP_STATE_CRASH_EXIT,
66         CP_STATE_BOOTING,
67         CP_STATE_ONLINE,
68         CP_STATE_NV_REBUILDING,
69         CP_STATE_LOADER_DONE,
70 };
71
72 typedef enum {
73         TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
74         TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
75         TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
76         TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
77 } TelMiscSNIndexType_t;
78
79 typedef struct {
80         TelMiscSNIndexType_t sn_index; /**< serial number index */
81         int sn_len; /**< Length */
82         unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
83 } TelMiscSNInformation;
84
85 /**
86  * Mobile Equipment Version Information
87  */
88 typedef struct {
89         unsigned char ver_mask; /**< version mask  - 0x01:SW_ver, 0x02:HW_ver, 0x04:RF_CAL_date, 0x08:Product_code, 0x10:Model_ID, 0x20:PRL, 0x04:ERI, 0xff:all */
90         unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
91         unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
92         unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
93         unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
94         unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
95         unsigned char prl_nam_num; /**< number of PRL NAM fields */
96         unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< prl version (only for CDMA), null termination */
97         unsigned char eri_nam_num; /**< number of PRL NAM fields */
98         unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< eri version (only for CDMA), null termination */
99 } TelMiscVersionInformation;
100
101
102 static void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback);
103 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data);
104 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data);
105 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
106
107 /* NVM */
108 static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data);
109 static void modem_unsuspend_nvm_updates(CoreObject *o);
110 static void modem_send_nvm_update_ack(CoreObject *o);
111 static void modem_send_nvm_update_request_ack(CoreObject *o);
112
113 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
114 {
115         dbg("on_confirmation_modem_message_send - msg out from queue.\n");
116
117         if (result == FALSE) {
118                 /* Fail */
119                 dbg("SEND FAIL");
120         } else {
121                 dbg("SEND OK");
122         }
123 }
124
125 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
126 {
127         const TcoreATResponse *resp = data;
128
129         if (resp->success > 0) {
130                 dbg("RESPONSE OK proactive command enabled");
131         } else {
132                 dbg("RESPONSE NOK proactive command disabled");
133         }
134 }
135
136 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data)
137 {
138         const TcoreATResponse *resp = data;
139
140         if (resp->success > 0) {
141                 dbg("registration attempt OK");
142         } else {
143                 dbg("registration attempt failed");
144         }
145 }
146
147 void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback)
148 {
149         TcoreATRequest *req = NULL;
150         TcoreHal *hal = NULL;
151         TcorePending *pending = NULL;
152         TReturn ret;
153
154         hal = tcore_object_get_hal(co);
155         dbg("hal: %p", hal);
156
157         pending = tcore_pending_new(co, 0);
158         if (!pending)
159                 dbg("Pending is NULL");
160         req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
161
162         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
163
164         tcore_pending_set_request_data(pending, 0, req);
165         tcore_pending_set_response_callback(pending, callback, NULL);
166         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
167         ret = tcore_hal_send_request(hal, pending);
168 }
169
170 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
171 {
172         CoreObject *o = 0;
173         TcoreHal *h = 0;
174
175         o = tcore_pending_ref_core_object(p);
176         h = tcore_object_get_hal(o);
177
178         dbg("modem power off");
179
180         tcore_hal_set_power_state(h, FALSE);
181 }
182
183 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
184 {
185         CoreObject *o = NULL;
186         UserRequest *ur = NULL;
187         const TcoreATResponse *ATresp = data;
188         GSList *tokens = NULL;
189         const char *line = NULL;
190         struct tresp_modem_set_flightmode res = {0};
191         int response = 0;
192         struct tnoti_modem_flight_mode modem_flight_mode = {0};
193         const struct treq_modem_set_flightmode *req_data = NULL;
194
195         o = tcore_pending_ref_core_object(p);
196
197         if (ATresp->success > 0) {
198                 dbg("RESPONSE OK - flight mode operation finished");
199                 res.result = TCORE_RETURN_SUCCESS;
200         } else {
201                 dbg("RESPONSE NOK");
202                 line = (const char *) ATresp->final_response;
203                 tokens = tcore_at_tok_new(line);
204
205                 if (g_slist_length(tokens) < 1) {
206                         dbg("err cause not specified or string corrupted");
207                         res.result = TCORE_RETURN_3GPP_ERROR;
208                 } else {
209                         response = atoi(g_slist_nth_data(tokens, 0));
210                         /* TODO: CMEE error mapping is required. */
211                         res.result = TCORE_RETURN_3GPP_ERROR;
212                 }
213         }
214
215         ur = tcore_pending_ref_user_request(p);
216         if (NULL == ur) {
217                 dbg("No user request. Internal request created during boot-up sequence");
218
219                 if (ATresp->success > 0) {
220                         modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
221                         dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
222
223                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
224                                                                                    sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
225                 }
226         } else {
227                 dbg("Sending response for Flight mode operation");
228
229                 req_data = tcore_user_request_ref_data(ur, NULL);
230
231                 if (TCORE_RETURN_SUCCESS == res.result) {
232                         if (TRUE == req_data->enable)
233                                 res.result = 1;
234                         else
235                                 res.result = 2;
236                 } else {
237                         res.result = 3;
238                 }
239
240                 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
241
242                 if (req_data->enable == 0) {
243                         dbg("Flight mode is disabled, trigger COPS to register on network");
244                         /* Trigger Network registration (for the moment automatic) */
245                         prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
246                 }
247         }
248
249         tcore_at_tok_free(tokens);
250 }
251
252 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
253 {
254         const TcoreATResponse *resp = data;
255         TcorePlugin *plugin = NULL;
256         struct tresp_modem_get_imei res;
257         TelMiscSNInformation *imei_property = NULL;
258         UserRequest *ur = NULL;
259         GSList *tokens = NULL;
260         const char *line;
261         int response = 0;
262
263         memset(&res, 0, sizeof(struct tresp_modem_get_imei));
264
265         if (resp->success > 0) {
266                 dbg("RESPONSE OK");
267                 if (resp->lines) {
268                         line = (const char *) resp->lines->data;
269                         tokens = tcore_at_tok_new(line);
270                         if (g_slist_length(tokens) != 1) {
271                                 msg("invalid message");
272                                 goto OUT;
273                         }
274                 }
275                 res.result = TCORE_RETURN_SUCCESS;
276                 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
277
278                 dbg("imei = [%s]", res.imei);
279
280                 plugin = tcore_pending_ref_plugin(p);
281                 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
282                 if (imei_property) {
283                         imei_property->sn_index = TAPI_MISC_ME_IMEI;
284                         imei_property->sn_len = strlen(res.imei);
285                         memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
286                 }
287         } else {
288                 dbg("RESPONSE NOK");
289                 if (resp->lines) {
290                         line = (const char *) resp->lines->data;
291                         tokens = tcore_at_tok_new(line);
292                 }
293
294
295                 if (g_slist_length(tokens) < 1) {
296                         dbg("err cause not specified or string corrupted");
297                         res.result = TCORE_RETURN_3GPP_ERROR;
298                 } else {
299                         response = atoi(g_slist_nth_data(tokens, 0));
300                         /* TODO: CMEE error mapping is required. */
301                         res.result = TCORE_RETURN_3GPP_ERROR;
302                 }
303         }
304
305         ur = tcore_pending_ref_user_request(p);
306         tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI,
307                                         sizeof(struct tresp_modem_get_imei), &res);
308
309 OUT:
310         if (tokens != NULL)
311                 tcore_at_tok_free(tokens);
312
313         return;
314 }
315
316 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
317 {
318         const TcoreATResponse *resp = data;
319         TcorePlugin *plugin = NULL;
320         struct tresp_modem_get_version res = {0};
321         TelMiscVersionInformation *vi_property = NULL;
322         TelMiscVersionInformation *vi = NULL;
323         UserRequest *ur = NULL;
324         GSList *tokens = NULL;
325         const char *line = NULL;
326         char *swver = NULL;
327         char *hwver = NULL;
328         char *caldate = NULL;
329         char *pcode = NULL;
330         char *id = NULL;
331
332         int response = 0;
333
334         if (resp->success > 0) {
335                 dbg("RESPONSE OK");
336                 if (resp->lines) {
337                         line = (const char *) resp->lines->data;
338                         tokens = tcore_at_tok_new(line);
339                         if (g_slist_length(tokens) == 1) {
340                                 swver = g_slist_nth_data(tokens, 0);
341                                 dbg("version: sw=[%s]", swver);
342                         } else if (g_slist_length(tokens) == 5) {
343                                 swver = g_slist_nth_data(tokens, 0);
344                                 hwver = g_slist_nth_data(tokens, 1);
345                                 caldate = g_slist_nth_data(tokens, 2);
346                                 pcode = g_slist_nth_data(tokens, 3);
347                                 id = g_slist_nth_data(tokens, 4);
348
349                                 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]",
350                                                                 swver, hwver, caldate, pcode, id);
351                         } else {
352                                 msg("invalid message");
353                                 goto OUT;
354                         }
355                 }
356
357                 vi = g_try_new0(TelMiscVersionInformation, 1);
358                 if (NULL != swver)
359                         memcpy(vi->szSwVersion, swver, strlen(swver));
360                 if (NULL != hwver)
361                         memcpy(vi->szHwVersion, hwver, strlen(hwver));
362                 if (NULL != caldate)
363                         memcpy(vi->szRfCalDate, caldate, strlen(caldate));
364                 if (NULL != pcode)
365                         memcpy(vi->szProductCode, pcode, strlen(pcode));
366                 if (NULL != id)
367                         memcpy(vi->szModelId, id, strlen(id));
368
369                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
370
371                 if (NULL != swver) {
372                         snprintf(res.software,
373                                 (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN),
374                                 "%s", swver);
375                 }
376
377                 if (NULL != hwver) {
378                         snprintf(res.hardware,
379                                 (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN),
380                                 "%s", hwver);
381                 }
382
383                 plugin = tcore_pending_ref_plugin(p);
384                 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
385                 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
386                 g_free(vi);
387         } else {
388                 dbg("RESPONSE NOK");
389                 if (resp->lines) {
390                         line = (const char *) resp->lines->data;
391                         tokens = tcore_at_tok_new(line);
392                 }
393
394                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
395
396
397                 if (g_slist_length(tokens) < 1) {
398                         dbg("err cause not specified or string corrupted");
399                         res.result = TCORE_RETURN_3GPP_ERROR;
400                 } else {
401                         response = atoi(g_slist_nth_data(tokens, 0));
402                         /* TODO: CMEE error mapping is required. */
403                         res.result = TCORE_RETURN_3GPP_ERROR;
404                 }
405         }
406
407         ur = tcore_pending_ref_user_request(p);
408         tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION,
409                                                 sizeof(struct tresp_modem_get_version), &res);
410
411 OUT:
412         if (tokens != NULL)
413                 tcore_at_tok_free(tokens);
414
415         return;
416 }
417
418 static enum tcore_hook_return on_hook_sim_status(Server *s,
419                                 CoreObject *source, enum tcore_notification_command command,
420                                 unsigned int data_len, void *data, void *user_data)
421 {
422         TcorePlugin *plugin;
423         const struct tnoti_sim_status *noti_sim_status;
424         CoreObject *co_sat;
425         CoreObject *co_network;
426
427         plugin = tcore_object_ref_plugin(source);
428         co_sat = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAT);
429         if (co_sat == NULL)
430                 return TCORE_HOOK_RETURN_CONTINUE;
431
432         co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
433         if (co_network == NULL)
434                 return TCORE_HOOK_RETURN_CONTINUE;
435
436         dbg("Get SIM status");
437         noti_sim_status = data;
438         if (noti_sim_status == NULL)
439                 return TCORE_HOOK_RETURN_CONTINUE;
440
441         /* If SIM is initialized, Enable STK and and attach to Network */
442         dbg("SIM Status: [%d]", noti_sim_status->sim_status);
443         if (noti_sim_status->sim_status == SIM_STATUS_INIT_COMPLETED) {
444                 dbg("SIM ready for attach!!! Enable STK and attach to Network");
445
446                 /* Sending AT+CFUN=6 */
447                 prepare_and_send_pending_request(co_sat, "AT+CFUN=6", NULL,
448                                                 TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
449
450                 /* Sending AT+COPS */
451                 prepare_and_send_pending_request(co_network, "AT+COPS=0", NULL,
452                                                 TCORE_AT_NO_RESULT, on_response_network_registration);
453         }
454
455         return TCORE_HOOK_RETURN_CONTINUE;
456 }
457
458 gboolean modem_power_on(TcorePlugin *plugin)
459 {
460         CoreObject *co_modem = NULL;
461         struct treq_modem_set_flightmode flight_mode_set = {0};
462         struct tnoti_modem_power modem_power = {0};
463         Storage *strg = NULL;
464
465         co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
466         if (co_modem == NULL) {
467                 err("Modem Core object is NULL");
468                 return FALSE;
469         }
470
471         /* Set Modem Power State to 'ON' */
472         tcore_modem_set_powered(co_modem, TRUE);
473
474         /* Get Flight mode from VCONFKEY */
475         strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf");
476         flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
477
478         /* Set Flight mode as per AP settings */
479         if (flight_mode_set.enable) {           /* Radio OFF */
480                 prepare_and_send_pending_request(co_modem, "AT+CFUN=4", NULL,
481                                                         TCORE_AT_NO_RESULT, on_response_set_flight_mode);
482
483                 /* Set Flight mode TRUE */
484                 tcore_modem_set_flight_mode_state(co_modem, TRUE);
485         } else {                                                        /* Radio ON */
486                 prepare_and_send_pending_request(co_modem, "AT+CFUN=1", NULL,
487                                                         TCORE_AT_NO_RESULT, on_response_set_flight_mode);
488
489                 /* Set Flight mode FALSE */
490                 tcore_modem_set_flight_mode_state(co_modem, FALSE);
491         }
492
493         /* Get IMEI */
494         prepare_and_send_pending_request(co_modem, "AT+CGSN", NULL,
495                                                         TCORE_AT_NUMERIC, on_response_imei);
496
497         /* Get Version Number  */
498         prepare_and_send_pending_request(co_modem, "AT+CGMR", NULL,
499                                                         TCORE_AT_SINGLELINE, on_response_version);
500
501         /* Send Notification to TAPI - MODEM_POWER */
502         modem_power.state = MODEM_STATE_ONLINE;
503
504         dbg("Sending notification - Modem Power state: [ONLINE]");
505         tcore_server_send_notification(tcore_plugin_ref_server(plugin),
506                 co_modem, TNOTI_MODEM_POWER, sizeof(modem_power), &modem_power);
507
508         return TRUE;
509 }
510
511 static TReturn power_off(CoreObject *o, UserRequest *ur)
512 {
513         TcoreHal *hal = NULL;
514         TcoreATRequest *req = NULL;
515         TcorePending *pending = NULL;
516
517         hal = tcore_object_get_hal(o);
518         pending = tcore_pending_new(o, 0);
519
520         req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
521
522         dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
523                                                 req->cmd, req->prefix, strlen(req->cmd));
524
525         tcore_pending_set_request_data(pending, 0, req);
526         tcore_pending_set_response_callback(pending, on_response_power_off, hal);
527         tcore_pending_link_user_request(pending, ur);
528         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
529
530         tcore_hal_send_request(hal, pending);
531
532         return TCORE_RETURN_SUCCESS;
533 }
534
535 static TReturn get_imei(CoreObject *o, UserRequest *ur)
536 {
537         TcoreHal *hal;
538         TcoreATRequest *req;
539         TcorePending *pending = NULL;
540
541         hal = tcore_object_get_hal(o);
542         if (FALSE == tcore_hal_get_power_state(hal)) {
543                 dbg("cp not ready/n");
544                 return TCORE_RETURN_ENOSYS;
545         }
546         pending = tcore_pending_new(o, 0);
547
548         req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
549
550         dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
551                                                 req->cmd, req->prefix, strlen(req->cmd));
552
553         tcore_pending_set_request_data(pending, 0, req);
554         tcore_pending_set_response_callback(pending, on_response_imei, hal);
555         tcore_pending_link_user_request(pending, ur);
556         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
557
558         return tcore_hal_send_request(hal, pending);
559 }
560
561
562 static TReturn get_version(CoreObject *o, UserRequest *ur)
563 {
564         TcoreHal *hal;
565         TcoreATRequest *req;
566         TcorePending *pending = NULL;
567
568         hal = tcore_object_get_hal(o);
569         if (FALSE == tcore_hal_get_power_state(hal)) {
570                 dbg("cp not ready/n");
571                 return TCORE_RETURN_ENOSYS;
572         }
573         pending = tcore_pending_new(o, 0);
574
575         req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
576
577         dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
578                                                 req->cmd, req->prefix, strlen(req->cmd));
579
580         tcore_pending_set_request_data(pending, 0, req);
581         tcore_pending_set_response_callback(pending, on_response_version, hal);
582         tcore_pending_link_user_request(pending, ur);
583         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
584
585         return tcore_hal_send_request(hal, pending);
586 }
587
588 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
589 {
590         TcoreHal *hal = NULL;
591         TcoreATRequest *req = NULL;
592         TcorePending *pending = NULL;
593         const struct treq_modem_set_flightmode *req_data = NULL;
594         char *cmd_str = NULL;
595
596         hal = tcore_object_get_hal(o);
597         if (FALSE == tcore_hal_get_power_state(hal)) {
598                 dbg("cp not ready/n");
599                 return TCORE_RETURN_ENOSYS;
600         }
601         pending = tcore_pending_new(o, 0);
602
603         req_data = tcore_user_request_ref_data(ur, NULL);
604
605         if (req_data->enable) {
606                 dbg("Flight mode on/n");
607                 cmd_str = g_strdup("AT+CFUN=4");
608         } else {
609                 dbg("Flight mode off/n");
610                 cmd_str = g_strdup("AT+CFUN=1");
611         }
612
613         req = tcore_at_request_new((const char *)cmd_str, NULL, TCORE_AT_NO_RESULT);
614         g_free(cmd_str);
615
616         dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
617                                                 req->cmd, req->prefix, strlen(req->cmd));
618
619         tcore_pending_set_request_data(pending, 0, req);
620         tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
621         tcore_pending_link_user_request(pending, ur);
622         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
623
624         return tcore_hal_send_request(hal, pending);
625 }
626
627
628 static struct tcore_modem_operations modem_ops = {
629         .power_on = NULL,
630         .power_off = power_off,
631         .power_reset = NULL,
632         .set_flight_mode = set_flight_mode,
633         .get_imei = get_imei,
634         .get_version = get_version,
635         .get_sn = NULL,
636         .dun_pin_ctrl = NULL,
637 };
638
639 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
640 {
641         TelMiscVersionInformation *vi_property;
642         TelMiscSNInformation *imei_property;
643         TelMiscSNInformation *sn_property;
644
645         dbg("Enter");
646
647         tcore_modem_override_ops(co_modem, &modem_ops);
648
649         vi_property = g_try_new0(TelMiscVersionInformation, 1);
650         tcore_plugin_link_property(cp, "VERSION", vi_property);
651
652         imei_property = g_try_new0(TelMiscSNInformation, 1);
653         tcore_plugin_link_property(cp, "IMEI", imei_property);
654
655         sn_property = g_try_new0(TelMiscSNInformation, 1);
656         tcore_plugin_link_property(cp, "SN", sn_property);
657
658         tcore_server_add_notification_hook(tcore_plugin_ref_server(cp),
659                                                         TNOTI_SIM_STATUS, on_hook_sim_status, NULL);
660         dbg("Registering for +XDRVI event");
661         tcore_object_add_callback(co_modem, "+XDRVI", on_event_nvm_update, NULL);
662
663         dbg("Exit");
664         return TRUE;
665 }
666
667 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
668 {
669         TelMiscVersionInformation *vi_property;
670         TelMiscSNInformation *imei_property;
671         TelMiscSNInformation *sn_property;
672         TcorePlugin *plugin = tcore_object_ref_plugin(co_modem);
673
674         vi_property = tcore_plugin_ref_property(plugin, "VERSION");
675         g_free(vi_property);
676
677         imei_property = tcore_plugin_ref_property(plugin, "IMEI");
678         g_free(imei_property);
679
680         sn_property = tcore_plugin_ref_property(plugin, "SN");
681         g_free(sn_property);
682
683         dbg("Exit");
684 }
685
686 /*
687  * NV Manager - Support for Remote File System
688  */
689 /* NVM Hook */
690 static gboolean modem_rfs_hook(const char *data)
691 {
692         if (data != NULL)
693                 if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
694                         return TRUE;
695
696         return FALSE;
697 }
698
699 /* NVM event Notification */
700 static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data)
701 {
702         GSList *tokens = NULL;
703         GSList *lines;
704         const char *line;
705         int function_id;
706
707         gboolean ret = TRUE;
708         dbg("Entered");
709
710         lines = (GSList *)event_info;
711         line = lines->data;
712         dbg("Line: [%s]", line);
713
714         function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]);
715         dbg("Function ID: [%d]", function_id);
716         if (IUFP_UPDATE == function_id) {
717                 dbg("Calling process nvm_update");
718
719                 /*
720                  * Process NV Update indication
721                  *
722                  * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
723                  */
724                 if (NVM_NO_ERR == nvm_process_nv_update(line)) {
725                         dbg("NV data processed successfully");
726
727                         /* Acknowledge NV Update */
728                         modem_send_nvm_update_ack(o);
729
730                         return ret;
731                 } else {
732                         err("NV data processing failed");
733                         ret = FALSE;
734                 }
735         } else {
736                 tokens = tcore_at_tok_new(line);
737                 if (g_slist_length(tokens) < 3) {
738                         err("XDRVI event with less number of tokens, Ignore!!!");
739                         ret = FALSE;
740                 }
741                 else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
742                         err("Group ID mismatch, Ignore!!!");
743                         ret = FALSE;
744                 }
745                 else {
746                         switch (atoi(g_slist_nth_data(tokens, 1))) {
747                                 case IUFP_UPDATE_REQ:
748                                         dbg("NV Update Request");
749
750                                         /* Acknowledge the Update Request */
751                                         modem_send_nvm_update_request_ack(o);
752                                 break;
753
754                                 case IUFP_NO_PENDING_UPDATE:
755                                         dbg("NO pending NV Update(s)!!!");
756                                         /* Can send FLUSH request to get fresh updates */
757                                 break;
758
759                                 default:
760                                         err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1)));
761                                         ret = FALSE;
762                         }
763                 }
764
765                 tcore_at_tok_free(tokens);
766         }
767
768         dbg("Exit");
769         return ret;
770 }
771
772 /* NVM Responses */
773 static gboolean __modem_check_nvm_response(const void *data, int command)
774 {
775         const TcoreATResponse *resp = data;
776         const char *line;
777         char *resp_str;
778         GSList *tokens = NULL;
779         gboolean ret = FALSE;
780         dbg("Entered");
781
782         /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
783         if (NULL == resp) {
784                 err("Input data is NULL");
785                 return FALSE;
786         }
787
788         if (resp->success > 0) {
789                 dbg("RESPONSE OK");
790                 line = (const char *) (((GSList *) resp->lines)->data);
791                 tokens = tcore_at_tok_new(line);
792
793                 /* Group ID */
794                 resp_str = g_slist_nth_data(tokens, 0);
795                 if (NULL == resp_str) {
796                         err("Group ID is missing ");
797                         goto OUT;
798                 }
799                 else if (IUFP_GROUP_ID != atoi(resp_str)) {
800                         err("Group ID mismatch");
801                         goto OUT;
802                 }
803
804                 /* Function ID */
805                 resp_str =  g_slist_nth_data(tokens, 1);
806                 if (NULL == resp_str) {
807                         err("Function ID is missing ");
808                         goto OUT;
809                 }
810                 else if (command != atoi(resp_str)) {
811                         err("Function ID mismatch");
812                         goto OUT;
813                 }
814
815                 /* XDRV Result */
816                 resp_str =  g_slist_nth_data(tokens, 2);
817                 if (NULL == resp_str) {
818                         err("XDRV result is missing ");
819                         goto OUT;
820                 }
821                 else if (XDRV_RESULT_OK != atoi(resp_str)) {
822                         err("XDRV result[%d] ", atoi(resp_str));
823                         goto OUT;
824                 }
825
826                 /* Result code */
827                 resp_str =  g_slist_nth_data(tokens, 3);
828                 if (NULL == resp_str) {
829                         err("UTA result is missing ");
830                         goto OUT;
831                 }
832                 else if (UTA_SUCCESS != atoi(resp_str)) {
833                         err("uta result[%d] ", atoi(resp_str));
834                         goto OUT;
835                 }
836
837                 ret = TRUE;
838         } else {
839                 dbg("Response NOK");
840         }
841
842 OUT:
843         tcore_at_tok_free(tokens);
844
845         dbg("Exit");
846         return ret;
847 }
848
849 static void _on_response_modem_unsuspend_nvm_updates(TcorePending *p,
850                                                         int data_len, const void *data, void *user_data)
851 {
852         /* Check NVM response */
853         if (TRUE == __modem_check_nvm_response(data, IUFP_SUSPEND)) {
854                 dbg("Priority level is set to get all updates since Boot-up");
855
856                 /* Create NV data file */
857                 if (nvm_create_nvm_data() == FALSE) {
858                         err("Failed to Create NV data file");
859                 }
860
861                 return;
862         }
863
864         err("Response NOT OK");
865 }
866
867 static void _on_response_modem_send_nvm_update_ack(TcorePending *p,
868                                                         int data_len, const void *data, void *user_data)
869 {
870         /* Check NVM response */
871         if (TRUE ==  __modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
872                 dbg("[UPDATE ACK] OK");
873                 return;
874         }
875
876         err("[UPDATE ACK] NOT OK");
877 }
878
879 static void _on_response_modem_send_nvm_update_request_ack(TcorePending *p,
880                                                         int data_len, const void *data, void *user_data)
881 {
882         /* Check NVM response */
883         if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
884                 dbg("[REQUEST ACK] OK");
885                 return;
886         }
887
888         err("[REQUEST ACK] NOT OK");
889 }
890
891 static void _on_response_modem_register_nvm(TcorePending *p,
892                                                 int data_len, const void *data, void *user_data)
893 {
894         /* Check NVM response */
895         if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
896                 dbg("Registering successful");
897
898                 /* Send SUSPEND_UPDATE for all UPDATES */
899                 modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p));
900
901                 dbg("Exit");
902                 return;
903         }
904
905         err("Response NOT OK");
906 }
907
908 /* NVM Requests */
909 static void modem_unsuspend_nvm_updates(CoreObject *o)
910 {
911         TcorePending *pending = NULL;
912         char *cmd_str;
913         dbg("Entered");
914
915         /* Prepare AT-Command */
916         cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d",
917                                         IUFP_GROUP_ID, IUFP_SUSPEND,
918                                         0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL);
919
920         /* Prepare pending request */
921         pending = tcore_at_pending_new(o,
922                                                                 cmd_str,
923                                                                 "+XDRV:",
924                                                                 TCORE_AT_SINGLELINE,
925                                                                 _on_response_modem_unsuspend_nvm_updates,
926                                                                 NULL);
927         if (pending == NULL) {
928                 err("Failed to form pending request");
929         }
930         else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
931                         != TCORE_RETURN_SUCCESS) {
932                 err("IUFP_SUSPEND - Unable to send AT-Command");
933         }
934         else {
935                 dbg("IUFP_SUSPEND - Successfully sent AT-Command");
936         }
937
938         g_free(cmd_str);
939 }
940
941 static void modem_send_nvm_update_ack(CoreObject *o)
942 {
943         TcorePending *pending = NULL;
944         char *cmd_str;
945         dbg("Entered");
946
947         /* Prepare AT-Command */
948         cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
949
950         /* Prepare pending request */
951         pending = tcore_at_pending_new(o,
952                                                                 cmd_str,
953                                                                 "+XDRV:",
954                                                                 TCORE_AT_SINGLELINE,
955                                                                 _on_response_modem_send_nvm_update_ack,
956                                                                 NULL);
957         if (pending == NULL) {
958                 err("Failed to form pending request");
959         }
960         else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
961                                                                                 != TCORE_RETURN_SUCCESS) {
962                 err("IUFP_UPDATE_ACK - Unable to send AT-Command");
963         }
964         else {
965                 dbg("IUFP_UPDATE_ACK - Successfully sent AT-Command");
966         }
967
968         g_free(cmd_str);
969 }
970
971 static void modem_send_nvm_update_request_ack(CoreObject *o)
972 {
973         TcorePending *pending = NULL;
974         char *cmd_str;
975         dbg("Entered");
976
977         /* Prepare AT-Command */
978         cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
979
980         /* Prepare pending request */
981         pending = tcore_at_pending_new(o,
982                                                                 cmd_str,
983                                                                 "+XDRV:",
984                                                                 TCORE_AT_SINGLELINE,
985                                                                 _on_response_modem_send_nvm_update_request_ack,
986                                                                 NULL);
987
988
989         if (pending == NULL) {
990                 err("Failed to form pending request");
991         }
992         else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
993                                                                         != TCORE_RETURN_SUCCESS) {
994                 err("IUFP_UPDATE_REQ_ACK - Unable to send AT-Ccommand");
995         }
996         else {
997                 dbg("IUFP_UPDATE_REQ_ACK - Successfully sent AT-Command");
998         }
999
1000         g_free(cmd_str);
1001 }
1002
1003 void modem_register_nvm(CoreObject *co_modem)
1004 {
1005         TcorePending *pending = NULL;
1006         char *cmd_str;
1007         dbg("Entered");
1008
1009         /* Prepare AT-Command */
1010         cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
1011                                         IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
1012
1013         /* Prepare pending request */
1014         pending = tcore_at_pending_new(co_modem,
1015                                                                 cmd_str,
1016                                                                 "+XDRV:",
1017                                                                 TCORE_AT_SINGLELINE,
1018                                                                 _on_response_modem_register_nvm,
1019                                                                 NULL);
1020         if (pending == NULL) {
1021                 err("Failed to form pending request");
1022         }
1023         else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending)
1024                                                                         != TCORE_RETURN_SUCCESS) {
1025                 err("IUFP_REGISTER (Enable) -Unable to send AT-Command");
1026         }
1027         else {
1028                 dbg("IUFP_REGISTER (Enable) -Successfully sent AT-Command");
1029
1030                 /* Add RFS hook */
1031                 tcore_at_add_hook(tcore_object_get_hal(co_modem), modem_rfs_hook);
1032         }
1033
1034         g_free(cmd_str);
1035 }