4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hayoon Ko <hayoon.ko@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.
28 #include <core_object.h>
38 #include "atchannel.h"
41 #define MAX_VERSION_LEN 32
42 #define TAPI_MISC_ME_SN_LEN_MAX 32
43 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX 32
44 #define TAPI_MISC_MODEL_ID_LEN_MAX 17
45 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX 17
53 CP_STATE_NV_REBUILDING,
58 enum TelMiscSNIndexType_t{
59 TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
60 TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
61 TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
62 TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
65 struct TelMiscSNInformation{
66 enum TelMiscSNIndexType_t sn_index; /**< serial number index */
67 int sn_len; /**< Length */
68 unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
72 * Mobile Equipment Version Information
74 struct TelMiscVersionInformation{
75 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 */
76 unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
77 unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
78 unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
79 unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
80 unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
81 unsigned char prl_nam_num; /**< number of PRL NAM fields */
82 unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3];/**< prl version (only for CDMA), null termination */
83 unsigned char eri_nam_num; /**< number of PRL NAM fields */
84 unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3];/**< eri version (only for CDMA), null termination */
87 extern struct ATResponse *sp_response;
88 extern char *s_responsePrefix;
89 extern enum ATCommandType s_type;
91 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data ); // from Kernel
93 static void on_confirmation_modem_message_send( TcorePending *p, gboolean result, void *user_data )
95 UserRequest* ur = NULL;
96 struct ATReqMetaInfo* metainfo = NULL;
97 unsigned int info_len =0;
98 dbg("on_confirmation_modem_message_send - msg out from queue. alloc ATRsp buffer & write rspPrefix if needed\n");
100 ReleaseResponse(); // release leftover
101 //alloc new sp_response
102 sp_response = at_response_new();
105 ur = tcore_pending_ref_user_request(p);
106 metainfo = (struct ATReqMetaInfo*)tcore_user_request_ref_metainfo(ur,&info_len);
108 if((metainfo->type == SINGLELINE)||
109 (metainfo->type == MULTILINE))
112 s_responsePrefix = strdup(metainfo->responsePrefix);
113 dbg("duplicating responsePrefix : %s\n", s_responsePrefix);
117 s_responsePrefix = NULL;
120 //set atcmd type into s_type
121 s_type = metainfo->type;
123 if (result == FALSE) {
131 static gboolean on_sys_event_modem_power(CoreObject *o, const void *event_info, void *user_data)
133 struct tnoti_modem_power modem_power;
134 enum cp_state *state;
136 state = (enum cp_state*)event_info;
137 dbg("state : (0x%x)", *state);
139 if ( *state == CP_STATE_OFFLINE || *state == CP_STATE_CRASH_RESET ) {
141 tcore_modem_set_powered(o, FALSE);
143 if ( *state == CP_STATE_OFFLINE )
144 modem_power.state = MODEM_STATE_OFFLINE;
146 modem_power.state = MODEM_STATE_ERROR;
149 dbg("useless state : (0x%x)", *state);
153 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_POWER,
154 sizeof(struct tnoti_modem_power), &modem_power);
158 static gboolean on_event_modem_power(CoreObject *o, const void *event_info, void *user_data)
160 struct treq_modem_set_flightmode flight_mode_set;
161 struct tnoti_modem_power modem_power;
166 strg = tcore_server_find_storage(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), "vconf");
167 flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_SETAPPL_FLIGHT_MODE_BOOL);
169 h = tcore_object_get_hal(o);
171 tcore_hal_set_power_state(h, TRUE);
173 ur = tcore_user_request_new(NULL, NULL);
174 tcore_user_request_set_data(ur, sizeof(struct treq_modem_set_flightmode), &flight_mode_set);
175 tcore_user_request_set_command(ur, TREQ_MODEM_SET_FLIGHTMODE);
176 tcore_object_dispatch_request(o, ur);
178 ur = tcore_user_request_new(NULL, NULL);
179 tcore_user_request_set_command(ur, TREQ_MODEM_GET_IMEI);
180 tcore_object_dispatch_request(o, ur);
182 ur = tcore_user_request_new(NULL, NULL);
183 tcore_user_request_set_command(ur, TREQ_MODEM_GET_VERSION);
184 tcore_object_dispatch_request(o, ur);
186 tcore_modem_set_powered(o, TRUE);
188 modem_power.state = MODEM_STATE_ONLINE;
190 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_POWER,
191 sizeof(struct tnoti_modem_power), &modem_power);
196 static gboolean on_event_modem_phone_state(CoreObject *o, const void *event_info, void *user_data)
198 char* line = (char*)event_info;
202 struct tresp_modem_set_flightmode res;
203 struct tnoti_modem_flight_mode modem_flight_mode;
204 #define SCFUN_MIN_FUNC 0
205 #define SCFUN_FULL_FUNC 1
207 dbg("received notification : %s", line);
211 err = at_tok_nextint(&line, &status);
216 tcore_modem_set_flight_mode_state(o, TRUE);
219 case SCFUN_FULL_FUNC:
221 tcore_modem_set_flight_mode_state(o, FALSE);
225 queue = tcore_object_ref_user_data(o);
227 ur = util_pop_waiting_job(queue, ID_RESERVED_AT);
229 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
233 modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
235 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
236 sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
240 static void on_response_poweron(TcorePending *p, int data_len, const void *data, void *user_data)
243 gboolean bpoweron = FALSE;
247 #define CPAS_RES_READY 0
248 #define CPAS_RES_UNAVAIL 1
249 #define CPAS_RES_UNKNOWN 2
250 #define CPAS_RES_RINGING 3
251 #define CPAS_RES_CALL_PROGRESS 4
252 #define CPAS_RES_ASLEEP 5
254 //print sp_response - for debug
257 if(sp_response->success > 0){
260 line = sp_response->p_intermediates->line;
262 err = at_tok_start(&line);
268 err = at_tok_nextint(&line, &response);
274 dbg("response %d",response);
279 case CPAS_RES_RINGING:
280 case CPAS_RES_CALL_PROGRESS:
281 case CPAS_RES_ASLEEP:
285 case CPAS_RES_UNAVAIL:
286 case CPAS_RES_UNKNOWN:
297 //5. release sp_response & s_responsePrefix - before sending user callback, because user callback can request additional request
298 // and if queue is empty, that req can be directly sent to mdm - can cause sp_response, s_responsePrefix dangling
301 if(bpoweron == TRUE){
302 dbg("Power on NOTI received");
303 //procees power up noti process
304 on_event_modem_power(tcore_pending_ref_core_object(p), NULL, NULL);
306 else{ //poweron not complete - proceed same process again
308 dbg("CPAS once again");
309 s_modem_send_poweron(tcore_object_ref_plugin(tcore_pending_ref_core_object(p)));
313 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
315 CoreObject *o = user_data;
318 struct tresp_modem_set_flightmode res;
323 //print sp_response - for debug
325 ur = tcore_pending_ref_user_request(p);
327 if(sp_response->success > 0)
331 queue = tcore_object_ref_user_data(o);
334 ur = tcore_user_request_ref(ur);
335 util_add_waiting_job(queue, ID_RESERVED_AT, ur);
343 line = sp_response->finalResponse;
344 err = at_tok_start(&line);
347 dbg("err cause not specified or string corrupted");
348 res.result = TCORE_RETURN_3GPP_ERROR;
352 err = at_tok_nextint(&line, &response);
355 dbg("err not specified or string not contail error");
356 res.result = TCORE_RETURN_3GPP_ERROR;
360 res.result = convertCMEError((enum ATCMEError)response);
365 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
369 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
372 struct tresp_modem_get_imei res;
374 struct TelMiscSNInformation *imei_property;
381 memset(&res, 0, sizeof(struct tresp_modem_get_imei));
383 if(sp_response->success > 0)
387 line = sp_response->p_intermediates->line;
389 res.result = TCORE_RETURN_SUCCESS;
390 strncpy(res.imei, line, 16);
392 dbg("imei = [%s]", res.imei);
394 plugin = tcore_pending_ref_plugin(p);
395 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
398 imei_property->sn_index = TAPI_MISC_ME_IMEI;
399 imei_property->sn_len = strlen(res.imei);
400 memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
406 line = sp_response->finalResponse;
408 err = at_tok_start(&line);
411 dbg("err cause not specified or string corrupted");
412 res.result = TCORE_RETURN_3GPP_ERROR;
416 err = at_tok_nextint(&line, &response);
419 dbg("err not specified or string not contail error");
420 res.result = TCORE_RETURN_3GPP_ERROR;
424 res.result = convertCMEError((enum ATCMEError)response);
431 ur = tcore_pending_ref_user_request(p);
432 tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI, sizeof(struct tresp_modem_get_imei), &res);
436 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
439 struct TelMiscVersionInformation *vi;
440 struct TelMiscVersionInformation *vi_property;
441 struct tresp_modem_get_version res;
444 char *swver= NULL,*hwver=NULL, *caldate=NULL,*pcode=NULL,*id=NULL;
450 #define AT_VER_LEN 20
451 if(sp_response->success > 0)
455 line = sp_response->p_intermediates->line;
456 err = at_tok_start(&line);
458 err = at_tok_nextstr(&line,&swver);
460 err = at_tok_nextstr(&line,&hwver);
462 err = at_tok_nextstr(&line,&caldate);
464 err = at_tok_nextstr(&line,&pcode);
466 err = at_tok_nextstr(&line,&id);
468 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]", swver, hwver, caldate, pcode, id);
470 vi = calloc(sizeof(struct TelMiscVersionInformation), 1);
471 memcpy(vi->szSwVersion, swver, strlen(swver));
472 memcpy(vi->szHwVersion, hwver, strlen(hwver));
473 memcpy(vi->szRfCalDate, caldate, strlen(caldate));
474 memcpy(vi->szProductCode, pcode,strlen(pcode));
475 memcpy(vi->szModelId, id, strlen(id));
477 memset(&res, 0, sizeof(struct tresp_modem_get_imei));
478 snprintf(res.software, (AT_VER_LEN >strlen(swver) ?strlen(swver):AT_VER_LEN), "%s", swver);
479 snprintf(res.hardware, (AT_VER_LEN >strlen(hwver) ?strlen(hwver):AT_VER_LEN), "%s", hwver);
481 plugin = tcore_pending_ref_plugin(p);
482 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
483 memcpy(vi_property, vi, sizeof(struct TelMiscVersionInformation));
488 line = sp_response->finalResponse;
490 memset(&res, 0, sizeof(struct tresp_modem_get_version));
492 err = at_tok_start(&line);
495 dbg("err cause not specified or string corrupted");
496 res.result = TCORE_RETURN_3GPP_ERROR;
500 err = at_tok_nextint(&line, &response);
503 dbg("err not specified or string not contail error");
504 res.result = TCORE_RETURN_3GPP_ERROR;
508 res.result = convertCMEError((enum ATCMEError)response);
515 ur = tcore_pending_ref_user_request(p);
516 tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION, sizeof(struct tresp_modem_get_version), &res);
520 static TReturn power_on(CoreObject *o, UserRequest *ur)
523 return TCORE_RETURN_SUCCESS;
526 static TReturn power_off(CoreObject *o, UserRequest *ur)
528 struct tnoti_modem_power modem_power;
529 modem_power.state = MODEM_STATE_OFFLINE;
531 tcore_modem_set_powered(o, FALSE);
533 tcore_server_send_notification( tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_POWER,
534 sizeof(struct tnoti_modem_power), &modem_power);
536 return TCORE_RETURN_SUCCESS;
538 static TReturn power_reset(CoreObject *o, UserRequest *ur)
541 return TCORE_RETURN_SUCCESS;
543 static TReturn get_imei(CoreObject *o, UserRequest *ur)
545 TcorePlugin *p = NULL;
547 TcorePending *pending = NULL;
548 char* cmd_str = NULL;
549 struct ATReqMetaInfo metainfo;
552 p = tcore_object_ref_plugin(o);
553 h = tcore_object_get_hal(o);
555 memset(&metainfo, 0, sizeof(struct ATReqMetaInfo));
556 metainfo.type = NUMERIC;
557 metainfo.responsePrefix[0] ='\0';
558 info_len = sizeof(struct ATReqMetaInfo);
560 tcore_user_request_set_metainfo(ur, info_len, &metainfo);
562 cmd_str = g_strdup("AT+CGSN\r");
563 dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",cmd_str, "N/A", strlen(cmd_str));
565 pending = tcore_pending_new(o, ID_RESERVED_AT);
566 tcore_pending_set_request_data(pending, strlen(cmd_str), cmd_str);
568 tcore_pending_set_timeout(pending, 0);
569 tcore_pending_set_response_callback(pending, on_response_imei, NULL);
570 tcore_pending_link_user_request(pending, ur);
571 tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
573 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
576 tcore_hal_send_request(h, pending);
578 return TCORE_RETURN_SUCCESS;
581 static TReturn get_version(CoreObject *o, UserRequest *ur)
583 TcorePlugin *p = NULL;
585 TcorePending *pending = NULL;
586 char* cmd_str = NULL;
587 struct ATReqMetaInfo metainfo;
590 p = tcore_object_ref_plugin(o);
591 h = tcore_object_get_hal(o);
593 memset(&metainfo, 0, sizeof(struct ATReqMetaInfo));
594 metainfo.type = SINGLELINE;
595 memcpy(metainfo.responsePrefix,"+CGMR:",strlen("+CGMR:"));
596 info_len = sizeof(struct ATReqMetaInfo);
598 tcore_user_request_set_metainfo(ur, info_len, &metainfo);
600 cmd_str = g_strdup("AT+CGMR\r");
602 dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",cmd_str, "N/A", strlen(cmd_str));
604 pending = tcore_pending_new(o, ID_RESERVED_AT);
605 tcore_pending_set_request_data(pending, strlen(cmd_str), cmd_str);
607 tcore_pending_set_timeout(pending, 0);
608 tcore_pending_set_response_callback(pending, on_response_version, NULL);
609 tcore_pending_link_user_request(pending, ur);
610 tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
612 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
614 tcore_hal_send_request(h, pending);
616 return TCORE_RETURN_SUCCESS;
619 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
621 TcorePlugin *p = NULL;
623 TcorePending *pending = NULL;
624 const struct treq_modem_set_flightmode *req_data;
625 char* cmd_str = NULL;
626 struct ATReqMetaInfo metainfo;
629 p = tcore_object_ref_plugin(o);
630 h = tcore_object_get_hal(o);
632 req_data = tcore_user_request_ref_data(ur, NULL);
634 if (req_data->enable) {
635 dbg("Flight mode on/n");
636 cmd_str = g_strdup("AT+CFUN=0\r");
639 dbg("Flight mode off/n");
640 cmd_str = g_strdup("AT+CFUN=1\r");
643 memset(&metainfo, 0, sizeof(struct ATReqMetaInfo));
644 metainfo.type = NO_RESULT;
645 metainfo.responsePrefix[0] ='\0';
646 info_len = sizeof(struct ATReqMetaInfo);
648 tcore_user_request_set_metainfo(ur, info_len, &metainfo);
650 dbg("cmd : %s, prefix(if any) : %s, cmd_len : %d",cmd_str, "N/A", strlen(cmd_str));
652 pending = tcore_pending_new(o, ID_RESERVED_AT);
653 tcore_pending_set_request_data(pending, strlen(cmd_str), cmd_str);
655 tcore_pending_set_timeout(pending, 0);
656 tcore_pending_set_response_callback(pending, on_response_set_flight_mode, o);
657 tcore_pending_link_user_request(pending, ur);
658 tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
660 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
662 tcore_hal_send_request(h, pending);
664 return TCORE_RETURN_SUCCESS;
667 static struct tcore_modem_operations modem_ops =
669 .power_on = power_on,
670 .power_off = power_off,
671 .power_reset = power_reset,
672 .set_flight_mode = set_flight_mode,
673 .get_imei = get_imei,
674 .get_version = get_version,
677 gboolean s_modem_init(TcorePlugin *p, TcoreHal *h)
681 struct TelMiscVersionInformation *vi_property;
682 struct TelMiscSNInformation *imei_property;
684 o = tcore_modem_new(p, "modem", &modem_ops, h);
688 work_queue = g_queue_new();
689 tcore_object_link_user_data(o, work_queue);
691 tcore_object_add_callback(o, EVENT_SYS_NOTI_MODEM_POWER, on_sys_event_modem_power, NULL);
693 tcore_object_add_callback(o, EVENT_MODEM_POWER, on_event_modem_power, NULL);
694 tcore_object_add_callback(o, EVENT_MODEM_PHONE_STATE, on_event_modem_phone_state, NULL);
696 vi_property = calloc(sizeof(struct TelMiscVersionInformation), 1);
697 tcore_plugin_link_property(p, "VERSION", vi_property);
699 imei_property = calloc(sizeof(struct TelMiscSNInformation), 1);
700 tcore_plugin_link_property(p, "IMEI", imei_property);
705 void s_modem_exit(TcorePlugin *p)
709 struct TelMiscVersionInformation *vi_property;
710 struct TelMiscSNInformation *imei_property;
715 o = tcore_plugin_ref_core_object(p, "modem");
717 work_queue = tcore_object_ref_user_data(o);
718 g_queue_free(work_queue);
720 vi_property = tcore_plugin_ref_property(p, "VERSION");
724 imei_property = tcore_plugin_ref_property(p, "IMEI");
731 gboolean s_modem_send_poweron(TcorePlugin *p)
735 TcorePending *pending = NULL;
738 char* cmd_str = NULL;
739 struct ATReqMetaInfo metainfo;
742 ur = tcore_user_request_new(NULL, NULL);
744 memset(&metainfo, 0, sizeof(struct ATReqMetaInfo));
745 metainfo.type = SINGLELINE;
746 memcpy(metainfo.responsePrefix,"+CPAS:",strlen("+CPAS:"));
747 info_len = sizeof(struct ATReqMetaInfo);
748 tcore_user_request_set_metainfo(ur, info_len, &metainfo);
750 cmd_str = g_strdup("AT+CPAS\r");
752 dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d",cmd_str, metainfo.responsePrefix, strlen(cmd_str));
754 o = tcore_plugin_ref_core_object(p, "modem");
755 hal = tcore_object_get_hal(o);
757 pending = tcore_pending_new(o, ID_RESERVED_AT);
758 tcore_pending_set_request_data(pending, strlen(cmd_str), cmd_str);
760 tcore_pending_set_timeout(pending, 0);
761 tcore_pending_set_response_callback(pending, on_response_poweron, NULL);
762 tcore_pending_link_user_request(pending, ur);
763 tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
765 tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
767 tcore_hal_send_request(hal, pending);