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>
45 #define ID_RESERVED_AT 0x0229
47 #define MAX_VERSION_LEN 32
48 #define TAPI_MISC_ME_SN_LEN_MAX 32
49 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX 32
50 #define TAPI_MISC_MODEL_ID_LEN_MAX 17
51 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX 17
53 #define CPAS_RES_READY 0
54 #define CPAS_RES_UNAVAIL 1
55 #define CPAS_RES_UNKNOWN 2
56 #define CPAS_RES_RINGING 3
57 #define CPAS_RES_CALL_PROGRESS 4
58 #define CPAS_RES_ASLEEP 5
68 CP_STATE_NV_REBUILDING,
73 TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
74 TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
75 TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
76 TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
77 } TelMiscSNIndexType_t;
80 TelMiscSNIndexType_t sn_index; /**< serial number index */
81 int sn_len; /**< Length */
82 unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
83 } TelMiscSNInformation;
86 * Mobile Equipment Version Information
89 unsigned char ver_mask; /**< version mask - 0x01:SW_ver, 0x02:HW_ver, 0x04:RF_CAL_date, 0x08:Product_code, 0x10:Model_ID, 0x20:PRL, 0x04:ERI, 0xff:all */
90 unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
91 unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
92 unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
93 unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
94 unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
95 unsigned char prl_nam_num; /**< number of PRL NAM fields */
96 unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< prl version (only for CDMA), null termination */
97 unsigned char eri_nam_num; /**< number of PRL NAM fields */
98 unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< eri version (only for CDMA), null termination */
99 } TelMiscVersionInformation;
102 static void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback);
103 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data);
104 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data);
105 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
108 static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data);
109 static void modem_send_nvm_update_ack(CoreObject *o);
110 static void modem_send_nvm_update_request_ack(CoreObject *o);
111 static void modem_unsuspend_nvm_updates(CoreObject *o);
112 static void modem_send_nvm_update_ack(CoreObject *o);
113 static void modem_send_nvm_update_request_ack(CoreObject *o);
114 static void modem_send_flush_nvm_update(CoreObject *o);
116 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
118 dbg("on_confirmation_modem_message_send - msg out from queue.\n");
120 if (result == FALSE) {
128 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
130 const TcoreATResponse *resp = data;
132 if (resp->success > 0) {
133 dbg("RESPONSE OK proactive command enabled");
135 dbg("RESPONSE NOK proactive command disabled");
139 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data)
141 const TcoreATResponse *resp = data;
143 if (resp->success > 0) {
144 dbg("registration attempt OK");
146 dbg("registration attempt failed");
150 void prepare_and_send_pending_request(CoreObject *co, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback)
152 TcoreATRequest *req = NULL;
153 TcoreHal *hal = NULL;
154 TcorePending *pending = NULL;
157 hal = tcore_object_get_hal(co);
160 pending = tcore_pending_new(co, 0);
162 dbg("Pending is NULL");
163 req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
165 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
167 tcore_pending_set_request_data(pending, 0, req);
168 tcore_pending_set_response_callback(pending, callback, NULL);
169 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
170 ret = tcore_hal_send_request(hal, pending);
173 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
178 o = tcore_pending_ref_core_object(p);
179 h = tcore_object_get_hal(o);
181 dbg("modem power off");
183 tcore_hal_set_power_state(h, FALSE);
186 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
188 CoreObject *o = NULL;
189 UserRequest *ur = NULL;
190 const TcoreATResponse *ATresp = data;
191 GSList *tokens = NULL;
192 const char *line = NULL;
193 struct tresp_modem_set_flightmode res = {0};
195 struct tnoti_modem_flight_mode modem_flight_mode = {0};
196 const struct treq_modem_set_flightmode *req_data = NULL;
198 o = tcore_pending_ref_core_object(p);
200 if (ATresp->success > 0) {
201 dbg("RESPONSE OK - flight mode operation finished");
202 res.result = TCORE_RETURN_SUCCESS;
205 line = (const char *) ATresp->final_response;
206 tokens = tcore_at_tok_new(line);
208 if (g_slist_length(tokens) < 1) {
209 dbg("err cause not specified or string corrupted");
210 res.result = TCORE_RETURN_3GPP_ERROR;
212 response = atoi(g_slist_nth_data(tokens, 0));
213 /* TODO: CMEE error mapping is required. */
214 res.result = TCORE_RETURN_3GPP_ERROR;
218 ur = tcore_pending_ref_user_request(p);
220 dbg("No user request. Internal request created during boot-up sequence");
222 if (ATresp->success > 0) {
223 modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
224 dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
226 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
227 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
230 dbg("Sending response for Flight mode operation");
232 req_data = tcore_user_request_ref_data(ur, NULL);
234 if (TCORE_RETURN_SUCCESS == res.result) {
235 if (TRUE == req_data->enable)
243 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
245 if (req_data->enable == 0) {
246 dbg("Flight mode is disabled, trigger COPS to register on network");
247 /* Trigger Network registration (for the moment automatic) */
248 prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
252 tcore_at_tok_free(tokens);
255 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
257 const TcoreATResponse *resp = data;
258 TcorePlugin *plugin = NULL;
259 struct tresp_modem_get_imei res;
260 TelMiscSNInformation *imei_property = NULL;
261 UserRequest *ur = NULL;
262 GSList *tokens = NULL;
266 memset(&res, 0, sizeof(struct tresp_modem_get_imei));
268 if (resp->success > 0) {
271 line = (const char *) resp->lines->data;
272 tokens = tcore_at_tok_new(line);
273 if (g_slist_length(tokens) != 1) {
274 msg("invalid message");
278 res.result = TCORE_RETURN_SUCCESS;
279 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
281 dbg("imei = [%s]", res.imei);
283 plugin = tcore_pending_ref_plugin(p);
284 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
286 imei_property->sn_index = TAPI_MISC_ME_IMEI;
287 imei_property->sn_len = strlen(res.imei);
288 memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
293 line = (const char *) resp->lines->data;
294 tokens = tcore_at_tok_new(line);
298 if (g_slist_length(tokens) < 1) {
299 dbg("err cause not specified or string corrupted");
300 res.result = TCORE_RETURN_3GPP_ERROR;
302 response = atoi(g_slist_nth_data(tokens, 0));
303 /* TODO: CMEE error mapping is required. */
304 res.result = TCORE_RETURN_3GPP_ERROR;
308 ur = tcore_pending_ref_user_request(p);
309 tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI,
310 sizeof(struct tresp_modem_get_imei), &res);
314 tcore_at_tok_free(tokens);
319 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
321 const TcoreATResponse *resp = data;
322 TcorePlugin *plugin = NULL;
323 struct tresp_modem_get_version res = {0};
324 TelMiscVersionInformation *vi_property = NULL;
325 TelMiscVersionInformation *vi = NULL;
326 UserRequest *ur = NULL;
327 GSList *tokens = NULL;
328 const char *line = NULL;
331 char *caldate = NULL;
337 if (resp->success > 0) {
340 line = (const char *) resp->lines->data;
341 tokens = tcore_at_tok_new(line);
342 if (g_slist_length(tokens) == 1) {
343 swver = g_slist_nth_data(tokens, 0);
344 dbg("version: sw=[%s]", swver);
345 } else if (g_slist_length(tokens) == 5) {
346 swver = g_slist_nth_data(tokens, 0);
347 hwver = g_slist_nth_data(tokens, 1);
348 caldate = g_slist_nth_data(tokens, 2);
349 pcode = g_slist_nth_data(tokens, 3);
350 id = g_slist_nth_data(tokens, 4);
352 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]",
353 swver, hwver, caldate, pcode, id);
355 msg("invalid message");
360 vi = g_try_new0(TelMiscVersionInformation, 1);
362 memcpy(vi->szSwVersion, swver, strlen(swver));
364 memcpy(vi->szHwVersion, hwver, strlen(hwver));
366 memcpy(vi->szRfCalDate, caldate, strlen(caldate));
368 memcpy(vi->szProductCode, pcode, strlen(pcode));
370 memcpy(vi->szModelId, id, strlen(id));
372 memset(&res, 0, sizeof(struct tresp_modem_get_version));
375 snprintf(res.software,
376 (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN),
381 snprintf(res.hardware,
382 (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN),
386 plugin = tcore_pending_ref_plugin(p);
387 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
388 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
393 line = (const char *) resp->lines->data;
394 tokens = tcore_at_tok_new(line);
397 memset(&res, 0, sizeof(struct tresp_modem_get_version));
400 if (g_slist_length(tokens) < 1) {
401 dbg("err cause not specified or string corrupted");
402 res.result = TCORE_RETURN_3GPP_ERROR;
404 response = atoi(g_slist_nth_data(tokens, 0));
405 /* TODO: CMEE error mapping is required. */
406 res.result = TCORE_RETURN_3GPP_ERROR;
410 ur = tcore_pending_ref_user_request(p);
411 tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION,
412 sizeof(struct tresp_modem_get_version), &res);
416 tcore_at_tok_free(tokens);
421 static enum tcore_hook_return on_hook_sim_status(Server *s,
422 CoreObject *source, enum tcore_notification_command command,
423 unsigned int data_len, void *data, void *user_data)
426 const struct tnoti_sim_status *noti_sim_status;
428 CoreObject *co_network;
430 plugin = tcore_object_ref_plugin(source);
431 co_sat = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAT);
433 return TCORE_HOOK_RETURN_CONTINUE;
435 co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
436 if (co_network == NULL)
437 return TCORE_HOOK_RETURN_CONTINUE;
439 dbg("Get SIM status");
440 noti_sim_status = data;
441 if (noti_sim_status == NULL)
442 return TCORE_HOOK_RETURN_CONTINUE;
444 /* If SIM is initialized, Enable STK and and attach to Network */
445 dbg("SIM Status: [%d]", noti_sim_status->sim_status);
446 if (noti_sim_status->sim_status == SIM_STATUS_INIT_COMPLETED) {
447 dbg("SIM ready for attach!!! Enable STK and attach to Network");
449 /* Sending AT+CFUN=6 */
450 prepare_and_send_pending_request(co_sat, "AT+CFUN=6", NULL,
451 TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
453 /* Sending AT+COPS */
454 prepare_and_send_pending_request(co_network, "AT+COPS=0", NULL,
455 TCORE_AT_NO_RESULT, on_response_network_registration);
458 return TCORE_HOOK_RETURN_CONTINUE;
461 gboolean modem_power_on(TcorePlugin *plugin)
463 CoreObject *co_modem = NULL;
464 struct treq_modem_set_flightmode flight_mode_set = {0};
465 struct tnoti_modem_power modem_power = {0};
466 Storage *strg = NULL;
468 co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
469 if (co_modem == NULL) {
470 err("Modem Core object is NULL");
474 /* Set Modem Power State to 'ON' */
475 tcore_modem_set_powered(co_modem, TRUE);
477 /* Get Flight mode from VCONFKEY */
478 strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf");
479 flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
481 /* Set Flight mode as per AP settings */
482 if (flight_mode_set.enable) { /* Radio OFF */
483 prepare_and_send_pending_request(co_modem, "AT+CFUN=4", NULL,
484 TCORE_AT_NO_RESULT, on_response_set_flight_mode);
486 /* Set Flight mode TRUE */
487 tcore_modem_set_flight_mode_state(co_modem, TRUE);
488 } else { /* Radio ON */
489 prepare_and_send_pending_request(co_modem, "AT+CFUN=1", NULL,
490 TCORE_AT_NO_RESULT, on_response_set_flight_mode);
492 /* Set Flight mode FALSE */
493 tcore_modem_set_flight_mode_state(co_modem, FALSE);
497 prepare_and_send_pending_request(co_modem, "AT+CGSN", NULL,
498 TCORE_AT_NUMERIC, on_response_imei);
500 /* Get Version Number */
501 prepare_and_send_pending_request(co_modem, "AT+CGMR", NULL,
502 TCORE_AT_SINGLELINE, on_response_version);
504 /* Send Notification to TAPI - MODEM_POWER */
505 modem_power.state = MODEM_STATE_ONLINE;
507 dbg("Sending notification - Modem Power state: [ONLINE]");
508 tcore_server_send_notification(tcore_plugin_ref_server(plugin),
509 co_modem, TNOTI_MODEM_POWER, sizeof(modem_power), &modem_power);
514 static TReturn power_off(CoreObject *o, UserRequest *ur)
516 TcoreHal *hal = NULL;
517 TcoreATRequest *req = NULL;
518 TcorePending *pending = NULL;
520 hal = tcore_object_get_hal(o);
521 pending = tcore_pending_new(o, 0);
523 req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
525 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
526 req->cmd, req->prefix, strlen(req->cmd));
528 tcore_pending_set_request_data(pending, 0, req);
529 tcore_pending_set_response_callback(pending, on_response_power_off, hal);
530 tcore_pending_link_user_request(pending, ur);
531 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
533 tcore_hal_send_request(hal, pending);
535 return TCORE_RETURN_SUCCESS;
538 static TReturn get_imei(CoreObject *o, UserRequest *ur)
542 TcorePending *pending = NULL;
544 hal = tcore_object_get_hal(o);
545 if (FALSE == tcore_hal_get_power_state(hal)) {
546 dbg("cp not ready/n");
547 return TCORE_RETURN_ENOSYS;
549 pending = tcore_pending_new(o, 0);
551 req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
553 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
554 req->cmd, req->prefix, strlen(req->cmd));
556 tcore_pending_set_request_data(pending, 0, req);
557 tcore_pending_set_response_callback(pending, on_response_imei, hal);
558 tcore_pending_link_user_request(pending, ur);
559 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
561 return tcore_hal_send_request(hal, pending);
565 static TReturn get_version(CoreObject *o, UserRequest *ur)
569 TcorePending *pending = NULL;
571 hal = tcore_object_get_hal(o);
572 if (FALSE == tcore_hal_get_power_state(hal)) {
573 dbg("cp not ready/n");
574 return TCORE_RETURN_ENOSYS;
576 pending = tcore_pending_new(o, 0);
578 req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
580 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
581 req->cmd, req->prefix, strlen(req->cmd));
583 tcore_pending_set_request_data(pending, 0, req);
584 tcore_pending_set_response_callback(pending, on_response_version, hal);
585 tcore_pending_link_user_request(pending, ur);
586 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
588 return tcore_hal_send_request(hal, pending);
591 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
593 TcoreHal *hal = NULL;
594 TcoreATRequest *req = NULL;
595 TcorePending *pending = NULL;
596 const struct treq_modem_set_flightmode *req_data = NULL;
597 char *cmd_str = NULL;
599 hal = tcore_object_get_hal(o);
600 if (FALSE == tcore_hal_get_power_state(hal)) {
601 dbg("cp not ready/n");
602 return TCORE_RETURN_ENOSYS;
604 pending = tcore_pending_new(o, 0);
606 req_data = tcore_user_request_ref_data(ur, NULL);
608 if (req_data->enable) {
609 dbg("Flight mode on/n");
610 cmd_str = g_strdup("AT+CFUN=4");
612 dbg("Flight mode off/n");
613 cmd_str = g_strdup("AT+CFUN=1");
616 req = tcore_at_request_new((const char *)cmd_str, NULL, TCORE_AT_NO_RESULT);
619 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
620 req->cmd, req->prefix, strlen(req->cmd));
622 tcore_pending_set_request_data(pending, 0, req);
623 tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
624 tcore_pending_link_user_request(pending, ur);
625 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
627 return tcore_hal_send_request(hal, pending);
631 static struct tcore_modem_operations modem_ops = {
633 .power_off = power_off,
635 .set_flight_mode = set_flight_mode,
636 .get_imei = get_imei,
637 .get_version = get_version,
639 .dun_pin_ctrl = NULL,
642 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
644 TelMiscVersionInformation *vi_property;
645 TelMiscSNInformation *imei_property;
646 TelMiscSNInformation *sn_property;
650 tcore_modem_override_ops(co_modem, &modem_ops);
652 vi_property = g_try_new0(TelMiscVersionInformation, 1);
653 tcore_plugin_link_property(cp, "VERSION", vi_property);
655 imei_property = g_try_new0(TelMiscSNInformation, 1);
656 tcore_plugin_link_property(cp, "IMEI", imei_property);
658 sn_property = g_try_new0(TelMiscSNInformation, 1);
659 tcore_plugin_link_property(cp, "SN", sn_property);
661 tcore_server_add_notification_hook(tcore_plugin_ref_server(cp),
662 TNOTI_SIM_STATUS, on_hook_sim_status, NULL);
663 dbg("Registering for +XDRVI event");
664 tcore_object_add_callback(co_modem, "+XDRVI", on_event_nvm_update, NULL);
670 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
672 TelMiscVersionInformation *vi_property;
673 TelMiscSNInformation *imei_property;
674 TelMiscSNInformation *sn_property;
675 TcorePlugin *plugin = tcore_object_ref_plugin(co_modem);
677 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
680 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
681 g_free(imei_property);
683 sn_property = tcore_plugin_ref_property(plugin, "SN");
690 * NV Manager - Support for Remote File System
693 static gboolean modem_rfs_hook(const char *data)
696 if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION)
702 /* NVM event Notification */
703 static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data)
705 GSList *tokens = NULL;
713 lines = (GSList *)event_info;
715 dbg("Line: [%s]", line);
717 function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]);
718 dbg("Function ID: [%d]", function_id);
719 if (IUFP_UPDATE == function_id) {
720 dbg("Calling process nvm_update");
723 * Process NV Update indication
725 * +XDRVI: IUFP_GROUP, IUFP_UPDATE, <xdrv_result>, <data>
727 if (NVM_NO_ERR == nvm_process_nv_update(line)) {
728 dbg("NV data processed successfully");
730 /* Acknowledge NV Update */
731 modem_send_nvm_update_ack(o);
735 err("NV data processing failed");
739 tokens = tcore_at_tok_new(line);
740 if (g_slist_length(tokens) < 3) {
741 err("XDRVI event with less number of tokens, Ignore!!!");
744 else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) {
745 err("Group ID mismatch, Ignore!!!");
749 switch (atoi(g_slist_nth_data(tokens, 1))) {
750 case IUFP_UPDATE_REQ:
751 dbg("NV Update Request");
753 /* Acknowledge the Update Request */
754 modem_send_nvm_update_request_ack(o);
757 case IUFP_NO_PENDING_UPDATE:
758 dbg("NO pending NV Update(s)!!!");
759 /* Can send FLUSH request to get fresh updates */
763 err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1)));
768 tcore_at_tok_free(tokens);
776 static gboolean __modem_check_nvm_response(const void *data, int command)
778 const TcoreATResponse *resp = data;
781 GSList *tokens = NULL;
782 gboolean ret = FALSE;
785 /* +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>] */
787 err("Input data is NULL");
791 if (resp->success > 0) {
793 line = (const char *) (((GSList *) resp->lines)->data);
794 tokens = tcore_at_tok_new(line);
797 resp_str = g_slist_nth_data(tokens, 0);
798 if (NULL == resp_str) {
799 err("Group ID is missing ");
802 else if (IUFP_GROUP_ID != atoi(resp_str)) {
803 err("Group ID mismatch");
808 resp_str = g_slist_nth_data(tokens, 1);
809 if (NULL == resp_str) {
810 err("Function ID is missing ");
813 else if (command != atoi(resp_str)) {
814 err("Function ID mismatch");
819 resp_str = g_slist_nth_data(tokens, 2);
820 if (NULL == resp_str) {
821 err("XDRV result is missing ");
824 else if (XDRV_RESULT_OK != atoi(resp_str)) {
825 err("XDRV result[%d] ", atoi(resp_str));
830 resp_str = g_slist_nth_data(tokens, 3);
831 if (NULL == resp_str) {
832 err("UTA result is missing ");
835 else if (UTA_SUCCESS != atoi(resp_str)) {
836 err("uta result[%d] ", atoi(resp_str));
846 tcore_at_tok_free(tokens);
852 static void _on_response_modem_unsuspend_nvm_updates(TcorePending *p,
853 int data_len, const void *data, void *user_data)
855 /* Check NVM response */
856 if (TRUE == __modem_check_nvm_response(data, IUFP_SUSPEND)) {
857 dbg("Priority level is set to get all updates since Boot-up");
859 /* Create NV data file */
860 if (nvm_create_nvm_data() == FALSE) {
861 err("Failed to Create NV data file");
867 err("Response NOT OK");
870 static void _on_response_modem_send_nvm_update_ack(TcorePending *p,
871 int data_len, const void *data, void *user_data)
873 /* Check NVM response */
874 if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_ACK)) {
875 dbg("[UPDATE ACK] OK");
879 err("[UPDATE ACK] NOT OK");
882 static void _on_response_modem_send_nvm_update_request_ack(TcorePending *p,
883 int data_len, const void *data, void *user_data)
885 /* Check NVM response */
886 if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) {
887 dbg("[REQUEST ACK] OK");
891 err("[REQUEST ACK] NOT OK");
894 static void _on_response_modem_send_flush_nvm_update(TcorePending *p,
895 int data_len, const void *data, void *user_data)
897 /* Check NVM response */
898 if (TRUE == __modem_check_nvm_response(data, IUFP_FLUSH)) {
899 dbg("Flushing of FLUSH data successful");
903 err("Response NOT OK");
906 static void _on_response_modem_register_nvm(TcorePending *p,
907 int data_len, const void *data, void *user_data)
909 /* Check NVM response */
910 if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
911 dbg("Registering successful");
913 /* Send SUSPEND_UPDATE for all UPDATES */
914 modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p));
920 err("Response NOT OK");
923 static void _on_response_modem_deregister_nvm(TcorePending *p,
924 int data_len, const void *data, void *user_data)
926 /* Check NVM response */
927 if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) {
928 dbg("Deregistering successful");
932 err("Response NOT OK");
936 static void modem_unsuspend_nvm_updates(CoreObject *o)
938 TcorePending *pending = NULL;
942 /* Prepare AT-Command */
943 cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d",
944 IUFP_GROUP_ID, IUFP_SUSPEND,
945 0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL);
947 /* Prepare pending request */
948 pending = tcore_at_pending_new(o,
952 _on_response_modem_unsuspend_nvm_updates,
954 if (pending == NULL) {
955 err("Failed to form pending request");
957 else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
958 != TCORE_RETURN_SUCCESS) {
959 err("IUFP_SUSPEND - Unable to send AT-Command");
962 dbg("IUFP_SUSPEND - Successfully sent AT-Command");
968 static void modem_send_nvm_update_ack(CoreObject *o)
970 TcorePending *pending = NULL;
974 /* Prepare AT-Command */
975 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR);
977 /* Prepare pending request */
978 pending = tcore_at_pending_new(o,
982 _on_response_modem_send_nvm_update_ack,
984 if (pending == NULL) {
985 err("Failed to form pending request");
987 else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
988 != TCORE_RETURN_SUCCESS) {
989 err("IUFP_UPDATE_ACK - Unable to send AT-Command");
992 dbg("IUFP_UPDATE_ACK - Successfully sent AT-Command");
998 static void modem_send_nvm_update_request_ack(CoreObject *o)
1000 TcorePending *pending = NULL;
1004 /* Prepare AT-Command */
1005 cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR);
1007 /* Prepare pending request */
1008 pending = tcore_at_pending_new(o,
1011 TCORE_AT_SINGLELINE,
1012 _on_response_modem_send_nvm_update_request_ack,
1016 if (pending == NULL) {
1017 err("Failed to form pending request");
1019 else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
1020 != TCORE_RETURN_SUCCESS) {
1021 err("IUFP_UPDATE_REQ_ACK - Unable to send AT-Ccommand");
1024 dbg("IUFP_UPDATE_REQ_ACK - Successfully sent AT-Command");
1030 static void modem_send_flush_nvm_update(CoreObject *o)
1032 TcorePending *pending = NULL;
1036 /* Prepare AT-Command */
1037 cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d", IUFP_GROUP_ID, IUFP_FLUSH, 0);
1039 /* Prepare pending request */
1040 pending = tcore_at_pending_new(o,
1043 TCORE_AT_SINGLELINE,
1044 _on_response_modem_send_flush_nvm_update,
1046 if (pending == NULL) {
1047 err("Failed to form pending request");
1049 else if (tcore_hal_send_request(tcore_object_get_hal(o), pending)
1050 != TCORE_RETURN_SUCCESS) {
1051 err("IUFP_FLUSH - Unable to send AT-Command");
1054 dbg("IUFP_FLUSH - Successfully sent AT-Command");
1060 void modem_register_nvm(CoreObject *co_modem)
1062 TcorePending *pending = NULL;
1066 /* Prepare AT-Command */
1067 cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
1068 IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE);
1070 /* Prepare pending request */
1071 pending = tcore_at_pending_new(co_modem,
1074 TCORE_AT_SINGLELINE,
1075 _on_response_modem_register_nvm,
1077 if (pending == NULL) {
1078 err("Failed to form pending request");
1080 else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending)
1081 != TCORE_RETURN_SUCCESS) {
1082 err("IUFP_REGISTER (Enable) -Unable to send AT-Command");
1085 dbg("IUFP_REGISTER (Enable) -Successfully sent AT-Command");
1088 tcore_at_add_hook(tcore_object_get_hal(co_modem), modem_rfs_hook);
1094 void modem_deregister_nvm(CoreObject *co_modem)
1096 TcorePending *pending = NULL;
1100 /* Prepare AT-Command */
1101 cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s",
1102 IUFP_GROUP, IUFP_REGISTER_STR, XDRV_DISABLE);
1104 /* Prepare pending request */
1105 pending = tcore_at_pending_new(co_modem,
1108 TCORE_AT_SINGLELINE,
1109 _on_response_modem_deregister_nvm,
1111 if (pending == NULL) {
1112 err("Failed to form pending request");
1114 else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending)
1115 != TCORE_RETURN_SUCCESS) {
1116 err("IUFP_REGISTER (Disable) -Unable to send AT-Command");
1119 dbg("IUFP_REGISTER (Disable) -Successfully sent AT-Command");