d92b17d030c7fd6b82f99c9cd648c3fe40d77808
[platform/core/telephony/tel-plugin-imc.git] / src / imc_network.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33 #include <tzplatform_config.h>
34
35 #include <co_network.h>
36
37 #include "imc_network.h"
38 #include "imc_common.h"
39
40 #define IMC_NETWORK_BASE_16     16
41
42 static TelNetworkAct __imc_network_map_act(guint act)
43 {
44         /*
45          * <ACT>
46          * 0    GSM
47          * 2    UTRAN
48          * 3    GSM w/EGPRS
49          * 4    UTRAN w/HSDPA
50          * 5    UTRAN w/HSUPA
51          * 6    UTRAN w/HSDPA and HSUPA
52          */
53         switch (act) {
54         case 0:
55                 return TEL_NETWORK_ACT_GSM;
56         case 2:
57                 return TEL_NETWORK_ACT_UMTS;
58         case 3:
59                 return TEL_NETWORK_ACT_EGPRS;
60         case 4:
61                 return TEL_NETWORK_ACT_HSDPA;
62         case 5:
63                 return TEL_NETWORK_ACT_HSUPA;
64         case 6:
65                 return TEL_NETWORK_ACT_HSPA;
66         default:
67                 return TEL_NETWORK_ACT_UNKNOWN;
68         }
69 }
70
71 static TelNetworkRegStatus __imc_network_map_stat(guint stat)
72 {
73         /*
74          * <stat>
75          * 0    Not registered, ME is not currently searching a
76          *      new operator to register to
77          * 1    Registered, home network
78          * 2    Not registered, but ME is currently searching a
79          *      new operator to register
80          * 3    Registration denied
81          * 4    Unknown
82          * 5    Registered, in roaming
83          */
84         switch (stat) {
85         case 0:
86                 return TEL_NETWORK_REG_STATUS_UNREGISTERED;
87         case 1:
88                 return TEL_NETWORK_REG_STATUS_REGISTERED;
89         case 2:
90                 return TEL_NETWORK_REG_STATUS_SEARCHING;
91         case 3:
92                 return TEL_NETWORK_REG_STATUS_DENIED;
93         case 4:
94                 return TEL_NETWORK_REG_STATUS_UNKNOWN;
95         case 5:
96                 return TEL_NETWORK_REG_STATUS_ROAMING;
97         default:
98                 return TEL_NETWORK_REG_STATUS_UNKNOWN;
99         }
100 }
101
102 static void __on_response_imc_network_registration(TcorePending *p,
103         guint data_len, const void *data, void *user_data)
104 {
105         const TcoreAtResponse *at_resp = data;
106         dbg("Entry");
107
108         if (at_resp && at_resp->success) {
109                 dbg("Network Registration - [OK]");
110         } else {
111                 err("Network Registration - [NOK]");
112         }
113 }
114
115 static void __imc_network_register_to_network(CoreObject *co)
116 {
117         TelReturn ret;
118
119         /* Send Request to modem */
120         ret = tcore_at_prepare_and_send_request(co,
121                 "AT+COPS=0", NULL,
122                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
123                 TCORE_PENDING_PRIORITY_DEFAULT,
124                 NULL,
125                 __on_response_imc_network_registration, NULL,
126                 on_send_imc_request, NULL,
127                 0, NULL, NULL);
128         dbg("Sending Network Registration request: [%s]",
129                 (ret == TEL_RETURN_SUCCESS ? "SUCCESS" : "FAIL"));
130 }
131
132 static void __on_response_imc_network_fetch_nw_name_internal(CoreObject *co,
133         gint result, const void *response, void *user_data)
134 {
135         TelNetworkIdentityInfo *identity = (TelNetworkIdentityInfo *)response;
136
137         /* Send notification if result is SUCCESS */
138         if (result == TEL_NETWORK_RESULT_SUCCESS)
139                 tcore_object_send_notification(co,
140                         TCORE_NOTIFICATION_NETWORK_IDENTITY,
141                         sizeof(TelNetworkIdentityInfo), identity);
142 }
143
144 static TcoreHookReturn __on_response_imc_hook_set_flight_mode(CoreObject *co,
145         gint result, TcoreCommand command, const void *response, const void *user_data)
146 {
147
148         tcore_check_return_value(result == TEL_MODEM_RESULT_SUCCESS,
149                 TCORE_HOOK_RETURN_CONTINUE);
150
151         dbg("Flight mode 'disabled', register to Network");
152
153         /*
154          * TODO - Check for selection_mode
155          *      Need to check if it is Manual or Automatic and based on
156          *      that need to initiate Network Registratin accordingly.
157          */
158         __imc_network_register_to_network(co);
159
160         return TCORE_HOOK_RETURN_CONTINUE;
161 }
162
163 static void __on_response_imc_network_fetch_nw_name(TcorePending *p,
164         guint data_len, const void *data, void *user_data)
165 {
166         const TcoreAtResponse *at_resp = data;
167         CoreObject *co = tcore_pending_ref_core_object(p);
168         ImcRespCbData *resp_cb_data = user_data;
169         TelNetworkIdentityInfo identity = {0, };
170
171         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE;
172
173         dbg("Enter");
174
175         tcore_check_return_assert(co != NULL);
176         tcore_check_return_assert(resp_cb_data != NULL);
177
178         if (at_resp && at_resp->success) {
179                 if (at_resp->lines) {
180                         const gchar *line;
181                         GSList *tokens = NULL;
182                         gchar *token_str;
183                         guint i, nol;
184
185                         /* Validate that only 3 lines of response is received */
186                         nol = g_slist_length(at_resp->lines);
187                         if (nol > 3) {
188                                 err("Invalid response message");
189                                 return;
190                         }
191
192                         /* Process the Multi-line response */
193                         for (i = 0; i < nol; i++) {
194                                 line = g_slist_nth_data(at_resp->lines, i);
195
196                                 /*
197                                  * Tokenize
198                                  *
199                                  * +XCOPS: <type>[,<name>[,<display_condition>]]
200                                  */
201                                 dbg("<line> : [%s]", line);
202                                 tokens = tcore_at_tok_new(line);
203
204                                 if ((token_str = tcore_at_tok_nth(tokens, 0))) {
205                                         guint type = atoi(token_str);
206                                         dbg("<type> : [%d]", type);
207
208                                         switch (type) {
209                                         case 0: /* PLMN (mcc, mnc) */
210                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
211                                                         if (strlen(token_str) > 0) {
212                                                                 identity.plmn = tcore_at_tok_extract((const char *)token_str);
213
214                                                                 /* Update PLMN */
215                                                                 tcore_network_set_plmn( co, identity.plmn);
216                                                         }
217                                                 }
218                                         break;
219
220                                         case 1: /* Short Name in ROM (NV-RAM) */
221                                         case 3: /* Short Network Operator Name (CPHS) */
222                                         case 5: /* Short NITZ Name */
223                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
224                                                         if (strlen(token_str) > 0) {
225                                                                 identity.short_name = tcore_at_tok_extract((const char *)token_str);
226
227
228                                                                 /* Update Short name */
229                                                                 tcore_network_set_short_name(co, identity.short_name);
230                                                         }
231                                                 }
232                                         break;
233
234                                         case 2: /* Long Name in ROM (NV-RAM) */
235                                         case 4: /* Long Network Operator Name (CPHS) */
236                                         case 6: /* Full NITZ Name */
237                                                 if ((token_str = tcore_at_tok_nth(tokens, 1))) {
238                                                         if (strlen(token_str) > 0) {
239                                                                 identity.long_name = tcore_at_tok_extract((const char *)token_str);
240
241                                                                 /* Update Long name */
242                                                                 tcore_network_set_long_name(co, identity.long_name);
243                                                         }
244                                                 }
245                                         break;
246
247                                         default:
248                                         break;
249                                         }
250                                 }
251
252                                 /* Free resource */
253                                 tcore_at_tok_free(tokens);
254                         }
255
256                         /* Send Notification - Network identity */
257                         dbg("Network name - Long name: [%s] Short name: [%s] "
258                                 "PLMN: [%s]", identity.long_name,
259                                 identity.short_name, identity.plmn);
260
261                         result = TEL_NETWORK_RESULT_SUCCESS;
262                 }
263         }
264
265         /* Invoke callback */
266         if (resp_cb_data->cb)
267                 resp_cb_data->cb(co, (gint)result, &identity, resp_cb_data->cb_data);
268
269         /* Free resource */
270         tcore_free(identity.long_name);
271         tcore_free(identity.short_name);
272         tcore_free(identity.plmn);
273
274         /* Free callback data */
275         imc_destroy_resp_cb_data(resp_cb_data);
276 }
277
278 /*
279  * Operation - fetch_nw_name
280  *
281  * Request -
282  * AT-Command: AT+XCOPS=<Type>
283  *
284  * <type> may be
285  * 0    numeric format of network MCC/MNC (three BCD
286  *      digit country code and two/three BCD digit network code)
287  * 1    Short Name in ROM (NV-RAM)
288  * 2    Long Name in ROM (NV-RAM)
289  * 3    Short Network Operator Name (CPHS)
290  * 4    Long Network Operator Name (CPHS)
291  * 5    Short NITZ Name
292  * 6    Full NITZ Name
293  * 7    Service Provider Name
294  * 8    EONS short operator name from EF-PNN
295  * 9    EONS long operator name from EF-PNN
296  * 11   Short PLMN name (When PS or CS is registered)
297  * 12   Long PLMN name (When PS or CS is registered)
298  * 13   numeric format of network MCC/MNC even in limited service
299  *
300  * Response - Network name
301  * Success: (Multiple Single line)
302  *      +XCOPS: <type>[,<name>[,<display_condition>]]
303  *      OK
304  * Failure:
305  *      +CME ERROR: <error>
306  */
307 static TelReturn __imc_network_fetch_nw_name(CoreObject *co,
308         TcoreObjectResponseCallback cb, void *cb_data)
309 {
310         ImcRespCbData *resp_cb_data = NULL;
311         TelReturn ret;
312
313         /* Response callback data */
314         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
315
316         /* Send Request to modem */
317         ret = tcore_at_prepare_and_send_request(co,
318                 "AT+XCOPS=0;+XCOPS=5;+XCOPS=6", "+XCOPS",
319                 TCORE_AT_COMMAND_TYPE_MULTILINE,
320                 TCORE_PENDING_PRIORITY_DEFAULT,
321                 NULL,
322                 __on_response_imc_network_fetch_nw_name, resp_cb_data,
323                 on_send_imc_request, NULL,
324                 0, NULL, NULL);
325         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Fetch Network name");
326
327         return ret;
328 }
329
330 /* Hook functions */
331 static TcoreHookReturn on_hook_imc_set_flight_mode(CoreObject *co,
332         TcoreCommand command, const void *request, const void *user_data,
333         TcoreObjectResponseCallback cb, const void *cb_data)
334 {
335         gboolean *flight_mode = (gboolean *)request;
336
337         /*
338          * Hook Set Flight mode request.
339          *
340          * Disable Flight mode - Hook response (if success Register to Network)
341          * Enable Flight mode - return
342          */
343         if(*flight_mode != TRUE) {
344                 /* Add response hook */
345                 tcore_object_add_response_hook(co, command, request,
346                         __on_response_imc_hook_set_flight_mode, NULL);
347
348                 return TCORE_HOOK_RETURN_CONTINUE;
349         }
350
351         dbg("Flight mode - [Enabled]");
352         return TCORE_HOOK_RETURN_CONTINUE;
353 }
354
355 static TcoreHookReturn on_hook_imc_sim_status(TcorePlugin *plugin,
356         TcoreNotification command, guint data_len, void *data, void *user_data)
357 {
358         const TelSimCardStatus *sim_status = (TelSimCardStatus *)data;
359
360         tcore_check_return_value(sim_status != NULL,
361                 TCORE_HOOK_RETURN_CONTINUE);
362
363         /*
364          * Hook SIM initialization Notification
365          *
366          * SIM INIT complete - Attach to network (Register to network)
367          * SIM INIT not complete - return
368          */
369         if (*sim_status == TEL_SIM_STATUS_SIM_INIT_COMPLETED) {
370                 CoreObject *co = (CoreObject *)user_data;
371                 dbg("SIM Initialized!!! Attach to Network");
372
373                 tcore_check_return_value_assert(co != NULL,
374                         TCORE_HOOK_RETURN_CONTINUE);
375
376                 /*
377                  * TODO - Check for selection_mode
378                  *      Need to check if it is Manual or Automatic and based on
379                  *      that need to initiate Network Registratin accordingly.
380                  */
381                 __imc_network_register_to_network(co);
382
383                 return TCORE_HOOK_RETURN_CONTINUE;
384         }
385
386         dbg("SIM not yet initialized - SIM Status: [%d]", *sim_status);
387         return TCORE_HOOK_RETURN_CONTINUE;
388 }
389
390 /* Notification callbacks */
391 /*
392  * Notification: +CREG: <stat>[,<lac>,<ci>[,<AcT>]]
393  *
394  * Possible values of <stat> can be
395  * 0    Not registered, ME is not currently searching
396  *      a new operator to register to
397  * 1    Registered, home network
398  * 2    Not registered, but ME is currently searching
399  *      a new operator to register
400  * 3    Registration denied
401  * 4    Unknown
402  * 5    Registered, in roaming
403  *
404  * <lac>
405  *      string type; two byte location area code in
406  *      hexadecimal format (e.g. 00C3)
407  *
408  * <ci>
409  *      string type; four byte cell ID in hexadecimal
410  *      format (e.g. 0000A13F)
411  *
412  * <ACT>
413  * 0    GSM
414  * 2    UTRAN
415  * 3    GSM w/EGPRS
416  * 4    UTRAN w/HSDPA
417  * 5    UTRAN w/HSUPA
418  * 6    UTRAN w/HSDPA and HSUPA
419  */
420 static gboolean on_notification_imc_cs_network_info(CoreObject *co,
421         const void *event_info, void *user_data)
422 {
423         GSList *lines = NULL;
424         gchar *line = NULL;
425
426         dbg("Network notification - CS network info: [+CREG]");
427
428         lines = (GSList *)event_info;
429         if (g_slist_length(lines) != 1) {
430                 err("+CREG unsolicited message expected to be Single line "
431                         "but received multiple lines");
432                 return TRUE;
433         }
434
435         line = (gchar *) (lines->data);
436         if (line != NULL) {
437                 TelNetworkRegStatusInfo registration_status = {0, };
438                 TelNetworkCellInfo cell_info = {0, };
439                 GSList *tokens = NULL;
440                 gchar *token_str;
441                 guint stat = 0, act = 0, lac = 0, ci = 0;
442                 gboolean roam_state = FALSE;
443
444                 /*
445                  * Tokenize
446                  *
447                  * +CREG: <stat>[,<lac>,<ci>[,<AcT>]]
448                  */
449                 tokens = tcore_at_tok_new(line);
450                 if (g_slist_length(tokens) < 1) {
451                         err("Invalid notification message");
452                         goto out;
453                 }
454
455                 /* <stat> */
456                 if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) {
457                         err("No <stat> in +CREG");
458                         goto out;
459                 }
460                 stat = __imc_network_map_stat(atoi(token_str));
461                 (void)tcore_network_set_cs_reg_status(co, stat);
462
463                 /* <lac> */
464                 if ((token_str = g_slist_nth_data(tokens, 1))) {
465                         token_str = tcore_at_tok_extract((const gchar *)token_str);
466
467                         lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
468
469                         /* Update Location Area Code (lac) information */
470                         (void)tcore_network_set_lac(co, lac);
471
472                         tcore_free(token_str);
473                 } else {
474                         dbg("No <lac> in +CREG");
475                         (void)tcore_network_get_lac(co, &lac);
476                 }
477
478                 /* <ci> */
479                 if ((token_str = g_slist_nth_data(tokens, 2))) {
480                         token_str = tcore_at_tok_extract((const gchar *)token_str);
481
482                         ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
483
484                         /* Update Cell ID (ci) information */
485                         (void)tcore_network_set_cell_id(co, ci);
486
487                         tcore_free(token_str);
488                 } else {
489                         dbg("No <ci> in +CREG");
490                         (void)tcore_network_get_cell_id(co, &ci);
491                 }
492
493                 /* <AcT> */
494                 if ((token_str = g_slist_nth_data(tokens, 3))) {
495                         act = __imc_network_map_act(atoi(token_str));
496                         (void)tcore_network_set_access_technology(co, act);
497                 } else {
498                         dbg("No <AcT> in +CREG");
499                         (void)tcore_network_get_access_technology(co, &act);
500                 }
501                 dbg("<stat>: %d <lac>: 0x%x <ci>: 0x%x <AcT>: %d", stat, lac, ci, act);
502
503                 /* Send Notification - Network (CS) Registration status */
504                 registration_status.cs_status = stat;
505                 registration_status.act = act;
506                 (void)tcore_network_get_ps_reg_status(co, &registration_status.ps_status);
507
508                 tcore_object_send_notification(co,
509                         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
510                         sizeof(TelNetworkRegStatusInfo), &registration_status);
511
512                 switch (stat) {
513                 case TEL_NETWORK_REG_STATUS_ROAMING:
514                         roam_state = TRUE; // no break
515                 case TEL_NETWORK_REG_STATUS_REGISTERED:
516                         /* Fetch Network name - Internal request */
517                         (void)__imc_network_fetch_nw_name(co,
518                                 __on_response_imc_network_fetch_nw_name_internal, NULL);
519                 break;
520                 default:
521                 break;
522                 }
523
524                 /* Set Roaming state */
525                 tcore_network_set_roam_state(co, roam_state);
526
527                 /* Send Notification - Cell info */
528                 cell_info.lac = (gint)lac;
529                 cell_info.cell_id = (gint)ci;
530                 (void)tcore_network_get_rac(co, &cell_info.rac);
531
532                 tcore_object_send_notification(co,
533                         TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO,
534                         sizeof(TelNetworkCellInfo), &cell_info);
535
536 out:
537                 /* Free resource */
538                 tcore_at_tok_free(tokens);
539         }
540
541         return TRUE;
542 }
543
544 /*
545  * Notification: +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]]
546  *
547  * Possible values of <stat> can be
548  * 0    Not registered, ME is not currently searching a
549  *      new operator to register to
550  * 1    Registered, home network
551  * 2    Not registered, but ME is currently searching a
552  *      new operator to register
553  * 3    Registration denied
554  * 4    Unknown
555  * 5    Registered, in roaming
556  *
557  * <lac>
558  *      string type; two byte location area code in
559  *      hexadecimal format (e.g. 00C3)
560  *
561  * <ci>
562  *      string type; four byte cell ID in hexadecimal
563  *      format (e.g. 0000A13F)
564  *
565  * <ACT>
566  * 0    GSM
567  * 2    UTRAN
568  * 3    GSM w/EGPRS
569  * 4    UTRAN w/HSDPA
570  * 5    UTRAN w/HSUPA
571  * 6    UTRAN w/HSDPA and HSUPA
572  *
573  * <rac>:
574  *      string type; one byte routing area code in hexadecimal format
575  */
576 static gboolean on_notification_imc_ps_network_info(CoreObject *co,
577         const void *event_info, void *user_data)
578 {
579         GSList *lines = NULL;
580         gchar *line = NULL;
581
582         dbg("Network notification - PS network info: [+CGREG]");
583
584         lines = (GSList *)event_info;
585         if (g_slist_length(lines) != 1) {
586                 err("+CGREG unsolicited message expected to be Single line "
587                         "but received multiple lines");
588                 return TRUE;
589         }
590
591         line = (gchar *) (lines->data);
592         if (line != NULL) {
593                 TelNetworkRegStatusInfo registration_status = {0, };
594                 TelNetworkCellInfo cell_info = {0, };
595                 GSList *tokens = NULL;
596                 gchar *token_str;
597                 guint stat = 0, act = 0, lac = 0, ci = 0, rac = 0;
598                 gboolean roam_state = FALSE;
599
600                 /*
601                  * Tokenize
602                  *
603                  * +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]]
604                  */
605                 tokens = tcore_at_tok_new(line);
606                 if (g_slist_length(tokens) < 1) {
607                         err("Invalid notification message");
608                         goto out;
609                 }
610
611                 /* <stat> */
612                 if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) {
613                         err("No <stat> in +CGREG");
614                         goto out;
615                 }
616                 stat = __imc_network_map_stat(atoi(token_str));
617                 (void)tcore_network_set_ps_reg_status(co, stat);
618
619                 /* <lac> */
620                 if ((token_str = g_slist_nth_data(tokens, 1))) {
621                         token_str = tcore_at_tok_extract((const gchar *)token_str);
622
623                         lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
624
625                         /* Update Location Area Code (lac) information */
626                         (void)tcore_network_set_lac(co, lac);
627
628                         tcore_free(token_str);
629                 } else {
630                         dbg("No <lac> in +CGREG");
631                         (void)tcore_network_get_lac(co, &lac);
632                 }
633
634                 /* <ci> */
635                 if ((token_str = g_slist_nth_data(tokens, 2))) {
636                         token_str = tcore_at_tok_extract((const gchar *)token_str);
637
638                         ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
639
640                         /* Update Cell ID (ci) information */
641                         (void)tcore_network_set_cell_id(co, ci);
642
643                         tcore_free(token_str);
644                 } else {
645                         dbg("No <ci> in +CGREG");
646                         (void)tcore_network_get_cell_id(co, &ci);
647                 }
648
649                 /* <AcT> */
650                 if ((token_str = g_slist_nth_data(tokens, 3))) {
651                         act = __imc_network_map_act(atoi(token_str));
652                         (void)tcore_network_set_access_technology(co, act);
653                 } else {
654                         dbg("No <AcT> in +CGREG");
655                         (void)tcore_network_get_access_technology(co, &act);
656                 }
657
658                 /* <rac> */
659                 if ((token_str = g_slist_nth_data(tokens, 4))) {
660                         token_str = tcore_at_tok_extract((const gchar *)token_str);
661
662                         rac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16);
663
664                         /* Update Routing Area Code (rac) information */
665                         (void)tcore_network_set_rac(co, rac);
666
667                         tcore_free(token_str);
668                 } else {
669                         err("No <ci> in +CGREG");
670                         (void)tcore_network_get_rac(co, &rac);
671                 }
672                 dbg("<stat>: %d <lac>: 0x%x <ci>: 0x%x <AcT>: %d <rac>: 0x%x", stat, lac, ci, act, rac);
673
674                 /* Send Notification - Network (PS) Registration status */
675                 registration_status.ps_status = stat;
676                 registration_status.act = act;
677                 (void)tcore_network_get_cs_reg_status(co, &registration_status.cs_status);
678
679                 tcore_object_send_notification(co,
680                         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
681                         sizeof(TelNetworkRegStatusInfo), &registration_status);
682
683                 /* Set Roaming state */
684                 if (registration_status.ps_status == TEL_NETWORK_REG_STATUS_ROAMING)
685                         roam_state = TRUE;
686
687                 tcore_network_set_roam_state(co, roam_state);
688
689                 /* Send Notification - Cell info */
690                 cell_info.lac = lac;
691                 cell_info.cell_id = ci;
692                 cell_info.rac = rac;
693                 tcore_object_send_notification(co,
694                         TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO,
695                         sizeof(TelNetworkCellInfo), &cell_info);
696
697 out:
698                 /* Free resource */
699                 tcore_at_tok_free(tokens);
700         }
701
702         return TRUE;
703 }
704
705 /*
706  * Notification: +XNITZINFO: <fullname>,<shortname>,<LTZ>,<UT>,<DST>
707  *
708  * <longname>
709  *      string type; Network name in long alphanumeric format.
710  *
711  * <shortname>
712  *      string type; Network name in short alphanumeric format.
713  *
714  * <LTZ>
715  *      Local Time Zone; represented as 1 unit = 15 minutes.
716  *
717  * <UT>
718  *      string type value; Universal Time
719  *      format is "yy/MM/dd,hh:mm:ss",
720  *      wherein characters indicates year, month, day, hour,
721  *      minutes, seconds.
722  * <DST>
723  *      Daylight Saving Time; represented in hours.
724  */
725 static gboolean on_notification_imc_network_time_info(CoreObject *co,
726         const void *event_info, void *user_data)
727 {
728         GSList *lines = NULL;
729         gchar *line = NULL;
730
731         dbg("Network notification - Time info: [+XNITZINFO]");
732
733         lines = (GSList *)event_info;
734         if (g_slist_length(lines) != 1) {
735                 err("+XNITZINFO unsolicited message expected to be Single line "
736                         "but received multiple lines");
737                 return TRUE;
738         }
739
740         line = (gchar *)lines->data;
741         if (line != NULL) {
742                 GSList *tokens = NULL;
743                 TelNetworkNitzInfoNoti nitz_info = {0, };
744                 gchar *fullname, *shortname;
745                 gchar *ltz, *time;
746                 gchar tmp_time[8] = {0};
747                 gchar *dstoff;
748
749                 /*
750                  * Tokenize
751                  *
752                  * +XNITZINFO: <fullname>,<shortname>,<LTZ>,<UT>,<DST>
753                  */
754                 tokens = tcore_at_tok_new(line);
755
756                 /* <fullname> */
757                 if ((fullname = tcore_at_tok_nth(tokens, 1))) {
758                         if (strlen(fullname) > 0) {
759                                 fullname = tcore_at_tok_extract((const char *)fullname);
760
761                                 /* Update Long name */
762                                 tcore_network_set_long_name(co, fullname);
763
764                                 tcore_free(fullname);
765                         }
766                 }
767
768                 /* <shortname> */
769                 if ((shortname = tcore_at_tok_nth(tokens, 1))) {
770                         if (strlen(shortname) > 0) {
771                                 shortname = tcore_at_tok_extract((const char *)shortname);
772
773                                 /* Update Short name */
774                                 tcore_network_set_short_name(co, shortname);
775
776                                 tcore_free(shortname);
777                         }
778                 }
779
780                 /* <LTZ> */
781                 if ((ltz = g_slist_nth_data(tokens, 2)))
782                         nitz_info.gmtoff = atoi(ltz) * 15;/* gmtoff in minutes */
783
784                 if ((time = g_slist_nth_data(tokens, 3))
785                                 && (strlen(time) > 18)) {
786                         /* (time + 1) - Skip past initial quote (") */
787                         g_strlcpy(tmp_time, time + 1, 2+1);
788                         nitz_info.year = atoi(tmp_time);
789
790                         /* skip slash (/) after year param */
791                         g_strlcpy(tmp_time, time + 4, 2+1);
792                         nitz_info.month = atoi(tmp_time);
793
794                         /* skip past slash (/) after month param */
795                         g_strlcpy(tmp_time, time + 7, 2+1);
796                         nitz_info.day = atoi(tmp_time);
797
798                         /* skip past comma (,) after day param */
799                         g_strlcpy(tmp_time, time + 10, 2+1);
800                         nitz_info.hour = atoi(tmp_time);
801
802                         /* skip past colon (:) after hour param */
803                         g_strlcpy(tmp_time, time + 13, 2+1);
804                         nitz_info.minute = atoi(tmp_time);
805
806                          /* skip past colon (:) after minute param */
807                          g_strlcpy(tmp_time, time + 16, 2+1);
808                         nitz_info.second = atoi(tmp_time);
809                 }
810
811                 /* <DST> */
812                 if ((dstoff = g_slist_nth_data(tokens, 4))) {
813                         nitz_info.dstoff = atoi(dstoff);
814                         nitz_info.isdst = TRUE;
815                 }
816
817                 /* Get PLMN */
818                 tcore_network_get_plmn(co, &nitz_info.plmn);
819
820                 /* Send Notification - Network time info */
821                 tcore_object_send_notification(co,
822                         TCORE_NOTIFICATION_NETWORK_TIMEINFO,
823                         sizeof(TelNetworkNitzInfoNoti), &nitz_info);
824
825                 /* Free resource */
826                 tcore_free(nitz_info.plmn);
827                 tcore_at_tok_free(tokens);
828         }
829
830         return TRUE;
831 }
832
833 /*
834  * Notification:
835  *      +XCIEV: <rssi>,
836  * or
837  *      +XCIEV:,<battery_level>
838  *
839  * 'Radio Signal Strength' <rssi> can have the values
840  * 0    -107 dBm or less or unknown
841  * 1    -99 dBm or less
842  * 2    -91 dBm or less
843  * 3    -83 dBm or less
844  * 4    -75 dBm or less
845  * 5    -67 dBm or less
846  * 6    -59 dBm or less
847  * 7    -51 dBm or less
848  *
849  * 'Battery Level' <battery_level> can have the values
850  * 0    0 % <= level < 5 %
851  * 1    5 % <= level < 15 %
852  * 2    15 % <= level < 25 %
853  * 3    25 % <= level < 40 %
854  * 4    40 % <= level < 55 %
855  * 5    55 % <= level < 70 %
856  * 6    70 % <= level < 85 %
857  * 7    85 % <= level <= 100 %
858  *
859  * NOTE:
860  *      <battery_level> is not consider for
861  *      TCORE_NOTIFICATION_NETWORK_RSSI notification
862  */
863 static gboolean on_notification_imc_network_rssi(CoreObject *co,
864         const void *event_info, void *user_data)
865 {
866         GSList *lines = NULL;
867         gchar *line = NULL;
868
869         dbg("Network notification - Icon (rssi) info: [+XCIEV]");
870
871         lines = (GSList *)event_info;
872         if (g_slist_length(lines) != 1) {
873                 err("+XCIEV unsolicited message expected to be Single line "
874                         "but received multiple lines");
875                 return TRUE;
876         }
877
878         line = (gchar *)lines->data;
879         if (line != NULL) {
880                 GSList *tokens = NULL;
881                 gchar *rssi_token;
882
883                 /*
884                  * Tokenize
885                  *
886                  * +XCIEV: <rssi>,
887                  */
888                 tokens = tcore_at_tok_new(line);
889
890                 rssi_token = (gchar *)g_slist_nth_data(tokens, 0);
891                 if (rssi_token && strlen(rssi_token)) {
892                         guint rssi_bar = atoi(rssi_token);
893                         dbg("RSSI Level: [%d]", rssi_bar);
894
895                         /* Send Notification - Network Rssi */
896                         tcore_object_send_notification(co,
897                                 TCORE_NOTIFICATION_NETWORK_RSSI,
898                                 sizeof(guint), &rssi_bar);
899                 }
900
901                 /* Free resource */
902                 tcore_at_tok_free(tokens);
903         }
904
905         return TRUE;
906 }
907
908 /* Network Responses */
909
910 static void on_response_imc_network_search(TcorePending *p,
911         guint data_len, const void *data, void *user_data)
912 {
913         const TcoreAtResponse *at_resp = data;
914         CoreObject *co = tcore_pending_ref_core_object(p);
915         ImcRespCbData *resp_cb_data = user_data;
916         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
917         TelNetworkPlmnList plmn_list = {0,};
918         guint num_network_avail;
919         guint count;
920         GSList *tokens = NULL;
921
922         dbg("Enter");
923         tcore_check_return_assert(co != NULL);
924         tcore_check_return_assert(resp_cb_data != NULL);
925
926         if (at_resp && at_resp->success) {
927                 const gchar *line;
928                 GSList *net_token = NULL;
929                 gchar *resp;
930                 gint act;
931
932                 if (!at_resp->lines) {
933                         err("invalid response received");
934                         goto END;
935                 }
936
937                 line = (char *) at_resp->lines->data;
938                 tokens = tcore_at_tok_new(line);
939                 num_network_avail = g_slist_length(tokens);
940                 if (num_network_avail < 1) {
941                         err("invalid message");
942                         goto END;
943                 }
944
945                 plmn_list.network_list = tcore_malloc0(sizeof(TelNetworkInfo) * num_network_avail);
946                 dbg("RESPONSE OK");
947                 plmn_list.count = 0;
948                 for (count = 0; count < num_network_avail; count++) {
949
950                         net_token = tcore_at_tok_new(g_slist_nth_data(tokens, count));
951                         if (NULL == net_token)
952                                 continue;
953
954                         resp = tcore_at_tok_nth(net_token, 0);
955                         if (resp != NULL) {
956                                 plmn_list.network_list[count].plmn_status = atoi(resp);
957                                 dbg("status[%d]", plmn_list.network_list[count].plmn_status);
958                         }
959
960                         if ((resp = tcore_at_tok_nth(net_token, 1))) {
961                                 /* Long Alpha name */
962                                 dbg("long alpha name[%s]", resp);
963                                 plmn_list.network_list[count].network_identity.long_name =
964                                         tcore_at_tok_extract(resp);
965                         }
966
967                         if ((resp = tcore_at_tok_nth(net_token, 2))) {
968                                 /* Short Alpha name */
969                                 dbg("Short Alpha name[%s]", resp);
970                                 plmn_list.network_list[count].network_identity.short_name =
971                                         tcore_at_tok_extract(resp);
972                         }
973
974                         /* PLMN ID */
975                         if ((resp = tcore_at_tok_nth(net_token, 3))) {
976                                 dbg("PLMN ID[%s]", resp);
977                                 plmn_list.network_list[count].network_identity.plmn =
978                                         tcore_at_tok_extract(resp);
979                         }
980
981                         /* Parse Access Technology */
982                         if ((resp = tcore_at_tok_nth(tokens, 4))) {
983                                         act = atoi(resp);
984                                         if (0 == act)
985                                                 plmn_list.network_list[count].act = TEL_NETWORK_ACT_GSM;
986                                         else if (2 == act)
987                                                 plmn_list.network_list[count].act = TEL_NETWORK_ACT_UMTS;
988                                 }
989
990                         dbg("Operator [%d] :: status = %d, long_name = %s, short_name = %s plmn = %s, AcT=%d",
991                                         plmn_list.count,
992                                         plmn_list.network_list[count].plmn_status,
993                                         plmn_list.network_list[count].network_identity.long_name,
994                                         plmn_list.network_list[count].network_identity.short_name,
995                                         plmn_list.network_list[count].network_identity.plmn,
996                                         plmn_list.network_list[count].act);
997
998                         plmn_list.count ++;
999                         tcore_at_tok_free(net_token);
1000                 }
1001                 result = TEL_NETWORK_RESULT_SUCCESS;
1002         } else {
1003                 err("RESPONSE NOK");
1004                 if (at_resp->lines)
1005                         err("CME Error[%s]",(char *)at_resp->lines->data);
1006         }
1007
1008 END:
1009         dbg("Network search : [%s]",
1010                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1011
1012         /* Invoke callback */
1013         if(resp_cb_data->cb)
1014                 resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data);
1015
1016         imc_destroy_resp_cb_data(resp_cb_data);
1017         /* Free resources*/
1018         for (count = 0; count < num_network_avail; count++) {
1019                 g_free(plmn_list.network_list[count].network_identity.long_name);
1020                 g_free(plmn_list.network_list[count].network_identity.short_name);
1021                 g_free(plmn_list.network_list[count].network_identity.plmn);
1022         }
1023
1024         tcore_free(plmn_list.network_list);
1025         tcore_at_tok_free(tokens);
1026 }
1027
1028 static void on_response_imc_network_get_selection_mode(TcorePending *p,
1029         guint data_len, const void *data, void *user_data)
1030 {
1031         const TcoreAtResponse *at_resp = data;
1032         CoreObject *co = tcore_pending_ref_core_object(p);
1033         ImcRespCbData *resp_cb_data = user_data;
1034         TelNetworkSelectionMode selection_mode = -1;
1035         GSList *tokens = NULL;
1036
1037         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1038         dbg("Enter");
1039
1040         tcore_check_return_assert(co != NULL);
1041         tcore_check_return_assert(resp_cb_data != NULL);
1042
1043         if (at_resp && at_resp->success) {
1044                 const gchar *line;
1045                 gint mode;
1046
1047                 if (!at_resp->lines) {
1048                         err("invalid response received");
1049                         goto END;
1050                 }
1051
1052                 line = (char *) at_resp->lines->data;
1053                 tokens = tcore_at_tok_new(line);
1054                 if (g_slist_length(tokens) < 1) {
1055                         msg("invalid message");
1056                         goto END;
1057                 }
1058                 dbg("RESPONSE OK");
1059
1060                 mode = atoi(tcore_at_tok_nth(tokens, 0));
1061                 if(mode == 0)
1062                         selection_mode = TEL_NETWORK_SELECTION_MODE_AUTOMATIC;
1063                 else if (mode == 1)
1064                         selection_mode = TEL_NETWORK_SELECTION_MODE_MANUAL;
1065
1066                 result = TEL_NETWORK_RESULT_SUCCESS;
1067                 dbg("selection mode[%d]", selection_mode);
1068
1069         } else {
1070                 err("RESPONSE NOK");
1071         }
1072
1073 END:
1074         dbg("Get selection mode : [%s]",
1075                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1076         /* Invoke callback */
1077         if (resp_cb_data->cb)
1078                 resp_cb_data->cb(co, (gint)result, &selection_mode, resp_cb_data->cb_data);
1079
1080         /* Free callback data */
1081         imc_destroy_resp_cb_data(resp_cb_data);
1082         /* Free resource*/
1083         tcore_at_tok_free(tokens);
1084 }
1085
1086 static void on_response_imc_network_default(TcorePending *p,
1087         guint data_len, const void *data, void *user_data)
1088 {
1089         const TcoreAtResponse *at_resp = data;
1090         CoreObject *co = tcore_pending_ref_core_object(p);
1091         ImcRespCbData *resp_cb_data = user_data;
1092         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1093
1094         dbg("Enter");
1095         tcore_check_return_assert(co != NULL);
1096         tcore_check_return_assert(resp_cb_data != NULL);
1097
1098         if (at_resp && at_resp->success) {
1099                 dbg("RESPONSE OK");
1100                 result = TEL_NETWORK_RESULT_SUCCESS;
1101         } else {
1102                 err("RESPONSE NOK");
1103                 if (at_resp->lines)
1104                         err("CME Error[%s]",(char *)at_resp->lines->data);
1105         }
1106
1107         /* Invoke callback */
1108         if(resp_cb_data->cb)
1109                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1110
1111         imc_destroy_resp_cb_data(resp_cb_data);
1112 }
1113
1114
1115 static void on_response_imc_network_get_mode(TcorePending *p,
1116         guint data_len, const void *data, void *user_data)
1117 {
1118         const TcoreAtResponse *at_resp = data;
1119         CoreObject *co = tcore_pending_ref_core_object(p);
1120         ImcRespCbData *resp_cb_data = user_data;
1121         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1122         TelNetworkMode mode = -1;
1123         GSList *tokens = NULL;
1124
1125         dbg("Enter");
1126         tcore_check_return_assert(co != NULL);
1127         tcore_check_return_assert(resp_cb_data != NULL);
1128
1129         if (at_resp && at_resp->success) {
1130                 const gchar *line;
1131                 gint net_mode;
1132
1133                 if (!at_resp->lines) {
1134                         err("invalid response received");
1135                         goto END;
1136                 }
1137
1138                 line = (char *) at_resp->lines->data;
1139                 tokens = tcore_at_tok_new(line);
1140                 if (g_slist_length(tokens) < 1) {
1141                         err("invalid message");
1142                         goto END;
1143                 }
1144
1145                 dbg("RESPONSE OK");
1146                 net_mode = atoi(tcore_at_tok_nth(tokens, 0));
1147                 dbg("mode = %d", net_mode);
1148
1149                 switch(net_mode) {
1150                 case 0:
1151                         mode = TEL_NETWORK_MODE_2G;
1152                         break;
1153                 case 1:
1154                         mode = TEL_NETWORK_MODE_AUTO;
1155                         break;
1156                 case 2:
1157                         mode = TEL_NETWORK_MODE_3G;
1158                         break;
1159                 default:
1160                         err("Unsupported  mode [%d]", net_mode);
1161                         goto END;
1162                 }
1163                 result = TEL_NETWORK_RESULT_SUCCESS;
1164         } else {
1165                 err("RESPONSE NOK");
1166         }
1167 END:
1168         /* Invoke callback */
1169         if (resp_cb_data->cb)
1170                 resp_cb_data->cb(co, (gint)result, &mode, resp_cb_data->cb_data);
1171
1172         /* Free callback data */
1173         imc_destroy_resp_cb_data(resp_cb_data);
1174         /* Free resource*/
1175         tcore_at_tok_free(tokens);
1176 }
1177
1178 static void on_response_imc_network_get_preferred_plmn(TcorePending *p,
1179         guint data_len, const void *data, void *user_data)
1180 {
1181         const TcoreAtResponse *at_resp = data;
1182         CoreObject *co = tcore_pending_ref_core_object(p);
1183         ImcRespCbData *resp_cb_data = user_data;
1184         TelNetworkPreferredPlmnList plmn_list = {0,};
1185         guint count = 0, total_lines = 0;
1186         TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required.
1187         dbg("Enter");
1188
1189         tcore_check_return_assert(co != NULL);
1190         tcore_check_return_assert(resp_cb_data != NULL);
1191
1192         if (at_resp && at_resp->success) {
1193                 GSList *tokens;
1194                 gchar *resp;
1195                 gchar *line;
1196                 gboolean gsm_act2 = FALSE, gsm_compact_act2 = FALSE;
1197                 gboolean utran_act2 = FALSE;
1198
1199                 if (!at_resp->lines) {
1200                         err("invalid response received");
1201                         goto END;
1202                 }
1203
1204                 total_lines = g_slist_length(at_resp->lines);
1205                 if (total_lines < 1) {
1206                         msg("invalid message");
1207                         goto END;
1208                 }
1209
1210                 dbg("RESPONSE OK");
1211                 result = TEL_NETWORK_RESULT_SUCCESS;
1212
1213                 plmn_list.list = tcore_malloc0(sizeof(TelNetworkPreferredPlmnInfo) * total_lines);
1214                 plmn_list.count = 0;
1215
1216                 for (count = 0; count < total_lines; count++) {
1217                         /* Take each line response at a time & parse it */
1218                         line = tcore_at_tok_nth(at_resp->lines, count);
1219                         tokens = tcore_at_tok_new(line);
1220
1221                         /*Index */
1222                         if ((resp = tcore_at_tok_nth(tokens, 0))) {
1223                                 plmn_list.list[count].index = atoi(resp);
1224                         }
1225
1226                         /* PLMN ID */
1227                         if ((resp = tcore_at_tok_nth(tokens, 2))) {
1228                                 plmn_list.list[count].plmn = tcore_at_tok_extract(resp);
1229                         }
1230
1231                         /*GSM_AcT1 */
1232                         if ((resp = tcore_at_tok_nth(tokens, 3))) {
1233                                 gsm_act2 = atoi(resp);
1234                         }
1235
1236                         /*GSM_Compact_AcT2 */
1237                         if ((resp = tcore_at_tok_nth(tokens, 4))) {
1238                                 gsm_compact_act2 = atoi(resp);
1239                         }
1240
1241                         /*UTRAN_AcT2 */
1242                         if ((resp = tcore_at_tok_nth(tokens, 5))) {
1243                                 utran_act2 = atoi(resp);
1244                         }
1245
1246                         if (gsm_act2)
1247                                 plmn_list.list[count].act = TEL_NETWORK_ACT_UMTS;
1248                         else if (utran_act2 || gsm_compact_act2)
1249                                 plmn_list.list[count].act = TEL_NETWORK_ACT_GSM;
1250
1251                         /* free tokens*/
1252                         tcore_at_tok_free(tokens);
1253
1254                         dbg("index[%d], plmn[%s], act[%d]",
1255                                 plmn_list.list[count].index,
1256                                 plmn_list.list[count].plmn,
1257                                 plmn_list.list[count].act);
1258
1259                 }
1260                 plmn_list.count = count;
1261         } else {
1262                 err("RESPONSE NOK");
1263                 if (at_resp->lines)
1264                         err("CME Error[%s]",(char *)at_resp->lines->data);
1265         }
1266
1267 END:
1268         dbg("get preferred plmn : [%s]",
1269                         (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1270
1271         /* Invoke callback */
1272         if (resp_cb_data->cb)
1273                 resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data);
1274
1275         /* Free callback data */
1276         imc_destroy_resp_cb_data(resp_cb_data);
1277
1278         for(count = 0; count < total_lines; count++) {
1279                 g_free(plmn_list.list[count].plmn);
1280         }
1281         tcore_free(plmn_list.list);
1282 }
1283
1284
1285 /* Network Operations */
1286 /*
1287  * Operation - set_power_status
1288  *
1289  * Request -
1290  * AT-Command: AT+XCOPS=<Type>
1291  *
1292  * <type> may be
1293  * 0    numeric format of network MCC/MNC (three BCD
1294  *      digit country code and two/three BCD digit network code)
1295  * 1    Short Name in ROM (NV-RAM)
1296  * 2    Long Name in ROM (NV-RAM)
1297  * 3    Short Network Operator Name (CPHS)
1298  * 4    Long Network Operator Name (CPHS)
1299  * 5    Short NITZ Name
1300  * 6    Full NITZ Name
1301  * 7    Service Provider Name
1302  * 8    EONS short operator name from EF-PNN
1303  * 9    EONS long operator name from EF-PNN
1304  * 11   Short PLMN name (When PS or CS is registered)
1305  * 12   Long PLMN name (When PS or CS is registered)
1306  * 13   numeric format of network MCC/MNC even in limited service
1307  *
1308  * Response - Network name
1309  * Success: (Multiple Single line)
1310  *      +XCOPS: <type>[,<name>[,<display_condition>]]
1311  *      OK
1312  * Failure:
1313  *      +CME ERROR: <error>
1314  */
1315 static TelReturn imc_network_get_identity_info(CoreObject *co,
1316         TcoreObjectResponseCallback cb, void *cb_data)
1317 {
1318         return __imc_network_fetch_nw_name(co, cb, cb_data);
1319 }
1320
1321 /*
1322  * Operation -  network search
1323  * Request -
1324  * AT-Command: AT+COPS=?
1325  *
1326  * Response -
1327  * Success: (Single line)
1328  * +COPS: [list of supported (<stat>,long alphanumeric <oper>
1329  * ,short alphanumeric <oper>,numeric <oper>[,< AcT>]
1330  * [,,(list of supported <mode>s),(list of supported <format>s)]
1331
1332  * <format>
1333  * describes the format in which operator name is to be displayed. Different values of <format> can be:
1334  * 0 <oper> format presentations are set to long alphanumeric. If Network name not available it displays
1335  *   combination of Mcc and MNC in string format.
1336  * 1 <oper> format presentation is set to short alphanumeric.
1337  * 2 <oper> format presentations set to numeric.
1338  * <oper>:
1339  * string type given in format <format>; this field may be up to 16 character long for long alphanumeric format, up
1340  * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes)
1341  * <stat>:
1342  * describes the status of the network. It is one of the response parameter for test command.
1343  * 0 Unknown Networks
1344  * 1 Network Available
1345  * 2 Current
1346  * 3 Forbidden Network
1347  * <AcT>
1348  * indicates the radio access technology and values can be:
1349  * 0 GSM
1350  * 2 UMTS
1351  * OK
1352  * Failure:
1353  * +CME ERROR: <error>
1354  */
1355
1356 static TelReturn imc_network_search(CoreObject *co,
1357         TcoreObjectResponseCallback cb, void *cb_data)
1358 {
1359         ImcRespCbData *resp_cb_data;
1360         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1361
1362         /* Response callback data */
1363         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1364
1365         /* Send Request to modem */
1366         ret = tcore_at_prepare_and_send_request(co,
1367                 "AT+COPS=?", "+COPS",
1368                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1369                 TCORE_PENDING_PRIORITY_DEFAULT,
1370                 NULL,
1371                 on_response_imc_network_search, resp_cb_data,
1372                 on_send_imc_request, NULL,
1373                 0, NULL, NULL);
1374
1375         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Network Search");
1376         return ret;
1377 }
1378
1379 static TelReturn imc_network_cancel_search(CoreObject *co,
1380         TcoreObjectResponseCallback cb, void *cb_data)
1381 {
1382         ImcRespCbData *resp_cb_data;
1383         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1384
1385         /* Response callback data */
1386         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1387
1388         /* Send Request to modem */
1389         ret = tcore_at_prepare_and_send_request(co,
1390                 "\e", NULL,
1391                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1392                 TCORE_PENDING_PRIORITY_IMMEDIATELY,
1393                 NULL,
1394                 on_response_imc_network_default, resp_cb_data,
1395                 on_send_imc_request, NULL,
1396                 0, NULL, NULL);
1397
1398         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Cancel network search");
1399         return ret;
1400 }
1401
1402 /*
1403  * Operation -  automatic network selection
1404  * Request -
1405  * AT-Command: AT+COPS= [<mode> [, <format> [, <oper>> [, <AcT>]]]]
1406  * where
1407  * <mode>
1408  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1409  * operator <oper> given in the format <format>.
1410  * The values of <mode> can be:
1411  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1412  * 1 Manual. Other parameters like format and operator need to be passed
1413  * 2 Deregister from network
1414  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1415  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered
1416  *
1417  * Response -
1418  * Success:(No result)
1419  * OK or
1420  * +CME ERROR: <err>
1421  */
1422 static TelReturn imc_network_select_automatic(CoreObject *co,
1423         TcoreObjectResponseCallback cb, void *cb_data)
1424 {
1425         ImcRespCbData *resp_cb_data;
1426         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1427         dbg("entry");
1428
1429         /* Response callback data */
1430         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1431
1432         /* Send Request to modem */
1433         ret = tcore_at_prepare_and_send_request(co,
1434                 "AT+COPS=0", NULL,
1435                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1436                 TCORE_PENDING_PRIORITY_DEFAULT,
1437                 NULL,
1438                 on_response_imc_network_default, resp_cb_data,
1439                 on_send_imc_request, NULL,
1440                 0, NULL, NULL);
1441
1442         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Automatic network selection");
1443         return ret;
1444 }
1445
1446 /*
1447  * Operation -  manual network selection
1448  * Request -
1449  * AT-Command: AT+COPS= [<mode> [, <format> [, <oper>> [, <AcT>]]]]
1450  * where
1451  * <mode>
1452  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1453  * operator <oper> given in the format <format>.
1454  * The values of <mode> can be:
1455  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1456  * 1 Manual. Other parameters like format and operator need to be passed
1457  * 2 Deregister from network
1458  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1459  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered.
1460  * <oper>
1461  * string type given in format <format>; this field may be up to 16 character long for long alphanumeric format, up
1462  * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes)
1463  * <AcT>
1464  * indicates the radio access technology and values can be:
1465  * 0 GSM
1466  * 2 UMTS
1467  *
1468  * Response -
1469  * Success:(No result)
1470  * OK or
1471  * +CME ERROR: <err>
1472  */
1473 static TelReturn imc_network_select_manual(CoreObject *co,
1474         const TelNetworkSelectManualInfo *sel_manual,
1475         TcoreObjectResponseCallback cb, void *cb_data)
1476 {
1477         ImcRespCbData *resp_cb_data;
1478         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1479         gchar *at_cmd;
1480         gint act;
1481         dbg("entry");
1482
1483         switch(sel_manual->act) {
1484         case TEL_NETWORK_ACT_GSM:
1485         case TEL_NETWORK_ACT_GPRS:
1486         case TEL_NETWORK_ACT_EGPRS:
1487                 act = 0;
1488                 break;
1489         case TEL_NETWORK_ACT_UMTS:
1490         case TEL_NETWORK_ACT_GSM_AND_UMTS:
1491         case TEL_NETWORK_ACT_HSDPA:
1492         case TEL_NETWORK_ACT_HSPA:
1493                 act = 2;
1494                 break;
1495         default:
1496                 err("unsupported AcT");
1497                 return ret;
1498         }
1499
1500         /* AT-Command */
1501         at_cmd = g_strdup_printf("AT+COPS=1,2,\"%s\",%d", sel_manual->plmn, act);
1502
1503         /* Response callback data */
1504         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1505
1506         /* Send Request to modem */
1507         ret = tcore_at_prepare_and_send_request(co,
1508                 at_cmd, NULL,
1509                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1510                 TCORE_PENDING_PRIORITY_DEFAULT,
1511                 NULL,
1512                 on_response_imc_network_default, resp_cb_data,
1513                 on_send_imc_request, NULL,
1514                 0, NULL, NULL);
1515
1516         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Manual network selection");
1517         /* Free resources*/
1518         g_free(at_cmd);
1519         return ret;
1520 }
1521
1522 /*
1523  * Operation -  get network selection mode
1524  * Request -
1525  * AT-Command: AT+COPS?
1526  *
1527  * Response -
1528  * Success: (Single line)
1529  * +COPS: <mode>[,<format>,<oper>[,< AcT>]]
1530  * <mode>
1531  * is used to select, whether the selection is done automatically by the ME or is forced by this command to
1532  * operator <oper> given in the format <format>.
1533  * The values of <mode> can be:
1534  * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME
1535  * 1 Manual. Other parameters like format and operator need to be passed
1536  * 2 Deregister from network
1537  * 3 It sets <format> value. In this case <format> becomes a mandatory input
1538  * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered
1539  * OK
1540  * Failure:
1541  * +CME ERROR: <error>
1542  */
1543 static TelReturn imc_network_get_selection_mode(CoreObject *co,
1544         TcoreObjectResponseCallback cb, void *cb_data)
1545 {
1546         ImcRespCbData *resp_cb_data;
1547         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1548
1549         /* Response callback data */
1550         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1551
1552         /* Send Request to modem */
1553         ret = tcore_at_prepare_and_send_request(co,
1554                 "AT+COPS?", "+COPS",
1555                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1556                 TCORE_PENDING_PRIORITY_DEFAULT,
1557                 NULL,
1558                 on_response_imc_network_get_selection_mode, resp_cb_data,
1559                 on_send_imc_request, NULL,
1560                 0, NULL, NULL);
1561
1562         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get selection mode");
1563         return ret;
1564 }
1565
1566 /*
1567  * Operation -  set preferred plmn
1568  * Request -
1569  * AT-Command: AT+CPOL=<index>][,<format>[,<oper>[,<GSM_AcT>,<GSM_Compact_AcT>,<UTRAN_AcT>]]]
1570  * where
1571  * <indexn> integer type; the order number of operator in the SIM/USIM preferred operator list
1572  * <format>
1573  * 0 long format alphanumeric <oper>
1574  * 1 short format alphanumeric <oper>
1575  * 2 numeric <oper>
1576  * <opern> string type; <format> indicates if the format is alphanumeric or numeric (see +COPS)
1577  * <GSM_AcTn>: GSM access technology
1578  * 0 access technology not selected
1579  * 1 access technology selected
1580  * <GSM_Compact_AcTn>: GSM compact access technology
1581  * 0 access technology not selected
1582  * 1 access technology selected
1583  * <UTRA_AcTn>: UTRA access technology
1584  * 0 access technology not selected
1585  * 1 access technology selected
1586  *
1587  * Response -
1588  * Success:(No Result)
1589  * OK
1590  * Failure:
1591  * +CME ERROR: <error>
1592  */
1593 static TelReturn imc_network_set_preferred_plmn(CoreObject *co,
1594         const TelNetworkPreferredPlmnInfo *pref_plmn,
1595         TcoreObjectResponseCallback cb, void *cb_data)
1596 {
1597         ImcRespCbData *resp_cb_data;
1598         gchar *at_cmd;
1599         gboolean gsm_act = FALSE;
1600         gboolean gsm_compact_act = FALSE;
1601         gboolean utran_act = FALSE;
1602         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1603         dbg("entry");
1604
1605         switch(pref_plmn->act) {
1606         case TEL_NETWORK_ACT_GSM:
1607         case TEL_NETWORK_ACT_GPRS:
1608         case TEL_NETWORK_ACT_EGPRS:
1609                 gsm_act = TRUE;
1610                 break;
1611         case TEL_NETWORK_ACT_UMTS:
1612         case TEL_NETWORK_ACT_HSDPA:
1613         case TEL_NETWORK_ACT_HSPA:
1614                 utran_act = TRUE;
1615                 break;
1616         case TEL_NETWORK_ACT_GSM_AND_UMTS:
1617                 gsm_act = utran_act = TRUE;
1618                 break;
1619         default:
1620                 warn("unsupported AcT");
1621         }
1622
1623         /* AT-Command */
1624         at_cmd = g_strdup_printf("AT+CPOL=%d,%d,\"%s\",%d,%d,%d",
1625                         pref_plmn->index, 2, pref_plmn->plmn, gsm_act, gsm_compact_act, utran_act);
1626
1627         /* Response callback data */
1628         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1629
1630         /* Send Request to modem */
1631         ret = tcore_at_prepare_and_send_request(co,
1632                 at_cmd, NULL,
1633                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1634                 TCORE_PENDING_PRIORITY_DEFAULT,
1635                 NULL,
1636                 on_response_imc_network_default, resp_cb_data,
1637                 on_send_imc_request, NULL,
1638                 0, NULL, NULL);
1639
1640         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set preferred plmn");
1641         g_free(at_cmd);
1642         return ret;
1643 }
1644
1645 /*
1646  * Operation -  get preferred plmn
1647  * Request -
1648  * AT-Command: AT+CPOL?
1649  * Response -
1650  * Success: (multiline)
1651  * +CPOL: <index1>,<format>,<oper1>
1652  * [,<GSM_AcT1>,<GSM_Compact_AcT1>,<UTRAN_AcT1>][<CR><LF>
1653  * +CPOL: <index2>,<format>,<oper2>[,<GSM_AcT2>,<GSM_Compact_AcT2>,<UTRAN_AcT2>] [\85]]
1654  *  OK
1655  * Failure
1656  * +CME ERROR: <err>
1657  */
1658 static TelReturn imc_network_get_preferred_plmn(CoreObject *co,
1659         TcoreObjectResponseCallback cb, void *cb_data)
1660 {
1661         ImcRespCbData *resp_cb_data;
1662         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1663         dbg("entry");
1664
1665         /* Response callback data */
1666         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1667
1668         /* Send Request to modem */
1669         ret = tcore_at_prepare_and_send_request(co,
1670                 "AT+CPOL=,2;+CPOL?", "+CPOL", //to make sure <oper> is numeric type in reponse.
1671                 TCORE_AT_COMMAND_TYPE_MULTILINE,
1672                 TCORE_PENDING_PRIORITY_DEFAULT,
1673                 NULL,
1674                 on_response_imc_network_get_preferred_plmn, resp_cb_data,
1675                 on_send_imc_request, NULL,
1676                 0, NULL, NULL);
1677
1678         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get preferred plmn");
1679         return ret;
1680 }
1681
1682 /*
1683  * Operation -  set network mode
1684  * Request -
1685  * AT-Command: AT+XRAT=<AcT> [, <PreferredAct>]
1686  * where
1687  * <AcT> indicates the radio access technology and may be
1688  * 0 GSM single mode
1689  * 1 GSM / UMTS Dual mode
1690  * 2 UTRAN (UMTS)
1691  * 3-7 Reserved for future use.
1692  * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and
1693  * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode.
1694  * Note : <Act> = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored
1695  * <PreferredAct>
1696  * This parameter is used for network registration in case of <AcT>=1.
1697  * 0 RAT GSM
1698  * 2 RAT UMTS
1699  * Response -
1700  * Success: (No result)
1701  * OK
1702  * Failure:
1703  * +CME ERROR: <error>
1704  */
1705 static TelReturn imc_network_set_mode(CoreObject *co, TelNetworkMode mode,
1706         TcoreObjectResponseCallback cb, void *cb_data)
1707 {
1708         ImcRespCbData *resp_cb_data;
1709         TelReturn ret = TEL_RETURN_INVALID_PARAMETER;
1710         int act;
1711         gchar *at_cmd;
1712
1713         switch(mode) {
1714         case TEL_NETWORK_MODE_AUTO:
1715                 act = 1;
1716                 break;
1717         case TEL_NETWORK_MODE_2G:
1718                 act = 0;
1719                 break;
1720         case TEL_NETWORK_MODE_3G:
1721                 act = 2;
1722                 break;
1723         case TEL_NETWORK_MODE_LTE:
1724         default:
1725                 err("Unsupported  mode");
1726                 return ret;
1727         }
1728
1729         if (act == 1)
1730                 /* AT-Command */
1731                 at_cmd = g_strdup_printf("AT+XRAT=%d,2", act); //PreferredAct is UMTS
1732         else
1733                 /* AT-Command */
1734                 at_cmd = g_strdup_printf("AT+XRAT=%d", act);
1735
1736         /* Response callback data */
1737         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1738
1739         /* Send Request to modem */
1740         ret = tcore_at_prepare_and_send_request(co,
1741                 at_cmd, NULL ,
1742                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
1743                 TCORE_PENDING_PRIORITY_DEFAULT,
1744                 NULL,
1745                 on_response_imc_network_default, resp_cb_data,
1746                 on_send_imc_request, NULL,
1747                 0, NULL, NULL);
1748         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set network mode");
1749         g_free(at_cmd);
1750         return ret;
1751 }
1752
1753 /*
1754  * Operation -  get network mode
1755  * Request -
1756  * AT-Command: AT+XRAT?
1757  *
1758  * Response -
1759  * Success: (Single line)
1760  * +XRAT : <Act>,<PreferredAct>
1761  * <AcT> indicates the radio access technology and may be
1762  * 0 GSM single mode
1763  * 1 GSM / UMTS Dual mode
1764  * 2 UTRAN (UMTS)
1765  * 3-7 Reserved for future use.
1766  * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and
1767  * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode.
1768  * Note : <Act> = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored
1769  * <PreferredAct>
1770  * This parameter is used for network registration in case of <AcT>=1.
1771  * 0 RAT GSM
1772  * 2 RAT UMTS
1773  * OK
1774  * Failure:
1775  * +CME ERROR: <error>
1776  */
1777
1778 static TelReturn imc_network_get_mode(CoreObject *co,
1779         TcoreObjectResponseCallback cb, void *cb_data)
1780 {
1781         ImcRespCbData *resp_cb_data;
1782         TelReturn ret;
1783         dbg("entry");
1784
1785         /* Response callback data */
1786         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1787
1788         /* Send Request to modem */
1789         ret = tcore_at_prepare_and_send_request(co,
1790                 "AT+XRAT?", "+XRAT",
1791                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
1792                 TCORE_PENDING_PRIORITY_DEFAULT,
1793                 NULL,
1794                 on_response_imc_network_get_mode, resp_cb_data,
1795                 on_send_imc_request, NULL,
1796                 0, NULL, NULL);
1797
1798         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get network mode");
1799         return ret;
1800 }
1801
1802 static TelReturn imc_network_get_neighboring_cell_info(CoreObject *co,
1803         TcoreObjectResponseCallback cb, void *cb_data)
1804 {
1805         /* TODO*/
1806         dbg("entry");
1807         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1808 }
1809
1810 /* Network Operations */
1811 static TcoreNetworkOps imc_network_ops = {
1812         .get_identity_info = imc_network_get_identity_info,
1813         .search = imc_network_search,
1814         .cancel_search = imc_network_cancel_search,
1815         .select_automatic = imc_network_select_automatic,
1816         .select_manual = imc_network_select_manual,
1817         .get_selection_mode = imc_network_get_selection_mode,
1818         .set_preferred_plmn = imc_network_set_preferred_plmn,
1819         .get_preferred_plmn = imc_network_get_preferred_plmn,
1820         .set_mode = imc_network_set_mode,
1821         .get_mode = imc_network_get_mode,
1822         .get_neighboring_cell_info = imc_network_get_neighboring_cell_info
1823 };
1824
1825 gboolean imc_network_init(TcorePlugin *p, CoreObject *co)
1826 {
1827         dbg("Enter");
1828
1829         /* Set operations */
1830         tcore_network_set_ops(co, &imc_network_ops);
1831
1832         /* Add Callbacks */
1833         tcore_object_add_callback(co, "+CREG", on_notification_imc_cs_network_info, NULL);
1834         tcore_object_add_callback(co, "+CGREG", on_notification_imc_ps_network_info, NULL);
1835         tcore_object_add_callback(co, "+XNITZINFO", on_notification_imc_network_time_info, NULL);
1836         tcore_object_add_callback(co, "+XCIEV", on_notification_imc_network_rssi, NULL);
1837
1838         /*
1839          * Add Hooks - Request and Notification
1840          */
1841         tcore_plugin_add_request_hook(p,
1842                 TCORE_COMMAND_MODEM_SET_FLIGHTMODE,
1843                 on_hook_imc_set_flight_mode, NULL);
1844         tcore_plugin_add_notification_hook(p,
1845                 TCORE_NOTIFICATION_SIM_STATUS,
1846                 on_hook_imc_sim_status, co);
1847
1848         //_insert_mcc_mnc_oper_list(cp, co_network);
1849
1850         dbg("Exit");
1851         return TRUE;
1852 }
1853
1854 void imc_network_exit(TcorePlugin *p, CoreObject *co)
1855 {
1856         dbg("Exit");
1857 }