First version, development moved to 5110-connected machine
[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   /* Send it out... */
165   if (!NULL_WritePhone(current,out_buffer))
166     return (false);
167
168   return (true);
169 }
170
171 int FBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
172   
173   u8 seqnum;
174
175   u8 frame_buffer[FBUS_MAX_CONTENT_LENGTH + 2];
176
177   u8 nom, lml;  /* number of messages, last message len */
178   int i;
179
180   seqnum = 0x40 + RequestSequenceNumber;
181   RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
182  
183   if (message_length > FBUS_MAX_CONTENT_LENGTH) {
184
185     nom = (message_length + FBUS_MAX_CONTENT_LENGTH - 1)
186                           / FBUS_MAX_CONTENT_LENGTH;
187     lml = message_length - ((nom - 1) * FBUS_MAX_CONTENT_LENGTH);
188
189     for (i = 0; i < nom - 1; i++) {
190
191       memcpy(frame_buffer, buffer + (i * FBUS_MAX_CONTENT_LENGTH),
192              FBUS_MAX_CONTENT_LENGTH);
193       frame_buffer[FBUS_MAX_CONTENT_LENGTH] = nom - i;
194       frame_buffer[FBUS_MAX_CONTENT_LENGTH + 1] = seqnum;
195
196       FBUS_SendFrame(FBUS_MAX_CONTENT_LENGTH + 2, message_type,
197                      frame_buffer);
198
199       seqnum = RequestSequenceNumber;
200       RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;    
201     }
202
203     memcpy(frame_buffer, buffer + ((nom - 1) * FBUS_MAX_CONTENT_LENGTH), lml);
204     frame_buffer[lml] = 0x01;
205     frame_buffer[lml + 1] = seqnum;
206     FBUS_SendFrame(lml + 2, message_type, frame_buffer);
207
208   } else {
209
210     memcpy(frame_buffer, buffer, message_length);
211     frame_buffer[message_length] = 0x01;
212     frame_buffer[message_length + 1] = seqnum;
213     FBUS_SendFrame(message_length + 2, message_type, frame_buffer);
214   }
215
216   return (true);
217 }
218
219 static int FBUS_SendAck(u8 message_type, u8 message_seq) {
220
221   unsigned char request[6];
222
223   request[0] = message_type;
224   request[1] = message_seq;
225
226 #ifdef DEBUG
227   fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
228 #endif /* DEBUG */
229
230   return FBUS_SendFrame(2, FBUS_FRTYPE_ACK, request);
231 }
232
233 /* Applications should call FBUS_Terminate to shut down the FBUS thread and
234    close the serial port. */
235 void FBUS_Terminate(void)
236 {
237   /* Request termination of thread */
238   CurrentRequestTerminate = true;
239
240   /* Close serial port. */
241   device_close();
242 }
243
244 /* RX_State machine for receive handling.  Called once for each character
245    received from the phone/phone. */
246
247 void FBUS_RX_StateMachine(unsigned char rx_byte) {
248
249   static struct timeval time_now, time_last, time_diff;
250   
251   static int checksum[2];
252   
253   int i=0;
254
255 //  if (CurrentConnectionType==GCT_DLR3) {
256 //    AT_RX_StateMachine(rx_byte);
257 //  } else {
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, 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, 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 }
525   
526 /* Called by initialisation code to open comm port in asynchronous mode. */
527 static bool FBUS_OpenSerial(void)
528 {
529   /* Uncomment, if want to test first method for DLR3 */
530 //  unsigned char req[3] = {"AT\r"};  
531 //  unsigned char req2[5] = {"AT&F\r"};  
532 //  unsigned char req3[13] = {"AT*NOKIAFBUS\r"};  
533
534 //  GSM_Error error;
535
536 //  GSM_Information *GSMINFOCOPY;
537 //  GSM_Functions *GSMCOPY;
538
539   switch (CurrentConnectionType) {
540      case GCT_FBUS:
541
542 #ifdef DEBUG
543        fprintf(stdout, _("Setting cable for FBUS communication...\n"));
544 #endif /* DEBUG */
545
546        device_changespeed(115200);
547    
548        /* Colin wrote:
549        The data suite cable has some electronics built into the connector. This of
550        course needs a power supply of some sorts to operate properly.
551
552        In this case power is drawn off the handshaking lines of the PC. DTR has to
553        be set and RTS have to be cleared, thus if you use a terminal program (that
554        does not set the handshaking lines to these conditions) you will get weird
555        results. It will not set them like this since if Request To Send (RTS) is
556        not set the other party will not send any data (in hardware handshaking)
557        and if DTS is not set (handshaking = none) the cable will not receive
558        power. */
559        /* clearing the RTS bit and setting the DTR bit*/
560        device_setdtrrts(1, 0);
561
562        break;
563 #ifndef UCLINUX
564      case GCT_DLR3:
565
566 #ifdef DEBUG
567        fprintf(stdout, _("Setting DLR3 cable for FBUS communication...\n"));
568 #endif /* DEBUG */
569
570        /* There are 2 ways to init DLR in FBUS: Here is first described by
571           Reuben Harris [reuben.harris@snowvalley.com] and used in Logo Manager,
572               1. Firstly set the connection baud to 19200, DTR off, RTS off,
573                  Parity on, one stop bit, 
574               2. Send "AT\r\n". The response should be "AT\r\n\r\nOK\r\n".
575               3. Send "AT&F\r\n". The response should be "AT&F\r\n\r\nOK\r\n".
576               4. Send "AT*NOKIAFBUS\r\n". The response should be
577                  "AT*NOKIAFBUS\r\n\r\nOK\r\n".
578               5. Set speed to 115200 
579
580           This is one should be used by us, because seems to be compatible with more
581           phones. But we make something wrong and often phones don't want to start transmision */
582
583        /* Uncomment and test if want */
584 //       device_changespeed(19200);
585
586        /*leave RTS low, DTR low for duration of session.*/
587 //       device_setdtrrts(0, 0);
588
589        /* Making copy of pointers */
590 //       GSMCOPY = GSM;
591 //       GSMINFOCOPY =GSM_Info;        
592
593        /* Set pointers to relevant addresses - new "AT" module here is required */
594 //       GSM = &Nat_Functions;
595 //       GSM_Info = &Nat_Information;
596
597        /* Note: We change Protocol inside function pointed by it.
598        That's why in FBUS_RX_StateMachine we must check it (changing
599        Protocol is not enough), This is for correct work and be sure... */
600 //       Protocol = &AT_Functions;
601
602 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 3, 0x00, req);
603 //       if (error!=GE_NONE) return false;
604
605 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 5, 0x00, req2);
606 //       if (error!=GE_NONE) return false;
607
608 //       error=N6110_SendMessageSequence (50, &CurrentGetHWError, 13, 0x00, req3);
609 //       if (error!=GE_NONE) return false;
610
611        /* Returning to old protocol */
612 //       Protocol = &FBUS_Functions;
613
614        /* Returning to old module */
615 //       GSM = GSMCOPY;
616 //       GSM_Info = GSMINFOCOPY;        
617
618 //       device_changespeed(115200);
619
620        /*  Second method for DLR3:
621                Used by some 7110 soft, but not compatible with some other
622                phones supporting DLR3 - 7160, NCP2.0
623                Used in this moment in mygnokii
624        */
625
626        device_changespeed(115200);
627
628        /*leave RTS low, DTR low for duration of session.*/
629        device_setdtrrts(0, 0);
630       
631        usleep(100000);
632
633        CurrentConnectionType=GCT_FBUS;
634
635        break;
636      case GCT_Infrared:
637        /* It's more complicated and not done here */
638        break;
639
640      case GCT_Tekram:
641        /* It's more complicated and not done here */
642        break;
643
644 #endif /* UCLINUX */
645      default:
646 #ifdef DEBUG
647        fprintf(stdout,_("Wrong connection type for fbus module. Inform marcin-wiacek@topnet.pl about it\n"));
648 #endif
649        break;
650   }
651
652   return (true);
653 }
654
655 /* Initialise variables and state machine. */
656 static GSM_Error FBUS_Initialise(char *port_device, char *initlength,
657                           GSM_ConnectionType connection,
658                           void (*rlp_callback)(RLP_F96Frame *frame))
659 {
660
661   if (!StartConnection (port_device,false,connection))
662     return GE_INTERNALERROR;
663       
664   CurrentConnectionType = connection;
665
666   if (FBUS_OpenSerial() != true) return GE_INTERNALERROR;
667
668   return (GE_NONE);
669 }