fix set language issue
[platform/core/telephony/tel-plugin-imc.git] / src / imc_modem.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33
34 #include <co_modem.h>
35
36 #include "imc_modem.h"
37 #include "imc_common.h"
38 #include "nvm/nvm.h"
39
40 static gboolean on_event_imc_nvm_update(CoreObject *co,
41         const void *event_info, void *user_data);
42
43 /* NVM Req/Response */
44 static gboolean __imc_modem_check_nvm_response(const void *data, int command)
45 {
46         const TcoreAtResponse *at_resp = data;
47         const char *line;
48         char *resp_str;
49         GSList *tokens = NULL;
50         gboolean ret = FALSE;
51
52         dbg("Entered");
53
54         /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
55         if (NULL == at_resp) {
56                 err("Input data is NULL");
57                 return FALSE;
58         }
59
60         if (at_resp->success > 0) {
61                 dbg("RESPONSE OK");
62                 line = (const char *) (((GSList *) at_resp->lines)->data);
63                 tokens = tcore_at_tok_new(line);
64
65                 /* Group ID */
66                 resp_str = g_slist_nth_data(tokens, 0);
67                 if (NULL == resp_str) {
68                         err("Group ID is missing ");
69                         goto OUT;
70                 }
71                 else if (IUFP_GROUP_ID != atoi(resp_str)) {
72                         err("Group ID mismatch");
73                         goto OUT;
74                 }
75
76                 /* Function ID */
77                 resp_str =  g_slist_nth_data(tokens, 1);
78                 if (NULL == resp_str) {
79                         err("Function ID is missing ");
80                         goto OUT;
81                 }
82                 else if (command != atoi(resp_str)) {
83                         err("Function ID mismatch");
84                         goto OUT;
85                 }
86
87                 /* XDRV Result */
88                 resp_str =  g_slist_nth_data(tokens, 2);
89                 if (NULL == resp_str) {
90                         err("XDRV result is missing ");
91                         goto OUT;
92                 }
93                 else if (XDRV_RESULT_OK != atoi(resp_str)) {
94                         err("XDRV result[%d] ", atoi(resp_str));
95                         goto OUT;
96                 }
97
98                 /* Result code */
99                 resp_str =  g_slist_nth_data(tokens, 3);
100                 if (NULL == resp_str) {
101                         err("UTA result is missing ");
102                         goto OUT;
103                 }
104                 else if (UTA_SUCCESS != atoi(resp_str)) {
105                         err("uta result[%d] ", atoi(resp_str));
106                         goto OUT;
107                 }
108
109                 ret = TRUE;
110         } else {
111                 dbg("Response NOK");
112         }
113
114 OUT:
115         tcore_at_tok_free(tokens);
116
117         dbg("Exit");
118         return ret;
119 }
120
121 static void __on_response_modem_unsuspend_nvm_updates(TcorePending *p,
122                                                         guint data_len, const void *data, void *user_data)
123 {
124         /* Check NVM response */
125         if (TRUE == __imc_modem_check_nvm_response(data, IUFP_SUSPEND)) {
126                 dbg("Priority level is set to get all updates since Boot-up");
127
128                 /* Create NV data file */
129                 if (nvm_create_nvm_data() == FALSE) {
130                         err("Failed to Create NV data file");
131                 }
132
133                 return;
134         }
135
136         err("Response NOT OK");
137 }
138
139 static void __imc_modem_unsuspend_nvm_updates(CoreObject *co)
140 {
141         char *cmd_str;
142         TelReturn ret;
143
144         /* Prepare AT-Command */
145         cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d",
146                                         IUFP_GROUP_ID, IUFP_SUSPEND,
147                                         0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL);
148
149         /* Send Request to modem */
150         ret = tcore_at_prepare_and_send_request(co,
151                 cmd_str, "+XDRV:",
152                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
153                 TCORE_PENDING_PRIORITY_DEFAULT,
154                 NULL,
155                 __on_response_modem_unsuspend_nvm_updates, NULL,
156                 on_send_imc_request, NULL,
157                 0, NULL, NULL);
158
159         IMC_CHECK_REQUEST_RET(ret, NULL, "Unsuspend Nvm Updates");
160
161         g_free(cmd_str);
162 }
163
164 static void __on_response_modem_send_nvm_update_ack(TcorePending *p,
165                                                         guint data_len, const void *data, void *user_data)
166 {
167         /* Check NVM response */
168         if (TRUE ==  __imc_modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
169                 dbg("[UPDATE ACK] OK");
170                 return;
171         }
172
173         err("[UPDATE ACK] NOT OK");
174 }
175
176 static void __imc_modem_send_nvm_update_ack(CoreObject *co)
177 {
178         char *cmd_str;
179         TelReturn ret;
180
181         /* Prepare AT-Command */
182         cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
183
184         /* Send Request to modem */
185         ret = tcore_at_prepare_and_send_request(co,
186                 cmd_str, "+XDRV:",
187                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
188                 TCORE_PENDING_PRIORITY_DEFAULT,
189                 NULL,
190                 __on_response_modem_send_nvm_update_ack, NULL,
191                 on_send_imc_request, NULL,
192                 0, NULL, NULL);
193
194         IMC_CHECK_REQUEST_RET(ret, NULL, "Nvm Update Ack");
195
196         g_free(cmd_str);
197 }
198
199 static void __on_response_modem_send_nvm_update_request_ack(TcorePending *p,
200                                                         guint data_len, const void *data, void *user_data)
201 {
202         /* Check NVM response */
203         if (TRUE == __imc_modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
204                 dbg("[REQUEST ACK] OK");
205                 return;
206         }
207
208         err("[REQUEST ACK] NOT OK");
209 }
210
211 static void __imc_modem_send_nvm_update_request_ack(CoreObject *co)
212 {
213         char *cmd_str;
214         TelReturn ret;
215
216         /* Prepare AT-Command */
217         cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
218
219         /* Send Request to modem */
220         ret = tcore_at_prepare_and_send_request(co,
221                 cmd_str, "+XDRV:",
222                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
223                 TCORE_PENDING_PRIORITY_DEFAULT,
224                 NULL,
225                 __on_response_modem_send_nvm_update_request_ack, NULL,
226                 on_send_imc_request, NULL,
227                 0, NULL, NULL);
228
229         IMC_CHECK_REQUEST_RET(ret, NULL, "Nvm Update Request Ack");
230
231         g_free(cmd_str);
232 }
233
234 static void __on_response_modem_register_nvm(TcorePending *p,
235                                                 guint data_len, const void *data, void *user_data)
236 {
237         /* Check NVM response */
238         if (TRUE == __imc_modem_check_nvm_response(data, IUFP_REGISTER)) {
239                 dbg("Registering successful");
240
241                 /* Send SUSPEND_UPDATE for all UPDATES */
242                 __imc_modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p));
243
244                 dbg("Exit");
245                 return;
246         }
247
248         err("Response NOT OK");
249 }
250
251 /* System function responses */
252 static void on_response_modem_set_flight_mode_internal(TcorePlugin *plugin,
253         gint result, const void *response, void *user_data)
254 {
255         CoreObject *co;
256         gboolean flight_mode;
257         dbg("Enter");
258
259         co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
260         tcore_check_return_assert(co != NULL);
261
262         tcore_check_return(result == TEL_MODEM_RESULT_SUCCESS);
263
264         /* Get Flight mode state */
265         (void)tcore_modem_get_flight_mode_state(co, &flight_mode);
266
267         dbg("Setting Modem Fiight mode (internal) - [%s] - [SUCCESS]",
268                 (flight_mode ? "ON": "OFF"));
269
270         /*
271          * Send notification
272          *
273          * This is an internal request to set Flight mode, which is sent during
274          * boot-up based on AP-side configuration (VCONF).
275          *
276          * Need to notify TAPI through Notiifcation -
277          *      TCORE_NOTIFICATION_MODEM_FLIGHT_MODE
278          */
279         (void)tcore_object_send_notification(co,
280                 TCORE_NOTIFICATION_MODEM_FLIGHT_MODE,
281                 sizeof(gboolean), &flight_mode);
282 }
283
284 /* System functions */
285 gboolean imc_modem_power_on_modem(TcorePlugin *plugin)
286 {
287         CoreObject *co;
288         TcoreStorage *strg;
289         gboolean flight_mode;
290         TelModemPowerStatus power_status;
291
292         co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
293         tcore_check_return_value_assert(co != NULL, FALSE);
294
295         /* Set Modem Power State to 'ON' */
296         tcore_modem_set_powered(co, TRUE);
297
298         /*
299          * Set Flight mode (as per AP settings -VCONF)
300          */
301         /* Get Flight mode from VCONFKEY */
302         strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf");
303         tcore_check_return_value_assert(strg != NULL, FALSE);
304
305         flight_mode = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE);
306
307         /*
308          * Set Flight mode request is dispatched to Core Object (Modem)
309          * to ensure that 'Request Hooks' get executed.
310          */
311         (void)tcore_object_dispatch_request(co, TRUE,
312                 TCORE_COMMAND_MODEM_SET_FLIGHTMODE,
313                 &flight_mode, sizeof(gboolean),
314                 on_response_modem_set_flight_mode_internal, NULL);
315
316         /*
317          * Send notification
318          *
319          * Need to notify Modem is Powered UP through Notiifcation -
320          *      TCORE_NOTIFICATION_MODEM_POWER
321          */
322         power_status = TEL_MODEM_POWER_ON;
323         (void)tcore_object_send_notification(co,
324                 TCORE_NOTIFICATION_MODEM_POWER,
325                 sizeof(TelModemPowerStatus), &power_status);
326
327         return TRUE;
328 }
329
330 /* Modem Responses */
331 static void on_response_imc_modem_set_power_status(TcorePending *p,
332         guint data_len, const void *data, void *user_data)
333 {
334         const TcoreAtResponse *at_resp = data;
335         CoreObject *co = tcore_pending_ref_core_object(p);
336         ImcRespCbData *resp_cb_data = user_data;
337         TelModemPowerStatus *status;
338         gboolean powered = FALSE;
339
340         TelModemResult result = TEL_MODEM_RESULT_FAILURE;
341         dbg("Enter");
342
343         tcore_check_return_assert(co != NULL);
344         tcore_check_return_assert(resp_cb_data != NULL);
345
346         if (at_resp && at_resp->success)
347                 result = TEL_MODEM_RESULT_SUCCESS;
348
349         status = (TelModemPowerStatus *)
350                 IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
351
352         /* Update Core Object */
353         switch (*status) {
354         case TEL_MODEM_POWER_ON:
355                 dbg("Setting Modem Power status [ON] - [%s]",
356                         (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
357                 powered = TRUE;
358         break;
359         case TEL_MODEM_POWER_OFF:
360                 dbg("Setting Modem Power status [OFF] - [%s]",
361                         (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
362                 powered = FALSE;
363         break;
364         default:
365                 warn("Unexpected - Setting Modem Power status [RESET] - [%s]",
366                         (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
367         break;
368         }
369         tcore_modem_set_powered(co, powered);
370
371         /* Invoke callback */
372         if (resp_cb_data->cb)
373                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
374
375         /* Free callback data */
376         imc_destroy_resp_cb_data(resp_cb_data);
377 }
378
379 static void on_response_imc_modem_set_flight_mode(TcorePending *p,
380         guint data_len, const void *data, void *user_data)
381 {
382         const TcoreAtResponse *at_resp = data;
383         CoreObject *co = tcore_pending_ref_core_object(p);
384         ImcRespCbData *resp_cb_data = user_data;
385         gboolean *enable;
386
387         TelModemResult result = TEL_MODEM_RESULT_FAILURE;
388         dbg("Enter");
389
390         tcore_check_return_assert(co != NULL);
391         tcore_check_return_assert(resp_cb_data != NULL);
392
393         if (at_resp && at_resp->success)
394                 result = TEL_MODEM_RESULT_SUCCESS;
395
396         enable = (gboolean *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
397
398         dbg("Setting Modem Fiight mode - [%s] - [%s]",
399                 (*enable ? "ON": "OFF"),
400                 (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
401
402         /* Update Core Object */
403         (void)tcore_modem_set_flight_mode_state(co, *enable);
404
405         /* Invoke callback */
406         if (resp_cb_data->cb)
407                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
408
409         /* Free callback data */
410         imc_destroy_resp_cb_data(resp_cb_data);
411
412         /*
413          * In case Flight mode is set to OFF, we need to trigger
414          * Network Registration.
415          *
416          * This is taken care by Network module which hooks on
417          * Set Flight mode Request of Modem module.
418          */
419 }
420
421 /* Current modem does not support this operation */
422 #if 0
423 static void on_response_imc_modem_get_version(TcorePending *p,
424         guint data_len, const void *data, void *user_data)
425 {
426         const TcoreAtResponse *at_resp = data;
427         CoreObject *co = tcore_pending_ref_core_object(p);
428         ImcRespCbData *resp_cb_data = user_data;
429         TelModemVersion version = {{0}, {0}, {0}, {0}};
430
431         TelModemResult result = TEL_MODEM_RESULT_FAILURE;
432         dbg("Enter");
433
434         tcore_check_return_assert(co != NULL);
435         tcore_check_return_assert(resp_cb_data != NULL);
436
437         if (at_resp) {
438                 if (at_resp->lines) {
439                         const gchar *line;
440                         GSList *tokens = NULL;
441
442                         line = (const gchar *)at_resp->lines->data;
443                         tokens = tcore_at_tok_new(line);
444                         if (g_slist_length(tokens) > 0) {
445                                 if (at_resp->success) {
446                                         gchar *sw_ver = NULL, *hw_ver = NULL;
447                                         gchar *calib_date = NULL, *p_code = NULL;
448
449                                         sw_ver = g_slist_nth_data(tokens, 0);
450                                         hw_ver = g_slist_nth_data(tokens, 1);
451                                         calib_date = g_slist_nth_data(tokens, 2);
452                                         p_code = g_slist_nth_data(tokens, 3);
453                                         if (sw_ver != NULL){
454                                                 g_strlcpy(version.software_version,
455                                                         sw_ver,
456                                                         TEL_MODEM_VERSION_LENGTH_MAX + 1);
457                                         }
458                                         if (hw_ver != NULL){
459                                                 g_strlcpy(version.hardware_version,
460                                                         hw_ver,
461                                                         TEL_MODEM_VERSION_LENGTH_MAX + 1);
462                                         }
463                                         if (calib_date != NULL){
464                                                 g_strlcpy(version.calibration_date,
465                                                         calib_date,
466                                                         TEL_MODEM_VERSION_LENGTH_MAX + 1);
467                                         }
468                                         if (p_code != NULL){
469                                                 g_strlcpy(version.product_code,
470                                                         p_code,
471                                                         TEL_MODEM_VERSION_LENGTH_MAX + 1);
472                                         }
473                                         dbg("Version - Software: [%s] Hardware: [%s] "
474                                                 "Calibration date: [%s] Product "
475                                                 "Code: [%s]", sw_ver, hw_ver,
476                                                 calib_date, p_code);
477
478                                         result = TEL_MODEM_RESULT_SUCCESS;
479                                 } else {
480                                         err("RESPONSE - [NOK]");
481                                         err("[%s]", g_slist_nth_data(tokens, 0));
482                                 }
483                         } else {
484                                 err("Invalid response message");
485                                 result = TEL_MODEM_RESULT_UNKNOWN_FAILURE;
486                         }
487                         tcore_at_tok_free(tokens);
488                 }
489         }
490
491         /* Invoke callback */
492         if (resp_cb_data->cb)
493                 resp_cb_data->cb(co, (gint)result, &version, resp_cb_data->cb_data);
494
495         /* Free callback data */
496         imc_destroy_resp_cb_data(resp_cb_data);
497 }
498 #endif
499
500 static void on_response_imc_modem_get_imei(TcorePending *p,
501         guint data_len, const void *data, void *user_data)
502 {
503         const TcoreAtResponse *at_resp = data;
504         CoreObject *co = tcore_pending_ref_core_object(p);
505         ImcRespCbData *resp_cb_data = user_data;
506         gchar imei[TEL_MODEM_IMEI_LENGTH_MAX +1] = {0};
507
508         TelModemResult result = TEL_MODEM_RESULT_FAILURE;
509         dbg("Enter");
510
511         tcore_check_return_assert(co != NULL);
512         tcore_check_return_assert(resp_cb_data != NULL);
513
514         if (at_resp) {
515                 if (at_resp->lines) {
516                         const gchar *line;
517                         GSList *tokens = NULL;
518
519                         line = (const gchar *)at_resp->lines->data;
520                         tokens = tcore_at_tok_new(line);
521                         if (g_slist_length(tokens) == 1) {
522                                 if (at_resp->success) {
523                                         dbg("RESPONSE - [OK]");
524                                         g_strlcpy(imei,
525                                                 (const gchar *)g_slist_nth_data(tokens, 0),
526                                                 TEL_MODEM_IMEI_LENGTH_MAX+1);
527                                         dbg("IMEI: [%s]", imei);
528
529                                         result = TEL_MODEM_RESULT_SUCCESS;
530                                 } else {
531                                         err("RESPONSE - [NOK]");
532                                         err("[%s]", g_slist_nth_data(tokens, 0));
533                                 }
534                         }  else {
535                                 err("Invalid response message");
536                                 result = TEL_MODEM_RESULT_UNKNOWN_FAILURE;
537                         }
538                         tcore_at_tok_free(tokens);
539                 }
540         }
541
542         /* Invoke callback */
543         if (resp_cb_data->cb)
544                 resp_cb_data->cb(co, (gint)result, imei, resp_cb_data->cb_data);
545
546         /* Free callback data */
547         imc_destroy_resp_cb_data(resp_cb_data);
548 }
549
550 /* Modem Operations */
551 /*
552  * Operation - set_power_status
553  *
554  * Request -
555  * AT-Command: AT+CFUN=<fun>
556  * where,
557  * <fun>
558  * 0    Mode to switch off MS
559  * ...  Other modes are available for other oprations
560  *
561  * Response -
562  * Success: (No Result)
563  *      OK
564  * Failure:
565  *      +CME ERROR: <error>
566  */
567 static TelReturn imc_modem_set_power_status(CoreObject *co,
568         TelModemPowerStatus status,
569         TcoreObjectResponseCallback cb, void *cb_data)
570 {
571         gchar *at_cmd;
572         guint power_mode;
573
574         ImcRespCbData *resp_cb_data;
575         TelReturn ret;
576
577         if (status == TEL_MODEM_POWER_ON) {
578                 warn("Modem Power ON - Not supported by CP");
579                 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
580         } else if (status == TEL_MODEM_POWER_ERROR) {
581                 err("Modem Power ERROR - Invalid mode");
582                 return TEL_RETURN_INVALID_PARAMETER;
583         } else {
584                 dbg("Modem Power OFF");
585                 power_mode = 0;
586         }
587
588         /* AT-Command */
589         at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode);
590
591         /* Response callback data */
592         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
593                                 &status, sizeof(TelModemPowerStatus));
594
595         /* Send Request to modem */
596         ret = tcore_at_prepare_and_send_request(co,
597                 at_cmd, NULL,
598                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
599                 TCORE_PENDING_PRIORITY_DEFAULT,
600                 NULL,
601                 on_response_imc_modem_set_power_status, resp_cb_data,
602                 on_send_imc_request, NULL,
603                 0, NULL, NULL);
604         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Power Status");
605
606         /* Free resources */
607         g_free(at_cmd);
608
609         return ret;
610 }
611
612 /*
613  * Operation - set_flight_mode
614  *
615  * Request -
616  * AT-Command: AT+CFUN=<fun>
617  * where,
618  * <fun>
619  * 0    Mode to switch off MS
620  * 1    Full functionality
621  * 4    Mode to disable phone both transmit and receive
622  *      RF circuits. Airplane mode.
623  * ...  Other modes are available for other oprations
624  *
625  * Response -
626  * Success: (No Result)
627  *      OK
628  * Failure:
629  *      +CME ERROR: <error>
630  */
631 static TelReturn imc_modem_set_flight_mode(CoreObject *co, gboolean enable,
632         TcoreObjectResponseCallback cb, void *cb_data)
633 {
634         gchar *at_cmd;
635         guint power_mode;
636
637         ImcRespCbData *resp_cb_data;
638         TelReturn ret;
639
640         if (enable) {
641                 dbg("Flight mode - [ON]");
642                 power_mode = 4;
643         } else {
644                 dbg("Flight mode - [OFF]");
645                 power_mode = 1;
646         }
647
648         /* AT-Command */
649         at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode);
650
651         /* Response callback data */
652         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
653                                 &enable, sizeof(gboolean));
654
655         /* Send Request to modem */
656         ret = tcore_at_prepare_and_send_request(co,
657                 at_cmd, NULL,
658                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
659                 TCORE_PENDING_PRIORITY_DEFAULT,
660                 NULL,
661                 on_response_imc_modem_set_flight_mode, resp_cb_data,
662                 on_send_imc_request, NULL,
663                 0, NULL, NULL);
664         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Flight mode");
665
666         /* Free resources */
667         g_free(at_cmd);
668
669         return ret;
670 }
671
672 /*
673  * Operation - get_flight_mode
674  *
675  * Request -
676  * AT-Command: None
677  *      Fetch information from Core Object
678  *
679  * Response - flight_mode (gboolean)
680  */
681 static TelReturn imc_modem_get_flight_mode(CoreObject *co,
682         TcoreObjectResponseCallback cb, void *cb_data)
683 {
684         gboolean flight_mode;
685
686         /* Fetch Flight mode from Core Object */
687         (void)tcore_modem_get_flight_mode_state(co, &flight_mode);
688         dbg("Modem Flight mode - [%s]", (flight_mode ? "ON": "OFF"));
689
690         /* Invoke response callback */
691         if (cb)
692                 cb(co, (gint)TEL_MODEM_RESULT_SUCCESS, &flight_mode, cb_data);
693
694         return TEL_RETURN_SUCCESS;
695 }
696
697 /*
698  * Operation - get_version
699  *
700  * Request -
701  * AT-Command: AT+CGMR
702  *
703  * Response - version (TelModemVersion)
704  * Success: (Single line) -
705  *      <sw_ver>, <hw_ver>, <calib_date>, <p_code>
706  *      OK
707  * Note:
708  *      Success Response is different from standard 3GPP AT-Command (+CGMR)
709  * Failure:
710  *      +CME ERROR: <error>
711  */
712 static TelReturn imc_modem_get_version(CoreObject *co,
713         TcoreObjectResponseCallback cb, void *cb_data)
714 {
715         dbg("entry");
716
717 /* Current modem does not support this operation */
718 #if 0
719         ImcRespCbData *resp_cb_data;
720         TelReturn ret;
721
722         /* Response callback data */
723         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
724                                 NULL, 0);
725
726         /* Send Request to modem */
727         ret = tcore_at_prepare_and_send_request(co,
728                 "AT+CGMR", NULL,
729                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
730                 TCORE_PENDING_PRIORITY_DEFAULT,
731                 NULL,
732                 on_response_imc_modem_get_version, resp_cb_data,
733                 on_send_imc_request, NULL,
734                 0, NULL, NULL);
735         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Version");
736
737         return ret;
738 #endif
739
740         dbg("exit");
741         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
742 }
743
744 /*
745  * Operation - get_imei
746  *
747  * Request -
748  * AT-Command: AT+CGSN
749  *
750  * Response - imei (gchar array of length 20+'\0' bytes)
751  * Success: (Single line)
752  *      <IMEI>
753  *      OK
754  * Failure:
755  *      +CME ERROR: <error>
756  */
757 static TelReturn imc_modem_get_imei(CoreObject *co,
758         TcoreObjectResponseCallback cb, void *cb_data)
759 {
760         ImcRespCbData *resp_cb_data;
761         TelReturn ret;
762
763         dbg("Enter");
764
765         /* Response callback data */
766         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
767                                 NULL, 0);
768
769         /* Send Request to modem */
770         ret = tcore_at_prepare_and_send_request(co,
771                 "AT+CGSN", NULL,
772                 TCORE_AT_COMMAND_TYPE_NUMERIC,
773                 TCORE_PENDING_PRIORITY_DEFAULT,
774                 NULL,
775                 on_response_imc_modem_get_imei, resp_cb_data,
776                 on_send_imc_request, NULL,
777                 0, NULL, NULL);
778         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get IMEI");
779
780         return ret;
781 }
782
783 /* Modem Operations */
784 static TcoreModemOps imc_modem_ops = {
785         .set_power_status = imc_modem_set_power_status,
786         .set_flight_mode = imc_modem_set_flight_mode,
787         .get_flight_mode = imc_modem_get_flight_mode,
788         .get_version = imc_modem_get_version,
789         .get_imei = imc_modem_get_imei
790 };
791
792 gboolean imc_modem_init(TcorePlugin *p, CoreObject *co)
793 {
794         dbg("Enter");
795
796         /* Set operations */
797         tcore_modem_set_ops(co, &imc_modem_ops);
798
799         /* Add Callbacks */
800         tcore_object_add_callback(co, "+XDRVI:", on_event_imc_nvm_update, NULL);
801
802         dbg("Exit");
803         return TRUE;
804 }
805
806 void imc_modem_exit(TcorePlugin *p, CoreObject *co)
807 {
808         dbg("Exit");
809 }
810
811 /*
812  * NV Manager - Support for Remote File System
813  */
814 /* NVM Hook */
815 static gboolean __imc_nvm_modem_rfs_hook(const char *data)
816 {
817         if (data != NULL)
818                 if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
819                         return TRUE;
820
821         return FALSE;
822 }
823
824 /* NVM Event */
825 gboolean on_event_imc_nvm_update(CoreObject *co,
826         const void *event_info, void *user_data)
827 {
828         GSList *tokens = NULL;
829         GSList *lines;
830         const char *line;
831         int function_id;
832
833         gboolean ret = TRUE;
834         dbg("Entered");
835
836         lines = (GSList *)event_info;
837         line = lines->data;
838         dbg("Line: [%s]", line);
839
840         function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]);
841         dbg("Function ID: [%d]", function_id);
842         if (IUFP_UPDATE == function_id) {
843                 dbg("Calling process nvm_update");
844
845                 /*
846                  * Process NV Update indication
847                  *
848                  * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
849                  */
850                 if (NVM_NO_ERR == nvm_process_nv_update(line)) {
851                         dbg("NV data processed successfully");
852
853                         /* Acknowledge NV Update */
854                         __imc_modem_send_nvm_update_ack(co);
855
856                         return ret;
857                 } else {
858                         err("NV data processing failed");
859                         ret = FALSE;
860                 }
861         } else {
862                 tokens = tcore_at_tok_new(line);
863                 if (g_slist_length(tokens) < 3) {
864                         err("XDRVI event with less number of tokens, Ignore!!!");
865                         ret = FALSE;
866                 }
867                 else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
868                         err("Group ID mismatch, Ignore!!!");
869                         ret = FALSE;
870                 }
871                 else {
872                         switch (atoi(g_slist_nth_data(tokens, 1))) {
873                                 case IUFP_UPDATE_REQ:
874                                         dbg("NV Update Request");
875
876                                         /* Acknowledge the Update Request */
877                                         __imc_modem_send_nvm_update_request_ack(co);
878                                 break;
879
880                                 case IUFP_NO_PENDING_UPDATE:
881                                         dbg("NO pending NV Update(s)!!!");
882                                         /* Can send FLUSH request to get fresh updates */
883                                 break;
884
885                                 default:
886                                         err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1)));
887                                         ret = FALSE;
888                         }
889                 }
890
891                 tcore_at_tok_free(tokens);
892         }
893
894         dbg("Exit");
895         return ret;
896 }
897
898 /* NVM Register */
899 void imc_modem_register_nvm(CoreObject *co)
900 {
901         char *cmd_str;
902         TelReturn ret;
903
904         /* Prepare AT-Command */
905         cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
906                                         IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
907
908         /* Send Request to modem */
909         ret = tcore_at_prepare_and_send_request(co,
910                 cmd_str, "+XDRV:",
911                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
912                 TCORE_PENDING_PRIORITY_DEFAULT,
913                 NULL,
914                 __on_response_modem_register_nvm, NULL,
915                 on_send_imc_request, NULL,
916                 0, NULL, NULL);
917         if (ret != TEL_RETURN_SUCCESS) {
918                 err("Failed to process request - [Register NVM]");
919         }
920         else {
921                 /* Add RFS hook */
922                 dbg("Adding NVM hook");
923                 tcore_at_add_hook(tcore_object_get_hal(co), __imc_nvm_modem_rfs_hook);
924         }
925
926         g_free(cmd_str);
927 }