:pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
[gnokii.git] / common / links / cbus.c
1 /* -*- linux-c -*-
2
3   Copyright (C) 2001 Pavel Machek <pavel@ucw.cz>
4   Copyright (C) 2001 Michl Ladislav <xmichl03@stud.fee.vutbr.cz>
5
6   Released under the terms of the GNU GPL, see file COPYING for more details.
7  
8  */
9
10 /* System header files */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <errno.h>
16
17 /* Various header file */
18 #include "config.h"
19 #ifndef DEBUG
20 #define DEBUG
21 #endif
22 #include "misc.h"
23 #include "gsm-common.h"
24 #include "gsm-ringtones.h"
25 #include "gsm-networks.h"
26 #include "device.h"
27 #include "links/utils.h"
28
29 #define __cbus_c
30 #include "links/cbus.h"
31
32 /* FIXME - pass device_* the link stuff?? */
33 /* FIXME - win32 stuff! */
34
35
36 /* Some globals */
37
38 GSM_Link *glink;
39 GSM_Phone *gphone;
40 CBUS_Link clink;        /* CBUS specific stuff, internal to this file */
41
42 int init_okay = 0;
43 int seen_okay;
44 char reply_buf[10240];
45
46 /*--------------------------------------------------------------------------*/
47
48 bool CBUS_OpenSerial()
49 {
50         int result;
51         result = device_open(glink->PortDevice, false, false, false, GCT_Serial);
52         if (!result) {
53                 perror(_("Couldn't open CBUS device"));
54                 return (false);
55         }
56         device_changespeed(9600);
57         device_setdtrrts(1, 0);
58         return (true);
59 }
60
61 /* -------------------------------------------------------------------- */
62
63 static int xread(unsigned char *d, int len)
64 {
65         int res;
66         while (len) {
67                 res = device_read(d, len);
68                 if (res == -1) {
69                         if (errno != EAGAIN) {
70                                 printf("I/O error : %m?!\n");
71                                 return -1;
72                         } else device_select(NULL);
73                 } else {
74                         d += res;
75                         len -= res;
76                         printf("(%d)", len);
77                 }
78         }
79         return 0;
80 }
81
82 static int xwrite(unsigned char *d, int len)
83 {
84         int res;
85         while (len) {
86                 res = device_write(d, len);
87                 if (res == -1) {
88                         if (errno != EAGAIN) {
89                                 printf("I/O error : %m?!\n");
90                                 return -1;
91                         }
92                 } else {
93                         d += res;
94                         len -= res;
95                         printf("<%d>", len);
96                 }
97         }
98         return 0;
99 }
100
101 static void
102 say(unsigned char *c, int len)
103 {
104         unsigned char d[10240];
105
106         xwrite(c, len);
107         xread(d, len);
108         if (memcmp(c, d, len)) {
109                 int i;
110                 printf("Did not get my own echo?: ");
111                 for (i=0; i<len; i++)
112                         printf("%x ", d[i]);
113                 printf("\n");
114         }                       
115 }
116
117 static int
118 waitack(void)
119 {
120         unsigned char c;
121         printf("Waiting ack\n");
122         if (xread(&c, 1) == 0) {
123                 printf("Got %x\n", c);
124                 if (c != 0xa5)
125                         printf("???\n");
126                 else return 1;
127         } else printf("Timeout?\n");
128         return 0;
129 }
130
131 static void
132 sendpacket(unsigned char *msg, int len, unsigned short cmd)
133 {
134         unsigned char p[10240], csum = 0;
135         int pos;
136
137         p[0] = 0x34;
138         p[1] = 0x19;
139         p[2] = cmd & 0xff;
140         p[3] = 0x68;
141         p[4] = len & 0xff;
142         p[5] = len >> 8;
143         memcpy(p+6, msg, len);
144         
145         pos = 6+len;
146         {
147                 int i;
148                 for (i=0; i<pos; i++) {
149                         csum = csum ^ p[i];
150                 }
151         }
152         p[pos] = csum;
153         {
154                 int i;
155                 printf("Sending: ");
156                 for (i=0; i<=pos; i++) {
157                         printf("%x ", p[i]);
158                 }
159                 printf("\n");
160         }
161         say(p, pos+1);
162         waitack();
163 }
164
165 /* -------------------------------------------------------------------- */
166
167
168 static GSM_Error CommandAck(int messagetype, unsigned char *buffer, int length)
169 {
170         printf("[ack]");
171         return GE_NONE;
172 }
173
174 static GSM_Error PhoneReply(int messagetype, unsigned char *buffer, int length)
175 {
176         if (!strncmp(buffer, "OK", 2)) {
177                 seen_okay = 1;
178                 printf("Phone okays\n");
179         } else {
180                 strncpy(reply_buf, buffer, length);
181                 reply_buf[length+1] = '\0';
182                 printf("Phone says: %s\n", reply_buf);
183         }
184         {
185                 u8 buf[2] = { 0x3e, 0x68 };
186                 usleep(10000);
187                 CBUS_SendMessage(2, 0x3f, buf);
188         }
189
190         return GE_NONE;
191 }
192
193 void
194 sendat(char *msg)
195 {
196         usleep(10000);
197         printf("AT command: %s\n", msg);
198         CBUS_SendMessage(strlen(msg), 0x3c, msg);
199         seen_okay = 0;
200         while (!seen_okay)
201                 CBUS_Loop(NULL);
202 //      getpacket();    /* This should be phone's acknowledge of AT command */
203 }
204
205
206 /* -------------------------------------------------- */
207
208 /* RX_State machine for receive handling.  Called once for each character
209    received from the phone. */
210
211 void
212 internal_dispatch(GSM_Link *glink, GSM_Phone *gphone, int type, u8 *buf, int len)
213 {
214         switch(type) {
215         case '=': CommandAck(type, buf, len);
216                 break;
217         case '>': PhoneReply(type, buf, len);
218                 break;
219         default: dprintf("Unknown Frame Type 68/ %02x\n", type);
220                 break;
221         }
222 }
223
224 void CBUS_RX_StateMachine(unsigned char rx_byte)
225 {
226         CBUS_IncomingFrame *i = &clink.i;
227
228         /* checksum is XOR of all bytes in the frame */
229         if (i->state != CBUS_RX_GetCSum) i->checksum ^= rx_byte;
230
231         switch (i->state) {
232
233         case CBUS_RX_Header:
234                 switch (rx_byte) {
235                         case 0x38:
236                         case 0x34:
237                                 if (i->prev_rx_byte == 0x19) {
238                                         i->state = CBUS_RX_FrameType1;
239                                 }
240                                 break;
241                         case 0x19:
242                                 if ((i->prev_rx_byte == 0x38) || (i->prev_rx_byte == 0x34)) {
243                                         i->state = CBUS_RX_FrameType1;
244                                 }
245                                 break;
246                         default:
247                 }
248                 if (i->state != CBUS_RX_Header) {
249                         i->FrameHeader1 = i->prev_rx_byte;
250                         i->FrameHeader2 = rx_byte;
251                         i->BufferCount = 0;
252                         i->checksum = i->prev_rx_byte ^ rx_byte;
253                 }
254                 break;
255         
256         /* FIXME: Do you know exact meaning? just mail me. ladis. */ 
257         case CBUS_RX_FrameType1:
258                 i->FrameType1 = rx_byte;
259                 i->state = CBUS_RX_FrameType2;
260                 break;
261
262         /* FIXME: Do you know exact meaning? just mail me. ladis. */
263         case CBUS_RX_FrameType2:
264                 i->FrameType2 = rx_byte; 
265                 i->state = CBUS_RX_GetLengthLB;
266                 break;
267
268         /* message length - low byte */
269         case CBUS_RX_GetLengthLB:
270                 i->MessageLength = rx_byte;
271                 i->state = CBUS_RX_GetLengthHB;
272                 break;
273         
274         /* message length - high byte */
275         case CBUS_RX_GetLengthHB:
276                 i->MessageLength = i->MessageLength | rx_byte << 8;
277                 /* there are also empty commands */
278                 if (i->MessageLength == 0) 
279                         i->state = CBUS_RX_GetCSum;
280                 else 
281                         i->state = CBUS_RX_GetMessage;
282                 break;
283
284         /* get each byte of the message body */
285         case CBUS_RX_GetMessage:
286                 i->buffer[i->BufferCount++] = rx_byte;
287                 /* avoid buffer overflow */
288                 if (i->BufferCount > CBUS_MAX_MSG_LENGTH) {
289                         dprintf("CBUS: Message buffer overun - resetting\n");
290                         i->state = CBUS_RX_Header;
291                         break;
292                 }
293                 
294                 if (i->BufferCount == i->MessageLength) 
295                         i->state = CBUS_RX_GetCSum;
296                 break;
297
298         /* get checksum */
299         case CBUS_RX_GetCSum:
300                 /* compare against calculated checksum. */
301                 if (i->checksum == rx_byte) {
302                         u8 ack = 0xa5;
303
304                         xwrite(&ack, 1);
305                         xread(&ack, 1);
306                         if (ack != 0xa5)
307                                 printf("ack lost, expect armagedon!\n");
308
309                         /* Got checksum, matches calculated one, so  
310                          * now pass to appropriate dispatch handler. */
311                         i->buffer[i->MessageLength + 1] = 0;
312                         /* FIXME: really call it :-) */
313
314                         switch(i->FrameType2) {
315                         case 0x68:
316                                 internal_dispatch(glink, gphone, i->FrameType1, i->buffer, i->MessageLength);
317                                 break;
318                         case 0x70:
319                                 if (i->FrameType1 == 0x91) {
320                                         init_okay = 1;
321                                         printf("Registration acknowledged\n");
322                                 } else
323                                         printf("Unknown message\n");
324                         }
325                 } else { 
326                         /* checksum doesn't match so ignore. */
327                         dprintf("CBUS: Checksum error; expected: %02x, got: %02x", i->checksum, rx_byte);
328                 }
329                 
330                 i->state = CBUS_RX_Header;
331                 break;
332                 
333         default:
334         }                       
335         i->prev_rx_byte = rx_byte;
336 }
337
338 int CBUS_SendMessage(u16 message_length, u8 message_type, void * buffer)
339 {
340         sendpacket(buffer, message_length, message_type);
341         return true;
342 }
343
344 static GSM_Error AT_SendMessage(u16 message_length, u8 message_type, void * buffer)
345 {
346         sendat(buffer);
347         return true;
348 }
349
350 /* This is the main loop function which must be called regularly */
351 /* timeout can be used to make it 'busy' or not */
352
353 /* ladis: this function ought to be the same for all phones... */
354
355 GSM_Error CBUS_Loop(struct timeval *timeout)
356 {
357         unsigned char buffer[255];
358         int count, res;
359
360         res = device_select(timeout);
361         if (res > 0) {
362                 res = device_read(buffer, 255);
363                 for (count = 0; count < res; count++)
364                         CBUS_RX_StateMachine(buffer[count]);
365         } else
366                 return GE_TIMEOUT;
367
368         /* This traps errors from device_read */
369         if (res > 0)
370                 return GE_NONE;
371         else
372                 return GE_INTERNALERROR;
373 }
374
375
376 int CBUS_TX_SendAck(u8 message_type, u8 message_seq)
377 {
378         dprintf("[Sending Ack]\n");
379         return (0);
380 }
381
382
383 /* Initialise variables and start the link */
384
385 GSM_Error CBUS_Initialise(GSM_Statemachine *state)
386 {
387         setvbuf(stdout, NULL, _IONBF, 0);
388         setvbuf(stderr, NULL, _IONBF, 0);
389
390         /* 'Copy in' the global structures */
391         glink = &(state->Link);
392         gphone = &(state->Phone);
393
394         /* Fill in the link functions */
395         glink->Loop = &CBUS_Loop;
396         glink->SendMessage = &AT_SendMessage;
397
398         if (glink->ConnectionType == GCT_Serial) {
399                 if (!CBUS_OpenSerial())
400                         return GE_DEVICEOPENFAILED;
401         } else {
402                 fprintf(stderr, "Device not supported by CBUS");
403                 return GE_DEVICEOPENFAILED;
404         }
405
406         dprintf("Saying hello...");
407         {
408                 char init1[] = { 0, 0x38, 0x19, 0xa6, 0x70, 0x00, 0x00, 0xf7, 0xa5 };
409                 say( init1, 8 );
410                 say( init1, 8 );
411         }
412         usleep(10000);
413         dprintf("second hello...");
414         {
415                 char init1[] = { 0x38, 0x19, 0x90, 0x70, 0x01, 0x00, 0x1f, 0xdf };
416                 say( init1, 8 );
417                 if (!waitack())
418                         return GE_BUSY;
419         }
420         while(!init_okay)
421                 CBUS_Loop(NULL);
422         return GE_NONE;
423 }