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