From: Paresh Agarwal Date: Tue, 7 May 2013 13:41:48 +0000 (+0530) Subject: Modem : NVM initial commit X-Git-Tag: accepted/tizen/20131007.095414~9 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Ftelephony%2Ftel-plugin-imc.git;a=commitdiff_plain;h=065e7073835059cc419b5ff04dce520e1a1f8bf8 Modem : NVM initial commit Change-Id: Idd562c0c35b9c0c395570a7efca1107f3fdb33f3 --- diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100644 new mode 100755 index 3ab8348..260778e --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ SET(SRCS src/s_phonebook.c src/s_sap.c src/s_gps.c + src/nvm/nvm.c ) diff --git a/include/nvm/nvm.h b/include/nvm/nvm.h new file mode 100755 index 0000000..a654bf2 --- /dev/null +++ b/include/nvm/nvm.h @@ -0,0 +1,125 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Paresh Agarwal + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NVM_H__ +#define __NVM_H__ + +/* Priority level for suspension of all updates */ +#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_ALL 4294967295 /* 0xFFFFFFFF */ + +/* Priority level for suspension of High priority updates */ +#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_HIGH 3221225472 /* 0xFFFFFFFF */ + +/* Priority level for suspension of all updates of dynamic data */ +#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_ALL_DYN 1610612735 /* 0x5FFFFFFF */ + +/* Priority level for suspension of Medium all updates */ +#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_MEDIUM 2147483648 /* 0x5FFFFFFF */ + +/* Priority level for suspension of Low updates of Medium */ +#define UTA_FLASH_PLUGIN_PRIO_SUSPEND_LOW 1073741824 /* 0x5FFFFFFF */ + +/* Priority level for unsuspension of all updates */ +#define UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL 0 /* 0x0 */ + +#define NVM_FUNCTION_ID_OFFSET 20 +#define XDRV_INDICATION 0x04 + +#define XDRV_DISABLE "0" +#define XDRV_ENABLE "1" +#define XDRV_UNSUSPEND "0" + +/* Identifies our group with the xdrv AT command set */ +#define IUFP_GROUP "43" +#define IUFP_GROUP_ID 43 + +#define IUFP_REGISTER 0 +#define IUFP_REGISTER_STR "0" + +#define IUFP_SUSPEND 1 +#define IUFP_SUSPEND_STR "1" + +#define IUFP_FLUSH 2 +#define IUFP_FLUSH_STR "2" + +#define IUFP_UPDATE_REQ 3 +#define IUFP_UPDATE_REQ_STR "3" + +#define IUFP_UPDATE_REQ_ACK 3 +#define IUFP_UPDATE_REQ_ACK_STR "3" + +#define IUFP_UPDATE 4 +#define IUFP_UPDATE_STR "4" + +#define IUFP_UPDATE_ACK 4 +#define IUFP_UPDATE_ACK_STR "4" + +#define IUFP_NO_PENDING_UPDATE 5 +#define IUFP_NO_PENDING_UPDATE_STR "5" + +/* XDRV command was executed without any error */ +#define XDRV_RESULT_OK 0 + +typedef enum uta_common_return_codes { + UTA_SUCCESS = 0, + UTA_FAILURE = -1, + UTA_ERROR_OUT_OF_MEMORY = -2, + UTA_ERROR_INVALID_HANDLE = -3, + UTA_ERROR_OUT_OF_RANGE_PARAM = -4, + UTA_ERROR_INVALID_PARAM = -5, + UTA_ERROR_TOO_SMALL_BUF_PARAM = -6, + UTA_ERROR_NOT_SUPPORTED = -7, + UTA_ERROR_TIMEOUT = -8, + UTA_ERROR_WRONG_STATE = -9, + UTA_ERROR_BAD_FORMAT = -10, + UTA_ERROR_INSUFFICIENT_PERMISSIONS = -11, + UTA_ERROR_IO_ERROR = -12, + UTA_ERROR_OUT_OF_HANDLES = -13, + UTA_ERROR_OPERATION_PENDING = -14, + UTA_ERROR_SPECIFIC = -100 +} nvm_return_codes; + +typedef enum nvm_error_numbers { + NVM_NO_ERR = 0, + NVM_CMD_ERR, + NVM_DATA_ERR, + NVM_MEM_FULL_ERR, + NVM_RES_ERR, + NVM_WRITE_ERR, + NVM_READ_ERR, + NVM_RES_LEN_ERR, + NVM_PCKT_ERR, + NVM_REG_FAIL_ERR, + NVM_DATA_LEN_ERR, + NVM_FILE_ERR, + NVM_AT_PORT_ERR, + NVM_READ_AT_ERR, + NVM_DATA_PORT_ERR, + NVM_NO_PENDING_UPDATE, + NVM_UPDATE, + NVM_REGISTER_ERR, + NVM_UNKNOWN_ERR +} nvm_error; + +int nvm_sum_4_bytes(const char *pos); +gboolean nvm_create_nvm_data(); +nvm_error nvm_process_nv_update(const char *data); + +#endif /* __NVM_H__ */ diff --git a/include/s_modem.h b/include/s_modem.h old mode 100644 new mode 100755 index d0fd6a8..3e22c74 --- a/include/s_modem.h +++ b/include/s_modem.h @@ -24,6 +24,8 @@ gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem); void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem); -gboolean modem_power_on(TcorePlugin *p); +gboolean modem_power_on(TcorePlugin *plugin); +void modem_register_nvm(CoreObject *co_modem); +void modem_deregister_nvm(CoreObject *co_modem); #endif diff --git a/src/desc.c b/src/desc.c old mode 100644 new mode 100755 index 62b4065..f3e98f6 --- a/src/desc.c +++ b/src/desc.c @@ -69,6 +69,7 @@ static void on_response_last_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data) { const TcoreATResponse *resp = data; + TcorePlugin *plugin = tcore_pending_ref_plugin(p); gboolean ret; dbg("Last Subscription - COMPLETED"); @@ -80,8 +81,14 @@ static void on_response_last_bootup_subscription(TcorePending *p, dbg("Boot-up configration completed for IMC modem. %s", "Bring CP to ONLINE state based on Flightmode status"); - ret = modem_power_on(tcore_pending_ref_plugin(p)); + + /* Modem Power */ + ret = modem_power_on(plugin); dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL")); + + /* NVM Registration */ + dbg("Registering modem for NVM manager"); + modem_register_nvm(tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM)); } static void _modem_subscribe_events(TcorePlugin *plugin) diff --git a/src/nvm/nvm.c b/src/nvm/nvm.c new file mode 100755 index 0000000..582220e --- /dev/null +++ b/src/nvm/nvm.c @@ -0,0 +1,314 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Paresh Agarwal + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "nvm/nvm.h" + +/* NVM file type */ +#define NVM_TYPE_CALIB 0 +#define NVM_TYPE_STATIC 1 +#define NVM_TYPE_DYNAMIC 2 +#define NVM_FILE_TYPE_POS 36 + +/* NVM Payload information */ +#define NVM_PAYLOAD_OFFSET_0 48 +#define NVM_PAYLOAD_LENGTH_0 52 +#define NVM_PAYLOAD_OFFSET_1 64 +#define NVM_PAYLOAD_LENGTH_1 68 +#define NVM_DATA_LEN_POS 80 + +/* Image Path information */ +#define MODEM_IMAGE_PATH "/boot/modem.bin" +#define NVM_DIR_PATH "/csa/nv" +#define NV_FILE_PATH NVM_DIR_PATH "/nvdata.bin" + +/* NV offsets and size */ +#define MODEM_NV_OFFSET 0xA00000 +#define MAX_NVDATA_SIZE 0x200000 +#define NVM_CALIB_OFFSET 0x80000 +#define NVM_STATIC_OFFSET 0x100000 + +struct nvm_payload_info { + unsigned long m_offset_0; + unsigned long m_length_0; + unsigned long m_offset_1; + unsigned long m_length_1; +}; + +static nvm_error __nvm_file_write(int nvm_type, const char *update_buf, int update_len, int offset) +{ + int nv_fd; + nvm_error ret_val = NVM_NO_ERR; + int ret; + + char err_str[256] = {0, }; + errno = 0; + dbg("Entered"); + + if (NULL == update_buf) { + err("Buffer is invalid!!!"); + return NVM_WRITE_ERR; + } + + switch (nvm_type) { + case NVM_TYPE_CALIB: + msg(" [NVM File] calib.nvm"); + offset = offset + NVM_CALIB_OFFSET; + break; + + case NVM_TYPE_STATIC: + msg(" [NVM File] static.nvm"); + offset = offset + NVM_STATIC_OFFSET; + break; + + case NVM_TYPE_DYNAMIC: + msg(" [NVM File] dynamic.nvm"); + break; + + default: + err("[NVM File] Wrong NVM file type: [%d]", nvm_type); + return NVM_FILE_ERR; + } + + /* Open NVM file for Write operation */ + nv_fd = open(NV_FILE_PATH, O_RDWR); + if (nv_fd < 0) { + strerror_r(errno, err_str, 255); + err("[OPEN] Failed: [%s]", err_str); + return NVM_READ_ERR; + } + + /* Seek the offset */ + ret = lseek(nv_fd, (long)offset, SEEK_SET); + if (ret < 0) { + strerror_r(errno, err_str, 255); + err("[SEEK] Failed: [%s]", err_str); + ret_val = NVM_RES_LEN_ERR; + } else { + dbg("Buffer: [0x%x] length: [%d]", update_buf, update_len); + + /* Write the buffer to file */ + ret = write(nv_fd, update_buf, update_len); + if (ret > 0) { + dbg("[WRITE] Successfully updated NVM data"); + } else if (ret == 0) { + strerror_r(errno, err_str, 255); + dbg("[WRITE] Nothing is written: [%s]", err_str); + } else { + strerror_r(errno, err_str, 255); + err("[WRITE] Failed: [%s]", err_str); + ret_val = NVM_MEM_FULL_ERR; + } + } + + /* Close 'fd' */ + close(nv_fd); + + return ret_val; +} + +static nvm_error __nvm_write_payload_1(int nvm_type, + const char *p_bin_buff, struct nvm_payload_info *nvm1) +{ + const char *p_buf_ptr = p_bin_buff; + + /* Write to file */ + return __nvm_file_write(nvm_type, + (p_buf_ptr + NVM_DATA_LEN_POS + nvm1->m_length_0), + nvm1->m_length_1, + nvm1->m_offset_1); +} + +static nvm_error __nvm_write_payload_0(int nvm_type, + const char *p_bin_buff, struct nvm_payload_info *nvm) +{ + nvm_error ret_val; + + /* Write to file */ + ret_val = __nvm_file_write(nvm_type, + (p_bin_buff + NVM_DATA_LEN_POS), + nvm->m_length_0, + nvm->m_offset_0); + if (NVM_NO_ERR == ret_val) { + /* The payload_0 has been done, so calls this method to write payload_1 to file */ + ret_val = __nvm_write_payload_1(nvm_type, p_bin_buff, nvm); + } else { + err("Failed to write to NV data file!!!"); + } + + return ret_val; +} + +int nvm_sum_4_bytes(const char *pos) +{ + int sum = 0; + sum = sum | (*(pos+3)) << 24; + sum = sum | (*(pos+2)) << 16; + sum = sum | (*(pos+1)) << 8; + sum = sum | *pos; + return sum; +} + +nvm_error nvm_process_nv_update(const char *data) +{ + struct nvm_payload_info nvm_info; + int nvm_type; + nvm_error ret_val; + dbg("Entered"); + + memset(&nvm_info, 0x0, sizeof(struct nvm_payload_info)); + + /* Determine lengths from the little-endian 4 bytes */ + nvm_info.m_length_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_0]); + nvm_info.m_offset_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_0]); + nvm_info.m_length_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_1]); + nvm_info.m_offset_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_1]); + dbg("Offsets - 0th: [%d] 1st: [%d]", nvm_info.m_offset_0, nvm_info.m_offset_1); + + nvm_type = *(data + NVM_FILE_TYPE_POS); + if ((NVM_TYPE_CALIB <= nvm_type) + && (NVM_TYPE_DYNAMIC >= nvm_type)) { + dbg("NVM type: [%d]", nvm_type); + + /* Write NVM data to file */ + ret_val = __nvm_write_payload_0(nvm_type, data, &nvm_info); + } else { + err("Wrong NVM file type: [%d]", nvm_type); + ret_val = NVM_RES_ERR; + } + + return ret_val; +} + +gboolean nvm_create_nvm_data() +{ + int modem_fd; + int nv_fd; + char *buffer = NULL; + char err_str[256] = {0, }; + + gboolean ret_val = FALSE; + dbg("Entered"); + + /* Open modem binary */ + modem_fd = open(MODEM_IMAGE_PATH, O_RDONLY | O_NDELAY); + if (modem_fd < 0) { + strerror_r(errno, err_str, 255); + err("[OPEN] Failed for (%s): [%s]", MODEM_IMAGE_PATH, err_str); + return ret_val; + } + + /* Create NV data folder if it doesn't exist */ + if (mkdir(NVM_DIR_PATH, 0755) < 0) { + if (errno != EEXIST) { + strerror_r(errno, err_str, 255); + err("mkdir() failed: [%s]", err_str); + + /* Close 'modem_fd' */ + close(modem_fd); + return ret_val; + } else if (open(NV_FILE_PATH, O_EXCL) > 0) { + /* NV data file already exists */ + dbg("File exists: [%s]", NV_FILE_PATH); + + /* Close 'modem_fd' */ + close(modem_fd); + return TRUE; + } else { + dbg("File does't exsits... need to create!!!"); + } + } + + /* Change directory permissions */ + if (chmod(NVM_DIR_PATH, 0755) < 0) { + strerror_r(errno, err_str, 255); + err("chmod() failed: [%s]", err_str); + + /* Close 'modem_fd' */ + close(modem_fd); + return ret_val; + } + + /* Open NV data file for different file operations */ + nv_fd = open(NV_FILE_PATH, O_RDWR | O_CREAT | O_SYNC, S_IRWXU); + if (nv_fd < 0) { + strerror_r(errno, err_str, 255); + err("[OPEN] Failed for (%s): %s", NV_FILE_PATH, err_str); + + /* Close 'modem_fd' */ + close(modem_fd); + return ret_val; + } + + dbg("Setting the file descriptor offset to NV data in modem.bin"); + do { + /* Seek pre-defined offset in modem binary */ + if (lseek(modem_fd, MODEM_NV_OFFSET, SEEK_SET) < 0) { + strerror_r(errno, err_str, 255); + err("[SEEK] Failed: [%s]", err_str); + break; + } + + /* Allocate memory */ + buffer = g_try_malloc0(MAX_NVDATA_SIZE); + if (NULL == buffer) { + err("Failed to allocate memory"); + break; + } + + /* Read NV data from modem binary */ + if (read(modem_fd, buffer, MAX_NVDATA_SIZE) < 0) { + strerror_r(errno, err_str, 255); + err("[READ] Failed: [%s]", err_str); + break; + } + + /* Write the data read from modem binary to nvdata */ + if (write(nv_fd, buffer, MAX_NVDATA_SIZE) < 0) { + strerror_r(errno, err_str, 255); + err("[WRITE} Failed: [%s]", err_str); + break; + } + + ret_val = TRUE; + } while (0); + + if (ret_val == FALSE) { + err("nvdata (%s) creation Failed!!!", NV_FILE_PATH); + } else { + dbg("nvdata (%s) created Success", NV_FILE_PATH); + } + + /* Close 'fds' */ + close(modem_fd); + close(nv_fd); + + /* Free 'buffer' */ + g_free(buffer); + + return ret_val; +} diff --git a/src/s_modem.c b/src/s_modem.c old mode 100644 new mode 100755 index b167868..9c99048 --- a/src/s_modem.c +++ b/src/s_modem.c @@ -39,6 +39,7 @@ #include "s_common.h" #include "s_modem.h" +#include "nvm/nvm.h" #define ID_RESERVED_AT 0x0229 @@ -103,6 +104,15 @@ static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data); static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data); +/* NVM */ +static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data); +static void modem_send_nvm_update_ack(CoreObject *o); +static void modem_send_nvm_update_request_ack(CoreObject *o); +static void modem_unsuspend_nvm_updates(CoreObject *o); +static void modem_send_nvm_update_ack(CoreObject *o); +static void modem_send_nvm_update_request_ack(CoreObject *o); +static void modem_send_flush_nvm_update(CoreObject *o); + static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data) { dbg("on_confirmation_modem_message_send - msg out from queue.\n"); @@ -448,14 +458,14 @@ static enum tcore_hook_return on_hook_sim_status(Server *s, return TCORE_HOOK_RETURN_CONTINUE; } -gboolean modem_power_on(TcorePlugin *p) +gboolean modem_power_on(TcorePlugin *plugin) { CoreObject *co_modem = NULL; struct treq_modem_set_flightmode flight_mode_set = {0}; struct tnoti_modem_power modem_power = {0}; Storage *strg = NULL; - co_modem = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_MODEM); + co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM); if (co_modem == NULL) { err("Modem Core object is NULL"); return FALSE; @@ -465,7 +475,7 @@ gboolean modem_power_on(TcorePlugin *p) tcore_modem_set_powered(co_modem, TRUE); /* Get Flight mode from VCONFKEY */ - strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf"); + strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf"); flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL); /* Set Flight mode as per AP settings */ @@ -495,7 +505,7 @@ gboolean modem_power_on(TcorePlugin *p) modem_power.state = MODEM_STATE_ONLINE; dbg("Sending notification - Modem Power state: [ONLINE]"); - tcore_server_send_notification(tcore_plugin_ref_server(p), + tcore_server_send_notification(tcore_plugin_ref_server(plugin), co_modem, TNOTI_MODEM_POWER, sizeof(modem_power), &modem_power); return TRUE; @@ -650,6 +660,8 @@ gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem) tcore_server_add_notification_hook(tcore_plugin_ref_server(cp), TNOTI_SIM_STATUS, on_hook_sim_status, NULL); + dbg("Registering for +XDRVI event"); + tcore_object_add_callback(co_modem, "+XDRVI", on_event_nvm_update, NULL); dbg("Exit"); return TRUE; @@ -673,3 +685,439 @@ void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem) dbg("Exit"); } + +/* + * NV Manager - Support for Remote File System + */ +/* NVM Hook */ +static gboolean modem_rfs_hook(const char *data) +{ + if (data != NULL) + if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION) + return TRUE; + + return FALSE; +} + +/* NVM event Notification */ +static gboolean on_event_nvm_update(CoreObject *o, const void *event_info, void *user_data) +{ + GSList *tokens = NULL; + GSList *lines; + const char *line; + int function_id; + + gboolean ret = TRUE; + dbg("Entered"); + + lines = (GSList *)event_info; + line = lines->data; + dbg("Line: [%s]", line); + + function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]); + dbg("Function ID: [%d]", function_id); + if (IUFP_UPDATE == function_id) { + dbg("Calling process nvm_update"); + + /* + * Process NV Update indication + * + * +XDRVI: IUFP_GROUP, IUFP_UPDATE, , + */ + if (NVM_NO_ERR == nvm_process_nv_update(line)) { + dbg("NV data processed successfully"); + + /* Acknowledge NV Update */ + modem_send_nvm_update_ack(o); + + return ret; + } else { + err("NV data processing failed"); + ret = FALSE; + } + } else { + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 3) { + err("XDRVI event with less number of tokens, Ignore!!!"); + ret = FALSE; + } + else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) { + err("Group ID mismatch, Ignore!!!"); + ret = FALSE; + } + else { + switch (atoi(g_slist_nth_data(tokens, 1))) { + case IUFP_UPDATE_REQ: + dbg("NV Update Request"); + + /* Acknowledge the Update Request */ + modem_send_nvm_update_request_ack(o); + break; + + case IUFP_NO_PENDING_UPDATE: + dbg("NO pending NV Update(s)!!!"); + /* Can send FLUSH request to get fresh updates */ + break; + + default: + err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1))); + ret = FALSE; + } + } + + tcore_at_tok_free(tokens); + } + + dbg("Exit"); + return ret; +} + +/* NVM Responses */ +static gboolean __modem_check_nvm_response(const void *data, int command) +{ + const TcoreATResponse *resp = data; + const char *line; + char *resp_str; + GSList *tokens = NULL; + gboolean ret = FALSE; + dbg("Entered"); + + /* +XDRV: ,,[,] */ + if (NULL == resp) { + err("Input data is NULL"); + return FALSE; + } + + if (resp->success > 0) { + dbg("RESPONSE OK"); + line = (const char *) (((GSList *) resp->lines)->data); + tokens = tcore_at_tok_new(line); + + /* Group ID */ + resp_str = g_slist_nth_data(tokens, 0); + if (NULL == resp_str) { + err("Group ID is missing "); + goto OUT; + } + else if (IUFP_GROUP_ID != atoi(resp_str)) { + err("Group ID mismatch"); + goto OUT; + } + + /* Function ID */ + resp_str = g_slist_nth_data(tokens, 1); + if (NULL == resp_str) { + err("Function ID is missing "); + goto OUT; + } + else if (command != atoi(resp_str)) { + err("Function ID mismatch"); + goto OUT; + } + + /* XDRV Result */ + resp_str = g_slist_nth_data(tokens, 2); + if (NULL == resp_str) { + err("XDRV result is missing "); + goto OUT; + } + else if (XDRV_RESULT_OK != atoi(resp_str)) { + err("XDRV result[%d] ", atoi(resp_str)); + goto OUT; + } + + /* Result code */ + resp_str = g_slist_nth_data(tokens, 3); + if (NULL == resp_str) { + err("UTA result is missing "); + goto OUT; + } + else if (UTA_SUCCESS != atoi(resp_str)) { + err("uta result[%d] ", atoi(resp_str)); + goto OUT; + } + + ret = TRUE; + } else { + dbg("Response NOK"); + } + +OUT: + tcore_at_tok_free(tokens); + + dbg("Exit"); + return ret; +} + +static void _on_response_modem_unsuspend_nvm_updates(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_SUSPEND)) { + dbg("Priority level is set to get all updates since Boot-up"); + + /* Create NV data file */ + if (nvm_create_nvm_data() == FALSE) { + err("Failed to Create NV data file"); + } + + return; + } + + err("Response NOT OK"); +} + +static void _on_response_modem_send_nvm_update_ack(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_ACK)) { + dbg("[UPDATE ACK] OK"); + return; + } + + err("[UPDATE ACK] NOT OK"); +} + +static void _on_response_modem_send_nvm_update_request_ack(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) { + dbg("[REQUEST ACK] OK"); + return; + } + + err("[REQUEST ACK] NOT OK"); +} + +static void _on_response_modem_send_flush_nvm_update(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_FLUSH)) { + dbg("Flushing of FLUSH data successful"); + return; + } + + err("Response NOT OK"); +} + +static void _on_response_modem_register_nvm(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) { + dbg("Registering successful"); + + /* Send SUSPEND_UPDATE for all UPDATES */ + modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p)); + + dbg("Exit"); + return; + } + + err("Response NOT OK"); +} + +static void _on_response_modem_deregister_nvm(TcorePending *p, + int data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __modem_check_nvm_response(data, IUFP_REGISTER)) { + dbg("Deregistering successful"); + return; + } + + err("Response NOT OK"); +} + +/* NVM Requests */ +static void modem_unsuspend_nvm_updates(CoreObject *o) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d", + IUFP_GROUP_ID, IUFP_SUSPEND, + 0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL); + + /* Prepare pending request */ + pending = tcore_at_pending_new(o, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_unsuspend_nvm_updates, + NULL); + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(o), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_SUSPEND - Unable to send AT-Command"); + } + else { + dbg("IUFP_SUSPEND - Successfully sent AT-Command"); + } + + g_free(cmd_str); +} + +static void modem_send_nvm_update_ack(CoreObject *o) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR); + + /* Prepare pending request */ + pending = tcore_at_pending_new(o, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_send_nvm_update_ack, + NULL); + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(o), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_UPDATE_ACK - Unable to send AT-Command"); + } + else { + dbg("IUFP_UPDATE_ACK - Successfully sent AT-Command"); + } + + g_free(cmd_str); +} + +static void modem_send_nvm_update_request_ack(CoreObject *o) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR); + + /* Prepare pending request */ + pending = tcore_at_pending_new(o, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_send_nvm_update_request_ack, + NULL); + + + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(o), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_UPDATE_REQ_ACK - Unable to send AT-Ccommand"); + } + else { + dbg("IUFP_UPDATE_REQ_ACK - Successfully sent AT-Command"); + } + + g_free(cmd_str); +} + +static void modem_send_flush_nvm_update(CoreObject *o) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d", IUFP_GROUP_ID, IUFP_FLUSH, 0); + + /* Prepare pending request */ + pending = tcore_at_pending_new(o, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_send_flush_nvm_update, + NULL); + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(o), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_FLUSH - Unable to send AT-Command"); + } + else { + dbg("IUFP_FLUSH - Successfully sent AT-Command"); + } + + g_free(cmd_str); +} + +void modem_register_nvm(CoreObject *co_modem) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s", + IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE); + + /* Prepare pending request */ + pending = tcore_at_pending_new(co_modem, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_register_nvm, + NULL); + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_REGISTER (Enable) -Unable to send AT-Command"); + } + else { + dbg("IUFP_REGISTER (Enable) -Successfully sent AT-Command"); + + /* Add RFS hook */ + tcore_at_add_hook(tcore_object_get_hal(co_modem), modem_rfs_hook); + } + + g_free(cmd_str); +} + +void modem_deregister_nvm(CoreObject *co_modem) +{ + TcorePending *pending = NULL; + char *cmd_str; + dbg("Entered"); + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s", + IUFP_GROUP, IUFP_REGISTER_STR, XDRV_DISABLE); + + /* Prepare pending request */ + pending = tcore_at_pending_new(co_modem, + cmd_str, + "+XDRV:", + TCORE_AT_SINGLELINE, + _on_response_modem_deregister_nvm, + NULL); + if (pending == NULL) { + err("Failed to form pending request"); + } + else if (tcore_hal_send_request(tcore_object_get_hal(co_modem), pending) + != TCORE_RETURN_SUCCESS) { + err("IUFP_REGISTER (Disable) -Unable to send AT-Command"); + } + else { + dbg("IUFP_REGISTER (Disable) -Successfully sent AT-Command"); + } + + g_free(cmd_str); +}