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.
36 #include "vdpram_dump.h"
38 #define VMODEM_HAL_NAME "vmodem"
40 #define DEVICE_NAME_LEN_MAX 16
41 #define DEVICE_NAME_PREFIX "pdp"
43 #define BUF_LEN_MAX 512
45 #define AT_CP_POWER_ON_TIMEOUT 500
47 static guint __vmodem_reencode_mt_sms(gchar *mt_sms, guint mt_sms_len)
49 #define VMODEM_CR 0x0D
50 #define VMODEM_LF 0x0A
51 #define VMODEM_COLON 0x3A
53 gchar sms_buf[BUF_LEN_MAX] = {0, };
54 guint sca_len, pdu_len, tpdu_len;
59 for (i = 0; i < mt_sms_len; i++) {
60 if ((mt_sms[i] == VMODEM_CR)
61 && (mt_sms[i+1] == VMODEM_LF)) {
62 sms_buf[i] = mt_sms[i];
64 sms_buf[i] = mt_sms[i];
68 else if (mt_sms[i] == VMODEM_COLON)
72 sms_buf[i] = mt_sms[i];
75 dbg("SCA length: [%d] TPDU length offset: [%d]", sca_len, tpdu_len_ptr);
77 pdu_len = (mt_sms_len-i);
78 tpdu_len = pdu_len - (sca_len+1);
79 dbg("PDU length: [%d] Actual TPDU Length: [%d]", pdu_len, tpdu_len);
81 tcore_util_byte_to_hex(&mt_sms[i], &sms_buf[i], pdu_len);
82 dbg("MT SMS: [%s]", sms_buf);
84 /* Append <CR> & <LF> */
86 sms_buf[i++] = VMODEM_CR;
87 sms_buf[i++] = VMODEM_LF;
89 /* Update actual TPDU length */
90 data = (tpdu_len/10) + '0';
91 sms_buf[tpdu_len_ptr] = data;
94 data = (tpdu_len%10) + '0';
95 sms_buf[tpdu_len_ptr] = data;
97 tcore_util_hex_dump(" ", (gint)i, sms_buf);
102 * 'data_len' is not accessed hence it need not be updated.
104 g_strlcpy(mt_sms, sms_buf, i+1);
105 dbg("Encoded MT SMS: [%d][%s]", i, mt_sms);
110 static guint __register_gio_watch(TcoreHal *h, int fd, void *callback)
112 GIOChannel *channel = NULL;
115 dbg("Register to Watch list - fd: [%d]", fd);
117 if ((fd < 0) || (callback == NULL))
120 channel = g_io_channel_unix_new(fd);
121 source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
122 g_io_channel_unref(channel);
128 static void __deregister_gio_watch(guint watch_id)
130 dbg("Deregister Watch ID: [%d]", watch_id);
133 g_source_remove(watch_id);
136 static TcoreHookReturn __on_hal_send(TcoreHal *hal,
137 guint data_len, void *data, void *user_data)
139 /* Dumping Send (Write) data */
140 vdpram_hex_dump(TRUE, data_len, data);
142 return TCORE_HOOK_RETURN_CONTINUE;
145 static void __on_hal_recv(TcoreHal *hal,
146 guint data_len, const void *data, void *user_data)
148 /* Dumping Receive (Read) data */
149 vdpram_hex_dump(FALSE, data_len, (void *)data);
152 static gboolean __modem_power(TcoreHal *hal, gboolean enable)
154 CustomData *user_data;
156 user_data = tcore_hal_ref_user_data(hal);
157 if (user_data == NULL) {
158 err("User data is NULL");
162 if (enable == TRUE) { /* POWER ON */
163 if (FALSE == vdpram_poweron(user_data->vdpram_fd)) {
164 err("Power ON - [FAIL]");
168 /* Set Power State - ON */
169 tcore_hal_set_power_state(hal, TRUE);
170 } else { /* POWER OFF */
171 if (vdpram_poweroff(user_data->vdpram_fd) == FALSE) {
172 err("Power OFF - [FAIL]");
176 /* Set Power state - OFF */
177 tcore_hal_set_power_state(hal, FALSE);
183 static gboolean __on_recv_vdpram_message(GIOChannel *channel,
184 GIOCondition condition, gpointer data)
186 TcoreHal *hal = data;
188 char buf[BUF_LEN_MAX] = {0, };
192 custom = tcore_hal_ref_user_data(hal);
193 memset(buf, 0x0, BUF_LEN_MAX);
195 /* Read from Device */
196 n = vdpram_tty_read(custom->vdpram_fd, buf, BUF_LEN_MAX);
198 err("Read error - Data received: [%d]", n);
201 dbg("DPRAM Receive - Data length: [%d]", n);
203 /* Emit receive callback */
206 msg("\n---------- [RECV] Length of received data: [%d] ----------\n", n);
208 /* Emit response callback */
209 tcore_hal_emit_recv_callback(hal, n, buf);
212 * This is to ensure that the received MT SMS (+CMT:) is
213 * encoded according to 3GPP standard
215 if (buf[0] == 0x2B && buf[1] == 0x43 && buf[2] == 0x4D
216 && buf[3] == 0x54 && buf[4] == 0x3A) {
217 dbg("Received - [MT SMS]");
218 n = __vmodem_reencode_mt_sms((gchar *)buf, n);
221 /* Dispatch received data to response handler */
222 ret = tcore_hal_dispatch_response_data(hal, 0, n, buf);
223 msg("\n---------- [RECV FINISH] Receive processing: [%d] ----------\n", ret);
228 static gboolean __power_on(gpointer data)
230 CustomData *user_data;
231 TcoreHal *hal = (TcoreHal*)data;
235 user_data = tcore_hal_ref_user_data(hal);
236 tcore_check_return_value_assert(user_data != NULL, TRUE);
239 * Open DPRAM device: Create and Open interface to CP
241 user_data->vdpram_fd = vdpram_open();
242 if (user_data->vdpram_fd < 1) {
243 TcorePlugin *plugin = tcore_hal_ref_plugin(hal);
244 Server *server = tcore_plugin_ref_server(plugin);
246 err("Failed to Create/Open CP interface");
248 /* Notify server a modem error occured */
249 tcore_server_send_server_notification(server,
250 TCORE_SERVER_NOTIFICATION_MODEM_ERR, 0, NULL);
254 dbg("Created AP-CP interface");
256 /* Register to Watch llist */
257 user_data->vdpram_watch_id = __register_gio_watch(hal,
258 user_data->vdpram_fd, __on_recv_vdpram_message);
259 dbg("fd: [%d] Watch ID: [%d]", user_data->vdpram_fd, user_data->vdpram_watch_id);
261 /* Power ON VDPRAM device */
262 if (__modem_power(hal, TRUE)) {
263 dbg("Power ON - [SUCCESS]");
265 err("Power ON - [FAIL]");
269 /* CP is ONLINE, send AT+CPAS */
270 vmodem_config_check_cp_power(hal);
272 /* To stop the cycle need to return FALSE */
276 /* TODO: Handle Deregister */
278 /* To stop the cycle need to return FALSE */
283 static TelReturn _hal_power(TcoreHal *hal, gboolean flag)
285 return __modem_power(hal, flag);
288 static TelReturn _hal_send(TcoreHal *hal,
289 guint data_len, void *data)
291 CustomData *user_data;
294 if (tcore_hal_get_power_state(hal) == FALSE) {
295 err("HAL Power state - OFF");
296 return TEL_RETURN_FAILURE;
299 user_data = tcore_hal_ref_user_data(hal);
300 if (user_data == NULL) {
301 err("User data is NULL");
302 return TEL_RETURN_FAILURE;
305 ret = vdpram_tty_write(user_data->vdpram_fd, data, data_len);
308 return TEL_RETURN_FAILURE;
310 dbg("vdpram_tty_write success ret=%d (fd=%d, len=%d)",
311 ret, user_data->vdpram_fd, data_len);
313 return TEL_RETURN_SUCCESS;
316 static TelReturn _hal_setup_netif(CoreObject *co,
317 TcoreHalSetupNetifCallback func, void *user_data,
318 guint cid, gboolean enable)
320 char ifname[DEVICE_NAME_LEN_MAX];
324 char *control = NULL;
327 err("Context ID: [%d]", cid);
328 return TEL_RETURN_INVALID_PARAMETER;
331 if (enable == TRUE) {
332 dbg("ACTIVATE - Context ID: [%d]", cid);
333 control = "/sys/class/net/svnet0/pdp/activate";
335 dbg("DEACTIVATE - Context ID: [%d]", cid);
336 control = "/sys/class/net/svnet0/pdp/deactivate";
339 fd = open(control, O_WRONLY);
341 err("Failed to Open interface: [%s]", control);
343 /* Invoke callback function */
345 func(co, -1, NULL, user_data);
347 return TEL_RETURN_FAILURE;
350 /* Context ID needs to be written to the Device */
351 snprintf(buf, sizeof(buf), "%d", cid);
352 size = write(fd, buf, strlen(buf));
358 snprintf(ifname, DEVICE_NAME_LEN_MAX, "%s%d", DEVICE_NAME_PREFIX, (cid - 1));
359 dbg("Interface Name: [%s]", ifname);
361 /* Invoke callback function */
363 func(co, 0, ifname, user_data);
365 return TEL_RETURN_SUCCESS;
369 static TcoreHalOperations hal_ops = {
372 .setup_netif = _hal_setup_netif,
375 static gboolean on_load()
382 static gboolean on_init(TcorePlugin *plugin)
388 tcore_check_return_value_assert(plugin != NULL, FALSE);
390 /* Custom data for Modem Interface Plug-in */
391 data = tcore_malloc0(sizeof(CustomData));
392 dbg("Created custom data memory");
394 /* Create Physical HAL */
395 hal = tcore_hal_new(plugin, VMODEM_HAL_NAME,
396 &hal_ops, TCORE_HAL_MODE_AT);
398 err("Failed to Create Physical HAL");
402 dbg("HAL [0x%x] created", hal);
404 /* Set HAL as Modem Interface Plug-in's User data */
405 tcore_plugin_link_user_data(plugin, hal);
407 /* Link Custom data to HAL's 'user_data' */
408 tcore_hal_link_user_data(hal, data);
410 /* Add callbacks for Send/Receive Hooks */
411 tcore_hal_add_send_hook(hal, __on_hal_send, NULL);
412 tcore_hal_add_recv_callback(hal, __on_hal_recv, NULL);
413 dbg("Added Send hook and Receive callback");
415 /* Set HAL state to Power OFF (FALSE) */
416 (void)tcore_hal_set_power_state(hal, FALSE);
417 dbg("HAL Power State: Power OFF");
419 /* Resgister to Server */
420 if (tcore_server_register_modem(tcore_plugin_ref_server(plugin),
422 err("Registration Failed");
428 dbg("Registered from Server");
430 /* Check CP Power ON */
431 g_timeout_add_full(G_PRIORITY_HIGH,
432 AT_CP_POWER_ON_TIMEOUT, __power_on, hal, NULL);
437 static void on_unload(TcorePlugin *plugin)
440 CustomData *user_data;
443 tcore_check_return_assert(plugin != NULL);
445 /* Unload Modem Plug-in */
446 tcore_server_unload_modem_plugin(tcore_plugin_ref_server(plugin), plugin);
448 /* Unregister Modem Interface Plug-in from Server */
449 tcore_server_unregister_modem(tcore_plugin_ref_server(plugin), plugin);
450 dbg("Unregistered from Server");
453 hal = tcore_plugin_ref_user_data(plugin);
459 user_data = tcore_hal_ref_user_data(hal);
460 if (user_data == NULL)
463 /* Deregister from Watch list */
464 __deregister_gio_watch(user_data->vdpram_watch_id);
465 dbg("Deregistered Watch ID");
467 /* Close VDPRAM device */
468 (void)vdpram_close(user_data->vdpram_fd);
469 dbg("Closed VDPRAM device");
471 /* Free custom data */
478 dbg("Unloaded MODEM Interface Plug-in");
481 /* VMODEM (Modem Interface Plug-in) descriptor */
482 EXPORT_API struct tcore_plugin_define_desc plugin_define_desc = {
484 .priority = TCORE_PLUGIN_PRIORITY_HIGH,