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