Branch update for mygnokii2002_03_17_19_29nl
[gnokii.git] / common / protocol / fbus.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8
9   This file provides an API for support for FBUS protocol
10
11 */
12
13 #include "config.h"
14
15 /* "Turn on" prototypes in fbus.h */
16 #define __fbus_c 
17
18 /* System header files */
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22  
23 #ifdef WIN32
24   #include <windows.h>
25   #include "misc_win32.h"
26 #else
27   #include <ctype.h>
28 #endif
29
30 /* Various header file */
31 #include "devices/device.h"
32 #include "gsm-api.h"
33 #include "protocol/fbus.h"
34 #include "protocol/at.h"
35 #include "newmodules/newat.h"
36 #ifndef UCLINUX
37 #include "newmodules/n6110.h"
38 #endif /* UCLINUX */
39 #include "misc.h"
40
41 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
42                           GSM_ConnectionType connection,
43                           void (*rlp_callback)(RLP_F96Frame *frame));
44
45 static int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer);
46 static int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer);
47 static void FBUS_Terminate(void);
48 static void FBUS_RX_StateMachine(unsigned char rx_byte);
49
50 GSM_Protocol FBUS_Functions = {
51   FBUS_Initialise,
52   FBUS_SendMessage,
53   FBUS_SendFrame,
54   NULL_WritePhone,
55   FBUS_Terminate,
56   FBUS_RX_StateMachine
57 };
58
59 /* Local variables */
60 static enum FBUS_RX_States RX_State;
61
62 static u8 MessageDestination, MessageSource;
63
64 static u16 BufferCount;
65
66 static u16 MessageLength, MultiMessageLength;
67
68 static bool RX_Multiple = false;
69
70 static u8 MessageType,MultiMessageType;
71
72 static u8 MessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6],MultiMessageBuffer[FBUS_MAX_RECEIVE_LENGTH * 6];
73
74 static u8        RequestSequenceNumber = 0x00;
75
76 #ifdef DEBUG    
77 static char *N61_PrintDevice(int Device)
78 {
79   switch (Device) {
80
81   case FBUS_DEVICE_PHONE:return _("Phone");
82   case FBUS_DEVICE_PC   :return _("PC");
83   default               :return _("Unknown");
84   }
85 }
86 #endif /* DEBUG */
87
88 /* N61_RX_DisplayMessage is called when a message we don't know about is
89    received so that the user can see what is going back and forth, and perhaps
90    shed some more light/explain another message type! */
91 static void N61_RX_DisplayMessage()
92 {
93 #ifdef DEBUG
94   fprintf(stdout, _("Msg Dest: %s\n"), N61_PrintDevice(MessageDestination));
95   fprintf(stdout, _("Msg Source: %s\n"), N61_PrintDevice(MessageSource));
96   fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
97
98   hexdump(MessageLength-2,MessageBuffer);
99 #endif
100
101   AppendLog(MessageBuffer,MessageLength-2,true);
102 }
103
104 /* Prepares the message header and sends it, prepends the message start byte
105            (0x1e) and other values according the value specified when called.
106            Calculates checksum and then sends the lot down the pipe... */
107 int FBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
108
109   /* Originally out_buffer[FBUS_MAX_CONTENT_LENGTH + 2],
110      but it made problems with MBUS */
111   u8 out_buffer[1000];
112   
113   int count, current=0;
114   unsigned char checksum;
115
116   /* FIXME - we should check for the message length ... */
117
118   /* Now construct the message header. */
119
120   if (CurrentConnectionType==GCT_FBUS)
121     out_buffer[current++] = FBUS_FRAME_ID;    /* Start of the frame indicator */
122   else
123     out_buffer[current++] = FBUS_IR_FRAME_ID; /* Start of the frame indicator */
124     
125   out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
126
127   out_buffer[current++] = FBUS_DEVICE_PC;    /* Source */
128
129   out_buffer[current++] = message_type; /* Type */
130
131   out_buffer[current++] = 0; /* Length1 */
132   out_buffer[current++] = message_length; /* Length2 */
133
134   /* Copy in data if any. */            
135   if (message_length != 0) {
136     memcpy(out_buffer + current, buffer, message_length);
137     current+=message_length;
138   }
139
140   /* If the message length is odd we should add pad byte 0x00 */
141   if (message_length % 2)
142     out_buffer[current++]=0x00;
143
144   /* Now calculate checksums over entire message and append to message. */
145
146   /* Odd bytes */
147   checksum = 0;
148   for (count = 0; count < current; count+=2)
149     checksum ^= out_buffer[count];
150
151   out_buffer[current++] = checksum;
152
153   /* Even bytes */
154   checksum = 0;
155   for (count = 1; count < current; count+=2)
156     checksum ^= out_buffer[count];
157
158   out_buffer[current++] = checksum;
159   
160 #ifdef DEBUG
161   NULL_TX_DisplayMessage(current, out_buffer);
162 #endif /* DEBUG */
163
164 #if 0
165 usleep(200000);
166 #endif
167
168   /* Send it out... */
169   if (!NULL_WritePhone(current,out_buffer))
170     return (false);
171
172   return (true);
173 }
174
175 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
176   
177   u8 seqnum;
178
179   u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
180
181   u8 nom, lml;  /* number of messages, last message len */
182   int i;
183
184   seqnum = 0x40 + RequestSequenceNumber;
185   RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
186  
187   if (message_length > FBUS_MAX_CONTENT_LENGTH) {
188
189     nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
190                           / FBUS_MAX_CONTENT_LENGTH;
191     lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
192
193     for (i = 0; i < nom - 1; i++) {
194
195       memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
196              FBUS_MAX_CONTENT_LENGTH);
197       frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
198       frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
199
200       FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
201                      frame_buffer);
202
203       seqnum = RequestSequenceNumber;
204       RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;    
205     }
206
207     memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
208     frame_buffer[lml] = 0x01;
209     frame_buffer[lml + 1] = seqnum;
210     FBUS_SendFrame(lml + 2, message_type, frame_buffer);
211
212   } else {
213
214     memcpy(frame_buffer, buffer, message_length);
215     frame_buffer[message_length] = 0x01;
216     frame_buffer[message_length + 1] = seqnum;
217     FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
218   }
219
220   return (true);
221 }
222
223 static int FBUS_SendAck(u8 message_type, u8 message_seq) {
224
225   unsigned char request[6];
226
227   request[0] = message_type;
228   request[1] = message_seq;
229
230 #ifdef DEBUG
231   fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
232 #endif /* DEBUG */
233
234   return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
235 }
236
237 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
238    close the serial port. */
239 void FBUS_Terminate(void)
240 {
241   /* Request termination of thread */
242   CurrentRequestTerminate = true;
243
244   /* Close serial port. */
245   device_close();
246 }
247
248 /* RX_State machine for receive handling.  Called once for each character
249    received from the phone/phone. */
250
251 void FBUS_RX_StateMachine(unsigned char rx_byte) {
252
253   static struct timeval time_now, time_last, time_diff;
254   
255   static int checksum[2];
256   
257   int i=0;
258
259 #ifdef DEBUG
260   /* For model sniff only display received bytes */
261   if (strcmp(GSM_Info->FBUSModels, "sniff"))
262   {
263 #endif
264
265   /* XOR the byte with the current checksum */
266   checksum[BufferCount&1] ^= rx_byte;
267
268   switch (RX_State) {
269         
270     /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
271        We use this to "synchronise" with the incoming data stream. However,
272        if we see something else, we assume we have lost sync and we require
273        a gap of at least 5ms before we start looking again. This is because
274        the data part of the frame could contain a byte which looks like the
275        sync byte */
276
277   case FBUS_RX_Discarding:
278
279 #ifndef VC6
280     gettimeofday(&time_now, NULL);
281     timersub(&time_now, &time_last, &time_diff);
282     if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
283       time_last = time_now;  /* no gap seen, continue discarding */
284       break;
285     }
286     /* else fall through to... */
287 #endif
288
289   case FBUS_RX_Sync:
290
291       if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
292           0/*((CurrentConnectionType==GCT_Infrared ||
293            CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)*/) {
294
295         BufferCount = 0;
296
297         RX_State = FBUS_RX_GetDestination;
298         
299         /* Initialize checksums. */
300         checksum[0] = rx_byte;
301         checksum[1] = 0;
302       } else {
303         /* Lost frame sync */
304         RX_State = FBUS_RX_Discarding;
305 #ifndef VC6
306         gettimeofday(&time_last, NULL);
307 #endif
308       }    
309     break;
310
311   case FBUS_RX_GetDestination:
312
313     MessageDestination=rx_byte;
314     RX_State = FBUS_RX_GetSource;
315
316     /* When there is a checksum error and things get out of sync we have to manage to resync */
317     /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
318     /* Then all sorts of horrible things happen because the packet length etc is wrong... */
319     /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
320     if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
321       RX_State=FBUS_RX_Sync;
322 #ifdef DEBUG
323       fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
324 #endif
325       AppendLogText("SYNC\n",false);
326     }
327
328     break;
329
330   case FBUS_RX_GetSource:
331
332     MessageSource=rx_byte;
333     RX_State = FBUS_RX_GetType;
334
335     /* Source should be 0x00 */
336     if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL)  {
337       RX_State=FBUS_RX_Sync;
338 #ifdef DEBUG
339       fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
340 #endif
341       AppendLogText("SYNC\n",false);
342     }
343     
344     break;
345
346   case FBUS_RX_GetType:
347
348     MessageType=rx_byte;
349
350     RX_State = FBUS_RX_GetLength1;
351
352     break;
353
354   case FBUS_RX_GetLength1:
355
356     MessageLength = 0;
357
358     RX_State = FBUS_RX_GetLength2;
359     
360     break;
361     
362   case FBUS_RX_GetLength2:
363
364     /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
365        higher not (probably because rx_byte is char type) - improtant
366        for MBUS. So, I make it double and strange - generally it should be
367        more simple and make simple convert rx_byte into MessageLength */      
368 #if defined(__svr4__) || defined(__FreeBSD__)
369     if (rx_byte!=0) {
370       for (i=0;i<rx_byte;i++)
371         MessageLength=MessageLength++;
372     }
373 #else
374     MessageLength = rx_byte;
375 #endif
376     
377     RX_State = FBUS_RX_GetMessage;
378     
379     break;
380     
381   case FBUS_RX_GetMessage:
382
383     MessageBuffer[BufferCount] = rx_byte;
384     BufferCount ++;
385     
386     if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
387 #ifdef DEBUG
388       fprintf(stdout, "FB61: Message buffer overun - resetting\n");
389 #endif
390       AppendLogText("OVERUN\n",false);
391       RX_Multiple=false;
392       RX_State = FBUS_RX_Sync;
393       break;
394     }
395
396     /* If this is the last byte, it's the checksum. */
397     if (BufferCount == MessageLength+(MessageLength%2)+2) {
398
399       /* Is the checksum correct? */
400       if (checksum[0] == checksum[1]) {
401           
402         if (RX_Multiple) {
403
404           if (MessageType==MultiMessageType) {
405
406             if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
407 #ifdef DEBUG
408               fprintf(stdout, "FB61: Message buffer overun - resetting\n");
409 #endif
410               AppendLogText("OVERUN\n",false);
411               RX_Multiple=false;
412               RX_State = FBUS_RX_Sync;
413               break;
414             }
415         
416             /* We copy next part of multiframe message into special buffer */
417             for (i=0;i<MessageLength;i++) {
418               MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
419             }
420             MultiMessageLength=MultiMessageLength+MessageLength-2;
421
422             FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);           
423                 
424             if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
425             {
426             } else {
427               for (i=0;i<MultiMessageLength+2;i++) {
428                 MessageBuffer[i]=MultiMessageBuffer[i];
429               }
430               MessageLength=MultiMessageLength+2;
431               RX_Multiple=false;
432
433               /* Do not debug Ack and RLP frames to detail. */
434               if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
435                 N61_RX_DisplayMessage();
436
437               GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
438             }
439
440           } else {
441
442             /* We do not want to send ACK of ACKs and ACK of RLP frames. */
443             if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
444               FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
445
446               if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
447               {
448 #ifdef DEBUG
449                 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
450                 fprintf(stdout,_("Please report it !\n"));
451 #endif
452                 RX_State = FBUS_RX_Sync;
453               }
454             }
455           }
456         } else {
457
458           /* We do not want to send ACK of ACKs and ACK of RLP frames. */
459           if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
460             FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
461
462             if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
463             {
464               /* We copy previous part of multiframe message into special buffer */
465               RX_Multiple = true;
466               for (i=0;i<MessageLength-2;i++) {
467                 MultiMessageBuffer[i]=MessageBuffer[i];
468               }
469               MultiMessageLength=MessageLength-2;
470               MultiMessageType=MessageType;
471             }
472           }
473
474           if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
475             /* Do not debug Ack and RLP frames to detail. */
476             if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
477               N61_RX_DisplayMessage();
478
479             GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
480           }
481
482 #ifdef DEBUG
483           /* When make debug and message is to phone display it */
484           if (MessageDestination==FBUS_DEVICE_PHONE) {
485             for (i=MessageLength;i>=0;i--)
486               MessageBuffer[i+6]=MessageBuffer[i];
487             MessageBuffer[0]=FBUS_FRAME_ID;
488             MessageBuffer[1]=FBUS_DEVICE_PHONE;
489             MessageBuffer[2]=FBUS_DEVICE_PC;
490             MessageBuffer[3]=MessageType;
491             MessageBuffer[4]=0;
492             MessageBuffer[5]=MessageLength;
493             MessageLength=MessageLength+8;
494             if (MessageLength % 2) MessageLength++;
495             NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
496           }
497 #endif    
498         }
499       } else {
500 #ifdef DEBUG
501           fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
502 #endif /* DEBUG */
503         AppendLogText("CHECKSUM\n",false);
504
505         /* Just to be sure! */
506         RX_Multiple=false;
507       }
508       RX_State = FBUS_RX_Sync;    
509     }
510     break;
511   }
512
513 #ifdef DEBUG
514   } else {
515     if (isprint(rx_byte))
516       fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
517     else
518       fprintf(stdout, "[%02x ]", rx_byte);
519
520   }
521 #endif
522 }
523   
524 /* Called by initialisation code to open comm port in asynchronous mode. */
525 static bool FBUS_OpenSerial(void)
526 {
527 #ifndef UCLINUX
528   /* Uncomment, if want to test first method for DLR3 */
529   unsigned char req[3]   = {"AT\r"};  
530   unsigned char req2[5]  = {"AT&F\r"};  
531   unsigned char req3[13] = {"AT*NOKIAFBUS\r"};  
532 #endif /* UCLINUX */
533
534   switch (CurrentConnectionType) {
535      case GCT_FBUS:
536
537 #ifdef DEBUG
538        fprintf(stdout, _("Setting cable for FBUS communication...\n"));
539 #endif /* DEBUG */
540
541        device_changespeed(115200);
542    
543        /* Colin wrote:
544        The data suite cable has some electronics built into the connector. This of
545        course needs a power supply of some sorts to operate properly.
546
547        In this case power is drawn off the handshaking lines of the PC. DTR has to
548        be set and RTS have to be cleared, thus if you use a terminal program (that
549        does not set the handshaking lines to these conditions) you will get weird
550        results. It will not set them like this since if Request To Send (RTS) is
551        not set the other party will not send any data (in hardware handshaking)
552        and if DTS is not set (handshaking = none) the cable will not receive
553        power. */
554        /* clearing the RTS bit and setting the DTR bit*/
555        device_setdtrrts(1, 0);
556
557        break;
558 #ifndef UCLINUX
559      case GCT_DLR3:
560
561 #ifdef DEBUG
562        fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
563 #endif /* DEBUG */
564
565        /* There are 2 ways to init DLR in FBUS: Here is first described by
566           Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
567             1. Firstly set the connection baud to 19200, DTR off, RTS off,
568                Parity on, one stop bit, 
569             2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
570             3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
571             4. Send "AT*NOKIAFBUS\r\n". The response should be
572                "AT*NOKIAFBUS\r\n\r\nOK\r\n".
573             5. Set speed to 115200 
574           This seems to be compatible with more phones*/
575
576        device_changespeed(19200);
577
578        /*leave RTS low, DTR low for duration of session.*/
579        device_setdtrrts(0, 0);
580                             
581        Protocol->WritePhone (3,req );usleep(300);
582        Protocol->WritePhone (5,req2);usleep(300);
583        Protocol->WritePhone(13,req3);usleep(300);
584
585        device_changespeed(115200);
586
587 //     /*  Second method for DLR3:
588 //         Used by some 7110 soft, but not compatible with some other
589 //         phones supporting DLR3 - 7160, NCP2.0*/
590 //     device_changespeed(115200);
591 //     /*leave RTS low, DTR low for duration of session.*/
592 //     device_setdtrrts(0, 0);      
593 //     usleep(100000);
594
595        CurrentConnectionType=GCT_FBUS;
596
597        break;
598      case GCT_Infrared:
599        /* It's more complicated and not done here */
600        break;
601
602      case GCT_Tekram:
603        /* It's more complicated and not done here */
604        break;
605
606 #endif /* UCLINUX */
607      default:
608 #ifdef DEBUG
609        fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
610 #endif
611        break;
612   }
613
614   return (true);
615 }
616
617 /* Initialise variables and state machine. */
618 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
619                           GSM_ConnectionType connection,
620                           void (*rlp_callback)(RLP_F96Frame *frame))
621 {
622
623   if (!StartConnection (port_device,false,connection))
624     return GE_INTERNALERROR;
625       
626   CurrentConnectionType = connection;
627
628   if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;
629
630   return (GE_NONE);
631 }