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); // from Kernel
103 void on_response_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data);
104 void on_response_last_bootup_subscription(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);
107 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
109 dbg("on_confirmation_modem_message_send - msg out from queue.\n");
111 if (result == FALSE) {
119 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
121 const TcoreATResponse *resp = data;
123 if (resp->success > 0) {
124 dbg("RESPONSE OK proactive command enabled");
126 dbg("RESPONSE NOK proactive command disabled");
130 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)
132 TcoreATRequest *req = NULL;
133 TcoreHal *hal = NULL;
134 TcorePending *pending = NULL;
137 hal = tcore_object_get_hal(co);
140 pending = tcore_pending_new(co, 0);
142 dbg("Pending is NULL");
143 req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
145 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
147 tcore_pending_set_request_data(pending, 0, req);
148 tcore_pending_set_response_callback(pending, callback, NULL);
149 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
150 ret = tcore_hal_send_request(hal, pending);
153 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
158 o = tcore_pending_ref_core_object(p);
159 h = tcore_object_get_hal(o);
161 dbg("modem power off");
163 tcore_hal_set_power_state(h, FALSE);
166 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
168 CoreObject *o = NULL;
169 UserRequest *ur = NULL;
170 const TcoreATResponse *ATresp = data;
171 GSList *tokens = NULL;
172 const char *line = NULL;
173 struct tresp_modem_set_flightmode res = {0};
175 struct tnoti_modem_flight_mode modem_flight_mode = {0};
176 const struct treq_modem_set_flightmode *req_data = NULL;
178 o = tcore_pending_ref_core_object(p);
180 if (ATresp->success > 0) {
181 dbg("RESPONSE OK - flight mode operation finished");
182 res.result = TCORE_RETURN_SUCCESS;
185 line = (const char *) ATresp->final_response;
186 tokens = tcore_at_tok_new(line);
188 if (g_slist_length(tokens) < 1) {
189 dbg("err cause not specified or string corrupted");
190 res.result = TCORE_RETURN_3GPP_ERROR;
192 response = atoi(g_slist_nth_data(tokens, 0));
193 /* TODO: CMEE error mapping is required. */
194 res.result = TCORE_RETURN_3GPP_ERROR;
198 ur = tcore_pending_ref_user_request(p);
200 dbg("No user request. Internal request created during boot-up sequence");
202 if (ATresp->success > 0) {
203 modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
204 dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
206 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
207 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
210 dbg("Sending response for Flight mode operation");
212 req_data = tcore_user_request_ref_data(ur, NULL);
214 if (TCORE_RETURN_SUCCESS == res.result) {
215 if (TRUE == req_data->enable)
223 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
225 if (req_data->enable == 0) {
226 dbg("Flight mode is disabled, trigger COPS to register on network");
227 /* Trigger Network registration (for the moment automatic) */
228 prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
232 tcore_at_tok_free(tokens);
235 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
237 const TcoreATResponse *resp = data;
238 TcorePlugin *plugin = NULL;
239 struct tresp_modem_get_imei res;
240 TelMiscSNInformation *imei_property = NULL;
241 UserRequest *ur = NULL;
242 GSList *tokens = NULL;
246 memset(&res, 0, sizeof(struct tresp_modem_get_imei));
248 if (resp->success > 0) {
251 line = (const char *) resp->lines->data;
252 tokens = tcore_at_tok_new(line);
253 if (g_slist_length(tokens) != 1) {
254 msg("invalid message");
258 res.result = TCORE_RETURN_SUCCESS;
259 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
261 dbg("imei = [%s]", res.imei);
263 plugin = tcore_pending_ref_plugin(p);
264 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
266 imei_property->sn_index = TAPI_MISC_ME_IMEI;
267 imei_property->sn_len = strlen(res.imei);
268 memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
273 line = (const char *) resp->lines->data;
274 tokens = tcore_at_tok_new(line);
278 if (g_slist_length(tokens) < 1) {
279 dbg("err cause not specified or string corrupted");
280 res.result = TCORE_RETURN_3GPP_ERROR;
282 response = atoi(g_slist_nth_data(tokens, 0));
283 /* TODO: CMEE error mapping is required. */
284 res.result = TCORE_RETURN_3GPP_ERROR;
288 ur = tcore_pending_ref_user_request(p);
289 tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI, sizeof(struct tresp_modem_get_imei), &res);
293 tcore_at_tok_free(tokens);
298 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
300 const TcoreATResponse *resp = data;
301 TcorePlugin *plugin = NULL;
302 struct tresp_modem_get_version res = {0};
303 TelMiscVersionInformation *vi_property = NULL;
304 TelMiscVersionInformation *vi = NULL;
305 UserRequest *ur = NULL;
306 GSList *tokens = NULL;
307 const char *line = NULL;
310 char *caldate = NULL;
316 if (resp->success > 0) {
319 line = (const char *) resp->lines->data;
320 tokens = tcore_at_tok_new(line);
321 if (g_slist_length(tokens) != 5) {
322 msg("invalid message");
327 swver = g_slist_nth_data(tokens, 0);
328 hwver = g_slist_nth_data(tokens, 1);
329 caldate = g_slist_nth_data(tokens, 2);
330 pcode = g_slist_nth_data(tokens, 3);
331 id = g_slist_nth_data(tokens, 4);
333 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]", swver, hwver, caldate, pcode, id);
335 vi = calloc(sizeof(TelMiscVersionInformation), 1);
337 memcpy(vi->szSwVersion, swver, strlen(swver));
339 memcpy(vi->szHwVersion, hwver, strlen(hwver));
341 memcpy(vi->szRfCalDate, caldate, strlen(caldate));
343 memcpy(vi->szProductCode, pcode, strlen(pcode));
345 memcpy(vi->szModelId, id, strlen(id));
347 memset(&res, 0, sizeof(struct tresp_modem_get_version));
350 snprintf(res.software, (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN), "%s", swver);
352 snprintf(res.hardware, (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN), "%s", hwver);
354 plugin = tcore_pending_ref_plugin(p);
355 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
356 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
361 line = (const char *) resp->lines->data;
362 tokens = tcore_at_tok_new(line);
365 memset(&res, 0, sizeof(struct tresp_modem_get_version));
368 if (g_slist_length(tokens) < 1) {
369 dbg("err cause not specified or string corrupted");
370 res.result = TCORE_RETURN_3GPP_ERROR;
372 response = atoi(g_slist_nth_data(tokens, 0));
373 /* TODO: CMEE error mapping is required. */
374 res.result = TCORE_RETURN_3GPP_ERROR;
378 ur = tcore_pending_ref_user_request(p);
379 tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION, sizeof(struct tresp_modem_get_version), &res);
383 tcore_at_tok_free(tokens);
388 static gboolean on_event_bootup_sim_status(CoreObject *o, const void *event_info, void *user_data)
391 GSList *lines = NULL;
395 lines = (GSList *) event_info;
396 if (1 != g_slist_length(lines)) {
397 dbg("unsolicited msg but multiple line");
400 line = (char *) (lines->data);
401 dbg("on_bootup_event_sim_status notification : %s", line);
403 tok = tcore_at_tok_new(line);
404 value = atoi(g_slist_nth_data(tok, 0));
407 dbg("SIM ready. request COPS & remove callback");
408 dbg("power on done set for proactive command receiving mode");
409 prepare_and_send_pending_request(o, "AT+CFUN=6", NULL, TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
410 prepare_and_send_pending_request(o, "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
416 tcore_at_tok_free(tok);
423 gboolean modem_power_on(TcorePlugin *p)
425 CoreObject *co_modem = NULL;
426 struct treq_modem_set_flightmode flight_mode_set = {0};
427 struct tnoti_modem_power modem_power = {0};
429 Storage *strg = NULL;
431 co_modem = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_MODEM);
433 strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
434 flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
436 h = tcore_object_get_hal(co_modem);
437 tcore_hal_set_power_state(h, TRUE);
439 /* Set Flight mode as per AP settings */
440 if (flight_mode_set.enable) { /* Radio Off */
441 prepare_and_send_pending_request(co_modem, "AT+CFUN=4", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
442 tcore_modem_set_flight_mode_state(co_modem, TRUE);
443 } else { /* Radio On */
444 prepare_and_send_pending_request(co_modem, "AT+CFUN=1", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
445 tcore_modem_set_flight_mode_state(co_modem, FALSE);
449 prepare_and_send_pending_request(co_modem, "AT+CGSN", NULL, TCORE_AT_NUMERIC, on_response_imei);
451 /* Get Version Number */
452 prepare_and_send_pending_request(co_modem, "AT+CGMR", NULL, TCORE_AT_SINGLELINE, on_response_version);
454 tcore_modem_set_powered(co_modem, TRUE);
456 modem_power.state = MODEM_STATE_ONLINE;
458 tcore_server_send_notification(tcore_plugin_ref_server(p), co_modem, TNOTI_MODEM_POWER,
459 sizeof(struct tnoti_modem_power), &modem_power);
464 static TReturn power_off(CoreObject *o, UserRequest *ur)
466 TcoreHal *hal = NULL;
467 TcoreATRequest *req = NULL;
468 TcorePending *pending = NULL;
470 hal = tcore_object_get_hal(o);
471 pending = tcore_pending_new(o, 0);
473 req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
475 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
477 tcore_pending_set_request_data(pending, 0, req);
478 tcore_pending_set_response_callback(pending, on_response_power_off, hal);
479 tcore_pending_link_user_request(pending, ur);
480 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
482 tcore_hal_send_request(hal, pending);
484 return TCORE_RETURN_SUCCESS;
487 static TReturn get_imei(CoreObject *o, UserRequest *ur)
491 TcorePending *pending = NULL;
493 hal = tcore_object_get_hal(o);
494 if (FALSE == tcore_hal_get_power_state(hal)) {
495 dbg("cp not ready/n");
496 return TCORE_RETURN_ENOSYS;
498 pending = tcore_pending_new(o, 0);
500 req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
502 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
504 tcore_pending_set_request_data(pending, 0, req);
505 tcore_pending_set_response_callback(pending, on_response_imei, hal);
506 tcore_pending_link_user_request(pending, ur);
507 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
509 tcore_hal_send_request(hal, pending);
511 return TCORE_RETURN_SUCCESS;
515 static TReturn get_version(CoreObject *o, UserRequest *ur)
519 TcorePending *pending = NULL;
521 hal = tcore_object_get_hal(o);
522 if (FALSE == tcore_hal_get_power_state(hal)) {
523 dbg("cp not ready/n");
524 return TCORE_RETURN_ENOSYS;
526 pending = tcore_pending_new(o, 0);
528 req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
530 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
532 tcore_pending_set_request_data(pending, 0, req);
533 tcore_pending_set_response_callback(pending, on_response_version, hal);
534 tcore_pending_link_user_request(pending, ur);
535 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
537 tcore_hal_send_request(hal, pending);
539 return TCORE_RETURN_SUCCESS;
542 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
544 TcoreHal *hal = NULL;
545 TcoreATRequest *req = NULL;
546 TcorePending *pending = NULL;
547 const struct treq_modem_set_flightmode *req_data = NULL;
548 char *cmd_str = NULL;
550 hal = tcore_object_get_hal(o);
551 if (FALSE == tcore_hal_get_power_state(hal)) {
552 dbg("cp not ready/n");
553 return TCORE_RETURN_ENOSYS;
555 pending = tcore_pending_new(o, 0);
557 req_data = tcore_user_request_ref_data(ur, NULL);
559 if (req_data->enable) {
560 dbg("Flight mode on/n");
561 cmd_str = g_strdup("AT+CFUN=4");
563 dbg("Flight mode off/n");
564 cmd_str = g_strdup("AT+CFUN=1");
567 req = tcore_at_request_new((const char *) cmd_str, NULL, TCORE_AT_NO_RESULT);
569 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
571 tcore_pending_set_request_data(pending, 0, req);
572 tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
573 tcore_pending_link_user_request(pending, ur);
574 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
576 tcore_hal_send_request(hal, pending);
578 return TCORE_RETURN_SUCCESS;
582 static struct tcore_modem_operations modem_ops = {
584 .power_off = power_off,
586 .set_flight_mode = set_flight_mode,
587 .get_imei = get_imei,
588 .get_version = get_version,
590 .dun_pin_ctrl = NULL,
593 gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem)
595 TelMiscVersionInformation *vi_property;
596 TelMiscSNInformation *imei_property;
597 TelMiscSNInformation *sn_property;
601 tcore_modem_override_ops(co_modem, &modem_ops);
603 vi_property = g_try_new0(TelMiscVersionInformation, 1);
604 tcore_plugin_link_property(cp, "VERSION", vi_property);
606 imei_property = g_try_new0(TelMiscSNInformation, 1);
607 tcore_plugin_link_property(cp, "IMEI", imei_property);
609 sn_property = g_try_new0(TelMiscSNInformation, 1);
610 tcore_plugin_link_property(cp, "SN", sn_property);
612 dbg("Registering for +XSIM event");
613 tcore_object_override_callback(co_modem, "+XSIM", on_event_bootup_sim_status, NULL);
620 void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem)
622 TelMiscVersionInformation *vi_property;
623 TelMiscSNInformation *imei_property;
624 TelMiscSNInformation *sn_property;
625 TcorePlugin *plugin = tcore_object_ref_plugin(co_modem);
627 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
630 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
631 g_free(imei_property);
633 sn_property = tcore_plugin_ref_property(plugin, "SN");