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