Revert manifest to default one
[framework/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                 tcore_user_request_send_response(ur, TRESP_MODEM_SET_FLIGHTMODE, sizeof(struct tresp_modem_set_flightmode), &res);
254
255                 req_data = tcore_user_request_ref_data(ur, NULL);
256
257                 if (req_data->enable == 0) {
258                         dbg("Flight mode is disabled, trigger COPS to register on network");
259                         /* Trigger Network registration (for the moment automatic) */
260                         prepare_and_send_pending_request(tcore_object_ref_plugin(o), "modem", "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, NULL);
261                 }
262         }
263
264         tcore_at_tok_free(tokens);
265 }
266
267 static void on_response_imei(TcorePending *p, int data_len, const void *data, void *user_data)
268 {
269         const TcoreATResponse *resp = data;
270         TcorePlugin *plugin = NULL;
271         struct tresp_modem_get_imei res;
272         TelMiscSNInformation *imei_property = NULL;
273         UserRequest *ur = NULL;
274         GSList *tokens = NULL;
275         const char *line;
276         int response = 0;
277
278         memset(&res, 0, sizeof(struct tresp_modem_get_imei));
279
280         if (resp->success > 0) {
281                 dbg("RESPONSE OK");
282                 if (resp->lines) {
283                         line = (const char *) resp->lines->data;
284                         tokens = tcore_at_tok_new(line);
285                         if (g_slist_length(tokens) != 1) {
286                                 msg("invalid message");
287                                 goto OUT;
288                         }
289                 }
290                 res.result = TCORE_RETURN_SUCCESS;
291                 strncpy(res.imei, g_slist_nth_data(tokens, 0), 16);
292
293                 dbg("imei = [%s]", res.imei);
294
295                 plugin = tcore_pending_ref_plugin(p);
296                 imei_property = tcore_plugin_ref_property(plugin, "IMEI");
297                 if (imei_property) {
298                         imei_property->sn_index = TAPI_MISC_ME_IMEI;
299                         imei_property->sn_len = strlen(res.imei);
300                         memcpy(imei_property->szNumber, res.imei, imei_property->sn_len);
301                 }
302         } else {
303                 dbg("RESPONSE NOK");
304                 if (resp->lines) {
305                         line = (const char *) resp->lines->data;
306                         tokens = tcore_at_tok_new(line);
307                 }
308
309
310                 if (g_slist_length(tokens) < 1) {
311                         dbg("err cause not specified or string corrupted");
312                         res.result = TCORE_RETURN_3GPP_ERROR;
313                 } else {
314                         response = atoi(g_slist_nth_data(tokens, 0));
315                         /* TODO: CMEE error mapping is required. */
316                         res.result = TCORE_RETURN_3GPP_ERROR;
317                 }
318         }
319
320         ur = tcore_pending_ref_user_request(p);
321         tcore_user_request_send_response(ur, TRESP_MODEM_GET_IMEI, sizeof(struct tresp_modem_get_imei), &res);
322
323 OUT:
324         if (tokens != NULL)
325                 tcore_at_tok_free(tokens);
326
327         return;
328 }
329
330 static void on_response_version(TcorePending *p, int data_len, const void *data, void *user_data)
331 {
332         const TcoreATResponse *resp = data;
333         TcorePlugin *plugin = NULL;
334         struct tresp_modem_get_version res = {0};
335         TelMiscVersionInformation *vi_property = NULL;
336         TelMiscVersionInformation *vi = NULL;
337         UserRequest *ur = NULL;
338         GSList *tokens = NULL;
339         const char *line = NULL;
340         char *swver = NULL;
341         char *hwver = NULL;
342         char *caldate = NULL;
343         char *pcode = NULL;
344         char *id = NULL;
345
346         int response = 0;
347
348         if (resp->success > 0) {
349                 dbg("RESPONSE OK");
350                 if (resp->lines) {
351                         line = (const char *) resp->lines->data;
352                         tokens = tcore_at_tok_new(line);
353                         if (g_slist_length(tokens) != 5) {
354                                 msg("invalid message");
355                                 goto OUT;
356                         }
357                 }
358
359                 swver = g_slist_nth_data(tokens, 0);
360                 hwver = g_slist_nth_data(tokens, 1);
361                 caldate = g_slist_nth_data(tokens, 2);
362                 pcode = g_slist_nth_data(tokens, 3);
363                 id = g_slist_nth_data(tokens, 4);
364
365                 dbg("version: sw=[%s], hw=[%s], rf_cal=[%s], product_code=[%s], model_id=[%s]", swver, hwver, caldate, pcode, id);
366
367                 vi = calloc(sizeof(TelMiscVersionInformation), 1);
368                 if (NULL != swver)
369                         memcpy(vi->szSwVersion, swver, strlen(swver));
370                 if (NULL != hwver)
371                         memcpy(vi->szHwVersion, hwver, strlen(hwver));
372                 if (NULL != caldate)
373                         memcpy(vi->szRfCalDate, caldate, strlen(caldate));
374                 if (NULL != pcode)
375                         memcpy(vi->szProductCode, pcode, strlen(pcode));
376                 if (NULL != id)
377                         memcpy(vi->szModelId, id, strlen(id));
378
379                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
380
381                 if (NULL != swver)
382                         snprintf(res.software, (AT_VER_LEN > strlen(swver) ? strlen(swver) : AT_VER_LEN), "%s", swver);
383                 if (NULL != hwver)
384                         snprintf(res.hardware, (AT_VER_LEN > strlen(hwver) ? strlen(hwver) : AT_VER_LEN), "%s", hwver);
385
386                 plugin = tcore_pending_ref_plugin(p);
387                 vi_property = tcore_plugin_ref_property(plugin, "VERSION");
388                 memcpy(vi_property, vi, sizeof(TelMiscVersionInformation));
389                 free(vi);
390         } else {
391                 dbg("RESPONSE NOK");
392                 if (resp->lines) {
393                         line = (const char *) resp->lines->data;
394                         tokens = tcore_at_tok_new(line);
395                 }
396
397                 memset(&res, 0, sizeof(struct tresp_modem_get_version));
398
399
400                 if (g_slist_length(tokens) < 1) {
401                         dbg("err cause not specified or string corrupted");
402                         res.result = TCORE_RETURN_3GPP_ERROR;
403                 } else {
404                         response = atoi(g_slist_nth_data(tokens, 0));
405                         /* TODO: CMEE error mapping is required. */
406                         res.result = TCORE_RETURN_3GPP_ERROR;
407                 }
408         }
409
410         ur = tcore_pending_ref_user_request(p);
411         tcore_user_request_send_response(ur, TRESP_MODEM_GET_VERSION, sizeof(struct tresp_modem_get_version), &res);
412
413 OUT:
414         if (tokens != NULL)
415                 tcore_at_tok_free(tokens);
416
417         return;
418 }
419
420 static gboolean on_event_bootup_sim_status(CoreObject *o, const void *event_info, void *user_data)
421 {
422         GSList *tok = NULL;
423         GSList *lines = NULL;
424         int value = -1;
425         char *line = NULL;
426
427         lines = (GSList *) event_info;
428         if (1 != g_slist_length(lines)) {
429                 dbg("unsolicited msg but multiple line");
430                 goto OUT;
431         }
432         line = (char *) (lines->data);
433         dbg("on_bootup_event_sim_status notification : %s", line);
434
435         tok = tcore_at_tok_new(line);
436         value = atoi(g_slist_nth_data(tok, 0));
437
438         if (7 == value) {
439                 dbg("SIM ready. request COPS & remove callback");
440                 dbg("power on done set for proactive command receiving mode");
441                 prepare_and_send_pending_request(tcore_object_ref_plugin(o), "sat", "AT+CFUN=6", NULL, TCORE_AT_NO_RESULT, on_response_enable_proactive_command);
442                 prepare_and_send_pending_request(tcore_object_ref_plugin(o), "umts_network", "AT+COPS=0", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
443                 return FALSE;
444         }
445
446 OUT:
447         if (tok != NULL)
448                 tcore_at_tok_free(tok);
449
450         return TRUE;
451 }
452
453
454
455 gboolean on_event_modem_power(TcoreAT *at, const char *line, TcorePlugin *p)
456 {
457         CoreObject *o = NULL;
458         struct treq_modem_set_flightmode flight_mode_set = {0};
459         struct tnoti_modem_power modem_power = {0};
460         TcoreHal *h = NULL;
461         Storage *strg = NULL;
462
463         o = tcore_plugin_ref_core_object(p, "modem");
464
465         strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "vconf");
466         flight_mode_set.enable = tcore_storage_get_bool(strg, STORAGE_KEY_SETAPPL_FLIGHT_MODE_BOOL);
467
468         h = tcore_object_get_hal(o);
469         tcore_hal_set_power_state(h, TRUE);
470
471         /* Set Flight mode as per AP settings */
472         if (flight_mode_set.enable) { /* Radio Off */
473                 prepare_and_send_pending_request(p, "modem", "AT+CFUN=4", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
474                 tcore_modem_set_flight_mode_state(o, TRUE);
475         } else { /* Radio On */
476                 prepare_and_send_pending_request(p, "modem", "AT+CFUN=1", NULL, TCORE_AT_NO_RESULT, on_response_set_flight_mode);
477                 tcore_modem_set_flight_mode_state(o, FALSE);
478         }
479
480         /* Get IMEI */
481         prepare_and_send_pending_request(p, "modem", "AT+CGSN", NULL, TCORE_AT_NUMERIC, on_response_imei);
482
483         /* Get Version Number  */
484         prepare_and_send_pending_request(p, "modem", "AT+CGMR", NULL, TCORE_AT_SINGLELINE, on_response_version);
485
486         tcore_modem_set_powered(o, TRUE);
487
488         modem_power.state = MODEM_STATE_ONLINE;
489
490         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o, TNOTI_MODEM_POWER,
491                                                                    sizeof(struct tnoti_modem_power), &modem_power);
492
493         return TRUE;
494 }
495
496 static void _modem_subscribe_events(TcorePlugin *plugin)
497 {
498         dbg("Entry");
499
500         /* XCALLSTAT subscription */
501         prepare_and_send_pending_request(plugin, "call", "at+xcallstat=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
502
503         /* XSIMSTATE subscription */
504         prepare_and_send_pending_request(plugin, "sim", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
505
506         prepare_and_send_pending_request(plugin, "umts_sms", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
507         prepare_and_send_pending_request(plugin, "modem", "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
508
509         /* CREG subscription */
510         prepare_and_send_pending_request(plugin, "umts_network", "at+creg=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
511
512         /* CGREG subscription */
513         prepare_and_send_pending_request(plugin, "umts_network", "at+cgreg=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
514
515         /* Allow automatic time Zone updation via NITZ */
516         prepare_and_send_pending_request(plugin, "umts_network", "at+ctzu=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
517
518         /* TZ, time & daylight changing event reporting subscription */
519         prepare_and_send_pending_request(plugin, "umts_network", "at+ctzr=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
520
521         /* XMER subscription */
522         prepare_and_send_pending_request(plugin, "umts_network", "at+xmer=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
523
524         /* CGEREP subscription */
525         prepare_and_send_pending_request(plugin, "umts_ps", "at+cgerep=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
526
527         /* XDATASTAT subscription */
528         prepare_and_send_pending_request(plugin, "umts_ps", "at+xdatastat=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
529
530         /* CSSN subscription */
531         prepare_and_send_pending_request(plugin, "call", "at+cssn=1,1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
532
533         /* CUSD subscription */
534         prepare_and_send_pending_request(plugin, "call", "at+cusd=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
535
536         /* XDNS subscription */
537         prepare_and_send_pending_request(plugin, "umts_ps", "at+xdns=1,1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
538
539         /* CLIP subscription */
540         prepare_and_send_pending_request(plugin, "call", "at+clip=1", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
541
542         /*CMEE subscription*/
543         prepare_and_send_pending_request(plugin, "umts_ps", "at+cmee=2", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
544
545         /*incoming sms,cb,status report subscription*/
546         prepare_and_send_pending_request(plugin, "umts_sms", "at+cnmi=1,2,2,1,0", NULL, TCORE_AT_NO_RESULT, on_response_bootup_subscription);
547
548         /* text/pdu mode subscription*/
549         prepare_and_send_pending_request(plugin, "umts_sms", "at+cmgf=0", NULL, TCORE_AT_NO_RESULT, on_response_last_bootup_subscription);
550
551         dbg("Exit");
552         return;
553 }
554
555
556 static void on_response_setupmux(TcorePending *p, int data_len, const void *data, void *user_data)
557 {
558         TcorePlugin *plugin = NULL;
559         TcoreHal *hal = NULL;
560         TReturn ret;
561         dbg("Entry");
562
563         /* IMC Plugin dereferenced from pending request */
564         plugin = tcore_pending_ref_plugin(p);
565
566         /* Actual HAL - like svnet(2) */
567         hal = (TcoreHal *) user_data;
568
569         /* Initialize CMUX */
570         ret = tcore_cmux_init(plugin, hal);
571         if (TCORE_RETURN_SUCCESS == ret) {
572                 dbg("Successfully initialized CMUX");
573         } else {
574                 err("Failed to initialize CMUX");
575         }
576
577         dbg("Exit");
578         return;
579 }
580
581
582
583 static void setup_mux(CoreObject *o)
584 {
585         TcoreHal *hal = NULL;
586         TcorePending *pending = NULL;
587         dbg("Entered");
588
589         /* HAL has type itself,
590          * e.g.) TCORE_HAL_MODE_AT
591          */
592         hal = tcore_object_get_hal(o);
593
594         pending = tcore_at_pending_new(o, "AT+CMUX=0,0,,1509,10,3,30,,", "+CMUX", TCORE_AT_NO_RESULT, on_response_setupmux, hal);
595
596         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
597
598         /* Send callback */
599         tcore_hal_send_request(hal, pending);
600
601         dbg("Exit");
602         return;
603 }
604
605
606 static gboolean on_event_mux_channel_up(CoreObject *o, const void *event_info, void *user_data)
607 {
608         TcorePlugin *plugin = NULL;
609         dbg("Entry");
610
611         plugin = (TcorePlugin *) user_data;
612         _modem_subscribe_events(plugin);
613         dbg("Exit");
614         return TRUE;
615 }
616
617
618 static void on_response_enable_logging(TcorePending *p, int data_len, const void *data, void *user_data)
619 {
620         const TcoreATResponse *resp = data;
621         TcorePlugin *plugin = NULL;
622
623         plugin = tcore_pending_ref_plugin(p);
624
625         /* DELETE ME: only for DEBUG */
626         if (!resp)
627                 dbg("no data");
628
629         dbg("response...(result = %d, final_response = '%s')", resp->success, resp->final_response);
630
631         if (resp->success) {
632                 dbg("RESPONSE OK");
633                 dbg("Enabling CP logging is success !!!\n");
634         } else {
635                 dbg("RESPONSE NOK");
636                 dbg("Enabling CP logging is failed !!!\n");
637         }
638
639         dbg("Calling setup_mux");
640         setup_mux(tcore_pending_ref_core_object(p));
641
642
643         dbg("Exit");
644         return;
645 }
646
647 static void _send_enable_logging_command(CoreObject *o)
648 {
649         TcoreATRequest *req = NULL;
650         TcoreHal *hal = NULL;
651         TcorePending *pending = NULL;
652         TReturn ret = 0;
653
654         /* DLELTE ME */
655         dbg("Send Trace enabling command for CP logging. \n");
656
657         if (!o) {
658                 dbg("Co-object is Null !!\n");
659                 // goto error;
660         }
661
662         hal = tcore_object_get_hal(o);
663         pending = tcore_pending_new(o, 0);
664         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);
665
666         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
667
668         tcore_pending_set_request_data(pending, 0, req);
669         tcore_pending_set_response_callback(pending, on_response_enable_logging, hal);
670         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
671
672         ret = tcore_hal_send_request(hal, pending);
673         if (ret != TCORE_RETURN_SUCCESS)
674                 dbg("tcore_hal_send_request fail !!! (hal: 0x%x, pending: 0x%x)\n", hal, pending);
675 }
676
677 static void on_response_poweron(TcorePending *p, int data_len, const void *data, void *user_data)
678 {
679         const TcoreATResponse *resp = data;
680         GSList *tokens = NULL;
681         const char *line = NULL;
682         gboolean bpoweron = FALSE;
683         int response = 0;
684
685         if (resp->success) {
686                 dbg("RESPONSE OK");
687                 /* Parse AT Response */
688                 if (resp->lines) {
689                         line = (const char *) resp->lines->data;
690                         tokens = tcore_at_tok_new(line);
691                         if (g_slist_length(tokens) != 1) {
692                                 dbg("invalid message");
693                                 bpoweron = FALSE;
694                                 goto error;
695                         }
696                 }
697
698                 response = atoi(g_slist_nth_data(tokens, 0));
699
700                 dbg("CPAS: response %d", response);
701
702                 switch (response) {
703                 case CPAS_RES_READY:
704                 case CPAS_RES_RINGING:
705                 case CPAS_RES_CALL_PROGRESS:
706                 case CPAS_RES_ASLEEP:
707                         bpoweron = TRUE;
708                         break;
709
710                 case CPAS_RES_UNAVAIL:
711                 case CPAS_RES_UNKNOWN:
712                 default:
713                         dbg("value is unvail/unknown - but CP responded - proceed poweron");
714                         // bpoweron = FALSE;
715                         bpoweron = TRUE;
716                         break;
717                 }
718         } else {
719                 dbg("CPAS: RESPONSE NOK");
720                 bpoweron = FALSE;
721         }
722
723 error:
724         /* DELE ME: AT request & response are freed after AT processing in HAL.
725          * ref.) _emit_pending_response (libtcore/src/at.c)
726          */
727         if (tokens != NULL)
728                 tcore_at_tok_free(tokens);
729
730         if (bpoweron == TRUE) {
731                 dbg("Power on NOTI received, (pending: 0x%x, co: 0x%x)\n", p, tcore_pending_ref_core_object(p));
732
733                 _send_enable_logging_command(tcore_pending_ref_core_object(p));
734         } else {
735                 dbg("CP is not ready, let us send CPAS once again");
736                 s_modem_send_poweron(tcore_object_ref_plugin(tcore_pending_ref_core_object(p)));
737         }
738         return;
739 }
740
741 static TReturn power_off(CoreObject *o, UserRequest *ur)
742 {
743         TcoreHal *hal = NULL;
744         TcoreATRequest *req = NULL;
745         TcorePending *pending = NULL;
746
747         hal = tcore_object_get_hal(o);
748         pending = tcore_pending_new(o, 0);
749
750         req = tcore_at_request_new("AT+CFUN=0", NULL, TCORE_AT_NO_RESULT);
751
752         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
753
754         tcore_pending_set_request_data(pending, 0, req);
755         tcore_pending_set_response_callback(pending, on_response_power_off, hal);
756         tcore_pending_link_user_request(pending, ur);
757         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
758
759         tcore_hal_send_request(hal, pending);
760
761         return TCORE_RETURN_SUCCESS;
762 }
763
764 static TReturn get_imei(CoreObject *o, UserRequest *ur)
765 {
766         TcoreHal *hal;
767         TcoreATRequest *req;
768         TcorePending *pending = NULL;
769
770         hal = tcore_object_get_hal(o);
771         pending = tcore_pending_new(o, 0);
772
773         req = tcore_at_request_new("AT+CGSN", NULL, TCORE_AT_NUMERIC);
774
775         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
776
777         tcore_pending_set_request_data(pending, 0, req);
778         tcore_pending_set_response_callback(pending, on_response_imei, hal);
779         tcore_pending_link_user_request(pending, ur);
780         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
781
782         tcore_hal_send_request(hal, pending);
783
784         return TCORE_RETURN_SUCCESS;
785 }
786
787
788 static TReturn get_version(CoreObject *o, UserRequest *ur)
789 {
790         TcoreHal *hal;
791         TcoreATRequest *req;
792         TcorePending *pending = NULL;
793
794         hal = tcore_object_get_hal(o);
795         pending = tcore_pending_new(o, 0);
796
797         req = tcore_at_request_new("AT+CGMR", NULL, TCORE_AT_SINGLELINE);
798
799         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
800
801         tcore_pending_set_request_data(pending, 0, req);
802         tcore_pending_set_response_callback(pending, on_response_version, hal);
803         tcore_pending_link_user_request(pending, ur);
804         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
805
806         tcore_hal_send_request(hal, pending);
807
808         return TCORE_RETURN_SUCCESS;
809 }
810
811 static TReturn set_flight_mode(CoreObject *o, UserRequest *ur)
812 {
813         TcoreHal *hal = NULL;
814         TcoreATRequest *req = NULL;
815         TcorePending *pending = NULL;
816         const struct treq_modem_set_flightmode *req_data = NULL;
817         char *cmd_str = NULL;
818
819         hal = tcore_object_get_hal(o);
820         pending = tcore_pending_new(o, 0);
821
822         req_data = tcore_user_request_ref_data(ur, NULL);
823
824         if (req_data->enable) {
825                 dbg("Flight mode on/n");
826                 cmd_str = g_strdup("AT+CFUN=4");
827         } else {
828                 dbg("Flight mode off/n");
829                 cmd_str = g_strdup("AT+CFUN=1");
830         }
831
832         req = tcore_at_request_new((const char *) cmd_str, NULL, TCORE_AT_NO_RESULT);
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_set_flight_mode, 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
847 static struct tcore_modem_operations modem_ops = {
848         .power_on = NULL,
849         .power_off = power_off,
850         .power_reset = NULL,
851         .set_flight_mode = set_flight_mode,
852         .get_imei = get_imei,
853         .get_version = get_version,
854         .get_sn = NULL,
855         .dun_pin_ctrl = NULL,
856 };
857
858 gboolean s_modem_init(TcorePlugin *p, TcoreHal *h)
859 {
860         CoreObject *o = NULL;
861         GQueue *work_queue = NULL;
862         TelMiscVersionInformation *vi_property = NULL;
863         TelMiscSNInformation *imei_property = NULL;
864         TelMiscSNInformation *sn_property = NULL;
865
866         o = tcore_modem_new(p, "modem", &modem_ops, h);
867         if (!o)
868                 return FALSE;
869
870         work_queue = g_queue_new();
871         tcore_object_link_user_data(o, work_queue);
872
873         vi_property = calloc(sizeof(TelMiscVersionInformation), 1);
874         tcore_plugin_link_property(p, "VERSION", vi_property);
875
876         imei_property = calloc(sizeof(TelMiscSNInformation), 1);
877         tcore_plugin_link_property(p, "IMEI", imei_property);
878
879         sn_property = calloc(sizeof(TelMiscSNInformation), 1);
880         tcore_plugin_link_property(p, "SN", sn_property);
881
882         dbg("Registerind for CMUX-UP event");
883         tcore_object_add_callback(o, "CMUX-UP", on_event_mux_channel_up, p);
884
885         dbg("Registering for +XSIM event");
886         tcore_object_add_callback(o, "+XSIM", on_event_bootup_sim_status, NULL);
887
888         return TRUE;
889 }
890
891 void s_modem_exit(TcorePlugin *p)
892 {
893         CoreObject *o = NULL;
894         GQueue *work_queue = NULL;
895         TelMiscVersionInformation *vi_property = NULL;
896         TelMiscSNInformation *imei_property = NULL;
897         TelMiscSNInformation *sn_property = NULL;
898
899         if (!p)
900                 return;
901
902         o = tcore_plugin_ref_core_object(p, "modem");
903
904         work_queue = tcore_object_ref_user_data(o);
905         g_queue_free(work_queue);
906
907         vi_property = tcore_plugin_ref_property(p, "VERSION");
908         if (vi_property)
909                 free(vi_property);
910
911         imei_property = tcore_plugin_ref_property(p, "IMEI");
912         if (imei_property)
913                 free(imei_property);
914
915         sn_property = tcore_plugin_ref_property(p, "SN");
916         if (sn_property)
917                 free(sn_property);
918
919         tcore_modem_free(o);
920         return;
921 }
922
923 gboolean s_modem_send_poweron(TcorePlugin *p)
924 {
925         TcoreHal *hal;
926         TcoreATRequest *req;
927         TcorePending *pending = NULL;
928         CoreObject *o;
929
930         o = tcore_plugin_ref_core_object(p, "modem");
931         hal = tcore_object_get_hal(o);
932
933         pending = tcore_pending_new(o, 0);
934
935         req = tcore_at_request_new("AT+CPAS", "+CPAS", TCORE_AT_SINGLELINE);
936
937         dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd));
938
939         tcore_pending_set_timeout(pending, 10);
940         tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT);
941         tcore_pending_set_timeout_callback(pending, on_timeout_modem_poweron, hal);
942
943         tcore_pending_set_request_data(pending, 0, req);
944         tcore_pending_set_response_callback(pending, on_response_poweron, hal);
945         tcore_pending_set_send_callback(pending, on_confirmation_modem_message_send, NULL);
946
947         tcore_hal_send_request(hal, pending);
948
949         return TRUE;
950 }