AT: Check async requests before canceling a sync request
[hayes-ril.git] / hayes-ril (copie).c
1 /**
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  * 
6  * 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"
24 #include <utils/Log.h>
25 #include <telephony/ril.h>
26
27 #include <hayes-ril.h>
28
29 #define RIL_VERSION_STRING "Hayes RIL"
30
31 struct ril_device *ril_device;
32
33 const char *ril_get_version()
34 {
35         return RIL_VERSION_STRING;
36 }
37
38 void ril_on_request(int request, void *data, size_t datalen, RIL_Token t)
39 {
40 //      RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
41         return;
42 }
43
44 RIL_RadioState ril_on_state_request()
45 {
46         LOGD("state request");
47         return RADIO_STATE_UNAVAILABLE;
48 }
49
50 int ril_on_supports(int requestCode)
51 {
52         return 1;
53 }
54
55 void ril_on_cancel(RIL_Token t)
56 {
57         return;
58 }
59
60 static const RIL_RadioFunctions ril_ops = {
61         RIL_VERSION,
62         ril_on_request,
63         ril_on_state_request,
64         ril_on_supports,
65         ril_on_cancel,
66         ril_get_version
67 };
68
69 /*
70 1- create structure (AT prefix or not?)
71 2- send structure
72 */
73
74 void at_send(char *string)
75 {
76         int len = strlen(string) + 2;
77         char *buffer = malloc(len);
78
79         memcpy(buffer, string, strlen(string));
80         buffer[len-2] = '\r';
81         buffer[len-1] = '\n';
82
83 //      LOGD("Sending: '%s'", buffer);
84         hex_dump(buffer, len);
85         ril_device_send(ril_device, buffer, len);
86 }
87
88 // http://www.technologuepro.com/gsm/commande_at.htm
89 /* Read all the lines -> parse each line (each \n and remove \r) -> for status, check the known cases of errors and fill status with "OK" only when OK found at this stage
90  * -> parsing response: if line starts by AT, set in the message name
91 NOPE * -> define the type after checking if there is any message by that name waiting
92  * -> if we have status (err code) and no command name -> assume answer to the last queued request, the one we block for (assume it's ok)
93  * -> if we don't have status but we do have a command name, assume unsol
94  * -> after parsing all the lines, see what we have: any unsol data? any response? any error code?
95  *
96  * STRUCTURE:
97  * -> command
98  * -> data
99  * -> status (int)
100  * -> error (string)
101  *
102  * FUNCTIONS
103  * -> at_response_process
104  *
105  * FIXME: how must we act when there is a status (error) code AND data? it probably doesn't happend but though, what's the most important? if we have data -> we have command -> we know if it matches the blocking pending one -> solved!
106  * STEPS:
107  * 1- Parse the data into multiple structures (switch to a new structure whenever a field was already set (andits value is new, cause if we have 2 rows of data, it'll start with thr same cmd) when parsing, that means we need uniq default values to be checked with)
108  *    Only fill what we know for sure, no guess yet: a status (error code), the command name, the command data
109  *    Return the number of structures?
110  * 2- If there is a blocking wait-for-status pending, make sure we have a status, check if we have the command name in our structs (then return, even though it may be bad if we have data, but we know the command for sure), or if we don't have a command name (even though echoing should be ON), return the status (and then free the structure 'cause nobody's waiting for them, just the status)
111  * 3- If there are non-blocking wait-for-data-to-a-function pending, check the list for the expected command (might be different from the issued one so we have to specify if it's the same in the request/response or not, maybe with two functions, one where you can specify a different return command name, that will anyway end up with the same structure), then if the expected command is there, pass the structure to the function (standard type), with queued token
112  *    Maybe make a special return code that tells to go unsol (when the function judges that it's not appropriated data)
113  * 4- We have no status (while both previous can have one!), or caught the magic rc from the given function, then consider the struct as UNSOL
114  *
115  * Ways of expecting data:
116  * - Blocking wait-for-status way: would be nice with a timeout given (like 5 secs, that's enough), a special status when timeout is hit FIXME: if called from unsol, same thread as ril loop -> locked 
117  *   Goes like this: locked once -> call function -> locked twice -> recv loop has wait-for-status pending struct that does matches what we expect -> extract status -> free structure -> unlock -> return status
118  * - Non-blocking wait-for-data-to-a-function way: function with a standard header (give the at struct, plus the registered token, plus some pdata), return magic rc when the at struct feels unsol (no need to be paranoid about it though)
119  */
120
121 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
122 {
123         int rc;
124
125         ril_device_register(&ril_device);
126
127         LOGD("Starting %s for device: %s", RIL_VERSION_STRING, ril_device->name);
128
129         rc = ril_device_init(ril_device);
130         if(rc < 0) {
131                 LOGE("Failed to init device!");
132                 ril_device_deinit(ril_device);
133
134                 return NULL;
135         }
136
137         rc = ril_device_recv_thread_start(ril_device);
138         if(rc < 0) {
139                 LOGE("Failed to start device thread!");
140                 ril_device_deinit(ril_device);
141
142                 return NULL;
143         }
144
145         LOGD("Initialization complete");
146
147         at_send("ATE0Q0V1");
148         usleep(500);
149         at_send("AT+CPIN?");
150         usleep(500);
151         at_send("AT+CREG=2");
152         usleep(500);
153         at_send("AT+CPIN=1234");
154         usleep(500);
155         at_send("AT+CPIN?");
156         usleep(500);
157
158         return &ril_ops;
159 }