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