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