d1b51e0fd85341d9c3168cc15bb3e49e10084379
[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 1
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 //  if (CurrentConnectionType==GCT_DLR3) {
260 //    AT_RX_StateMachine(rx_byte);
261 //  } else {
262
263 #ifdef XDEBUG_LaceDisabled
264   if (isprint(rx_byte))
265     fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
266   else
267     fprintf(stdout, "[%02x ]", rx_byte);
268   fflush(stdout);
269 #endif
270
271 #ifdef DEBUG
272   /* For model sniff only display received bytes */
273   if (strcmp(GSM_Info->FBUSModels, "sniff"))
274   {
275 #endif
276
277   /* XOR the byte with the current checksum */
278   checksum[BufferCount&1] ^= rx_byte;
279
280   switch (RX_State) {
281         
282     /* Messages from the phone start with an 0x1e (FBUS) or 0x1c (IR) or 0x1f (MBUS).
283        We use this to "synchronise" with the incoming data stream. However,
284        if we see something else, we assume we have lost sync and we require
285        a gap of at least 5ms before we start looking again. This is because
286        the data part of the frame could contain a byte which looks like the
287        sync byte */
288
289   case FBUS_RX_Discarding:
290
291 #ifndef VC6
292     gettimeofday(&time_now, NULL);
293     timersub(&time_now, &time_last, &time_diff);
294     if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
295       time_last = time_now;  /* no gap seen, continue discarding */
296       break;
297     }
298     /* else fall through to... */
299 #endif
300
301   case FBUS_RX_Sync:
302
303       if ((CurrentConnectionType==GCT_FBUS && rx_byte == FBUS_FRAME_ID) ||
304           0/*((CurrentConnectionType==GCT_Infrared ||
305            CurrentConnectionType==GCT_Tekram) && rx_byte == FBUS_IR_FRAME_ID)*/) {
306
307         BufferCount = 0;
308
309         RX_State = FBUS_RX_GetDestination;
310         
311         /* Initialize checksums. */
312         checksum[0] = rx_byte;
313         checksum[1] = 0;
314       } else {
315         /* Lost frame sync */
316         RX_State = FBUS_RX_Discarding;
317 #ifndef VC6
318         gettimeofday(&time_last, NULL);
319 #endif
320       }    
321     break;
322
323   case FBUS_RX_GetDestination:
324
325     MessageDestination=rx_byte;
326     RX_State = FBUS_RX_GetSource;
327
328     /* When there is a checksum error and things get out of sync we have to manage to resync */
329     /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
330     /* Then all sorts of horrible things happen because the packet length etc is wrong... */
331     /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
332     if (rx_byte!=FBUS_DEVICE_PC && strstr(GSM_Info->FBUSModels, "sniff")==NULL) {
333       RX_State=FBUS_RX_Sync;
334 #ifdef DEBUG
335       fprintf(stdout,"The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
336 #endif
337       AppendLogText("SYNC\n",false);
338     }
339
340     break;
341
342   case FBUS_RX_GetSource:
343
344     MessageSource=rx_byte;
345     RX_State = FBUS_RX_GetType;
346
347     /* Source should be 0x00 */
348     if (rx_byte!=FBUS_DEVICE_PHONE && strstr(GSM_Info->FBUSModels, "sniff")==NULL)  {
349       RX_State=FBUS_RX_Sync;
350 #ifdef DEBUG
351       fprintf(stdout,"The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
352 #endif
353       AppendLogText("SYNC\n",false);
354     }
355     
356     break;
357
358   case FBUS_RX_GetType:
359
360     MessageType=rx_byte;
361
362     RX_State = FBUS_RX_GetLength1;
363
364     break;
365
366   case FBUS_RX_GetLength1:
367
368     MessageLength = 0;
369
370     RX_State = FBUS_RX_GetLength2;
371     
372     break;
373     
374   case FBUS_RX_GetLength2:
375
376     /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
377        higher not (probably because rx_byte is char type) - improtant
378        for MBUS. So, I make it double and strange - generally it should be
379        more simple and make simple convert rx_byte into MessageLength */      
380 #if defined(__svr4__) || defined(__FreeBSD__)
381     if (rx_byte!=0) {
382       for (i=0;i<rx_byte;i++)
383         MessageLength=MessageLength++;
384     }
385 #else
386     MessageLength = rx_byte;
387 #endif
388     
389     RX_State = FBUS_RX_GetMessage;
390     
391     break;
392     
393   case FBUS_RX_GetMessage:
394
395     MessageBuffer[BufferCount] = rx_byte;
396     BufferCount ++;
397     
398     if (BufferCount>FBUS_MAX_RECEIVE_LENGTH*6) {
399 #ifdef DEBUG
400       fprintf(stdout, "FB61: Message buffer overun - resetting\n");
401 #endif
402       AppendLogText("OVERUN\n",false);
403       RX_Multiple=false;
404       RX_State = FBUS_RX_Sync;
405       break;
406     }
407
408     /* If this is the last byte, it's the checksum. */
409     if (BufferCount == MessageLength+(MessageLength%2)+2) {
410
411       /* Is the checksum correct? */
412       if (checksum[0] == checksum[1]) {
413           
414         if (RX_Multiple) {
415
416           if (MessageType==MultiMessageType) {
417
418             if (MessageLength+MultiMessageLength>FBUS_MAX_RECEIVE_LENGTH*6) {
419 #ifdef DEBUG
420               fprintf(stdout, "FB61: Message buffer overun - resetting\n");
421 #endif
422               AppendLogText("OVERUN\n",false);
423               RX_Multiple=false;
424               RX_State = FBUS_RX_Sync;
425               break;
426             }
427         
428             /* We copy next part of multiframe message into special buffer */
429             for (i=0;i<MessageLength;i++) {
430               MultiMessageBuffer[i+MultiMessageLength]=MessageBuffer[i];
431             }
432             MultiMessageLength=MultiMessageLength+MessageLength-2;
433
434             FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);           
435                 
436             if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
437             {
438             } else {
439               for (i=0;i<MultiMessageLength+2;i++) {
440                 MessageBuffer[i]=MultiMessageBuffer[i];
441               }
442               MessageLength=MultiMessageLength+2;
443               RX_Multiple=false;
444
445               /* Do not debug Ack and RLP frames to detail. */
446               if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
447                 N61_RX_DisplayMessage();
448
449               GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
450             }
451
452           } else {
453
454             /* We do not want to send ACK of ACKs and ACK of RLP frames. */
455             if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
456               FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
457
458               if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
459               {
460 #ifdef DEBUG
461                 fprintf(stdout,_("Multiframe message in multiframe message !\n"));
462                 fprintf(stdout,_("Please report it !\n"));
463 #endif
464                 RX_State = FBUS_RX_Sync;
465               }
466             }
467           }
468         } else {
469
470           /* We do not want to send ACK of ACKs and ACK of RLP frames. */
471           if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1) {
472             FBUS_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
473
474             if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
475             {
476               /* We copy previous part of multiframe message into special buffer */
477               RX_Multiple = true;
478               for (i=0;i<MessageLength-2;i++) {
479                 MultiMessageBuffer[i]=MessageBuffer[i];
480               }
481               MultiMessageLength=MessageLength-2;
482               MultiMessageType=MessageType;
483             }
484           }
485
486           if (!RX_Multiple && MessageDestination!=FBUS_DEVICE_PHONE ) {
487             /* Do not debug Ack and RLP frames to detail. */
488             if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
489               N61_RX_DisplayMessage();
490
491             GSM->DispatchMessage(MessageLength-2, MessageBuffer, MessageType);
492           }
493
494 #ifdef DEBUG
495           /* When make debug and message is to phone display it */
496           if (MessageDestination==FBUS_DEVICE_PHONE) {
497             for (i=MessageLength;i>=0;i--)
498               MessageBuffer[i+6]=MessageBuffer[i];
499             MessageBuffer[0]=FBUS_FRAME_ID;
500             MessageBuffer[1]=FBUS_DEVICE_PHONE;
501             MessageBuffer[2]=FBUS_DEVICE_PC;
502             MessageBuffer[3]=MessageType;
503             MessageBuffer[4]=0;
504             MessageBuffer[5]=MessageLength;
505             MessageLength=MessageLength+8;
506             if (MessageLength % 2) MessageLength++;
507             NULL_TX_DisplayMessage(MessageLength, MessageBuffer);
508           }
509 #endif    
510         }
511       } else {
512 #ifdef DEBUG
513           fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),checksum[0],checksum[1],MessageLength);
514 #endif /* DEBUG */
515         AppendLogText("CHECKSUM\n",false);
516
517         /* Just to be sure! */
518         RX_Multiple=false;
519       }
520       RX_State = FBUS_RX_Sync;    
521     }
522     break;
523   }
524
525 #ifdef DEBUG
526   } else {
527     if (isprint(rx_byte))
528       fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
529     else
530       fprintf(stdout, "[%02x ]", rx_byte);
531
532   }
533 #endif
534
535 //  }
536 }
537   
538 /* Called by initialisation code to open comm port in asynchronous mode. */
539 static bool FBUS_OpenSerial(void)
540 {
541   /* Uncomment, if want to test first method for DLR3 */
542 //  unsigned char req[3] = {"AT\r"};  
543 //  unsigned char req2[5] = {"AT&F\r"};  
544 //  unsigned char req3[13] = {"AT*NOKIAFBUS\r"};  
545
546 //  GSM_Error error;
547
548 //  GSM_Information *GSMINFOCOPY;
549 //  GSM_Functions *GSMCOPY;
550
551   switch (CurrentConnectionType) {
552      case GCT_FBUS:
553
554 #ifdef DEBUG
555        fprintf(stdout, _("Setting cable for FBUS communication...\n"));
556 #endif /* DEBUG */
557
558        device_changespeed(115200);
559    
560        /* Colin wrote:
561        The data suite cable has some electronics built into the connector. This of
562        course needs a power supply of some sorts to operate properly.
563
564        In this case power is drawn off the handshaking lines of the PC. DTR has to
565        be set and RTS have to be cleared, thus if you use a terminal program (that
566        does not set the handshaking lines to these conditions) you will get weird
567        results. It will not set them like this since if Request To Send (RTS) is
568        not set the other party will not send any data (in hardware handshaking)
569        and if DTS is not set (handshaking = none) the cable will not receive
570        power. */
571        /* clearing the RTS bit and setting the DTR bit*/
572        device_setdtrrts(1, 0);
573
574        break;
575 #ifndef UCLINUX
576      case GCT_DLR3:
577
578 #ifdef DEBUG
579        fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
580 #endif /* DEBUG */
581
582        /* There are 2 ways to init DLR in FBUS: Here is first described by
583           Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
584               1. Firstly set the connection baud to 19200, DTR off, RTS off,
585                  Parity on, one stop bit, 
586               2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
587               3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
588               4. Send "AT*NOKIAFBUS\r\n". The response should be
589                  "AT*NOKIAFBUS\r\n\r\nOK\r\n".
590               5. Set speed to 115200 
591
592           This is one should be used by us, because seems to be compatible with more
593           phones. But we make something wrong and often phones don't want to start transmision */
594
595        /* Uncomment and test if want */
596 //       device_changespeed(19200);
597
598        /*leave RTS low, DTR low for duration of session.*/
599 //       device_setdtrrts(0, 0);
600
601        /* Making copy of pointers */
602 //       GSMCOPY = GSM;
603 //       GSMINFOCOPY =GSM_Info;        
604
605        /* Set pointers to relevant addresses - new "AT" module here is required */
606 //       GSM = &Nat_Functions;
607 //       GSM_Info = &Nat_Information;
608
609        /* Note: We change Protocol inside function pointed by it.
610        That's why in FBUS_RX_StateMachine we must check it (changing
611        Protocol is not enough), This is for correct work and be sure... */
612 //       Protocol = &AT_Functions;
613
614 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
615 //       if (error!=GE_NONE) return false;
616
617 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
618 //       if (error!=GE_NONE) return false;
619
620 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
621 //       if (error!=GE_NONE) return false;
622
623        /* Returning to old protocol */
624 //       Protocol = &FBUS_Functions;
625
626        /* Returning to old module */
627 //       GSM = GSMCOPY;
628 //       GSM_Info = GSMINFOCOPY;        
629
630 //       device_changespeed(115200);
631
632        /*  Second method for DLR3:
633                Used by some 7110 soft, but not compatible with some other
634                phones supporting DLR3 - 7160, NCP2.0
635                Used in this moment in mygnokii
636        */
637
638        device_changespeed(115200);
639
640        /*leave RTS low, DTR low for duration of session.*/
641        device_setdtrrts(0, 0);
642       
643        usleep(100000);
644
645        CurrentConnectionType=GCT_FBUS;
646
647        break;
648      case GCT_Infrared:
649        /* It's more complicated and not done here */
650        break;
651
652      case GCT_Tekram:
653        /* It's more complicated and not done here */
654        break;
655
656 #endif /* UCLINUX */
657      default:
658 #ifdef DEBUG
659        fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
660 #endif
661        break;
662   }
663
664   return (true);
665 }
666
667 /* Initialise variables and state machine. */
668 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
669                           GSM_ConnectionType connection,
670                           void (*rlp_callback)(RLP_F96Frame *frame))
671 {
672
673   if (!StartConnection (port_device,false,connection))
674     return GE_INTERNALERROR;
675       
676   CurrentConnectionType = connection;
677
678   if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;
679
680   return (GE_NONE);
681 }