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