Tizen 2.1 base
[platform/core/telephony/tel-plugin-imc.git] / src / s_modem.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Harish Bishnoi <hbishnoi@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <glib.h>
27
28 #include <tcore.h>
29 #include <hal.h>
30 #include <core_object.h>
31 #include <plugin.h>
32 #include <queue.h>
33 #include <co_modem.h>
34 #include <storage.h>
35 #include <server.h>
36 #include <at.h>
37 #include <mux.h>
38
39 #include "s_common.h"
40 #include "s_modem.h"
41
42
43 #define ID_RESERVED_AT 0x0229
44
45 #define MAX_VERSION_LEN 32
46 #define TAPI_MISC_ME_SN_LEN_MAX             32
47 #define TAPI_MISC_PRODUCT_CODE_LEN_MAX      32
48 #define TAPI_MISC_MODEL_ID_LEN_MAX          17
49 #define TAPI_MISC_PRL_ERI_VER_LEN_MAX       17
50
51 #define CPAS_RES_READY          0
52 #define CPAS_RES_UNAVAIL            1
53 #define CPAS_RES_UNKNOWN            2
54 #define CPAS_RES_RINGING            3
55 #define CPAS_RES_CALL_PROGRESS  4
56 #define CPAS_RES_ASLEEP           5
57 #define AT_VER_LEN 20
58
59
60 enum cp_state {
61         CP_STATE_OFFLINE,
62         CP_STATE_CRASH_RESET,
63         CP_STATE_CRASH_EXIT,
64         CP_STATE_BOOTING,
65         CP_STATE_ONLINE,
66         CP_STATE_NV_REBUILDING,
67         CP_STATE_LOADER_DONE,
68 };
69
70 typedef enum {
71         TAPI_MISC_ME_IMEI = 0x00, /**< 0x00: IMEI, GSM/UMTS device */
72         TAPI_MISC_ME_ESN = 0x01, /**< 0x01: ESN(Electronic Serial Number), It`s essentially run out. CDMA device */
73         TAPI_MISC_ME_MEID = 0x02, /**< 0x02: MEID, This value can have hexa decimal digits. CDMA device */
74         TAPI_MISC_ME_MAX = 0xff /**< 0xff: reserved */
75 } TelMiscSNIndexType_t;
76
77 typedef struct {
78         TelMiscSNIndexType_t sn_index; /**< serial number index */
79         int sn_len; /**< Length */
80         unsigned char szNumber[TAPI_MISC_ME_SN_LEN_MAX]; /**< Number */
81 } TelMiscSNInformation;
82
83 /**
84  * Mobile Equipment Version Information
85  */
86 typedef struct {
87         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 */
88         unsigned char szSwVersion[MAX_VERSION_LEN]; /**< Software version, null termination */
89         unsigned char szHwVersion[MAX_VERSION_LEN]; /**< Hardware version, null termination */
90         unsigned char szRfCalDate[MAX_VERSION_LEN]; /**< Calculation Date, null termination */
91         unsigned char szProductCode[TAPI_MISC_PRODUCT_CODE_LEN_MAX]; /**< product code, null termination */
92         unsigned char szModelId[TAPI_MISC_MODEL_ID_LEN_MAX]; /**< model id (only for CDMA), null termination */
93         unsigned char prl_nam_num; /**< number of PRL NAM fields */
94         unsigned char szPrlVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< prl version (only for CDMA), null termination */
95         unsigned char eri_nam_num; /**< number of PRL NAM fields */
96         unsigned char szEriVersion[TAPI_MISC_PRL_ERI_VER_LEN_MAX * 3]; /**< eri version (only for CDMA), null termination */
97 } TelMiscVersionInformation;
98
99
100 void prepare_and_send_pending_request(TcorePlugin *plugin, char *co_name, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback);
101 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data);     // from Kernel
102 void on_response_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data);
103 void on_response_last_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data);
104 static void on_timeout_modem_poweron(TcorePending *p, void *user_data);
105 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data);
106
107 static void on_timeout_modem_poweron(TcorePending *p, void *user_data)
108 {
109         unsigned int data_len = 0;
110         char data[] = "AT+CPAS";
111         dbg("TIMEOUT for 1st AT Command !!!!! NO Response for initial AT command. Resending it");
112         data_len = sizeof(data);
113
114         /* Retransmit 1st AT command directly via HAL, don't disturb pending queue. */
115         /* HAL was passed as user_data, re-use it */
116         if (user_data) {
117                 tcore_hal_send_data(user_data, data_len, (void *) data);
118         }
119 }
120
121 static void on_confirmation_modem_message_send(TcorePending *p, gboolean result, void *user_data)
122 {
123         dbg("on_confirmation_modem_message_send - msg out from queue.\n");
124
125         if (result == FALSE) {
126                 /* Fail */
127                 dbg("SEND FAIL");
128         } else {
129                 dbg("SEND OK");
130         }
131 }
132
133 static void on_response_enable_proactive_command(TcorePending *p, int data_len, const void *data, void *user_data)
134 {
135         const TcoreATResponse *resp = data;
136
137         if (resp->success > 0) {
138                 dbg("RESPONSE OK proactive command enabled");
139         } else {
140                 dbg("RESPONSE NOK proactive command disabled");
141         }
142 }
143
144 void prepare_and_send_pending_request(TcorePlugin *plugin, char *co_name, const char *at_cmd, const char *prefix, enum tcore_at_command_type at_cmd_type, TcorePendingResponseCallback callback)
145 {
146         TcoreATRequest *req = NULL;
147         TcoreHal *hal = NULL;
148         CoreObject *o = NULL;
149         TcorePending *pending = NULL;
150         TReturn ret;
151
152         o = tcore_plugin_ref_core_object(plugin, co_name);
153         hal = tcore_object_get_hal(o);
154         dbg("hal: %p", hal);
155
156         pending = tcore_pending_new(o, 0);
157         if (!pending)
158                 dbg("Pending is NULL");
159         req = tcore_at_request_new(at_cmd, prefix, at_cmd_type);
160
161         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
162
163         tcore_pending_set_request_data(pending, 0, req);
164         tcore_pending_set_response_callback(pending, callback, NULL);
165         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
166         tcore_pending_link_user_request(pending, NULL); // set user request to NULL - this is intenal request
167         ret = tcore_hal_send_request(hal, pending);
168         return;
169 }
170
171 void on_response_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data)
172 {
173         const TcoreATResponse *resp = data;
174         dbg("entry of on_response_bootup_subscription() - response comes\n");
175
176         if (resp->success) {
177                 dbg("result OK");
178         } else {
179                 dbg("result ERROR");
180         }
181 }
182
183 void on_response_last_bootup_subscription(TcorePending *p, int data_len, const void *data, void *user_data)
184 {
185         const TcoreATResponse *resp = data;
186         dbg("enry of on_response_last_bootup_subscription() - final response comes\n");
187         if (resp->success) {
188                 dbg("SEND OK");
189         } else {
190                 dbg("SEND FAIL");
191         }
192         dbg("Response for AT+CLIP. Boot-up configration completed for IMC modem. Bring CP to online based on Flightmode status\n");
193         on_event_modem_power(NULL, NULL, tcore_pending_ref_plugin(p));
194 }
195
196 static void on_response_power_off(TcorePending *p, int data_len, const void *data, void *user_data)
197 {
198         CoreObject *o = 0;
199         TcoreHal *h = 0;
200         o = tcore_pending_ref_core_object(p);
201         h = tcore_object_get_hal(o);
202
203         dbg("modem power off");
204
205         tcore_hal_set_power_state(h, FALSE);
206 }
207
208 static void on_response_set_flight_mode(TcorePending *p, int data_len, const void *data, void *user_data)
209 {
210         CoreObject *o = NULL;
211         UserRequest *ur = NULL;
212         const TcoreATResponse *ATresp = data;
213         GSList *tokens = NULL;
214         const char *line = NULL;
215         struct tresp_modem_set_flightmode res = {0};
216         int response = 0;
217         struct tnoti_modem_flight_mode modem_flight_mode = {0};
218         const struct treq_modem_set_flightmode *req_data = NULL;
219
220         o = tcore_pending_ref_core_object(p);
221
222         if (ATresp->success > 0) {
223                 dbg("RESPONSE OK - flight mode operation finished");
224                 res.result = TCORE_RETURN_SUCCESS;
225         } else {
226                 dbg("RESPONSE NOK");
227                 line = (const char *) ATresp->final_response;
228                 tokens = tcore_at_tok_new(line);
229
230                 if (g_slist_length(tokens) < 1) {
231                         dbg("err cause not specified or string corrupted");
232                         res.result = TCORE_RETURN_3GPP_ERROR;
233                 } else {
234                         response = atoi(g_slist_nth_data(tokens, 0));
235                         /* TODO: CMEE error mapping is required. */
236                         res.result = TCORE_RETURN_3GPP_ERROR;
237                 }
238         }
239
240         ur = tcore_pending_ref_user_request(p);
241         if (NULL == ur) {
242                 dbg("No user request. Internal request created during boot-up sequence");
243
244                 if (ATresp->success > 0) {
245                         modem_flight_mode.enable = tcore_modem_get_flight_mode_state(o);
246                         dbg("sucess case - Sending Flight Mode Notification (%d) to Telephony Server", modem_flight_mode.enable);
247
248                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_FLIGHT_MODE,
249                                                                                    sizeof(struct tnoti_modem_flight_mode), &modem_flight_mode);
250                 }
251         } else {
252                 dbg("Sending response for Flight mode operation");
253
254                 req_data = tcore_user_request_ref_data(ur, NULL);
255
256                 if (TCORE_RETURN_SUCCESS == res.result) {
257                         if (TRUE == req_data->enable)
258                                 res.result = 1;
259                         else
260                                 res.result = 2;
261                 } else {
262                         res.result = 3;
263                 }
264
265                 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
266
267                 if (req_data->enable == 0) {
268                         dbg("Flight mode is disabled, trigger COPS to register on network");
269                         /* Trigger Network registration (for the moment automatic) */
270                         prepare_and_send_pending_request(tcore_object_ref_plugin(o), "modem", "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
271                 }
272         }
273
274         tcore_at_tok_free(tokens);
275 }
276
277 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
278 {
279         const TcoreATResponse *resp = data;
280         TcorePlugin *plugin = NULL;
281         struct tresp_modem_get_imei res;
282         TelMiscSNInformation *imei_property = NULL;
283         UserRequest *ur = NULL;
284         GSList *tokens = NULL;
285         const char *line;
286         int response = 0;
287
288         memset(&res, 0, sizeof(struct tresp_modem_get_imei));
289
290         if (resp->success > 0) {
291                 dbg("RESPONSE OK");
292                 if (resp->lines) {
293                         line = (const char *) resp->lines->data;
294                         tokens = tcore_at_tok_new(line);
295                         if (g_slist_length(tokens) != 1) {
296                                 msg("invalid message");
297                                 goto OUT;
298                         }
299                 }
300                 res.result = TCORE_RETURN_SUCCESS;
301                 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
302
303                 dbg("imei = [%s]", res.imei);
304
305                 plugin = tcore_pending_ref_plugin(p);
306                 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
307                 if (imei_property) {
308                         imei_property->sn_index = TAPI_MISC_ME_IMEI;
309                         imei_property->sn_len = strlen(res.imei);
310                         memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
311                 }
312         } else {
313                 dbg("RESPONSE NOK");
314                 if (resp->lines) {
315                         line = (const char *) resp->lines->data;
316                         tokens = tcore_at_tok_new(line);
317                 }
318
319
320                 if (g_slist_length(tokens) < 1) {
321                         dbg("err cause not specified or string corrupted");
322                         res.result = TCORE_RETURN_3GPP_ERROR;
323                 } else {
324                         response = atoi(g_slist_nth_data(tokens, 0));
325                         /* TODO: CMEE error mapping is required. */
326                         res.result = TCORE_RETURN_3GPP_ERROR;
327                 }
328         }
329
330         ur = tcore_pending_ref_user_request(p);
331         tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI, sizeof(struct tresp_modem_get_imei), &res);
332
333 OUT:
334         if (tokens != NULL)
335                 tcore_at_tok_free(tokens);
336
337         return;
338 }
339
340 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
341 {
342         const TcoreATResponse *resp = data;
343         TcorePlugin *plugin = NULL;
344         struct tresp_modem_get_version res = {0};
345         TelMiscVersionInformation *vi_property = NULL;
346         TelMiscVersionInformation *vi = NULL;
347         UserRequest *ur = NULL;
348         GSList *tokens = NULL;
349         const char *line = NULL;
350         char *swver = NULL;
351         char *hwver = NULL;
352         char *caldate = NULL;
353         char *pcode = NULL;
354         char *id = NULL;
355
356         int response = 0;
357
358         if (resp->success > 0) {
359                 dbg("RESPONSE OK");
360                 if (resp->lines) {
361                         line = (const char *) resp->lines->data;
362                         tokens = tcore_at_tok_new(line);
363                         if (g_slist_length(tokens) != 5) {
364                                 msg("invalid message");
365                                 goto OUT;
366                         }
367                 }
368
369                 swver = g_slist_nth_data(tokens, 0);
370                 hwver = g_slist_nth_data(tokens, 1);
371                 caldate = g_slist_nth_data(tokens, 2);
372                 pcode = g_slist_nth_data(tokens, 3);
373                 id = g_slist_nth_data(tokens, 4);
374
375                 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]", swver, hwver, caldate, pcode, id);
376
377                 vi = calloc(sizeof(TelMiscVersionInformation), 1);
378                 if (NULL != swver)
379                         memcpy(vi->szSwVersion, swver, strlen(swver));
380                 if (NULL != hwver)
381                         memcpy(vi->szHwVersion, hwver, strlen(hwver));
382                 if (NULL != caldate)
383                         memcpy(vi->szRfCalDate, caldate, strlen(caldate));
384                 if (NULL != pcode)
385                         memcpy(vi->szProductCode, pcode, strlen(pcode));
386                 if (NULL != id)
387                         memcpy(vi->szModelId, id, strlen(id));
388
389                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
390
391                 if (NULL != swver)
392                         snprintf(res.software, (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN), "%s", swver);
393                 if (NULL != hwver)
394                         snprintf(res.hardware, (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN), "%s", hwver);
395
396                 plugin = tcore_pending_ref_plugin(p);
397                 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
398                 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
399                 free(vi);
400         } else {
401                 dbg("RESPONSE NOK");
402                 if (resp->lines) {
403                         line = (const char *) resp->lines->data;
404                         tokens = tcore_at_tok_new(line);
405                 }
406
407                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
408
409
410                 if (g_slist_length(tokens) < 1) {
411                         dbg("err cause not specified or string corrupted");
412                         res.result = TCORE_RETURN_3GPP_ERROR;
413                 } else {
414                         response = atoi(g_slist_nth_data(tokens, 0));
415                         /* TODO: CMEE error mapping is required. */
416                         res.result = TCORE_RETURN_3GPP_ERROR;
417                 }
418         }
419
420         ur = tcore_pending_ref_user_request(p);
421         tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION, sizeof(struct tresp_modem_get_version), &res);
422
423 OUT:
424         if (tokens != NULL)
425                 tcore_at_tok_free(tokens);
426
427         return;
428 }
429
430 static gboolean on_event_bootup_sim_status(CoreObject *o, const void *event_info, void *user_data)
431 {
432         GSList *tok = NULL;
433         GSList *lines = NULL;
434         int value = -1;
435         char *line = NULL;
436
437         lines = (GSList *) event_info;
438         if (1 != g_slist_length(lines)) {
439                 dbg("unsolicited msg but multiple line");
440                 goto OUT;
441         }
442         line = (char *) (lines->data);
443         dbg("on_bootup_event_sim_status notification : %s", line);
444
445         tok = tcore_at_tok_new(line);
446         value = atoi(g_slist_nth_data(tok, 0));
447
448         if (7 == value) {
449                 dbg("SIM ready. request COPS & remove callback");
450                 dbg("power on done set for proactive command receiving mode");
451                 prepare_and_send_pending_request(tcore_object_ref_plugin(o), "sat", "AT+CFUN=6", NULL, TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
452                 prepare_and_send_pending_request(tcore_object_ref_plugin(o), "umts_network", "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
453                 return FALSE;
454         }
455
456 OUT:
457         if (tok != NULL)
458                 tcore_at_tok_free(tok);
459
460         return TRUE;
461 }
462
463
464
465 gboolean on_event_modem_power(TcoreAT *at, const char *line, TcorePlugin *p)
466 {
467         CoreObject *o = NULL;
468         struct treq_modem_set_flightmode flight_mode_set = {0};
469         struct tnoti_modem_power modem_power = {0};
470         TcoreHal *h = NULL;
471         Storage *strg = NULL;
472
473         o = tcore_plugin_ref_core_object(p, "modem");
474
475         strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
476         flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE_BOOL);
477
478         h = tcore_object_get_hal(o);
479         tcore_hal_set_power_state(h, TRUE);
480
481         /* Set Flight mode as per AP settings */
482         if (flight_mode_set.enable) { /* Radio Off */
483                 prepare_and_send_pending_request(p, "modem", "AT+CFUN=4", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
484                 tcore_modem_set_flight_mode_state(o, TRUE);
485         } else { /* Radio On */
486                 prepare_and_send_pending_request(p, "modem", "AT+CFUN=1", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
487                 tcore_modem_set_flight_mode_state(o, FALSE);
488         }
489
490         /* Get IMEI */
491         prepare_and_send_pending_request(p, "modem", "AT+CGSN", NULL, TCORE_AT_NUMERIC, on_response_imei);
492
493         /* Get Version Number  */
494         prepare_and_send_pending_request(p, "modem", "AT+CGMR", NULL, TCORE_AT_SINGLELINE, on_response_version);
495
496         tcore_modem_set_powered(o, TRUE);
497
498         modem_power.state = MODEM_STATE_ONLINE;
499
500         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_POWER,
501                                                                    sizeof(struct tnoti_modem_power), &modem_power);
502
503         return TRUE;
504 }
505
506 static void _modem_subscribe_events(TcorePlugin *plugin)
507 {
508         dbg("Entry");
509
510         /* XCALLSTAT subscription */
511         prepare_and_send_pending_request(plugin, "call", "at+xcallstat=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
512
513         /* XSIMSTATE subscription */
514         prepare_and_send_pending_request(plugin, "sim", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
515
516         prepare_and_send_pending_request(plugin, "umts_sms", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
517         prepare_and_send_pending_request(plugin, "modem", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
518
519         /* CREG subscription */
520         prepare_and_send_pending_request(plugin, "umts_network", "at+creg=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
521
522         /* CGREG subscription */
523         prepare_and_send_pending_request(plugin, "umts_network", "at+cgreg=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
524
525         /* Allow automatic time Zone updation via NITZ */
526         prepare_and_send_pending_request(plugin, "umts_network", "at+ctzu=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
527
528         /* TZ, time & daylight changing event reporting subscription */
529         prepare_and_send_pending_request(plugin, "umts_network", "at+ctzr=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
530
531         /* XMER subscription */
532         prepare_and_send_pending_request(plugin, "umts_network", "at+xmer=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
533
534         /* CGEREP subscription */
535         prepare_and_send_pending_request(plugin, "umts_ps", "at+cgerep=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
536
537         /* XDATASTAT subscription */
538         prepare_and_send_pending_request(plugin, "umts_ps", "at+xdatastat=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
539
540         /* CSSN subscription */
541         prepare_and_send_pending_request(plugin, "call", "at+cssn=1,1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
542
543         /* CUSD subscription */
544         prepare_and_send_pending_request(plugin, "call", "at+cusd=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
545
546         /* XDNS subscription */
547         prepare_and_send_pending_request(plugin, "umts_ps", "at+xdns=1,1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
548
549         /* CLIP subscription */
550         prepare_and_send_pending_request(plugin, "call", "at+clip=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
551
552         /*CMEE subscription for ps*/
553         prepare_and_send_pending_request(plugin, "umts_ps", "at+cmee=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
554
555         /*CMEE subscription for sms*/
556         prepare_and_send_pending_request(plugin, "umts_sms", "at+cmee=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
557
558         /*incoming sms,cb,status report subscription*/
559         prepare_and_send_pending_request(plugin, "umts_sms", "at+cnmi=1,2,2,1,0", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
560
561         /* XBCSTAT subscription */
562         prepare_and_send_pending_request(plugin, "sap", "at+xbcstat=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
563
564         /* text/pdu mode subscription*/
565         prepare_and_send_pending_request(plugin, "umts_sms", "at+cmgf=0", NULL, TCORE_AT_NO_RESULT, on_response_last_bootup_subscription);
566
567         dbg("Exit");
568         return;
569 }
570
571
572 static void on_response_setupmux(TcorePending *p, int data_len, const void *data, void *user_data)
573 {
574         TcorePlugin *plugin = NULL;
575         TcoreHal *hal = NULL;
576         TReturn ret;
577         dbg("Entry");
578
579         /* IMC Plugin dereferenced from pending request */
580         plugin = tcore_pending_ref_plugin(p);
581
582         /* Actual HAL - like svnet(2) */
583         hal = (TcoreHal *) user_data;
584
585         /* Initialize CMUX */
586         ret = tcore_cmux_init(plugin, hal);
587         if (TCORE_RETURN_SUCCESS == ret) {
588                 dbg("Successfully initialized CMUX");
589         } else {
590                 err("Failed to initialize CMUX");
591         }
592
593         dbg("Exit");
594         return;
595 }
596
597
598
599 static void setup_mux(CoreObject *o)
600 {
601         TcoreHal *hal = NULL;
602         TcorePending *pending = NULL;
603         dbg("Entered");
604
605         /* HAL has type itself,
606          * e.g.) TCORE_HAL_MODE_AT
607          */
608         hal = tcore_object_get_hal(o);
609
610         pending = tcore_at_pending_new(o, "AT+CMUX=0,0,,1509,10,3,30,,", "+CMUX", TCORE_AT_NO_RESULT, on_response_setupmux, hal);
611
612         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
613
614         /* Send callback */
615         tcore_hal_send_request(hal, pending);
616
617         dbg("Exit");
618         return;
619 }
620
621
622 static gboolean on_event_mux_channel_up(CoreObject *o, const void *event_info, void *user_data)
623 {
624         TcorePlugin *plugin = NULL;
625         dbg("Entry");
626
627         plugin = (TcorePlugin *) user_data;
628         _modem_subscribe_events(plugin);
629         dbg("Exit");
630         return TRUE;
631 }
632
633
634 static void on_response_enable_logging(TcorePending *p, int data_len, const void *data, void *user_data)
635 {
636         const TcoreATResponse *resp = data;
637         TcorePlugin *plugin = NULL;
638
639         plugin = tcore_pending_ref_plugin(p);
640
641         /* DELETE ME: only for DEBUG */
642         if (!resp)
643                 dbg("no data");
644
645         dbg("response...(result = %d, final_response = '%s')", resp->success, resp->final_response);
646
647         if (resp->success) {
648                 dbg("RESPONSE OK");
649                 dbg("Enabling CP logging is success !!!\n");
650         } else {
651                 dbg("RESPONSE NOK");
652                 dbg("Enabling CP logging is failed !!!\n");
653         }
654
655         dbg("Calling setup_mux");
656         setup_mux(tcore_pending_ref_core_object(p));
657
658
659         dbg("Exit");
660         return;
661 }
662
663 static void _send_enable_logging_command(CoreObject *o)
664 {
665         TcoreATRequest *req = NULL;
666         TcoreHal *hal = NULL;
667         TcorePending *pending = NULL;
668         TReturn ret = 0;
669
670         /* DLELTE ME */
671         dbg("Send Trace enabling command for CP logging. \n");
672
673         if (!o) {
674                 dbg("Co-object is Null !!\n");
675                 // goto error;
676         }
677
678         hal = tcore_object_get_hal(o);
679         pending = tcore_pending_new(o, 0);
680         req = tcore_at_request_new("at+xsystrace=1,\"digrf=1;bb_sw=1;3g_sw=1\",\"digrf=0x84\",\"oct=4\";+xsystrace=11;+trace=1", NULL, TCORE_AT_NO_RESULT);
681
682         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
683
684         tcore_pending_set_request_data(pending, 0, req);
685         tcore_pending_set_response_callback(pending, on_response_enable_logging, hal);
686         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
687
688         ret = tcore_hal_send_request(hal, pending);
689         if (ret != TCORE_RETURN_SUCCESS)
690                 dbg("tcore_hal_send_request fail !!! (hal: 0x%x, pending: 0x%x)\n", hal, pending);
691 }
692
693 static void on_response_poweron(TcorePending *p, int data_len, const void *data, void *user_data)
694 {
695         const TcoreATResponse *resp = data;
696         GSList *tokens = NULL;
697         const char *line = NULL;
698         gboolean bpoweron = FALSE;
699         int response = 0;
700
701         if (resp->success) {
702                 dbg("RESPONSE OK");
703                 /* Parse AT Response */
704                 if (resp->lines) {
705                         line = (const char *) resp->lines->data;
706                         tokens = tcore_at_tok_new(line);
707                         if (g_slist_length(tokens) != 1) {
708                                 dbg("invalid message");
709                                 bpoweron = FALSE;
710                                 goto error;
711                         }
712                 }
713
714                 response = atoi(g_slist_nth_data(tokens, 0));
715
716                 dbg("CPAS: response %d", response);
717
718                 switch (response) {
719                 case CPAS_RES_READY:
720                 case CPAS_RES_RINGING:
721                 case CPAS_RES_CALL_PROGRESS:
722                 case CPAS_RES_ASLEEP:
723                         bpoweron = TRUE;
724                         break;
725
726                 case CPAS_RES_UNAVAIL:
727                 case CPAS_RES_UNKNOWN:
728                 default:
729                         dbg("value is unvail/unknown - but CP responded - proceed poweron");
730                         // bpoweron = FALSE;
731                         bpoweron = TRUE;
732                         break;
733                 }
734         } else {
735                 dbg("CPAS: RESPONSE NOK");
736                 bpoweron = FALSE;
737         }
738
739 error:
740         /* DELE ME: AT request & response are freed after AT processing in HAL.
741          * ref.) _emit_pending_response (libtcore/src/at.c)
742          */
743         if (tokens != NULL)
744                 tcore_at_tok_free(tokens);
745
746         if (bpoweron == TRUE) {
747                 dbg("Power on NOTI received, (pending: 0x%x, co: 0x%x)\n", p, tcore_pending_ref_core_object(p));
748
749                 _send_enable_logging_command(tcore_pending_ref_core_object(p));
750         } else {
751                 dbg("CP is not ready, let us send CPAS once again");
752                 s_modem_send_poweron(tcore_object_ref_plugin(tcore_pending_ref_core_object(p)));
753         }
754         return;
755 }
756
757 static TReturn power_off(CoreObject *o, UserRequest *ur)
758 {
759         TcoreHal *hal = NULL;
760         TcoreATRequest *req = NULL;
761         TcorePending *pending = NULL;
762
763         hal = tcore_object_get_hal(o);
764         pending = tcore_pending_new(o, 0);
765
766         req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
767
768         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
769
770         tcore_pending_set_request_data(pending, 0, req);
771         tcore_pending_set_response_callback(pending, on_response_power_off, hal);
772         tcore_pending_link_user_request(pending, ur);
773         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
774
775         tcore_hal_send_request(hal, pending);
776
777         return TCORE_RETURN_SUCCESS;
778 }
779
780 static TReturn get_imei(CoreObject *o, UserRequest *ur)
781 {
782         TcoreHal *hal;
783         TcoreATRequest *req;
784         TcorePending *pending = NULL;
785
786         hal = tcore_object_get_hal(o);
787         if(FALSE == tcore_hal_get_power_state(hal)){
788                 dbg("cp not ready/n");
789                 return TCORE_RETURN_ENOSYS;
790         }
791         pending = tcore_pending_new(o, 0);
792
793         req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
794
795         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
796
797         tcore_pending_set_request_data(pending, 0, req);
798         tcore_pending_set_response_callback(pending, on_response_imei, hal);
799         tcore_pending_link_user_request(pending, ur);
800         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
801
802         tcore_hal_send_request(hal, pending);
803
804         return TCORE_RETURN_SUCCESS;
805 }
806
807
808 static TReturn get_version(CoreObject *o, UserRequest *ur)
809 {
810         TcoreHal *hal;
811         TcoreATRequest *req;
812         TcorePending *pending = NULL;
813
814         hal = tcore_object_get_hal(o);
815         if(FALSE == tcore_hal_get_power_state(hal)){
816                 dbg("cp not ready/n");
817                 return TCORE_RETURN_ENOSYS;
818         }
819         pending = tcore_pending_new(o, 0);
820
821         req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
822
823         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
824
825         tcore_pending_set_request_data(pending, 0, req);
826         tcore_pending_set_response_callback(pending, on_response_version, hal);
827         tcore_pending_link_user_request(pending, ur);
828         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
829
830         tcore_hal_send_request(hal, pending);
831
832         return TCORE_RETURN_SUCCESS;
833 }
834
835 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
836 {
837         TcoreHal *hal = NULL;
838         TcoreATRequest *req = NULL;
839         TcorePending *pending = NULL;
840         const struct treq_modem_set_flightmode *req_data = NULL;
841         char *cmd_str = NULL;
842
843         hal = tcore_object_get_hal(o);
844         if(FALSE == tcore_hal_get_power_state(hal)){
845                 dbg("cp not ready/n");
846                 return TCORE_RETURN_ENOSYS;
847         }
848         pending = tcore_pending_new(o, 0);
849
850         req_data = tcore_user_request_ref_data(ur, NULL);
851
852         if (req_data->enable) {
853                 dbg("Flight mode on/n");
854                 cmd_str = g_strdup("AT+CFUN=4");
855         } else {
856                 dbg("Flight mode off/n");
857                 cmd_str = g_strdup("AT+CFUN=1");
858         }
859
860         req = tcore_at_request_new((const char *) cmd_str, NULL, TCORE_AT_NO_RESULT);
861
862         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
863
864         tcore_pending_set_request_data(pending, 0, req);
865         tcore_pending_set_response_callback(pending, on_response_set_flight_mode, hal);
866         tcore_pending_link_user_request(pending, ur);
867         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
868
869         tcore_hal_send_request(hal, pending);
870
871         return TCORE_RETURN_SUCCESS;
872 }
873
874
875 static struct tcore_modem_operations modem_ops = {
876         .power_on = NULL,
877         .power_off = power_off,
878         .power_reset = NULL,
879         .set_flight_mode = set_flight_mode,
880         .get_imei = get_imei,
881         .get_version = get_version,
882         .get_sn = NULL,
883         .dun_pin_ctrl = NULL,
884 };
885
886 gboolean s_modem_init(TcorePlugin *p, TcoreHal *h)
887 {
888         CoreObject *o = NULL;
889         GQueue *work_queue = NULL;
890         TelMiscVersionInformation *vi_property = NULL;
891         TelMiscSNInformation *imei_property = NULL;
892         TelMiscSNInformation *sn_property = NULL;
893
894         o = tcore_modem_new(p, "modem", &modem_ops, h);
895         if (!o)
896                 return FALSE;
897
898         work_queue = g_queue_new();
899         tcore_object_link_user_data(o, work_queue);
900
901         vi_property = calloc(sizeof(TelMiscVersionInformation), 1);
902         tcore_plugin_link_property(p, "VERSION", vi_property);
903
904         imei_property = calloc(sizeof(TelMiscSNInformation), 1);
905         tcore_plugin_link_property(p, "IMEI", imei_property);
906
907         sn_property = calloc(sizeof(TelMiscSNInformation), 1);
908         tcore_plugin_link_property(p, "SN", sn_property);
909
910         dbg("Registerind for CMUX-UP event");
911         tcore_object_add_callback(o, "CMUX-UP", on_event_mux_channel_up, p);
912
913         dbg("Registering for +XSIM event");
914         tcore_object_add_callback(o, "+XSIM", on_event_bootup_sim_status, NULL);
915
916         return TRUE;
917 }
918
919 void s_modem_exit(TcorePlugin *p)
920 {
921         CoreObject *o = NULL;
922         GQueue *work_queue = NULL;
923         TelMiscVersionInformation *vi_property = NULL;
924         TelMiscSNInformation *imei_property = NULL;
925         TelMiscSNInformation *sn_property = NULL;
926
927         if (!p)
928                 return;
929
930         o = tcore_plugin_ref_core_object(p, "modem");
931
932         work_queue = tcore_object_ref_user_data(o);
933         g_queue_free(work_queue);
934
935         vi_property = tcore_plugin_ref_property(p, "VERSION");
936         if (vi_property)
937                 free(vi_property);
938
939         imei_property = tcore_plugin_ref_property(p, "IMEI");
940         if (imei_property)
941                 free(imei_property);
942
943         sn_property = tcore_plugin_ref_property(p, "SN");
944         if (sn_property)
945                 free(sn_property);
946
947         tcore_modem_free(o);
948         return;
949 }
950
951 gboolean s_modem_send_poweron(TcorePlugin *p)
952 {
953         TcoreHal *hal;
954         TcoreATRequest *req;
955         TcorePending *pending = NULL;
956         CoreObject *o;
957
958         o = tcore_plugin_ref_core_object(p, "modem");
959         hal = tcore_object_get_hal(o);
960
961         pending = tcore_pending_new(o, 0);
962
963         req = tcore_at_request_new("AT+CPAS", "+CPAS", TCORE_AT_SINGLELINE);
964
965         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
966
967         tcore_pending_set_timeout(pending, 10);
968         tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
969         tcore_pending_set_timeout_callback(pending, on_timeout_modem_poweron, hal);
970
971         tcore_pending_set_request_data(pending, 0, req);
972         tcore_pending_set_response_callback(pending, on_response_poweron, hal);
973         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
974
975         tcore_hal_send_request(hal, pending);
976
977         return TRUE;
978 }