4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Harish Bishnoi <hbishnoi@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
30 #include <core_object.h>
32 #include <user_request.h>
39 #include "imc_common.h"
40 #include "imc_modem.h"
48 gboolean imei_valid; /**< IMEI validatity flag */
49 char imei[MODEM_DEVICE_IMEI_LEN_MAX];
51 /* Version information */
52 gboolean version_valid; /**< Version validatity flag */
56 char product_code[33];
59 static void on_confirmation_modem_message_send(TcorePending *pending,
60 gboolean result, void *user_data);
61 static void on_response_network_registration(TcorePending *pending,
62 int data_len, const void *data, void *user_data);
63 static void on_response_enable_proactive_command(TcorePending *pending,
64 int data_len, const void *data, void *user_data);
67 static gboolean on_event_modem_nvm_update(CoreObject *co_modem,
68 const void *event_info, void *user_data);
69 static void modem_unsuspend_nvm_updates(CoreObject *co_modem);
70 static void modem_send_nvm_update_ack(CoreObject *co_modem);
71 static void modem_send_nvm_update_request_ack(CoreObject *co_modem);
73 static void on_confirmation_modem_message_send(TcorePending *pending,
74 gboolean result, void *user_data)
76 dbg("Request send: [%s]", (result == TRUE ? "Success" : "Fail"));
79 static void on_response_enable_proactive_command(TcorePending *pending,
80 int data_len, const void *data, void *user_data)
82 const TcoreATResponse *at_resp = data;
84 dbg("[Response] Pro-active command enabling - RESPONSE '%s'",
85 (at_resp->success > 0 ? "OK" : "NOK"));
88 static void on_response_network_registration(TcorePending *pending,
89 int data_len, const void *data, void *user_data)
91 const TcoreATResponse *at_resp = data;
93 dbg("[Response] Network Registration enable - RESPONSE '%s'",
94 (at_resp->success > 0 ? "OK" : "NOK"));
97 static void on_response_modem_power_off(TcorePending *pending,
98 int data_len, const void *data, void *user_data)
100 const TcoreATResponse *at_resp = data;
101 struct tresp_modem_power_off modem_power_off_resp;
102 CoreObject *co_modem = 0;
106 dbg("[Response] Modem Power OFF - RESPONSE '%s'",
107 (at_resp->success > 0 ? "OK" : "NOK"));
109 co_modem = tcore_pending_ref_core_object(pending);
110 h = tcore_object_get_hal(co_modem);
112 if (at_resp->success > 0) {
113 modem_power_off_resp.result = TCORE_RETURN_SUCCESS;
115 /* Update HAL state */
116 tcore_hal_set_power_state(h, FALSE);
118 modem_power_off_resp.result = TCORE_RETURN_FAILURE;
122 ur = tcore_pending_ref_user_request(pending);
123 tcore_user_request_send_response(ur,
124 TRESP_MODEM_POWER_OFF,
125 sizeof(struct tresp_modem_power_off), &modem_power_off_resp);
128 static void on_response_modem_set_flight_mode(TcorePending *pending,
129 int data_len, const void *data, void *user_data)
131 CoreObject *co_modem = NULL;
132 UserRequest *ur = NULL;
133 const TcoreATResponse *at_resp = data;
134 struct tresp_modem_set_flightmode modem_set_flightmode_resp = {0};
136 struct tnoti_modem_flight_mode modem_flight_mode = {0};
138 co_modem = tcore_pending_ref_core_object(pending);
139 ur = tcore_pending_ref_user_request(pending);
141 dbg("[Response] Modem Set Flight mode - RESPONSE '%s'",
142 (at_resp->success > 0 ? "OK" : "NOK"));
144 if (at_resp->success > 0) {
145 modem_set_flightmode_resp.result = TCORE_RETURN_SUCCESS;
147 GSList *tokens = NULL;
148 const char *line = NULL;
150 line = (const char *) at_resp->final_response;
151 tokens = tcore_at_tok_new(line);
153 if (g_slist_length(tokens) < 1) {
154 dbg("err cause not specified or string corrupted");
156 response = atoi(g_slist_nth_data(tokens, 0));
157 err("error response: %d", response);
158 /* TODO: CMEE error mapping is required. */
160 tcore_at_tok_free(tokens);
161 modem_set_flightmode_resp.result = TCORE_RETURN_3GPP_ERROR;
165 dbg("Internal request created during boot-up sequence");
167 if (at_resp->success > 0) {
170 modem_flight_mode.enable =
171 tcore_modem_get_flight_mode_state(co_modem);
172 dbg("Sending Flight Mode Notification (%d) to Telephony Server",
173 modem_flight_mode.enable);
175 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_modem));
177 /* Send Notification */
178 tcore_server_send_notification(server,
179 co_modem, TNOTI_MODEM_FLIGHT_MODE,
180 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
184 const struct treq_modem_set_flightmode *req_data = NULL;
186 dbg("Sending response for Flight mode operation");
188 req_data = tcore_user_request_ref_data(ur, NULL);
190 if (TCORE_RETURN_SUCCESS == modem_set_flightmode_resp.result) {
191 if (TRUE == req_data->enable)
192 tcore_modem_set_flight_mode_state(co_modem, TRUE);
194 tcore_modem_set_flight_mode_state(co_modem, FALSE);
198 tcore_user_request_send_response(ur,
199 TRESP_MODEM_SET_FLIGHTMODE,
200 sizeof(struct tresp_modem_set_flightmode), &modem_set_flightmode_resp);
202 modem_flight_mode.enable = tcore_modem_get_flight_mode_state(co_modem);
205 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_modem));
207 /* Send Notification */
208 tcore_server_send_notification(server,
209 co_modem, TNOTI_MODEM_FLIGHT_MODE,
210 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
212 if (req_data->enable == 0) {
213 dbg("Flight mode is disabled, trigger COPS to register on network");
215 /* Trigger Network registration (for the moment automatic) */
216 tcore_prepare_and_send_at_request(co_modem,
218 TCORE_AT_NO_RESULT, NULL,
220 NULL, NULL, 0, NULL, NULL);
225 static void on_response_modem_get_imei(TcorePending *pending,
226 int data_len, const void *data, void *user_data)
228 const TcoreATResponse *at_resp = data;
229 struct tresp_modem_get_imei modem_get_imei_resp;
230 UserRequest *ur = NULL;
231 GSList *tokens = NULL;
234 memset(&modem_get_imei_resp, 0x0, sizeof(struct tresp_modem_get_imei));
236 if (at_resp->success > 0) {
237 CoreObject *co = NULL;
238 PrivateData *priv_data = NULL;
242 if (at_resp->lines) {
243 line = (const char *) at_resp->lines->data;
244 tokens = tcore_at_tok_new(line);
245 if (g_slist_length(tokens) != 1) {
246 msg("invalid message");
251 modem_get_imei_resp.result = TCORE_RETURN_SUCCESS;
252 strncpy(modem_get_imei_resp.imei, g_slist_nth_data(tokens, 0), MODEM_DEVICE_IMEI_LEN_MAX - 1);
253 dbg("IMEI: [%s]", modem_get_imei_resp.imei);
256 co = tcore_pending_ref_core_object(pending);
257 priv_data = tcore_object_ref_user_data(co);
258 priv_data->imei_valid = TRUE;
259 strncpy(priv_data->imei, modem_get_imei_resp.imei, MODEM_DEVICE_IMEI_LEN_MAX - 1);
263 if (at_resp->lines) {
264 line = (const char *) at_resp->lines->data;
265 tokens = tcore_at_tok_new(line);
268 if (g_slist_length(tokens) < 1) {
269 dbg("err cause not specified or string corrupted");
271 modem_get_imei_resp.result = TCORE_RETURN_3GPP_ERROR;
273 int response = atoi(g_slist_nth_data(tokens, 0));
274 err("error response: %d", response);
276 /* TODO: CMEE error mapping is required. */
277 modem_get_imei_resp.result = TCORE_RETURN_3GPP_ERROR;
282 ur = tcore_pending_ref_user_request(pending);
283 tcore_user_request_send_response(ur,
284 TRESP_MODEM_GET_IMEI,
285 sizeof(struct tresp_modem_get_imei), &modem_get_imei_resp);
288 tcore_at_tok_free(tokens);
291 static void on_response_modem_get_version(TcorePending *pending,
292 int data_len, const void *data, void *user_data)
294 const TcoreATResponse *at_resp = data;
295 struct tresp_modem_get_version modem_get_version_resp;
296 UserRequest *ur = NULL;
297 GSList *tokens = NULL;
298 const char *line = NULL;
300 memset(&modem_get_version_resp, 0, sizeof(struct tresp_modem_get_version));
302 if (at_resp->success > 0) {
303 CoreObject *co = NULL;
304 PrivateData *priv_data = NULL;
306 char *software_version = NULL;
307 char *hardware_version = NULL;
308 char *calibration_date = NULL;
309 char *product_code = NULL;
310 char *model_id = NULL;
314 if (at_resp->lines) {
315 line = (const char *) at_resp->lines->data;
317 tokens = tcore_at_tok_new(line);
318 if (g_slist_length(tokens) == 1) {
319 software_version = g_slist_nth_data(tokens, 0);
320 dbg("Software version: [%s]", software_version);
321 } else if (g_slist_length(tokens) == 5) {
322 software_version = g_slist_nth_data(tokens, 0);
323 hardware_version = g_slist_nth_data(tokens, 1);
324 calibration_date = g_slist_nth_data(tokens, 2);
325 product_code = g_slist_nth_data(tokens, 3);
326 model_id = g_slist_nth_data(tokens, 4);
328 dbg("Software version: [%s] Hardware version: [%s] " \
329 "Calibration: [%s] Product code: [%s] Model ID: [%s]",
330 software_version, hardware_version,
331 calibration_date, product_code, model_id);
333 err("Invalid message");
338 co = tcore_pending_ref_core_object(pending);
339 priv_data = tcore_object_ref_user_data(co);
342 * Update response structure and Cache data
344 priv_data->version_valid = TRUE;
346 /* Software version */
347 if (software_version) {
348 snprintf(modem_get_version_resp.software,
349 33, "%s", software_version);
350 snprintf(priv_data->software,
351 33, "%s", software_version);
354 /* Hardware version */
355 if (hardware_version) {
356 snprintf(modem_get_version_resp.hardware,
357 33, "%s", hardware_version);
358 snprintf(priv_data->hardware,
359 33, "%s", hardware_version);
362 /* Calibration date */
363 if (calibration_date) {
364 snprintf(modem_get_version_resp.calibration,
365 33, "%s", calibration_date);
366 snprintf(priv_data->calibration,
367 33, "%s", calibration_date);
372 snprintf(modem_get_version_resp.product_code,
373 33, "%s", product_code);
374 snprintf(priv_data->product_code,
375 33, "%s", product_code);
379 if (at_resp->lines) {
380 line = (const char *) at_resp->lines->data;
381 tokens = tcore_at_tok_new(line);
384 if (g_slist_length(tokens) < 1) {
385 dbg("err cause not specified or string corrupted");
387 modem_get_version_resp.result = TCORE_RETURN_3GPP_ERROR;
389 int response = atoi(g_slist_nth_data(tokens, 0));
390 err("error response: %d", response);
392 /* TODO: CMEE error mapping is required. */
393 modem_get_version_resp.result = TCORE_RETURN_3GPP_ERROR;
398 ur = tcore_pending_ref_user_request(pending);
399 tcore_user_request_send_response(ur,
400 TRESP_MODEM_GET_VERSION,
401 sizeof(struct tresp_modem_get_version), &modem_get_version_resp);
404 tcore_at_tok_free(tokens);
407 static enum tcore_hook_return on_hook_modem_sim_init_status(Server *s,
408 CoreObject *source, enum tcore_notification_command command,
409 unsigned int data_len, void *data, void *user_data)
411 const struct tnoti_sim_status *noti_sim_status;
413 dbg("SIM INIT Status");
415 noti_sim_status = data;
416 if (noti_sim_status == NULL) {
417 err("SIM notification data is NULL");
418 return TCORE_HOOK_RETURN_CONTINUE;
421 /* If SIM is initialized, Enable STK and and attach to Network */
422 dbg("SIM Status: [%d]", noti_sim_status->sim_status);
423 if (noti_sim_status->sim_status == SIM_STATUS_INIT_COMPLETED) {
425 CoreObject *co_network;
428 dbg("SIM ready for attach!!! Enable STK and attach to Network");
430 plugin = tcore_object_ref_plugin(source);
432 co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
434 /* Sending AT+COPS */
435 tcore_prepare_and_send_at_request(co_network,
437 TCORE_AT_NO_RESULT, NULL,
438 on_response_network_registration, NULL,
439 NULL, NULL, 0, NULL, NULL);
442 co_sat = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAT);
444 /* Sending AT+CFUN=6 */
445 tcore_prepare_and_send_at_request(co_sat,
447 TCORE_AT_NO_RESULT, NULL,
448 on_response_enable_proactive_command, NULL,
449 NULL, NULL, 0, NULL, NULL);
454 return TCORE_HOOK_RETURN_CONTINUE;
457 gboolean modem_power_on(TcorePlugin *plugin)
460 CoreObject *co_modem = NULL;
461 struct treq_modem_set_flightmode flight_mode_set;
462 struct tnoti_modem_power modem_power;
463 Storage *strg = NULL;
465 co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
466 if (co_modem == NULL) {
467 err("Modem Core object is NULL");
471 /* Set Modem Power State to 'ON' */
472 tcore_modem_set_powered(co_modem, TRUE);
474 server = tcore_plugin_ref_server(plugin);
476 /* Get Flight mode from VCONFKEY */
477 strg = tcore_server_find_storage(server, "vconf");
478 flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
481 * Set Flight mode as per AP settings
483 if (flight_mode_set.enable) { /* Radio OFF */
484 dbg("Enabling Flight mode");
486 tcore_prepare_and_send_at_request(co_modem,
488 TCORE_AT_NO_RESULT, NULL,
489 on_response_modem_set_flight_mode, NULL,
490 NULL, NULL, 0, NULL, NULL);
492 /* Set Flight mode TRUE */
493 tcore_modem_set_flight_mode_state(co_modem, TRUE);
494 } else { /* Radio ON */
495 dbg("Disabling Flight mode");
497 tcore_prepare_and_send_at_request(co_modem,
499 TCORE_AT_NO_RESULT, NULL,
500 on_response_modem_set_flight_mode, NULL,
501 NULL, NULL, 0, NULL, NULL);
503 /* Set Flight mode FALSE */
504 tcore_modem_set_flight_mode_state(co_modem, FALSE);
508 tcore_prepare_and_send_at_request(co_modem,
510 TCORE_AT_NUMERIC, NULL,
511 on_response_modem_get_imei, NULL,
512 NULL, NULL, 0, NULL, NULL);
514 /* Get Version Number */
515 tcore_prepare_and_send_at_request(co_modem,
517 TCORE_AT_SINGLELINE, NULL,
518 on_response_modem_get_version, NULL,
519 NULL, NULL, 0, NULL, NULL);
521 /* Send Notification - MODEM_POWER */
522 modem_power.state = MODEM_STATE_ONLINE;
524 dbg("Sending notification - Modem Power state: [ONLINE]");
525 tcore_server_send_notification(server, co_modem,
527 sizeof(modem_power), &modem_power);
532 static TReturn modem_power_off(CoreObject *co_modem, UserRequest *ur)
536 hal = tcore_object_get_hal(co_modem);
537 if (FALSE == tcore_hal_get_power_state(hal)) {
538 struct tresp_modem_power_off modem_power_off_resp;
540 err("Modem is in Powered OFF state!");
542 modem_power_off_resp.result = TCORE_RETURN_SUCCESS;
544 tcore_user_request_send_response(ur,
545 TRESP_MODEM_POWER_OFF,
546 sizeof(struct tresp_modem_power_off), &modem_power_off_resp);
548 return TCORE_RETURN_SUCCESS;
551 dbg("[Request] Modem Power OFF - Command: [%s]", "AT+CFUN=0");
553 return tcore_prepare_and_send_at_request(co_modem,
555 TCORE_AT_NO_RESULT, ur,
556 on_response_modem_power_off, hal,
557 on_confirmation_modem_message_send, NULL,
561 static TReturn modem_get_imei(CoreObject *co_modem, UserRequest *ur)
563 PrivateData *priv_data = NULL;
568 hal = tcore_object_get_hal(co_modem);
569 if (FALSE == tcore_hal_get_power_state(hal)) {
570 err("CP not ready!");
571 return TCORE_RETURN_ENOSYS;
575 * Check if valid IMEI is available in Cache -
576 * if Yes, then provide form Cache;
577 * else, fetch from CP
579 priv_data = tcore_object_ref_user_data(co_modem);
580 if (priv_data && priv_data->imei_valid) {
581 struct tresp_modem_get_imei modem_get_imei_resp;
584 memset(&modem_get_imei_resp, 0x0, sizeof(struct tresp_modem_get_imei));
586 modem_get_imei_resp.result = TCORE_RETURN_SUCCESS;
587 memcpy(modem_get_imei_resp.imei,
588 priv_data->imei, MODEM_DEVICE_IMEI_LEN_MAX);
590 dbg("Valid IMEI information present in cache - IMEI: [%s]",
591 modem_get_imei_resp.imei);
594 ret = tcore_user_request_send_response(ur,
595 TRESP_MODEM_GET_IMEI,
596 sizeof(struct tresp_modem_get_imei), &modem_get_imei_resp);
597 if (ret == TCORE_RETURN_SUCCESS)
598 tcore_user_request_unref(ur);
603 dbg("[Request] Get IMEI - Command: [%s]", "AT+CGSN");
605 return tcore_prepare_and_send_at_request(co_modem,
607 TCORE_AT_NUMERIC, ur,
608 on_response_modem_get_imei, hal,
609 on_confirmation_modem_message_send, NULL,
614 static TReturn modem_get_version(CoreObject *co_modem, UserRequest *ur)
616 PrivateData *priv_data = NULL;
619 hal = tcore_object_get_hal(co_modem);
620 if (FALSE == tcore_hal_get_power_state(hal)) {
621 err("CP not ready!");
622 return TCORE_RETURN_ENOSYS;
626 * Check if valid Version information is available in Cache -
627 * if Yes, then provide form Cache;
628 * else, fetch from CP
630 priv_data = tcore_object_ref_user_data(co_modem);
631 if (priv_data && priv_data->version_valid) {
632 struct tresp_modem_get_version modem_get_version_resp;
635 memset(&modem_get_version_resp, 0x0, sizeof(struct tresp_modem_get_version));
637 modem_get_version_resp.result = TCORE_RETURN_SUCCESS;
638 snprintf(modem_get_version_resp.software,
639 33, "%s", priv_data->software);
640 snprintf(modem_get_version_resp.hardware,
641 33, "%s", priv_data->hardware);
642 snprintf(modem_get_version_resp.calibration,
643 33, "%s", priv_data->calibration);
644 snprintf(modem_get_version_resp.product_code,
645 33, "%s", priv_data->product_code);
647 dbg("Valid Version information present in cache -" \
648 "Software: [%s] Hardware: [%s] Calibration: [%s] Product code: [%s]",
649 modem_get_version_resp.software, modem_get_version_resp.hardware,
650 modem_get_version_resp.calibration, modem_get_version_resp.product_code);
653 ret = tcore_user_request_send_response(ur,
654 TRESP_MODEM_GET_VERSION,
655 sizeof(struct tresp_modem_get_version), &modem_get_version_resp);
656 if (ret == TCORE_RETURN_SUCCESS)
657 tcore_user_request_unref(ur);
662 dbg("[Request] Get VERSION - Command: [%s]", "AT+CGMR");
664 return tcore_prepare_and_send_at_request(co_modem,
666 TCORE_AT_SINGLELINE, ur,
667 on_response_modem_get_version, hal,
668 on_confirmation_modem_message_send, NULL,
672 static TReturn modem_set_flight_mode(CoreObject *co_modem, UserRequest *ur)
674 TcoreHal *hal = NULL;
675 const struct treq_modem_set_flightmode *req_data = NULL;
676 char *cmd_str = NULL;
678 hal = tcore_object_get_hal(co_modem);
679 if (FALSE == tcore_hal_get_power_state(hal)) {
680 err("CP not ready!");
681 return TCORE_RETURN_ENOSYS;
684 req_data = tcore_user_request_ref_data(ur, NULL);
685 if (req_data->enable)
686 cmd_str = "AT+CFUN=4";
688 cmd_str = "AT+CFUN=1";
690 dbg("[Request] Set Modem Flight mode [%s] - Command: [%s]",
691 (req_data->enable ? "ON" : "OFF"), cmd_str);
693 return tcore_prepare_and_send_at_request(co_modem,
694 (const char *)cmd_str, NULL,
695 TCORE_AT_NO_RESULT, ur,
696 on_response_modem_set_flight_mode, hal,
697 on_confirmation_modem_message_send, NULL,
701 static TReturn modem_get_flight_mode(CoreObject *co_modem, UserRequest *ur)
703 struct tresp_modem_get_flightmode modem_get_flightmode_resp;
706 dbg("[Request] Get Modem Flight mode");
708 memset(&modem_get_flightmode_resp, 0x0, sizeof(struct tresp_modem_get_flightmode));
710 modem_get_flightmode_resp.result = TCORE_RETURN_SUCCESS;
711 modem_get_flightmode_resp.enable = tcore_modem_get_flight_mode_state(co_modem);
712 dbg("Flight mode: [%s]", (modem_get_flightmode_resp.enable ? "ON" : "OFF"));
714 ret = tcore_user_request_send_response(ur,
715 TRESP_MODEM_GET_FLIGHTMODE,
716 sizeof(struct tresp_modem_get_flightmode), &modem_get_flightmode_resp);
717 if (ret == TCORE_RETURN_SUCCESS)
718 tcore_user_request_unref(ur);
723 /* Modem operations */
724 static struct tcore_modem_operations modem_ops = {
726 .power_off = modem_power_off,
728 .set_flight_mode = modem_set_flight_mode,
729 .get_flight_mode = modem_get_flight_mode,
730 .get_imei = modem_get_imei,
731 .get_version = modem_get_version,
733 .dun_pin_ctrl = NULL,
736 gboolean imc_modem_init(TcorePlugin *plugin, CoreObject *co_modem)
738 PrivateData *priv_data = NULL;
743 tcore_modem_set_ops(co_modem, &modem_ops, TCORE_OPS_TYPE_CP);
746 priv_data = g_malloc0(sizeof(PrivateData));
747 priv_data->imei_valid = FALSE;
748 priv_data->version_valid = FALSE;
749 tcore_object_link_user_data(co_modem, priv_data);
751 /* Notification hooks */
752 tcore_server_add_notification_hook(tcore_plugin_ref_server(plugin),
753 TNOTI_SIM_STATUS, on_hook_modem_sim_init_status, NULL);
755 dbg("Registering for +XDRVI event");
756 tcore_object_add_callback(co_modem,
757 "+XDRVI", on_event_modem_nvm_update, NULL);
763 void imc_modem_exit(TcorePlugin *plugin, CoreObject *co_modem)
765 PrivateData *priv_data = NULL;
769 priv_data = tcore_object_ref_user_data(co_modem);
774 * NV Manager - Support for Remote File System
777 static gboolean __modem_rfs_hook(const char *data)
779 if (data && data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
785 /* NVM event Notification */
786 static gboolean on_event_modem_nvm_update(CoreObject *co_modem,
787 const void *event_info, void *user_data)
789 GSList *tokens = NULL;
797 lines = (GSList *)event_info;
799 dbg("Line: [%s]", line);
801 function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]);
802 dbg("Function ID: [%d]", function_id);
803 if (IUFP_UPDATE == function_id) {
804 dbg("Calling process nvm_update");
807 * Process NV Update indication
809 * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
811 if (NVM_NO_ERR == nvm_process_nv_update(line)) {
812 dbg("NV data processed successfully");
814 /* Acknowledge NV Update */
815 modem_send_nvm_update_ack(co_modem);
819 err("NV data processing failed");
823 tokens = tcore_at_tok_new(line);
824 if (g_slist_length(tokens) < 3) {
825 err("XDRVI event with less number of tokens, Ignore!!!");
827 } else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
828 err("Group ID mismatch, Ignore!!!");
831 int command = atoi(g_slist_nth_data(tokens, 1));
833 case IUFP_UPDATE_REQ:
834 dbg("NV Update Request");
836 /* Acknowledge the Update Request */
837 modem_send_nvm_update_request_ack(co_modem);
840 case IUFP_NO_PENDING_UPDATE:
841 dbg("NO pending NV Update(s)!!!");
842 /* Can send FLUSH request to get fresh updates */
846 err("Unspported Function ID [%d], Ignore", command);
852 tcore_at_tok_free(tokens);
860 static gboolean __modem_check_nvm_response(const void *data, int command)
862 const TcoreATResponse *at_resp = data;
865 GSList *tokens = NULL;
866 gboolean ret = FALSE;
869 /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
870 if (NULL == at_resp) {
871 err("Input data is NULL");
875 if (at_resp->success <= 0) {
881 line = (const char *) (((GSList *) at_resp->lines)->data);
882 tokens = tcore_at_tok_new(line);
885 resp_str = g_slist_nth_data(tokens, 0);
886 if (NULL == resp_str) {
887 err("Group ID is missing ");
889 } else if (IUFP_GROUP_ID != atoi(resp_str)) {
890 err("Group ID mismatch");
895 resp_str = g_slist_nth_data(tokens, 1);
896 if (NULL == resp_str) {
897 err("Function ID is missing ");
899 } else if (command != atoi(resp_str)) {
900 err("Function ID mismatch");
905 resp_str = g_slist_nth_data(tokens, 2);
906 if (NULL == resp_str) {
907 err("XDRV result is missing ");
909 } else if (XDRV_RESULT_OK != atoi(resp_str)) {
910 err("XDRV result[%d] ", atoi(resp_str));
915 resp_str = g_slist_nth_data(tokens, 3);
916 if (NULL == resp_str) {
917 err("UTA result is missing ");
919 } else if (UTA_SUCCESS != atoi(resp_str)) {
920 err("uta result[%d] ", atoi(resp_str));
927 tcore_at_tok_free(tokens);
933 static void on_response_modem_unsuspend_nvm_updates(TcorePending *pending,
934 int data_len, const void *data, void *user_data)
936 /* Check NVM response */
937 if (TRUE == __modem_check_nvm_response(data, IUFP_SUSPEND)) {
938 dbg("Priority level is set to get all updates since Boot-up");
940 /* Create NV data file */
941 if (nvm_create_nvm_data() == FALSE)
942 err("Failed to Create NV data file");
947 err("Response NOT OK");
950 static void on_response_modem_send_nvm_update_ack(TcorePending *pending,
951 int data_len, const void *data, void *user_data)
953 /* Check NVM response */
954 if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
955 dbg("[UPDATE ACK] OK");
959 err("[UPDATE ACK] NOT OK");
962 static void on_response_modem_send_nvm_update_request_ack(TcorePending *pending,
963 int data_len, const void *data, void *user_data)
965 /* Check NVM response */
966 if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
967 dbg("[REQUEST ACK] OK");
971 err("[REQUEST ACK] NOT OK");
974 static void on_response_modem_register_nvm(TcorePending *pending,
975 int data_len, const void *data, void *user_data)
977 /* Check NVM response */
978 if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
979 dbg("Registering successful!");
981 /* Send SUSPEND_UPDATE for all UPDATES */
982 modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(pending));
988 err("Response NOT OK");
992 static void modem_unsuspend_nvm_updates(CoreObject *co_modem)
999 /* Prepare AT-Command */
1000 cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d",
1001 IUFP_GROUP_ID, IUFP_SUSPEND,
1002 0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL);
1004 /* Prepare pending request */
1005 ret = tcore_prepare_and_send_at_request(co_modem,
1007 TCORE_AT_SINGLELINE, NULL,
1008 on_response_modem_unsuspend_nvm_updates, NULL,
1009 NULL, NULL, 0, NULL, NULL);
1010 if (ret != TCORE_RETURN_SUCCESS)
1011 err("IUFP_SUSPEND - Unable to send AT-Command");
1013 dbg("IUFP_SUSPEND - Successfully sent AT-Command");
1018 static void modem_send_nvm_update_ack(CoreObject *co_modem)
1025 /* Prepare AT-Command */
1026 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
1028 /* Prepare pending request */
1029 ret = tcore_prepare_and_send_at_request(co_modem,
1031 TCORE_AT_SINGLELINE, NULL,
1032 on_response_modem_send_nvm_update_ack, NULL,
1033 NULL, NULL, 0, NULL, NULL);
1034 if (ret != TCORE_RETURN_SUCCESS)
1035 err("IUFP_UPDATE_ACK - Unable to send AT-Command");
1037 dbg("IUFP_UPDATE_ACK - Successfully sent AT-Command");
1042 static void modem_send_nvm_update_request_ack(CoreObject *co_modem)
1049 /* Prepare AT-Command */
1050 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
1052 /* Prepare pending request */
1053 ret = tcore_prepare_and_send_at_request(co_modem,
1055 TCORE_AT_SINGLELINE, NULL,
1056 on_response_modem_send_nvm_update_request_ack, NULL,
1057 NULL, NULL, 0, NULL, NULL);
1058 if (ret != TCORE_RETURN_SUCCESS)
1059 err("IUFP_UPDATE_REQ_ACK - Unable to send AT-Ccommand");
1061 dbg("IUFP_UPDATE_REQ_ACK - Successfully sent AT-Command");
1066 void modem_register_nvm(CoreObject *co_modem)
1073 /* Prepare AT-Command */
1074 cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
1075 IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
1077 /* Prepare pending request */
1078 ret = tcore_prepare_and_send_at_request(co_modem,
1080 TCORE_AT_SINGLELINE, NULL,
1081 on_response_modem_register_nvm, NULL,
1082 NULL, NULL, 0, NULL, NULL);
1083 if (ret != TCORE_RETURN_SUCCESS) {
1084 err("IUFP_REGISTER (Enable) -Unable to send AT-Command");
1086 dbg("IUFP_REGISTER (Enable) -Successfully sent AT-Command");
1089 /* Todo unblock this api */
1090 tcore_at_add_hook(tcore_object_get_hal(co_modem),