Branch update for mygnokii2002_03_17_19_29nl
[gnokii.git] / common / protocol / mbus.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 MBUS protocol
10
11 */
12
13 #include "config.h"
14
15 /* "Turn on" prototypes in MBUS.h */
16 #define __MBUS_c 
17
18 /* System header files */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23
24 #ifdef WIN32
25   #include <windows.h>
26   #include "misc_win32.h"
27 #else
28   #include <ctype.h>
29 #endif
30  
31 /* Various header file */
32 #include "devices/device.h"
33 #include "gsm-api.h"
34 #include "protocol/mbus.h"
35 #include "protocol/fbus.h"
36
37 GSM_Protocol MBUS_Functions = {
38   MBUS_Initialise,
39   MBUS_SendMessage,
40   MBUS_SendFrame,
41   MBUS_WritePhone,
42   MBUS_Terminate,
43   MBUS_RX_StateMachine
44 };
45
46 /* Local variables */
47 enum FBUS_RX_States RX_State;
48
49 u8 MessageDestination, MessageSource;
50
51 u16 BufferCount;
52
53 u16 MessageLength;
54
55 u8 MessageType;
56
57 u8 MessageBuffer[MBUS_MAX_RECEIVE_LENGTH * 6];
58
59 static u8 RequestSequenceNumber = 0x00;
60   
61 #ifdef DEBUG    
62 char *MBUS_PrintDevice(int Device)
63 {
64   switch (Device) {
65
66   case FBUS_DEVICE_PHONE:
67     return _("Phone");
68
69   case MBUS_DEVICE_PC1:
70     return _("PC");
71
72   case MBUS_DEVICE_PC2:
73     return _("PC");
74
75   default:
76     return _("Unknown");
77
78   }
79 }
80
81 /* N61_RX_DisplayMessage is called when a message we don't know about is
82    received so that the user can see what is going back and forth, and perhaps
83    shed some more light/explain another message type! */
84 void MBUS_RX_DisplayMessage()
85 {
86   fprintf(stdout, _("Msg Dest: %s\n"), MBUS_PrintDevice(MessageDestination));
87   fprintf(stdout, _("Msg Source: %s\n"), MBUS_PrintDevice(MessageSource));
88   fprintf(stdout, _("Msg Type: %02x\n"), MessageType);
89
90   hexdump(MessageLength,MessageBuffer);
91 }
92
93 #endif /* DEBUG */
94
95 /* Prepares the message header and sends it, prepends the message start byte
96            (0x1e) and other values according the value specified when called.
97            Calculates checksum and then sends the lot down the pipe... */
98 int MBUS_SendFrame(u16 message_length, u8 message_type, u8 *buffer) {
99   u8 out_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
100   
101   int count, current=0;
102   unsigned char checksum;
103
104   /* FIXME - we should check for the message length ... */
105
106   /* Now construct the message header. */
107
108   out_buffer[current++] = MBUS_FRAME_ID;    /* Start of the frame indicator */
109
110   out_buffer[current++] = FBUS_DEVICE_PHONE; /* Destination */
111
112   out_buffer[current++] = MBUS_DEVICE_PC1;    /* Source */
113
114   out_buffer[current++] = message_type; /* Type */
115
116   out_buffer[current++] = (message_length-1)/256; /* Length1 */
117   out_buffer[current++] = (message_length-1)%256; /* Length2 */
118
119   /* Copy in data if any. */    
120         
121   if (message_length != 0) {
122     memcpy(out_buffer + current, buffer, message_length);
123     current+=message_length;
124   }
125
126   /* Now calculate checksum over entire message and append to message. */
127
128   /* All bytes */
129   checksum = 0;
130   for (count = 0; count < current; count++)
131     checksum ^= out_buffer[count];
132
133   out_buffer[current++] = checksum;
134
135 #ifdef DEBUG
136   NULL_TX_DisplayMessage(current, out_buffer);
137 #endif /* DEBUG */
138
139   /* Send it out... */
140   if (!MBUS_WritePhone(current,out_buffer))
141     return (false);
142
143   return (true);
144 }
145
146 int MBUS_SendMessage(u16 message_length, u8 message_type, u8 *buffer) {
147   
148   u8 frame_buffer[MBUS_MAX_CONTENT_LENGTH + 2];
149
150     RequestSequenceNumber++;
151
152     memcpy(frame_buffer, buffer, message_length);
153     frame_buffer[message_length] = RequestSequenceNumber;  
154     MBUS_SendFrame(message_length + 1, message_type, frame_buffer);
155
156   return (true);
157 }
158
159 int MBUS_SendAck(u8 message_type, u8 message_seq) {
160
161   unsigned char request[6];
162
163   int count;
164
165   request[0]=MBUS_FRAME_ID;
166   request[1]=FBUS_DEVICE_PHONE;
167   request[2]=MBUS_DEVICE_PC1;
168   request[3]=FBUS_FRTYPE_ACK;
169   request[4] = message_seq;
170   request[5]=0;
171
172   /* Checksum */
173   for (count = 0; count < 5; count++)
174     request[5] ^= request[count];
175
176 #ifdef DEBUG
177   fprintf(stdout, _("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
178
179   NULL_TX_DisplayMessage(5, request);
180 #endif /* DEBUG */
181
182   if (!MBUS_WritePhone(6, request)) {
183 #ifdef DEBUG
184     fprintf(stdout,_("Sending ACK failed %i !\n"),count);
185 #endif
186     return (false);
187   }
188
189   return(true);
190 }
191
192 /* Applications should call MBUS_Terminate to shut down the MBUS thread and
193    close the serial port. */
194 void MBUS_Terminate(void)
195 {  
196   /* Request termination of thread */
197   CurrentRequestTerminate = true;
198
199   /* RTS low */
200   device_setdtrrts(0, 0);
201
202   /* Close serial port. */
203   device_close();
204 }
205
206 /* RX_State machine for receive handling.  Called once for each character
207    received from the phone/phone. */
208 void MBUS_RX_StateMachine(unsigned char rx_byte) {
209
210   static struct timeval time_now, time_last, time_diff;
211   
212   unsigned char max;
213
214   static int checksum[2];
215
216 #if defined(__svr4__) || defined(__FreeBSD__) || defined(DEBUG)
217   int i=0;
218 #endif
219
220 #ifdef DEBUG
221   if (strcmp(GSM_Info->MBUSModels, "mbussniff"))
222   {
223 #endif
224
225   checksum[0]=checksum[1];
226   checksum[1] ^= rx_byte;
227
228   switch (RX_State) {
229         
230   /* Messages from the phone start with an 0x1f (MBUS).
231      We use this to "synchronise" with the incoming data stream. However,
232      if we see something else, we assume we have lost sync and we require
233      a gap of at least 5ms before we start looking again. This is because
234      the data part of the frame could contain a byte which looks like the
235      sync byte */
236   case FBUS_RX_Discarding:
237 #ifndef VC6
238     gettimeofday(&time_now, NULL);
239     timersub(&time_now, &time_last, &time_diff);
240     if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
241       time_last = time_now;  /* no gap seen, continue discarding */
242       break;
243     }
244     /* else fall through to... */
245 #endif
246
247   case FBUS_RX_Sync:
248
249     if (rx_byte == MBUS_FRAME_ID) {
250
251       BufferCount = 0;
252         
253       RX_State = FBUS_RX_GetDestination;
254         
255       /* Initialize checksum. */
256       checksum[1] = MBUS_FRAME_ID;
257     } else {
258       /* Lost frame sync */
259       RX_State = FBUS_RX_Discarding;
260 #ifndef VC6
261       gettimeofday(&time_last, NULL);
262 #endif
263     }
264     
265     break;
266
267   case FBUS_RX_GetDestination:
268
269     MessageDestination=rx_byte;
270     RX_State = FBUS_RX_GetSource;
271
272     /* When there is a checksum error and things get out of sync we have to manage to resync */
273     /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
274     /* Then all sorts of horrible things happen because the packet length etc is wrong... */
275     /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
276     /* The same testing for MBUS. Only one change: MBUS returns, what we send.
277        So, the byte can be 0x10 (destination MBUS) or 0x00 (phone) */
278     if (rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2 && rx_byte!=FBUS_DEVICE_PHONE) {
279       RX_State=FBUS_RX_Sync;
280 #ifdef DEBUG
281       fprintf(stdout,"The mbus stream is out of sync - expected 0x10 or 0x00, got %2x\n",rx_byte);
282 #endif
283     }
284
285     break;
286
287   case FBUS_RX_GetSource:
288
289     MessageSource=rx_byte;
290     RX_State = FBUS_RX_GetType;
291
292     /* Source should be 0x00 or 0x10 */
293     if (rx_byte!=FBUS_DEVICE_PHONE && rx_byte!=MBUS_DEVICE_PC1 && rx_byte!=MBUS_DEVICE_PC2)  {
294       RX_State=FBUS_RX_Sync;
295 #ifdef DEBUG
296       fprintf(stdout,"The mbus stream is out of sync - expected 0x00 or 0x10, got %2x\n",rx_byte);
297 #endif
298     }    
299     
300     break;
301
302   case FBUS_RX_GetType:
303
304     MessageType=rx_byte;
305
306     RX_State = FBUS_RX_GetLength1;
307
308     break;
309
310   case FBUS_RX_GetLength1:
311
312     MessageLength=0;
313
314     /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
315        higher not (probably because rx_byte is char type) - improtant
316        for MBUS. So, I make it double and strange - generally it should be
317        more simple and make simple convert rx_byte into MessageLength */
318     if (rx_byte!=0) {
319       max=rx_byte;
320       MessageLength=max*256;
321     }
322
323     RX_State = FBUS_RX_GetLength2;
324     
325     break;
326     
327   case FBUS_RX_GetLength2:
328
329     /* MW:Here are problems with conversion. For chars 0-127 it's OK, for
330        higher not (probably because rx_byte is char type) - improtant
331        for MBUS. So, I make it double and strange - generally it should be
332        more simple and make simple convert rx_byte into MessageLength */      
333 #if defined(__svr4__) || defined(__FreeBSD__)
334     if (rx_byte!=0) {
335       for (i=0;i<rx_byte;i++)
336         MessageLength=MessageLength++;
337     }
338 #else
339     if (rx_byte!=0) {
340       max=rx_byte;
341       MessageLength=MessageLength+max;
342     }
343 #endif
344     
345     RX_State = FBUS_RX_GetMessage;
346
347     /* In MBUS ACK ends here */
348     if (MessageType==FBUS_FRTYPE_ACK)
349     {
350 #ifdef DEBUG
351       fprintf(stdout, _("[Received Ack from phone]\n"));
352 #endif /* DEBUG */
353       RX_State = FBUS_RX_Sync;
354     }
355     
356     break;
357     
358   case FBUS_RX_GetMessage:
359
360     MessageBuffer[BufferCount] = rx_byte;
361     BufferCount ++;
362
363     /* If this is the last byte, it's the checksum. */
364     if (BufferCount == MessageLength+2) {
365         
366       /* Is the checksum correct? */
367       if (checksum[0] == rx_byte) {
368
369         /* We do not want to send ACK of ACKs and ACK of RLP frames. */
370         if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1
371             && (MessageDestination==MBUS_DEVICE_PC1 || MessageDestination==MBUS_DEVICE_PC2)) {
372           MBUS_SendAck(MessageType, MessageBuffer[BufferCount-2]);
373         }
374
375         /* We don't write info about messages sent to phone */
376         if (MessageDestination!=FBUS_DEVICE_PHONE) {
377 #ifdef DEBUG
378           /* Do not debug Ack and RLP frames to detail. */
379           if (MessageType != FBUS_FRTYPE_ACK && MessageType != 0xf1)
380               MBUS_RX_DisplayMessage();
381 #endif /* DEBUG */
382
383           GSM->DispatchMessage(MessageLength, MessageBuffer, MessageType);
384
385         } else {
386 #ifdef DEBUG
387           if (strstr(GSM_Info->MBUSModels, "sniff") != NULL) {
388              fprintf(stdout, _("PC: "));
389
390              fprintf(stdout, "%02x:", MBUS_FRAME_ID);
391              fprintf(stdout, "%02x:", MBUS_DEVICE_PC1);
392              fprintf(stdout, "%02x:", FBUS_DEVICE_PHONE);
393              fprintf(stdout, "%02x:", MessageType);
394              fprintf(stdout, "%02x:", MessageLength/256);
395              fprintf(stdout, "%02x:", MessageLength%256);
396
397 //             NULL_TX_DisplayMessage(current, out_buffer);
398
399              for (i = 0; i < BufferCount; i++)
400                fprintf(stdout, "%02x:", MessageBuffer[i]);
401
402              fprintf(stdout, "\n");
403           }
404 #endif /* DEBUG */
405         }
406       } else {
407 #ifdef DEBUG
408         fprintf(stdout, _("Bad checksum %02x (should be %02x), msg len=%i !\n"),rx_byte,checksum[0],MessageLength);
409 #endif /* DEBUG */
410       }
411       RX_State = FBUS_RX_Sync;
412     }
413     break;
414   }
415
416 #ifdef DEBUG
417
418   } else {
419     if (isprint(rx_byte))
420       fprintf(stdout, "[%02x%c]", rx_byte, rx_byte);
421     else
422       fprintf(stdout, "[%02x ]", rx_byte);
423
424   }
425
426 #endif
427 }
428
429 /* Called by initialisation code to open comm port in asynchronous mode. */
430 bool MBUS_OpenSerial(void)
431 {
432 #ifdef DEBUG
433   fprintf(stdout, _("Setting MBUS communication...\n"));
434 #endif /* DEBUG */
435
436   device_changespeed(9600);
437
438   usleep(100);
439
440   if (strstr(GSM_Info->MBUSModels, "sniff") == NULL) {
441
442     /* leave RTS high, DTR low for duration of session. */
443     device_setdtrrts(0, 1);
444   
445     usleep(100);
446   }
447
448   return (true);
449
450 }
451
452 /* Initialise variables and state machine. */
453 GSM_Error MBUS_Initialise(char *port_device, char *initlength,
454                           GSM_ConnectionType connection,
455                           void (*rlp_callback)(RLP_F96Frame *frame))
456 {
457   if (!StartConnection (port_device,true,connection))
458     return GE_INTERNALERROR;
459     
460   CurrentConnectionType = connection;
461
462   if (MBUS_OpenSerial() != true) {
463     /* Fail so sit here till calling code works out there is a problem. */
464 //    while (!CurrentRequestTerminate)
465 //      usleep (100000);
466           
467     return GE_INTERNALERROR;
468   }
469
470   return (GE_NONE);
471 }
472
473 bool MBUS_WritePhone (u16 length, u8 *buffer) {
474
475   if (!CurrentDisableKeepAlive)
476     usleep(150);
477
478   if (device_write(buffer,length)!=length)
479     return false;
480   else
481     return true;
482 }