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