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