1 /*
2
3 G N O K I I
4
5 A Linux/Unix toolset and driver for the mobile phones.
6
7 This file is part of gnokii.
8
9 Gnokii is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 Gnokii is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with gnokii; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 Copyright (C) 2001-2002 Manfred Jonsson <manfred.jonsson@gmx.de>
24 Copyright (C) 2001-2003 Ladis Michl
25 Copyright (C) 2001-2011 Pawel Kot
26 Copyright (C) 2002-2004 BORBELY Zoltan
27 Copyright (C) 2002 Pavel Machek
28
29 */
30
31 #include "config.h"
32
33 /* System header files */
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <errno.h>
38
39 /* Various header file */
40 #include "compat.h"
41 #include "misc.h"
42 #include "links/atbus.h"
43 #include "links/utils.h"
44
45 #include "gnokii-internal.h"
46 #include "gnokii.h"
47
48 #include "device.h"
49
50 /* ugly hack, but we need GN_OP_AT_Ring -- bozo */
51 #include "phones/atgen.h"
52
53 /*
54 * FIXME - when sending an AT command while another one is still in progress,
55 * the old command is aborted and the new ignored. the result is _one_ error
56 * message from the phone.
57 */
58
xwrite(unsigned char * d,size_t len,struct gn_statemachine * sm)59 static int xwrite(unsigned char *d, size_t len, struct gn_statemachine *sm)
60 {
61 size_t res;
62
63 at_dprintf("write: ", d, len);
64
65 while (len) {
66 res = device_write(d, len, sm);
67 if (res == -1) {
68 if (errno != EAGAIN) {
69 perror(_("gnokii I/O error"));
70 return -1;
71 }
72 } else {
73 d += res;
74 len -= res;
75 }
76 }
77 return 0;
78 }
79
atbus_open(int mode,char * device,struct gn_statemachine * sm)80 static bool atbus_open(int mode, char *device, struct gn_statemachine *sm)
81 {
82 int result = device_open(device, false, false, mode, sm->config.connection_type, sm);
83
84 if (!result) {
85 perror(_("Couldn't open ATBUS device"));
86 return false;
87 }
88 if (mode) {
89 /*
90 * make 7110 with dlr-3 happy. the nokia dlr-3 cable provides
91 * hardware handshake lines but is, at least at initialization,
92 * slow. to be properly detected, state changes must be longer
93 * than 700 ms. if the timing is too fast all commands after dtr
94 * high will be ignored by the phone until dtr is toggled again.
95 * to reset the phone and set a sane state, dtr must pulled low.
96 * when irda is turned on in the phone, dtr must pulled high to
97 * switch on the serial line of the phone (this will switch off
98 * irda). only set it high after serial line initialization
99 * (when it probably was low before) is not enough. so we do
100 * high, low and high again, always with one second apply time.
101 * also wait one second before sending commands or init will
102 * fail.
103 */
104 device_setdtrrts(1, 1, sm);
105 sleep(1);
106 device_setdtrrts(0, 1, sm);
107 sleep(1);
108 device_setdtrrts(1, 1, sm);
109 sleep(1);
110 } else {
111 device_setdtrrts(1, 1, sm);
112 }
113 return true;
114 }
115
at_send_message(unsigned int message_length,unsigned char message_type,unsigned char * msg,struct gn_statemachine * sm)116 static gn_error at_send_message(unsigned int message_length, unsigned char message_type, unsigned char *msg, struct gn_statemachine *sm)
117 {
118 usleep(10000);
119 sm_incoming_acknowledge(sm);
120 return xwrite(msg, message_length, sm) ? GN_ERR_UNKNOWN : GN_ERR_NONE;
121 }
122
findcrlfbw(unsigned char * str,int len)123 char *findcrlfbw(unsigned char *str, int len)
124 {
125 while (len-- && (*str != '\n') && (*str-1 != '\r'))
126 str--;
127 return len > 0 ? str+1 : NULL;
128 }
129
numchar(unsigned char * str,unsigned char ch)130 int numchar(unsigned char *str, unsigned char ch)
131 {
132 int count = 0;
133
134 while (*str && *str != '\r') {
135 if (*str++ == ch)
136 count++;
137 }
138
139 return count;
140 }
141
142 /*
143 * rx state machine for receive handling. called once for each character
144 * received from the phone.
145 */
atbus_rx_statemachine(unsigned char rx_char,struct gn_statemachine * sm)146 static void atbus_rx_statemachine(unsigned char rx_char, struct gn_statemachine *sm)
147 {
148 int error;
149 atbus_instance *bi = AT_BUSINST(sm);
150 int unsolicited, count;
151 char *start;
152
153 if (!bi)
154 return;
155
156 if (bi->rbuf_pos >= bi->rbuf_size - 1) {
157 bi->rbuf_size += RBUF_SEG;
158 bi->rbuf = realloc(bi->rbuf, bi->rbuf_size);
159 }
160
161 bi->rbuf[bi->rbuf_pos++] = rx_char;
162 bi->rbuf[bi->rbuf_pos] = '\0';
163
164 if (bi->rbuf_pos < bi->binlen)
165 return;
166
167 bi->rbuf[0] = GN_AT_NONE;
168 /* first check if <cr><lf> is found at end of reply_buf.
169 * none: the needed length is greater 4 because we don't
170 * need to enter if no result/error will be found. */
171 if (bi->rbuf_pos == 3 && !strcmp(bi->rbuf + 1, "\r\n")) {
172 bi->rbuf_pos = 1;
173 bi->rbuf[1] = '\0';
174 }
175 unsolicited = 0;
176 if (bi->rbuf_pos > 4 && !strncmp(bi->rbuf + bi->rbuf_pos - 2, "\r\n", 2)) {
177 /* try to find previous <cr><lf> */
178 start = findcrlfbw(bi->rbuf + bi->rbuf_pos - 2, bi->rbuf_pos - 1);
179 /* if not found, start at buffer beginning */
180 if (!start)
181 start = bi->rbuf+1;
182 /* there are certainly more that 2 chars in buffer */
183 if (!strncmp(start, "OK", 2))
184 bi->rbuf[0] = GN_AT_OK;
185 else if (bi->rbuf_pos > 7 && !strncmp(start, "ERROR", 5))
186 bi->rbuf[0] = GN_AT_ERROR;
187 /* FIXME: use error codes some useful way */
188 else if (sscanf(start, "+CMS ERROR: %d", &error) == 1) {
189 bi->rbuf[0] = GN_AT_CMS;
190 bi->rbuf[1] = error / 256;
191 bi->rbuf[2] = error % 256;
192 } else if (sscanf(start, "+CME ERROR: %d", &error) == 1) {
193 bi->rbuf[0] = GN_AT_CME;
194 bi->rbuf[1] = error / 256;
195 bi->rbuf[2] = error % 256;
196 } else if (!strncmp(start, "RING", 4) ||
197 !strncmp(start, "CONNECT", 7) ||
198 !strncmp(start, "BUSY", 4) ||
199 !strncmp(start, "NO ANSWER", 9) ||
200 !strncmp(start, "NO CARRIER", 10) ||
201 !strncmp(start, "NO DIALTONE", 11)) {
202 bi->rbuf[0] = GN_OP_AT_Ring;
203 unsolicited = 1;
204 } else if (*start == '+') {
205 /* check for possible unsolicited responses */
206 if (!strncmp(start + 1, "CREG:", 5)) {
207 count = numchar(start, ',');
208 if (count == 2) {
209 bi->rbuf[0] = GN_OP_GetNetworkInfo;
210 unsolicited = 1;
211 }
212 } else if (!strncmp(start + 1, "CPIN:", 5)) {
213 bi->rbuf[0] = GN_AT_OK;
214 } else if (!strncmp(start + 1, "CRING:", 6) ||
215 !strncmp(start + 1, "CLIP:", 5) ||
216 !strncmp(start + 1, "CLCC:", 5)) {
217 bi->rbuf[0] = GN_OP_AT_Ring;
218 unsolicited = 1;
219 } else if (!strncmp(start + 1, "CMTI:", 5)) {
220 bi->rbuf[0] = GN_OP_AT_IncomingSMS;
221 unsolicited = 1;
222 }
223 }
224 }
225 /* check if SMS prompt is found */
226 if (bi->rbuf_pos > 4 && !strncmp(bi->rbuf + bi->rbuf_pos - 4, "\r\n> ", 4))
227 bi->rbuf[0] = GN_AT_PROMPT;
228 if (bi->rbuf[0] != GN_AT_NONE) {
229 int rbuf_pos = bi->rbuf_pos;
230 at_dprintf("read : ", bi->rbuf + 1, bi->rbuf_pos - 1);
231 bi->rbuf_pos = 1;
232 bi->binlen = 1;
233 if (unsolicited)
234 sm_incoming_function(bi->rbuf[0], start, rbuf_pos - 1 - (start - bi->rbuf), sm);
235 else
236 sm_incoming_function(sm->last_msg_type, bi->rbuf, rbuf_pos - 1, sm);
237 free(bi->rbuf);
238 bi->rbuf = NULL;
239 bi->rbuf_size = 0;
240 return;
241 }
242 #if 0
243 /* needed for binary date etc */
244 TODO: correct reading of variable length integers
245 if (reply_buf_pos == 12) {
246 if (!strncmp(reply_buf + 3, "ABC", 3) {
247 binlength = atoi(reply_buf + 8);
248 }
249 }
250 #endif
251 }
252
atbus_loop(struct timeval * timeout,struct gn_statemachine * sm)253 static gn_error atbus_loop(struct timeval *timeout, struct gn_statemachine *sm)
254 {
255 unsigned char buffer[BUFFER_SIZE];
256 int count, res;
257
258 res = device_select(timeout, sm);
259 if (res > 0) {
260 res = device_read(buffer, sizeof(buffer), sm);
261 for (count = 0; count < res; count++) {
262 atbus_rx_statemachine(buffer[count], sm);
263 }
264 } else
265 return GN_ERR_TIMEOUT;
266 /* This traps errors from device_read */
267 if (res > 0)
268 return GN_ERR_NONE;
269 else
270 return GN_ERR_INTERNALERROR;
271 }
272
atbus_reset(struct gn_statemachine * state)273 static void atbus_reset(struct gn_statemachine *state)
274 {
275 atbus_instance *bi = AT_BUSINST(state);
276 bi->rbuf = NULL;
277 bi->rbuf_size = 0;
278 bi->rbuf_pos = 1;
279 bi->binlen = 1;
280 }
281
282
283 /* Initialise variables and start the link */
284 /* Fixme we allow serial and irda for connection to reduce */
285 /* bug reports. this is pretty silly for /dev/ttyS?. */
atbus_initialise(int mode,struct gn_statemachine * state)286 gn_error atbus_initialise(int mode, struct gn_statemachine *state)
287 {
288 gn_error error = GN_ERR_NONE;
289 atbus_instance *businst;
290
291 if (!state)
292 return GN_ERR_FAILED;
293
294 if (!(businst = malloc(sizeof(atbus_instance))))
295 return GN_ERR_FAILED;
296
297 /* Fill in the link functions */
298 state->link.loop = &atbus_loop;
299 state->link.send_message = &at_send_message;
300 state->link.reset = &atbus_reset;
301 state->link.cleanup = NULL;
302 AT_BUSINST(state) = businst;
303 atbus_reset(state);
304
305 switch (state->config.connection_type) {
306 case GN_CT_Irda:
307 if (!strcasecmp(state->config.port_device, "IrDA:IrCOMM")) {
308 if (!device_open(state->config.port_device, false, false, false, state->config.connection_type, state)) {
309 error = GN_ERR_FAILED;
310 goto err;
311 }
312 break;
313 }
314 /* FALLTHROUGH */
315 case GN_CT_Serial:
316 case GN_CT_TCP:
317 if (!atbus_open(mode, state->config.port_device, state)) {
318 error = GN_ERR_FAILED;
319 goto err;
320 }
321 break;
322 case GN_CT_Bluetooth:
323 if (!device_open(state->config.port_device, false, false, false, state->config.connection_type, state)) {
324 error = GN_ERR_FAILED;
325 goto err;
326 }
327 break;
328 default:
329 dprintf("Device not supported by AT bus\n");
330 error = GN_ERR_FAILED;
331 goto err;
332 }
333 goto out;
334 err:
335 dprintf("AT bus initialization failed (%d)\n", error);
336 free(AT_BUSINST(state));
337 AT_BUSINST(state) = NULL;
338 out:
339 return error;
340 }
341