Network: Added operator request
[hayes-ril.git] / network.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Parts of this code are based on htcgeneric-ril, reference-ril:
7  * Copyright 2006-2011, htcgeneric-ril contributors
8  * Copyright 2006, The Android Open Source Project
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #define LOG_TAG "RIL-NET"
24 #include <utils/Log.h>
25 #include <telephony/ril.h>
26
27 #include <hayes-ril.h>
28
29 /*
30  * Signal Strength
31  */
32
33 void at2ril_signal_strength(RIL_SignalStrength *ss, int *values)
34 {
35         const int dbm_table[8] = {135,125,115,105,95,85,75,70};
36         const int edbm_table[8] = {120,110,100,90,80,75,70,65};
37         const int ecio_table[8] = {200,150,130,120,110,100,90,80};
38
39         memset(ss, 0, sizeof(RIL_SignalStrength));
40
41         if(ril_device->type == DEV_GSM) {
42                 ss->GW_SignalStrength.signalStrength = values[0];
43                 ss->GW_SignalStrength.bitErrorRate = values[1];
44         } else {
45                 /* 1st # is CDMA, 2nd is EVDO */
46                 ss->CDMA_SignalStrength.dbm = dbm_table[values[0]];
47                 ss->CDMA_SignalStrength.ecio = ecio_table[values[0]];
48                 ss->EVDO_SignalStrength.dbm = edbm_table[values[1]];
49                 ss->EVDO_SignalStrength.ecio = ecio_table[values[1]];
50                 ss->EVDO_SignalStrength.signalNoiseRatio = values[1];
51         }
52 }
53
54 int at_csq_expect(struct at_response *response, void *data, RIL_Token t)
55 {
56         struct at_response_data **response_data = NULL;
57         int response_data_count = 0;
58
59         RIL_SignalStrength ss;
60         int values[2] = { 0 };
61
62         if(response->status == AT_STATUS_UNDEF)
63                 return AT_RESPONSE_UNHANDELD_REASON_STATUS;
64
65         if(response->data == NULL || response->data_count <= 0) {
66                 LOGE("No data given to AT+CSQ response!");
67                 return AT_RESPONSE_HANDLED_ERROR;
68         }
69
70         LOGE("Caught valid AT+CSQ response!");
71
72         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
73         if(response_data_count < 2)
74                 goto error_data;
75
76         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
77                 goto error_data;
78         values[0] = response_data[0]->value.n;
79
80         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
81                 goto error_data;
82         values[1] = response_data[1]->value.n;
83
84         at2ril_signal_strength(&ss, values);
85
86         RIL_onRequestComplete(t, RIL_E_SUCCESS, &ss, sizeof(RIL_SignalStrength));
87
88         at_response_data_free(response_data, response_data_count);
89
90         return AT_RESPONSE_HANDLED_OK;
91
92 error_data:
93         LOGE("No valid data given to AT+CSQ response!");
94
95         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
96
97         at_response_data_free(response_data, response_data_count);
98         return AT_RESPONSE_HANDLED_ERROR;
99 }
100
101 void ril_request_signal_strength(RIL_Token t, void *data, size_t length)
102 {
103         at_send_expect_to_func("AT+CSQ", NULL, NULL, t, at_csq_expect);
104 }
105
106 /*
107  * Network registration
108  */
109
110 int at_creg_handle(char **registration_state, struct at_response_data **response_data, int response_data_count)
111 {
112         int state = 0;
113         char *lac = NULL;
114         char *cid = NULL;
115
116         if(registration_state == NULL || response_data == NULL || response_data_count <= 0)
117                 return -1;
118
119         /*
120          * Ok you have to be careful here
121          * The solicited version of the CREG response is
122          * +CREG: n, stat, [lac, cid]
123          * and the unsolicited version is
124          * +CREG: stat, [lac, cid]
125          * The <n> parameter is basically "is unsolicited creg on?"
126          * which it should always be
127          *
128          * Also since the LAC and CID are only reported when registered,
129          * we can have 1, 2, 3, or 4 arguments here
130          *
131          * finally, a +CGREG: answer may have a fifth value that corresponds
132          * to the network type, as in;
133          *
134          *   +CGREG: n, stat [,lac, cid [,networkType]]
135          */
136
137         // Only handle CREG responses
138         switch(response_data_count) {
139                 case 1: // UNSOL response, unregistered
140                         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
141                                 return -1;
142                         state = response_data[0]->value.n;
143
144                         break;
145                 case 2: // SOL response, unregistered
146                         // Skip first argument
147                         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
148                                 return -1;
149                         state = response_data[1]->value.n;
150
151                         break;
152                 case 3: // UNSOL response, registered
153                         if(response_data[0]->type != AT_RESPONSE_DATA_NUMERIC)
154                                 return -1;
155                         state = response_data[0]->value.n;
156
157                         if(response_data[1]->type != AT_RESPONSE_DATA_STRING)
158                                 return -1;
159                         lac = response_data[1]->value.s;
160
161                         if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
162                                 return -1;
163                         cid = response_data[2]->value.s;
164
165                         break;
166                 case 4: // SOL response, registered
167                         if(response_data[1]->type != AT_RESPONSE_DATA_NUMERIC)
168                                 return -1;
169                         state = response_data[1]->value.n;
170
171                         if(response_data[2]->type != AT_RESPONSE_DATA_STRING)
172                                 return -1;
173                         lac = response_data[2]->value.s;
174
175                         if(response_data[3]->type != AT_RESPONSE_DATA_STRING)
176                                 return -1;
177                         cid = response_data[3]->value.s;
178
179                         break;
180                 default:
181                         return -1;
182         }
183
184         asprintf(&(registration_state[0]), "%d", state);
185         registration_state[1] = strdup(lac);
186         registration_state[2] = strdup(cid);
187
188         return 0;
189 }
190
191 void ril_registration_state_free(char **registration_state)
192 {
193         int i;
194
195         for(i=0 ; i < 14 ; i++) {
196                 if(registration_state[i] != NULL)
197                         free(registration_state[i]);
198         }
199
200
201         free(registration_state);
202 }
203
204 int at_creg_expect(struct at_response *response, void *data, RIL_Token t)
205 {
206         struct at_response_data **response_data = NULL;
207         int response_data_count = 0;
208
209         char **registration_state = NULL;
210         int rc;
211
212         if(response->status == AT_STATUS_UNDEF)
213                 return AT_RESPONSE_UNHANDELD_REASON_STATUS;
214
215         if(response->data == NULL || response->data_count <= 0) {
216                 LOGE("No data given to AT+CREG response!");
217                 return AT_RESPONSE_HANDLED_ERROR;
218         }
219
220         LOGE("Caught valid AT+CREG response!");
221
222         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
223         if(response_data_count <= 0)
224                 goto error_data;
225
226         registration_state = calloc(1, sizeof(char *) * 15);
227         rc = at_creg_handle(registration_state, response_data, response_data_count);
228         if(rc < 0) {
229                 ril_registration_state_free(registration_state);
230                 goto error_data;
231         }
232
233         RIL_onRequestComplete(t, RIL_E_SUCCESS, registration_state,  sizeof(char *) * 15);
234
235         ril_registration_state_free(registration_state);
236         at_response_data_free(response_data, response_data_count);
237
238         return AT_RESPONSE_HANDLED_OK;
239
240 error_data:
241         LOGE("No valid data given to AT+CREG response!");
242
243         RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
244
245         at_response_data_free(response_data, response_data_count);
246
247         return AT_RESPONSE_HANDLED_ERROR;
248 }
249
250 void at_creg_unexpect(struct at_response *response)
251 {
252         struct at_response_data **response_data = NULL;
253         int response_data_count = 0;
254
255         char **registration_state = NULL;
256         int rc;
257
258         if(response->data == NULL || response->data_count <= 0) {
259                 LOGE("No data given to AT+CREG unsol!");
260                 return;
261         }
262
263         LOGE("Caught valid AT+CREG unsol!");
264
265         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
266         if(response_data_count <= 0)
267                 goto error_data;
268
269         registration_state = calloc(1, sizeof(char *) * 15);
270         rc = at_creg_handle(registration_state, response_data, response_data_count);
271         if(rc < 0) {
272                 ril_registration_state_free(registration_state);
273                 goto error_data;
274         }
275
276         if(ril_globals.registration_state != NULL)
277                 ril_registration_state_free(ril_globals.registration_state);
278
279         ril_globals.registration_state = registration_state;
280
281         RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED, NULL, 0);
282
283 error_data:
284         LOGE("No valid data given to AT+CREG unsol!");
285
286         at_response_data_free(response_data, response_data_count);
287 }
288
289 void ril_request_registration_state(RIL_Token t, void *data, size_t length)
290 {
291         if(ril_globals.registration_state != NULL) {
292                 // There is UNSOL data there
293                 RIL_onRequestComplete(t, RIL_E_SUCCESS, ril_globals.registration_state,  sizeof(char *) * 15);
294
295                 ril_registration_state_free(ril_globals.registration_state);
296                 ril_globals.registration_state = NULL;
297         } else {
298                 at_send_expect_to_func("AT+CREG?", NULL, NULL, t, at_creg_expect);
299         }
300 }
301
302 /*
303  * Operator
304  */
305
306 char *at_cops_request(int index)
307 {
308         struct at_response_data **response_data = NULL;
309         struct at_response *response = NULL;
310         int response_data_count = 0;
311         int status = AT_STATUS_UNDEF;
312         char *result = NULL;
313         char *data = NULL;
314
315         asprintf(&data, "3,%d", index);
316
317         status = at_send_expect_status("AT+COPS", data);
318         if(at_status_error(status))
319                 goto error;
320
321         response = at_send_sync("AT+COPS?", NULL);
322         if(response == NULL || response->data == NULL || response->data_count <= 0)
323                 goto error;
324
325         response_data_count = at_response_data_process(&response_data, response->data[0], strlen(response->data[0]));
326         if(response_data_count <= 0)
327                 goto error;
328         if(response_data_count >= 3 && response_data[2]->type == AT_RESPONSE_DATA_STRING) {
329                 result = strdup(response_data[2]->value.s);
330         }
331         at_response_data_free(response_data, response_data_count);
332
333         free(response);
334         free(data);
335 LOGE(">%s<", result);
336         return result;
337
338 error:
339         free(data);
340         if(response != NULL)
341                 free(response);
342         if(response_data != NULL)
343                 at_response_data_free(response_data, response_data_count);
344
345         return NULL;
346 }
347
348 void ril_request_operator(RIL_Token t, void *data, size_t length)
349 {
350         char *operator[3] = { NULL };
351
352         // Reuqest long operator string
353         operator[0] = at_cops_request(0);
354         // Reuqest short operator string
355         operator[1] = at_cops_request(1);
356         // Reuqest MCC+MNC string
357         operator[2] = at_cops_request(2);
358
359         RIL_onRequestComplete(t, RIL_E_SUCCESS, operator,  sizeof(operator));
360
361         if(operator[0] != NULL)
362                 free(operator[0]);
363         if(operator[1] != NULL)
364                 free(operator[1]);
365         if(operator[2] != NULL)
366                 free(operator[2]);
367 }