4 * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
28 #include <core_object.h>
36 #include "imc_modem.h"
37 #include "imc_common.h"
40 static gboolean on_event_imc_nvm_update(CoreObject *co,
41 const void *event_info, void *user_data);
43 /* NVM Req/Response */
44 static gboolean __imc_modem_check_nvm_response(const void *data, int command)
46 const TcoreAtResponse *at_resp = data;
49 GSList *tokens = NULL;
54 /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
55 if (NULL == at_resp) {
56 err("Input data is NULL");
60 if (at_resp->success > 0) {
62 line = (const char *) (((GSList *) at_resp->lines)->data);
63 tokens = tcore_at_tok_new(line);
66 resp_str = g_slist_nth_data(tokens, 0);
67 if (NULL == resp_str) {
68 err("Group ID is missing ");
71 else if (IUFP_GROUP_ID != atoi(resp_str)) {
72 err("Group ID mismatch");
77 resp_str = g_slist_nth_data(tokens, 1);
78 if (NULL == resp_str) {
79 err("Function ID is missing ");
82 else if (command != atoi(resp_str)) {
83 err("Function ID mismatch");
88 resp_str = g_slist_nth_data(tokens, 2);
89 if (NULL == resp_str) {
90 err("XDRV result is missing ");
93 else if (XDRV_RESULT_OK != atoi(resp_str)) {
94 err("XDRV result[%d] ", atoi(resp_str));
99 resp_str = g_slist_nth_data(tokens, 3);
100 if (NULL == resp_str) {
101 err("UTA result is missing ");
104 else if (UTA_SUCCESS != atoi(resp_str)) {
105 err("uta result[%d] ", atoi(resp_str));
115 tcore_at_tok_free(tokens);
121 static void __on_response_modem_unsuspend_nvm_updates(TcorePending *p,
122 guint data_len, const void *data, void *user_data)
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");
128 /* Create NV data file */
129 if (nvm_create_nvm_data() == FALSE) {
130 err("Failed to Create NV data file");
136 err("Response NOT OK");
139 static void __imc_modem_unsuspend_nvm_updates(CoreObject *co)
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);
149 /* Send Request to modem */
150 ret = tcore_at_prepare_and_send_request(co,
152 TCORE_AT_COMMAND_TYPE_SINGLELINE,
154 __on_response_modem_unsuspend_nvm_updates, NULL,
155 on_send_imc_request, NULL);
156 IMC_CHECK_REQUEST_RET(ret, NULL, "Unsuspend Nvm Updates");
161 static void __on_response_modem_send_nvm_update_ack(TcorePending *p,
162 guint data_len, const void *data, void *user_data)
164 /* Check NVM response */
165 if (TRUE == __imc_modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
166 dbg("[UPDATE ACK] OK");
170 err("[UPDATE ACK] NOT OK");
173 static void __imc_modem_send_nvm_update_ack(CoreObject *co)
178 /* Prepare AT-Command */
179 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
181 /* Send Request to modem */
182 ret = tcore_at_prepare_and_send_request(co,
184 TCORE_AT_COMMAND_TYPE_SINGLELINE,
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");
193 static void __on_response_modem_send_nvm_update_request_ack(TcorePending *p,
194 guint data_len, const void *data, void *user_data)
196 /* Check NVM response */
197 if (TRUE == __imc_modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
198 dbg("[REQUEST ACK] OK");
202 err("[REQUEST ACK] NOT OK");
205 static void __imc_modem_send_nvm_update_request_ack(CoreObject *co)
210 /* Prepare AT-Command */
211 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
213 /* Send Request to modem */
214 ret = tcore_at_prepare_and_send_request(co,
216 TCORE_AT_COMMAND_TYPE_SINGLELINE,
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");
225 static void __on_response_modem_register_nvm(TcorePending *p,
226 guint data_len, const void *data, void *user_data)
228 /* Check NVM response */
229 if (TRUE == __imc_modem_check_nvm_response(data, IUFP_REGISTER)) {
230 dbg("Registering successful");
232 /* Send SUSPEND_UPDATE for all UPDATES */
233 __imc_modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p));
239 err("Response NOT OK");
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)
247 gboolean flight_mode;
250 co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
251 tcore_check_return_assert(co != NULL);
253 tcore_check_return(result == TEL_MODEM_RESULT_SUCCESS);
255 /* Get Flight mode state */
256 (void)tcore_modem_get_flight_mode_state(co, &flight_mode);
258 dbg("Setting Modem Fiight mode (internal) - [%s] - [SUCCESS]",
259 (flight_mode ? "ON": "OFF"));
264 * This is an internal request to set Flight mode, which is sent during
265 * boot-up based on AP-side configuration (VCONF).
267 * Need to notify TAPI through Notiifcation -
268 * TCORE_NOTIFICATION_MODEM_FLIGHT_MODE
270 (void)tcore_object_send_notification(co,
271 TCORE_NOTIFICATION_MODEM_FLIGHT_MODE,
272 sizeof(gboolean), &flight_mode);
275 /* System functions */
276 gboolean imc_modem_power_on_modem(TcorePlugin *plugin)
280 gboolean flight_mode;
281 TelModemPowerStatus power_status;
283 co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
284 tcore_check_return_value_assert(co != NULL, FALSE);
286 /* Set Modem Power State to 'ON' */
287 tcore_modem_set_powered(co, TRUE);
290 * Set Flight mode (as per AP settings -VCONF)
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);
296 flight_mode = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE);
299 * Set Flight mode request is dispatched to Core Object (Modem)
300 * to ensure that 'Request Hooks' get executed.
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);
310 * Need to notify Modem is Powered UP through Notiifcation -
311 * TCORE_NOTIFICATION_MODEM_POWER
313 power_status = TEL_MODEM_POWER_ON;
314 (void)tcore_object_send_notification(co,
315 TCORE_NOTIFICATION_MODEM_POWER,
316 sizeof(TelModemPowerStatus), &power_status);
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)
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;
331 TelModemResult result = TEL_MODEM_RESULT_FAILURE;
334 tcore_check_return_assert(co != NULL);
335 tcore_check_return_assert(resp_cb_data != NULL);
337 if (at_resp && at_resp->success)
338 result = TEL_MODEM_RESULT_SUCCESS;
340 status = (TelModemPowerStatus *)
341 IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
343 /* Update Core Object */
345 case TEL_MODEM_POWER_ON:
346 dbg("Setting Modem Power status [ON] - [%s]",
347 (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
350 case TEL_MODEM_POWER_OFF:
351 dbg("Setting Modem Power status [OFF] - [%s]",
352 (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
356 warn("Unexpected - Setting Modem Power status [RESET] - [%s]",
357 (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
360 tcore_modem_set_powered(co, powered);
362 /* Invoke callback */
363 if (resp_cb_data->cb)
364 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
366 /* Free callback data */
367 imc_destroy_resp_cb_data(resp_cb_data);
370 static void on_response_imc_modem_set_flight_mode(TcorePending *p,
371 guint data_len, const void *data, void *user_data)
373 const TcoreAtResponse *at_resp = data;
374 CoreObject *co = tcore_pending_ref_core_object(p);
375 ImcRespCbData *resp_cb_data = user_data;
378 TelModemResult result = TEL_MODEM_RESULT_FAILURE;
381 tcore_check_return_assert(co != NULL);
382 tcore_check_return_assert(resp_cb_data != NULL);
384 if (at_resp && at_resp->success)
385 result = TEL_MODEM_RESULT_SUCCESS;
387 enable = (gboolean *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
389 dbg("Setting Modem Fiight mode - [%s] - [%s]",
390 (*enable ? "ON": "OFF"),
391 (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
393 /* Update Core Object */
394 (void)tcore_modem_set_flight_mode_state(co, *enable);
396 /* Invoke callback */
397 if (resp_cb_data->cb)
398 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
400 /* Free callback data */
401 imc_destroy_resp_cb_data(resp_cb_data);
404 * In case Flight mode is set to OFF, we need to trigger
405 * Network Registration.
407 * This is taken care by Network module which hooks on
408 * Set Flight mode Request of Modem module.
412 /* Current modem does not support this operation */
414 static void on_response_imc_modem_get_version(TcorePending *p,
415 guint data_len, const void *data, void *user_data)
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}};
422 TelModemResult result = TEL_MODEM_RESULT_FAILURE;
425 tcore_check_return_assert(co != NULL);
426 tcore_check_return_assert(resp_cb_data != NULL);
429 if (at_resp->lines) {
431 GSList *tokens = NULL;
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;
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);
445 g_strlcpy(version.software_version,
447 TEL_MODEM_VERSION_LENGTH_MAX + 1);
450 g_strlcpy(version.hardware_version,
452 TEL_MODEM_VERSION_LENGTH_MAX + 1);
454 if (calib_date != NULL){
455 g_strlcpy(version.calibration_date,
457 TEL_MODEM_VERSION_LENGTH_MAX + 1);
460 g_strlcpy(version.product_code,
462 TEL_MODEM_VERSION_LENGTH_MAX + 1);
464 dbg("Version - Software: [%s] Hardware: [%s] "
465 "Calibration date: [%s] Product "
466 "Code: [%s]", sw_ver, hw_ver,
469 result = TEL_MODEM_RESULT_SUCCESS;
471 err("RESPONSE - [NOK]");
472 err("[%s]", g_slist_nth_data(tokens, 0));
475 err("Invalid response message");
476 result = TEL_MODEM_RESULT_UNKNOWN_FAILURE;
478 tcore_at_tok_free(tokens);
482 /* Invoke callback */
483 if (resp_cb_data->cb)
484 resp_cb_data->cb(co, (gint)result, &version, resp_cb_data->cb_data);
486 /* Free callback data */
487 imc_destroy_resp_cb_data(resp_cb_data);
491 static void on_response_imc_modem_get_imei(TcorePending *p,
492 guint data_len, const void *data, void *user_data)
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};
499 TelModemResult result = TEL_MODEM_RESULT_FAILURE;
502 tcore_check_return_assert(co != NULL);
503 tcore_check_return_assert(resp_cb_data != NULL);
506 if (at_resp->lines) {
508 GSList *tokens = NULL;
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]");
516 (const gchar *)g_slist_nth_data(tokens, 0),
517 TEL_MODEM_IMEI_LENGTH_MAX+1);
518 dbg("IMEI: [%s]", imei);
520 result = TEL_MODEM_RESULT_SUCCESS;
522 err("RESPONSE - [NOK]");
523 err("[%s]", g_slist_nth_data(tokens, 0));
526 err("Invalid response message");
527 result = TEL_MODEM_RESULT_UNKNOWN_FAILURE;
529 tcore_at_tok_free(tokens);
533 /* Invoke callback */
534 if (resp_cb_data->cb)
535 resp_cb_data->cb(co, (gint)result, imei, resp_cb_data->cb_data);
537 /* Free callback data */
538 imc_destroy_resp_cb_data(resp_cb_data);
541 /* Modem Operations */
543 * Operation - set_power_status
546 * AT-Command: AT+CFUN=<fun>
549 * 0 Mode to switch off MS
550 * ... Other modes are available for other oprations
553 * Success: (No Result)
556 * +CME ERROR: <error>
558 static TelReturn imc_modem_set_power_status(CoreObject *co,
559 TelModemPowerStatus status,
560 TcoreObjectResponseCallback cb, void *cb_data)
565 ImcRespCbData *resp_cb_data;
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;
575 dbg("Modem Power OFF");
580 at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode);
582 /* Response callback data */
583 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
584 &status, sizeof(TelModemPowerStatus));
586 /* Send Request to modem */
587 ret = tcore_at_prepare_and_send_request(co,
589 TCORE_AT_COMMAND_TYPE_NO_RESULT,
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");
602 * Operation - set_flight_mode
605 * AT-Command: AT+CFUN=<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
615 * Success: (No Result)
618 * +CME ERROR: <error>
620 static TelReturn imc_modem_set_flight_mode(CoreObject *co, gboolean enable,
621 TcoreObjectResponseCallback cb, void *cb_data)
626 ImcRespCbData *resp_cb_data;
630 dbg("Flight mode - [ON]");
633 dbg("Flight mode - [OFF]");
638 at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode);
640 /* Response callback data */
641 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
642 &enable, sizeof(gboolean));
644 /* Send Request to modem */
645 ret = tcore_at_prepare_and_send_request(co,
647 TCORE_AT_COMMAND_TYPE_NO_RESULT,
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");
660 * Operation - get_flight_mode
664 * Fetch information from Core Object
666 * Response - flight_mode (gboolean)
668 static TelReturn imc_modem_get_flight_mode(CoreObject *co,
669 TcoreObjectResponseCallback cb, void *cb_data)
671 gboolean flight_mode;
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"));
677 /* Invoke response callback */
679 cb(co, (gint)TEL_MODEM_RESULT_SUCCESS, &flight_mode, cb_data);
681 return TEL_RETURN_SUCCESS;
685 * Operation - get_version
688 * AT-Command: AT+CGMR
690 * Response - version (TelModemVersion)
691 * Success: (Single line) -
692 * <sw_ver>, <hw_ver>, <calib_date>, <p_code>
695 * Success Response is different from standard 3GPP AT-Command (+CGMR)
697 * +CME ERROR: <error>
699 static TelReturn imc_modem_get_version(CoreObject *co,
700 TcoreObjectResponseCallback cb, void *cb_data)
704 /* Current modem does not support this operation */
706 ImcRespCbData *resp_cb_data;
709 /* Response callback data */
710 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
713 /* Send Request to modem */
714 ret = tcore_at_prepare_and_send_request(co,
716 TCORE_AT_COMMAND_TYPE_SINGLELINE,
717 TCORE_PENDING_PRIORITY_DEFAULT,
719 on_response_imc_modem_get_version, resp_cb_data,
720 on_send_imc_request, NULL,
722 IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Version");
728 return TEL_RETURN_OPERATION_NOT_SUPPORTED;
732 * Operation - get_imei
735 * AT-Command: AT+CGSN
737 * Response - imei (gchar array of length 20+'\0' bytes)
738 * Success: (Single line)
742 * +CME ERROR: <error>
744 static TelReturn imc_modem_get_imei(CoreObject *co,
745 TcoreObjectResponseCallback cb, void *cb_data)
747 ImcRespCbData *resp_cb_data;
752 /* Response callback data */
753 resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
756 /* Send Request to modem */
757 ret = tcore_at_prepare_and_send_request(co,
759 TCORE_AT_COMMAND_TYPE_NUMERIC,
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");
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
777 gboolean imc_modem_init(TcorePlugin *p, CoreObject *co)
782 tcore_modem_set_ops(co, &imc_modem_ops);
785 tcore_object_add_callback(co, "+XDRVI:", on_event_imc_nvm_update, NULL);
791 void imc_modem_exit(TcorePlugin *p, CoreObject *co)
797 * NV Manager - Support for Remote File System
800 static gboolean __imc_nvm_modem_rfs_hook(const char *data)
803 if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
810 gboolean on_event_imc_nvm_update(CoreObject *co,
811 const void *event_info, void *user_data)
813 GSList *tokens = NULL;
821 lines = (GSList *)event_info;
823 dbg("Line: [%s]", line);
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");
831 * Process NV Update indication
833 * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
835 if (NVM_NO_ERR == nvm_process_nv_update(line)) {
836 dbg("NV data processed successfully");
838 /* Acknowledge NV Update */
839 __imc_modem_send_nvm_update_ack(co);
843 err("NV data processing failed");
847 tokens = tcore_at_tok_new(line);
848 if (g_slist_length(tokens) < 3) {
849 err("XDRVI event with less number of tokens, Ignore!!!");
852 else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
853 err("Group ID mismatch, Ignore!!!");
857 switch (atoi(g_slist_nth_data(tokens, 1))) {
858 case IUFP_UPDATE_REQ:
859 dbg("NV Update Request");
861 /* Acknowledge the Update Request */
862 __imc_modem_send_nvm_update_request_ack(co);
865 case IUFP_NO_PENDING_UPDATE:
866 dbg("NO pending NV Update(s)!!!");
867 /* Can send FLUSH request to get fresh updates */
871 err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1)));
876 tcore_at_tok_free(tokens);
884 void imc_modem_register_nvm(CoreObject *co)
889 /* Prepare AT-Command */
890 cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
891 IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
893 /* Send Request to modem */
894 ret = tcore_at_prepare_and_send_request(co,
896 TCORE_AT_COMMAND_TYPE_SINGLELINE,
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]");
905 dbg("Adding NVM hook");
906 tcore_at_add_hook(tcore_object_get_hal(co), __imc_nvm_modem_rfs_hook);