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>
44 #define ID_RESERVED_AT 0x0229
46 #define MAX_VERSION_LEN 32
47 #define TAPI_MISC_ME_SN_LEN_MAX 32
48 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX 32
49 #define TAPI_MISC_MODEL_ID_LEN_MAX 17
50 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX 17
52 #define CPAS_RES_READY 0
53 #define CPAS_RES_UNAVAIL 1
54 #define CPAS_RES_UNKNOWN 2
55 #define CPAS_RES_RINGING 3
56 #define CPAS_RES_CALL_PROGRESS 4
57 #define CPAS_RES_ASLEEP 5
67 CP_STATE_NV_REBUILDING,
72 TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
73 TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
74 TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
75 TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
76 } TelMiscSNIndexType_t;
79 TelMiscSNIndexType_t sn_index; /**< serial number index */
80 int sn_len; /**< Length */
81 unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
82 } TelMiscSNInformation;
85 * Mobile Equipment Version Information
88 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 */
89 unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
90 unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
91 unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
92 unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
93 unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
94 unsigned char prl_nam_num; /**< number of PRL NAM fields */
95 unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< prl version (only for CDMA), null termination */
96 unsigned char eri_nam_num; /**< number of PRL NAM fields */
97 unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< eri version (only for CDMA), null termination */
98 } TelMiscVersionInformation;
101 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);
102 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data);
103 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data);
104 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
106 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
108 dbg("on_confirmation_modem_message_send - msg out from queue.\n");
110 if (result == FALSE) {
118 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
120 const TcoreATResponse *resp = data;
122 if (resp->success > 0) {
123 dbg("RESPONSE OK proactive command enabled");
125 dbg("RESPONSE NOK proactive command disabled");
129 static void on_response_network_registration(TcorePending *p, int data_len, const void *data, void *user_data)
131 const TcoreATResponse *resp = data;
133 if (resp->success > 0) {
134 dbg("registration attempt OK");
136 dbg("registration attempt failed");
140 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)
142 TcoreATRequest *req = NULL;
143 TcoreHal *hal = NULL;
144 TcorePending *pending = NULL;
147 hal = tcore_object_get_hal(co);
150 pending = tcore_pending_new(co, 0);
152 dbg("Pending is NULL");
153 req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
155 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
157 tcore_pending_set_request_data(pending, 0, req);
158 tcore_pending_set_response_callback(pending, callback, NULL);
159 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
160 ret = tcore_hal_send_request(hal, pending);
163 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
168 o = tcore_pending_ref_core_object(p);
169 h = tcore_object_get_hal(o);
171 dbg("modem power off");
173 tcore_hal_set_power_state(h, FALSE);
176 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
178 CoreObject *o = NULL;
179 UserRequest *ur = NULL;
180 const TcoreATResponse *ATresp = data;
181 GSList *tokens = NULL;
182 const char *line = NULL;
183 struct tresp_modem_set_flightmode res = {0};
185 struct tnoti_modem_flight_mode modem_flight_mode = {0};
186 const struct treq_modem_set_flightmode *req_data = NULL;
188 o = tcore_pending_ref_core_object(p);
190 if (ATresp->success > 0) {
191 dbg("RESPONSE OK - flight mode operation finished");
192 res.result = TCORE_RETURN_SUCCESS;
195 line = (const char *) ATresp->final_response;
196 tokens = tcore_at_tok_new(line);
198 if (g_slist_length(tokens) < 1) {
199 dbg("err cause not specified or string corrupted");
200 res.result = TCORE_RETURN_3GPP_ERROR;
202 response = atoi(g_slist_nth_data(tokens, 0));
203 /* TODO: CMEE error mapping is required. */
204 res.result = TCORE_RETURN_3GPP_ERROR;
208 ur = tcore_pending_ref_user_request(p);
210 dbg("No user request. Internal request created during boot-up sequence");
212 if (ATresp->success > 0) {
213 modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
214 dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
216 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
217 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
220 dbg("Sending response for Flight mode operation");
222 req_data = tcore_user_request_ref_data(ur, NULL);
224 if (TCORE_RETURN_SUCCESS == res.result) {
225 if (TRUE == req_data->enable)
233 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
235 if (req_data->enable == 0) {
236 dbg("Flight mode is disabled, trigger COPS to register on network");
237 /* Trigger Network registration (for the moment automatic) */
238 prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
242 tcore_at_tok_free(tokens);
245 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
247 const TcoreATResponse *resp = data;
248 TcorePlugin *plugin = NULL;
249 struct tresp_modem_get_imei res;
250 TelMiscSNInformation *imei_property = NULL;
251 UserRequest *ur = NULL;
252 GSList *tokens = NULL;
256 memset(&res, 0, sizeof(struct tresp_modem_get_imei));
258 if (resp->success > 0) {
261 line = (const char *) resp->lines->data;
262 tokens = tcore_at_tok_new(line);
263 if (g_slist_length(tokens) != 1) {
264 msg("invalid message");
268 res.result = TCORE_RETURN_SUCCESS;
269 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
271 dbg("imei = [%s]", res.imei);
273 plugin = tcore_pending_ref_plugin(p);
274 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
276 imei_property->sn_index = TAPI_MISC_ME_IMEI;
277 imei_property->sn_len = strlen(res.imei);
278 memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
283 line = (const char *) resp->lines->data;
284 tokens = tcore_at_tok_new(line);
288 if (g_slist_length(tokens) < 1) {
289 dbg("err cause not specified or string corrupted");
290 res.result = TCORE_RETURN_3GPP_ERROR;
292 response = atoi(g_slist_nth_data(tokens, 0));
293 /* TODO: CMEE error mapping is required. */
294 res.result = TCORE_RETURN_3GPP_ERROR;
298 ur = tcore_pending_ref_user_request(p);
299 tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI,
300 sizeof(struct tresp_modem_get_imei), &res);
304 tcore_at_tok_free(tokens);
309 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
311 const TcoreATResponse *resp = data;
312 TcorePlugin *plugin = NULL;
313 struct tresp_modem_get_version res = {0};
314 TelMiscVersionInformation *vi_property = NULL;
315 TelMiscVersionInformation *vi = NULL;
316 UserRequest *ur = NULL;
317 GSList *tokens = NULL;
318 const char *line = NULL;
321 char *caldate = NULL;
327 if (resp->success > 0) {
330 line = (const char *) resp->lines->data;
331 tokens = tcore_at_tok_new(line);
332 if (g_slist_length(tokens) == 1) {
333 swver = g_slist_nth_data(tokens, 0);
334 dbg("version: sw=[%s]", swver);
335 } else if (g_slist_length(tokens) == 5) {
336 swver = g_slist_nth_data(tokens, 0);
337 hwver = g_slist_nth_data(tokens, 1);
338 caldate = g_slist_nth_data(tokens, 2);
339 pcode = g_slist_nth_data(tokens, 3);
340 id = g_slist_nth_data(tokens, 4);
342 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]",
343 swver, hwver, caldate, pcode, id);
345 msg("invalid message");
350 vi = g_try_new0(TelMiscVersionInformation, 1);
352 memcpy(vi->szSwVersion, swver, strlen(swver));
354 memcpy(vi->szHwVersion, hwver, strlen(hwver));
356 memcpy(vi->szRfCalDate, caldate, strlen(caldate));
358 memcpy(vi->szProductCode, pcode, strlen(pcode));
360 memcpy(vi->szModelId, id, strlen(id));
362 memset(&res, 0, sizeof(struct tresp_modem_get_version));
365 snprintf(res.software,
366 (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN),
371 snprintf(res.hardware,
372 (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN),
376 plugin = tcore_pending_ref_plugin(p);
377 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
378 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
383 line = (const char *) resp->lines->data;
384 tokens = tcore_at_tok_new(line);
387 memset(&res, 0, sizeof(struct tresp_modem_get_version));
390 if (g_slist_length(tokens) < 1) {
391 dbg("err cause not specified or string corrupted");
392 res.result = TCORE_RETURN_3GPP_ERROR;
394 response = atoi(g_slist_nth_data(tokens, 0));
395 /* TODO: CMEE error mapping is required. */
396 res.result = TCORE_RETURN_3GPP_ERROR;
400 ur = tcore_pending_ref_user_request(p);
401 tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION,
402 sizeof(struct tresp_modem_get_version), &res);
406 tcore_at_tok_free(tokens);
411 static enum tcore_hook_return on_hook_sim_status(Server *s,
412 CoreObject *source, enum tcore_notification_command command,
413 unsigned int data_len, void *data, void *user_data)
416 const struct tnoti_sim_status *noti_sim_status;
418 CoreObject *co_network;
420 plugin = tcore_object_ref_plugin(source);
421 co_sat = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAT);
423 return TCORE_HOOK_RETURN_CONTINUE;
425 co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
426 if (co_network == NULL)
427 return TCORE_HOOK_RETURN_CONTINUE;
429 dbg("Get SIM status");
430 noti_sim_status = data;
431 if (noti_sim_status == NULL)
432 return TCORE_HOOK_RETURN_CONTINUE;
434 /* If SIM is initialized, Enable STK and and attach to Network */
435 dbg("SIM Status: [%d]", noti_sim_status->sim_status);
436 if (noti_sim_status->sim_status == SIM_STATUS_INIT_COMPLETED) {
437 dbg("SIM ready for attach!!! Enable STK and attach to Network");
439 /* Sending AT+CFUN=6 */
440 prepare_and_send_pending_request(co_sat, "AT+CFUN=6", NULL,
441 TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
443 /* Sending AT+COPS */
444 prepare_and_send_pending_request(co_network, "AT+COPS=0", NULL,
445 TCORE_AT_NO_RESULT, on_response_network_registration);
448 return TCORE_HOOK_RETURN_CONTINUE;
451 gboolean modem_power_on(TcorePlugin *p)
453 CoreObject *co_modem = NULL;
454 struct treq_modem_set_flightmode flight_mode_set = {0};
455 struct tnoti_modem_power modem_power = {0};
456 Storage *strg = NULL;
458 co_modem = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_MODEM);
459 if (co_modem == NULL) {
460 err("Modem Core object is NULL");
464 /* Set Modem Power State to 'ON' */
465 tcore_modem_set_powered(co_modem, TRUE);
467 /* Get Flight mode from VCONFKEY */
468 strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
469 flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
471 /* Set Flight mode as per AP settings */
472 if (flight_mode_set.enable) { /* Radio OFF */
473 prepare_and_send_pending_request(co_modem, "AT+CFUN=4", NULL,
474 TCORE_AT_NO_RESULT, on_response_set_flight_mode);
476 /* Set Flight mode TRUE */
477 tcore_modem_set_flight_mode_state(co_modem, TRUE);
478 } else { /* Radio ON */
479 prepare_and_send_pending_request(co_modem, "AT+CFUN=1", NULL,
480 TCORE_AT_NO_RESULT, on_response_set_flight_mode);
482 /* Set Flight mode FALSE */
483 tcore_modem_set_flight_mode_state(co_modem, FALSE);
487 prepare_and_send_pending_request(co_modem, "AT+CGSN", NULL,
488 TCORE_AT_NUMERIC, on_response_imei);
490 /* Get Version Number */
491 prepare_and_send_pending_request(co_modem, "AT+CGMR", NULL,
492 TCORE_AT_SINGLELINE, on_response_version);
494 /* Send Notification to TAPI - MODEM_POWER */
495 modem_power.state = MODEM_STATE_ONLINE;
497 dbg("Sending notification - Modem Power state: [ONLINE]");
498 tcore_server_send_notification(tcore_plugin_ref_server(p),
499 co_modem, TNOTI_MODEM_POWER, sizeof(modem_power), &modem_power);
504 static TReturn power_off(CoreObject *o, UserRequest *ur)
506 TcoreHal *hal = NULL;
507 TcoreATRequest *req = NULL;
508 TcorePending *pending = NULL;
510 hal = tcore_object_get_hal(o);
511 pending = tcore_pending_new(o, 0);
513 req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
515 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
516 req->cmd, req->prefix, strlen(req->cmd));
518 tcore_pending_set_request_data(pending, 0, req);
519 tcore_pending_set_response_callback(pending, on_response_power_off, hal);
520 tcore_pending_link_user_request(pending, ur);
521 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
523 tcore_hal_send_request(hal, pending);
525 return TCORE_RETURN_SUCCESS;
528 static TReturn get_imei(CoreObject *o, UserRequest *ur)
532 TcorePending *pending = NULL;
534 hal = tcore_object_get_hal(o);
535 if (FALSE == tcore_hal_get_power_state(hal)) {
536 dbg("cp not ready/n");
537 return TCORE_RETURN_ENOSYS;
539 pending = tcore_pending_new(o, 0);
541 req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
543 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
544 req->cmd, req->prefix, strlen(req->cmd));
546 tcore_pending_set_request_data(pending, 0, req);
547 tcore_pending_set_response_callback(pending, on_response_imei, hal);
548 tcore_pending_link_user_request(pending, ur);
549 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
551 return tcore_hal_send_request(hal, pending);
555 static TReturn get_version(CoreObject *o, UserRequest *ur)
559 TcorePending *pending = NULL;
561 hal = tcore_object_get_hal(o);
562 if (FALSE == tcore_hal_get_power_state(hal)) {
563 dbg("cp not ready/n");
564 return TCORE_RETURN_ENOSYS;
566 pending = tcore_pending_new(o, 0);
568 req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
570 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
571 req->cmd, req->prefix, strlen(req->cmd));
573 tcore_pending_set_request_data(pending, 0, req);
574 tcore_pending_set_response_callback(pending, on_response_version, hal);
575 tcore_pending_link_user_request(pending, ur);
576 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
578 return tcore_hal_send_request(hal, pending);
581 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
583 TcoreHal *hal = NULL;
584 TcoreATRequest *req = NULL;
585 TcorePending *pending = NULL;
586 const struct treq_modem_set_flightmode *req_data = NULL;
587 char *cmd_str = NULL;
589 hal = tcore_object_get_hal(o);
590 if (FALSE == tcore_hal_get_power_state(hal)) {
591 dbg("cp not ready/n");
592 return TCORE_RETURN_ENOSYS;
594 pending = tcore_pending_new(o, 0);
596 req_data = tcore_user_request_ref_data(ur, NULL);
598 if (req_data->enable) {
599 dbg("Flight mode on/n");
600 cmd_str = g_strdup("AT+CFUN=4");
602 dbg("Flight mode off/n");
603 cmd_str = g_strdup("AT+CFUN=1");
606 req = tcore_at_request_new((const char *)cmd_str, NULL, TCORE_AT_NO_RESULT);
609 dbg("Command: [%s], Prefix(if any): [%s], Command Length: [%d]",
610 req->cmd, req->prefix, strlen(req->cmd));
612 tcore_pending_set_request_data(pending, 0, req);
613 tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
614 tcore_pending_link_user_request(pending, ur);
615 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
617 return tcore_hal_send_request(hal, pending);
621 static struct tcore_modem_operations modem_ops = {
623 .power_off = power_off,
625 .set_flight_mode = set_flight_mode,
626 .get_imei = get_imei,
627 .get_version = get_version,
629 .dun_pin_ctrl = NULL,
632 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
634 TelMiscVersionInformation *vi_property;
635 TelMiscSNInformation *imei_property;
636 TelMiscSNInformation *sn_property;
640 tcore_modem_override_ops(co_modem, &modem_ops);
642 vi_property = g_try_new0(TelMiscVersionInformation, 1);
643 tcore_plugin_link_property(cp, "VERSION", vi_property);
645 imei_property = g_try_new0(TelMiscSNInformation, 1);
646 tcore_plugin_link_property(cp, "IMEI", imei_property);
648 sn_property = g_try_new0(TelMiscSNInformation, 1);
649 tcore_plugin_link_property(cp, "SN", sn_property);
651 tcore_server_add_notification_hook(tcore_plugin_ref_server(cp),
652 TNOTI_SIM_STATUS, on_hook_sim_status, NULL);
658 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
660 TelMiscVersionInformation *vi_property;
661 TelMiscSNInformation *imei_property;
662 TelMiscSNInformation *sn_property;
663 TcorePlugin *plugin = tcore_object_ref_plugin(co_modem);
665 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
668 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
669 g_free(imei_property);
671 sn_property = tcore_plugin_ref_property(plugin, "SN");