+/*
+ * tel-plugin-vmodem
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <glib.h>
+
+#include <tcore.h>
+#include <server.h>
+#include <plugin.h>
+#include <storage.h>
+#include <core_object.h>
+#include <hal.h>
+#include <at.h>
+
+#include "config.h"
+
+#define AT_MODEM_PLUGIN_NAME "atmodem-plugin.so"
+
+/* Maximum Core objects per Logical HAL (indirectly per Channel) */
+#define MAX_CO_PER_CHANNEL 2
+
+/* CP States */
+#define AT_CPAS_RESULT_READY 0
+#define AT_CPAS_RESULT_UNAVAIL 1
+#define AT_CPAS_RESULT_UNKNOWN 2
+#define AT_CPAS_RESULT_RINGING 3
+#define AT_CPAS_RESULT_CALL_PROGRESS 4
+#define AT_CPAS_RESULT_ASLEEP 5
+
+typedef struct {
+ guint type;
+ gchar *name;
+} VmodemSupportedCo;
+
+/*
+ * List of supported Core Object types
+ */
+static VmodemSupportedCo supported_modules[] = {
+ {CORE_OBJECT_TYPE_MODEM, "Modem"},
+ {CORE_OBJECT_TYPE_NETWORK, "Network"},
+ {CORE_OBJECT_TYPE_CALL, "Call"},
+ {CORE_OBJECT_TYPE_SIM, "Sim"},
+ {CORE_OBJECT_TYPE_SMS, "Sms"},
+ {CORE_OBJECT_TYPE_SS, "SS"},
+ {CORE_OBJECT_TYPE_PS, "PS"},
+ {0, ""},
+};
+
+static gboolean __check_cp_poweron(TcoreHal *hal);
+
+static void __assign_objects_to_hal(TcoreHal *hal)
+{
+ TcorePlugin *plugin;
+ gboolean ret;
+ guint i = 0;
+
+ plugin = tcore_hal_ref_plugin(hal);
+
+ while (supported_modules[i].type != 0) {
+ /* Add Core Object type for specific 'hal' */
+ ret = tcore_server_add_cp_mapping_tbl_entry(plugin,
+ supported_modules[i].type, hal);
+ if (ret == TRUE) {
+ dbg("Core Object Type: [0x%x] - Success",
+ supported_modules[i].name);
+ } else {
+ err("Core Object Type: [0x%x] - Fail",
+ supported_modules[i].name);
+ }
+
+ i++;
+ };
+}
+
+static void __deassign_objects_from_hal(TcoreHal *hal)
+{
+ TcorePlugin *plugin;
+
+ plugin = tcore_hal_ref_plugin(hal);
+
+ /* Remove mapping table entry */
+ tcore_server_remove_cp_mapping_tbl_entry(plugin, hal);
+}
+
+static gboolean __load_modem_plugin(gpointer data)
+{
+ TcoreHal *hal = (TcoreHal *)data;
+ TcorePlugin *plugin;
+
+ dbg("Entry");
+
+ if (hal == NULL) {
+ err("hal is NULL");
+ return FALSE;
+ }
+
+ plugin = tcore_hal_ref_plugin(hal);
+
+ /* Load Modem Plug-in */
+ if (tcore_server_load_modem_plugin(tcore_plugin_ref_server(plugin),
+ plugin, AT_MODEM_PLUGIN_NAME) != TEL_RETURN_SUCCESS) {
+ err("Load Modem Plug-in - [FAIL]");
+
+ /* Clean-up */
+ __deassign_objects_from_hal(hal);
+
+ goto EXIT;
+ } else {
+ dbg("Load Modem Plug-in - [SUCCESS]");
+ }
+
+ return TRUE;
+
+EXIT:
+ /* TODO: Handle Deregister */
+
+ return FALSE;
+}
+
+static void __on_confirmation_send_message(TcorePending *p,
+ TelReturn send_status, void *user_data)
+{
+ dbg("Message send confirmation - [%s]",
+ ((send_status != TEL_RETURN_SUCCESS) ? "FAIL" : "OK"));
+}
+
+static void __on_timeout_check_cp_poweron(TcorePending *p, void *user_data)
+{
+ TcoreHal *hal = user_data;
+ guint data_len = 0;
+ char *data = "AT+CPAS";
+
+ data_len = sizeof(data);
+
+ dbg("Resending Command: [%s] Command Length: [%d]", data, data_len);
+
+ /*
+ * Retransmit 1st AT command (AT+CPAS) directly via HAL without disturbing
+ * pending queue.
+ * HAL was passed as user_data, re-using it
+ */
+ tcore_hal_send_data(hal, data_len, (void *)data);
+}
+
+static void __on_response_check_cp_poweron(TcorePending *pending,
+ guint data_len, const void *data, void *user_data)
+{
+ const TcoreAtResponse *resp = data;
+ TcoreHal *hal = user_data;
+
+ GSList *tokens = NULL;
+ const char *line;
+ gboolean bpoweron = FALSE;
+ int response = 0;
+
+ if (resp && resp->success) {
+ dbg("Check CP POWER - [OK]");
+
+ /* Parse AT Response */
+ if (resp->lines) {
+ dbg("Check CP POWER - [OK]");
+ line = (const char *) resp->lines->data;
+ dbg("line: %s", line);
+ tokens = tcore_at_tok_new(line);
+ dbg("tokens: %p", tokens);
+ if (g_slist_length(tokens) != 1) {
+ err("Invalid message");
+ goto ERROR;
+ }
+
+ dbg("Check CP POWER - [OK]");
+
+ response = atoi(g_slist_nth_data(tokens, 0));
+ dbg("CPAS State: [%d]", response);
+
+ switch (response) {
+ case AT_CPAS_RESULT_READY:
+ case AT_CPAS_RESULT_RINGING:
+ case AT_CPAS_RESULT_CALL_PROGRESS:
+ case AT_CPAS_RESULT_ASLEEP:
+ dbg("CP Power ON!!!");
+ bpoweron = TRUE;
+ break;
+
+ case AT_CPAS_RESULT_UNAVAIL:
+ case AT_CPAS_RESULT_UNKNOWN:
+ default:
+ err("Value is Unvailable/Unknown - but CP responded - proceed with Power ON!!!");
+ bpoweron = TRUE;
+ break;
+ }
+ }
+ else {
+ err("Check CP POWER - [NOK] - lines NULL");
+ }
+ } else {
+ err("Check CP POWER - [NOK]");
+ }
+
+ERROR:
+ /* Free tokens */
+ tcore_at_tok_free(tokens);
+
+ if (bpoweron == TRUE) {
+ dbg("CP Power ON received");
+
+ /* Load Modem Plug-in */
+ if(__load_modem_plugin(hal) == FALSE) {
+ /* TODO: Handle Deregistration */
+ }
+ else {
+ dbg("Modem Plug-in loaded successfully");
+ }
+ } else {
+ err("CP is not ready, send CPAS again");
+ __check_cp_poweron(hal);
+ }
+}
+
+static gboolean __check_cp_poweron(TcoreHal *hal)
+{
+ TcoreAtRequest *at_req;
+ TcorePending *pending = NULL;
+
+ /* Create Pending request */
+ pending = tcore_pending_new(NULL, 0);
+
+ /* Create AT Request */
+ at_req = tcore_at_request_new("AT+CPAS",
+ "+CPAS:", TCORE_AT_COMMAND_TYPE_SINGLELINE);
+
+ dbg("AT-Command: [%s] Prefix(if any): [%s] Command length: [%d]",
+ at_req->cmd, at_req->prefix, strlen(at_req->cmd));
+
+ tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
+
+ /* Set timeout value and timeout callback */
+ tcore_pending_set_timeout(pending, 10);
+ tcore_pending_set_timeout_callback(pending,
+ __on_timeout_check_cp_poweron, hal);
+
+ /* Set request data and register Response and Send callbacks */
+ tcore_pending_set_request_data(pending, 0, at_req);
+ tcore_pending_set_response_callback(pending,
+ __on_response_check_cp_poweron, hal);
+ tcore_pending_set_send_callback(pending,
+ __on_confirmation_send_message, NULL);
+
+ /* Send command to CP */
+ if (tcore_hal_send_request(hal, pending) != TEL_RETURN_SUCCESS) {
+ err("Failed to send CPAS");
+
+ /* Free resource */
+ tcore_at_request_free(at_req);
+ tcore_pending_free(pending);
+
+ return FALSE;
+ }
+
+ dbg("Successfully sent CPAS");
+ return TRUE;
+}
+
+void vmodem_config_check_cp_power(TcoreHal *hal)
+{
+ gboolean ret;
+ dbg("Entry");
+
+ tcore_check_return(hal != NULL);
+
+ ret = __check_cp_poweron(hal);
+ if (ret == TRUE) {
+ dbg("Successfully sent check CP Power ON command");
+
+ /* Add Core Objects list to HAL */
+ __assign_objects_to_hal(hal);
+ } else {
+ err("Failed to send check CP Power ON command");
+ /* TODO: Handle Deregister */
+ }
+}