Found in "gnokii-working" directory, some November-patches version
[gnokii.git] / common / mbus-640.c
1 /*
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   This is the main part of 640 support.
14
15   $Log$
16   Revision 1.1.1.2  2002/04/03 00:07:59  short
17   Found in "gnokii-working" directory, some November-patches version
18
19   Revision 1.22  2001/06/28 00:28:45  pkot
20   Small docs updates (Pawel Kot)
21         
22
23 */
24
25 #ifndef WIN32
26
27 #define         __mbus_640_c    /* "Turn on" prototypes in mbus-640.h */
28
29 #include        "misc.h"
30
31 #include        <termios.h>
32 #include        <stdio.h>
33 #include        <stdlib.h>
34 #include        <unistd.h>
35 #include        <fcntl.h>
36 #include        <ctype.h>
37 #include        <signal.h>
38 #include        <sys/types.h>
39 #include        <sys/time.h>
40 #include        <sys/ioctl.h>
41
42 #if __unices__
43 #  include <sys/file.h>
44 #endif
45
46 #include        <string.h>
47 #include        <pthread.h>
48 #include        <errno.h>
49
50 #include        "gsm-common.h"
51 #include        "mbus-640.h"
52 #include        "phones/nokia.h"
53
54         /* Global variables used by code in gsm-api.c to expose the
55            functions supported by this model of phone.  */
56 bool                                    MB640_LinkOK;
57 char          PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
58 char          *MB640_Revision = 0,
59               *MB640_RevisionDate = 0,
60               *MB640_Model = 0,
61               MB640_VersionInfo[64];
62
63 GSM_Functions                   MB640_Functions = {
64                 MB640_Initialise,
65                 MB640_Terminate,
66                 MB640_GetMemoryLocation,
67                 MB640_WritePhonebookLocation,
68                 UNIMPLEMENTED,
69                 UNIMPLEMENTED,
70                 MB640_GetMemoryStatus,
71                 UNIMPLEMENTED,
72                 UNIMPLEMENTED,
73                 UNIMPLEMENTED,
74                 UNIMPLEMENTED,
75                 UNIMPLEMENTED,
76                 UNIMPLEMENTED,
77                 UNIMPLEMENTED,
78                 MB640_GetRFLevel,
79                 MB640_GetBatteryLevel,
80                 UNIMPLEMENTED,
81                 UNIMPLEMENTED,
82                 UNIMPLEMENTED,
83                 UNIMPLEMENTED,
84                 MB640_GetIMEI,
85                 MB640_GetRevision,
86                 MB640_GetModel,
87                 PNOK_GetManufacturer,
88                 UNIMPLEMENTED,
89                 UNIMPLEMENTED,
90                 UNIMPLEMENTED,
91                 UNIMPLEMENTED,
92                 UNIMPLEMENTED,
93                 UNIMPLEMENTED,
94                 UNIMPLEMENTED,
95                 UNIMPLEMENTED,
96                 UNIMPLEMENTED,
97                 UNIMPLEMENTED,
98                 UNIMPLEMENTED,
99                 UNIMPLEMENTED,
100                 UNIMPLEMENTED,
101                 MB640_GetBitmap,
102                 MB640_SetBitmap,
103                 UNIMPLEMENTED,
104                 MB640_Reset,
105                 UNIMPLEMENTED,
106                 UNIMPLEMENTED,
107                 MB640_SendRLPFrame,
108                 UNIMPLEMENTED,
109                 UNIMPLEMENTED,
110                 UNIMPLEMENTED,
111                 UNIMPLEMENTED,
112                 UNIMPLEMENTED,
113                 UNIMPLEMENTED,
114                 UNIMPLEMENTED,
115                 UNIMPLEMENTED,
116                 UNIMPLEMENTED
117 };
118
119         /* FIXME - these are guesses only... */
120 GSM_Information                 MB640_Information = {
121                 "640",                                  /* Models */
122                 4,                                              /* Max RF Level */
123                 0,                                              /* Min RF Level */
124                 GRF_Arbitrary,                  /* RF level units */
125                 4,                              /* Max Battery Level */
126                 0,                                              /* Min Battery Level */
127                 GBU_Arbitrary,                  /* Battery level units */
128                 GDT_None,                               /* No date/time support */
129                 GDT_None,                               /* No alarm support */
130                 0,                                              /* Max alarms = 0 */
131                 0, 0,                   /* Startup logo size */
132                 0, 0,                   /* Op logo size */
133                 0, 0                    /* Caller logo size */
134 };
135
136 char MB640_2_KOI8[] = 
137 {
138   ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
139   ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
140   ' ','!','"','#','$','&','%','\'','(',')','*','+',',','-','.','/',
141   '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
142
143   '!','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
144   'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
145   '?','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
146   'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',' ',
147   ' ',' ',' ','á','â','÷','ç','ä','å','ö','ú','é','ê','ë','ì','í',
148   'î','ï','ð','ò','ó','ô','õ','æ','è','ã','þ','û','ý','ÿ','ù','ø',
149   ' ',' ',' ','Á','Â','×','Ç','Ä','Å','Ö','Ú','É','Ê','Ë','Ì','Í',
150   'Î','Ï','Ð','Ò','Ó','Ô','Õ','Æ','È','Ã','Þ','Û','Ý','ß','Ù','Ø',
151
152   ' ','ü','à','ñ',' ','Ü','À','Ñ',' ',' ',' ',' ',' ',' ',' ',' ',
153   ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
154   ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
155   ' ',' ',' ',' ',' ',' ',' ',' ','E',' ',' ','@','$','L','Y',' ',
156 };
157
158 char KOI8_2_MB640[] = 
159 {
160    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
161    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
162    ' ','!','"','#',0xFC,'&','%','\'','(',')','*','+',',','-','.','/',
163    '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
164
165    0xFB,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
166    'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
167    '?','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
168    'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~',' ',
169
170    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
171    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
172    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
173    ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
174 /*  À    Á    Â    Ã    Ä    Å    Æ    Ç    È    É    Ê    Ë    Ì    Í    Î    Ï*/
175   0xC6,0xA3,0xA4,0xB9,0xA7,0xA8,0xB7,0xA6,0xB8,0xAB,0xBC,0xAD,0xAE,0xAF,0xB0,0xB1,
176 /*  Ð    Ñ    Ò    Ó    Ô    Õ    Ö    ×    Ø    Ù    Ú    Û    Ü    Ý    Þ    ß*/
177   0xB2,0xC7,0xB3,0xB4,0xB5,0xB6,0xA9,0xA5,0xBD,0xBE,0xAA,0xBB,0xC5,0xBC,0xBA,0xBF,
178 /*  à    á    â    ã    ä    å    æ    ç    è    é    ê    ë    ì    í    î    ï*/
179   0xC2,0x83,0x84,0x99,0x87,0x88,0x97,0x86,0x98,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,
180 /*  ð    ñ    ò    ó    ô    õ    ö    ÷    ø    ù    ú    û    ü    ý    þ    ÿ*/
181   0x92,0xC3,0x93,0x94,0x95,0x96,0x89,0x85,0x9D,0x9E,0x8A,0x9B,0xC1,0x9C,0x9A,0x9F,
182 };
183
184 /* Local variables */
185 pthread_t      Thread;
186 bool                                     RequestTerminate;
187 int            PortFD;
188 struct termios old_termios; /* old termios */
189 u8             MB640_TXPacketNumber = 0x00;
190 char           Model[MB640_MAX_MODEL_LENGTH];
191 bool           ModelValid     = false;
192 unsigned char  PacketData[256];
193 bool           MB640_ACKOK    = false,
194                MB640_PacketOK = false,
195                MB640_EchoOK   = false;
196
197         /* The following functions are made visible to gsm-api.c and friends. */
198
199         /* Initialise variables and state machine. */
200 GSM_Error   MB640_Initialise(char *port_device, char *initlength,
201                             GSM_ConnectionType connection,
202                             void (*rlp_callback)(RLP_F96Frame *frame))
203 {int rtn;
204
205         /* ConnectionType is ignored in 640 code. */
206   RequestTerminate = false;
207         MB640_LinkOK     = false;
208   memset(MB640_VersionInfo,0,sizeof(MB640_VersionInfo));
209   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
210         rtn = pthread_create(&Thread, NULL, (void *) MB640_ThreadLoop, (void *)NULL);
211   if(rtn == EAGAIN || rtn == EINVAL)
212   {
213     return (GE_INTERNALERROR);
214   }
215         return (GE_NONE);
216 }
217
218         /* Applications should call MB640_Terminate to close the serial port. */
219 void MB640_Terminate(void)
220 {
221   /* Request termination of thread */
222   RequestTerminate = true;
223   /* Now wait for thread to terminate. */
224   pthread_join(Thread, NULL);
225         /* Close serial port. */
226   if( PortFD >= 0 )
227   {
228     tcsetattr(PortFD, TCSANOW, &old_termios);
229     close( PortFD );
230   }
231 }
232
233         /* Routine to get specifed phone book location.  Designed to 
234            be called by application.  Will block until location is
235            retrieved or a timeout/error occurs. */
236 GSM_Error       MB640_GetMemoryLocation(GSM_PhonebookEntry *entry)
237 {int  timeout,i,len;
238  u8   pkt[] = {0x0f, 0x2d, 3, 0, 7, 0x1f, 0x7f, 0xf0, 0, 0, 0, 0}, digit;
239  char *digit_map = " 1234567890*#pw+";
240
241   if(!entry->Location) return (GE_INVALIDPHBOOKLOCATION);
242   switch(entry->MemoryType)
243   {
244     case GMT_ME:
245 /*      if(entry->Location > 100) return (GE_INVALIDPHBOOKLOCATION); */
246       pkt[9] = entry->Location - 1;
247       break;
248     case GMT_LD: 
249       if(entry->Location > 5) return (GE_INVALIDPHBOOKLOCATION);
250       pkt[9] = entry->Location + 99;
251       break;
252     case GMT_ON: 
253       if(entry->Location > 1) return (GE_INVALIDPHBOOKLOCATION);
254       pkt[9] = 115;
255       break;
256     default: return (GE_INVALIDMEMORYTYPE);
257   }
258
259   MB640_PacketOK = false;
260   MB640_ACKOK    = false;
261   timeout        = 3;
262   while(!MB640_PacketOK)
263   {
264     if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
265     if(!--timeout || RequestTerminate)
266     {
267       return(GE_TIMEOUT);
268     }
269     usleep(100000);
270   }
271   entry->Empty = (PacketData[18] == 0 && PacketData[34] == 0);
272   if( !entry->Empty )
273   {
274     for( i = 0; PacketData[34 + i] && i < 16; i++ )
275     {
276       entry->Name[i] = MB640_2_KOI8[ PacketData[34 + i] ];
277     }
278     entry->Name[i] = 0;
279
280     len = PacketData[18];
281     for( i = 0; i < len; i++ )
282     {
283       digit = PacketData[19 + i/2];
284       entry->Number[i] = digit_map[((i % 2) ? digit : digit >> 4) & 0x0F];
285     }
286     entry->Number[i] = 0;
287     entry->Group = PacketData[50];
288   }
289   else
290   {
291     entry->Name[0] = 0;
292     entry->Number[0] = 0;
293     entry->Group = 255;
294   }
295         return (GE_NONE);
296 }
297
298         /* Routine to write phonebook location in phone. Designed to 
299            be called by application code.  Will block until location
300            is written or timeout occurs.  */
301 GSM_Error       MB640_WritePhonebookLocation(GSM_PhonebookEntry *entry)
302 {int timeout,i;
303
304   switch(entry->MemoryType)
305   {
306     case GMT_ME:
307       {u8 pkt[47], digit;
308        char *s;
309
310         pkt[0]  = 0x10;
311         pkt[1]  = 0x08;
312         pkt[2]  = 0x03;
313         pkt[3]  = 0x00;
314         pkt[4]  = 0x07;
315         pkt[5]  = 0x1F;
316         pkt[6]  = 0x7F;
317         pkt[7]  = 0xF0;
318         pkt[8]  = 0x00;
319         pkt[9]  = entry->Location - 1;
320         pkt[10] = 0x00;
321         pkt[11] = 0x00;
322         pkt[12] = 0x00;
323         pkt[13] = 0x21;
324         memset(&pkt[14],0,32);
325         pkt[46] = 0x05/*entry->Group*/;
326
327         for( i = 0; entry->Name[i] && i < 15; i++ )
328         {
329           pkt[30 + i] = KOI8_2_MB640[ (u8)entry->Name[i] ];
330         }
331         pkt[30 + i] = 0;
332
333         
334         for( i = 0, s = entry->Number; *s && i < 30; s++ )
335         {
336           switch(*s)
337           {
338             case '1'...'9': digit = *s - '0'; break;
339             case '0':       digit = 0xA;      break;
340             case '*':       digit = 0xB;      break;
341             case '#':       digit = 0xC;      break;
342             case 'p':       digit = 0xD;      break;
343             case 'w':       digit = 0xE;      break;
344             case '+':       digit = 0xF;      break;
345             default: continue;
346           }
347           pkt[15 + i/2] |= (i % 2) ? digit : digit << 4;
348           i++;
349         }
350         pkt[14] = i;
351
352         /* And write it! */
353         MB640_PacketOK = false;
354         MB640_ACKOK    = false;
355         timeout        = 3;
356         while(!MB640_PacketOK)
357         {
358           if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
359           if(!--timeout || RequestTerminate)
360           {
361             return(GE_TIMEOUT);
362           }
363           usleep(100000);
364         }
365       }
366     break;
367     default: return (GE_NOTIMPLEMENTED);
368   }
369   return (GE_NONE);
370 }
371
372         /* MB640_GetRFLevel
373            FIXME (sort of...)
374            For now, GetRFLevel and GetBatteryLevel both rely
375            on data returned by the "keepalive" packets.  I suspect
376            that we don't actually need the keepalive at all but
377            will await the official doco before taking it out.  HAB19990511 */
378 GSM_Error       MB640_GetRFLevel(GSM_RFUnits *units, float *level)
379 {u8  pkt[] = 
380      /*{0x0f, 0x5A, 3, 0, 7, 0x39, 0x7f, 0xf0, 0, 0, 0, 0}*/
381      {0x19, 2, 1, 7}
382      /*{0,3,0}*/;
383  int timeout;
384
385   MB640_PacketOK = false;
386   MB640_ACKOK    = false;
387   timeout        = 3;
388   while(!MB640_PacketOK)
389   {
390     if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
391     if(!--timeout || RequestTerminate)
392     {
393       return(GE_TIMEOUT);
394     }
395     usleep(100000);
396   }
397   *level = 0/*(float)(PacketData[6] * 256 + PacketData[7]) / 256.0*/;
398         return (GE_NONE);
399 }
400
401         /* MB640_GetBatteryLevel - get value from ADC #0
402            FIXME (see above...) */
403 GSM_Error       MB640_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
404 {u8  pkt[] = {0x19, 2, 1, 0};
405  int timeout;
406
407   if (*units == GBU_Arbitrary)
408   {
409     MB640_PacketOK = false;
410     MB640_ACKOK    = false;
411     timeout        = 3;
412     while(!MB640_PacketOK)
413     {
414       if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
415       if(!--timeout || RequestTerminate)
416       {
417         return(GE_TIMEOUT);
418       }
419       usleep(100000);
420     }
421     *level = (float)(PacketData[6] * 256 + PacketData[7]) / 256.0;
422     return (GE_NONE);
423   }
424   return (GE_INTERNALERROR);
425 }
426
427 /* Really there are no IMEI in NMT phones. Equivalent IMHO is phone
428  * Serial Number */
429 GSM_Error       MB640_GetIMEI(char *imei)
430 {u8  pkt[] = {0x0f, 0x19, 3, 0, 0x01, 0x0b, 0, 0};
431  int timeout;
432
433   MB640_PacketOK = false;
434   MB640_ACKOK    = false;
435   timeout        = 3;
436   while(!MB640_PacketOK)
437   {
438     if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
439     if(!--timeout || RequestTerminate)
440     {
441       return(GE_TIMEOUT);
442     }
443     usleep(100000);
444   }
445
446   memcpy(imei,&PacketData[14],PacketData[13]);
447   imei[PacketData[13]] = 0;
448         return (GE_NONE);
449 }
450
451 GSM_Error MB640_GetVersionInfo()
452 {u8   pkt[] = {0, 3, 0};
453  int  timeout;
454  char *s = MB640_VersionInfo;
455
456   MB640_PacketOK = false;
457   MB640_ACKOK    = false;
458   timeout        = 3;
459   while(!MB640_PacketOK)
460   {
461     if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
462     if(!--timeout || RequestTerminate)
463     {
464       return(GE_TIMEOUT);
465     }
466     usleep(100000);
467   }
468
469   strncpy( s, &PacketData[6], sizeof(MB640_VersionInfo) );
470
471   for( MB640_Revision     = s; *s != 0x0A; s++ ) if( !*s ) goto out;
472   *s++ = 0;
473   for( MB640_RevisionDate = s; *s != 0x0A; s++ ) if( !*s ) goto out;
474   *s++ = 0;
475   for( MB640_Model        = s; *s != 0x0A; s++ ) if( !*s ) goto out;
476   *s++ = 0;
477 out:
478         return (GE_NONE);
479 }
480
481 GSM_Error       MB640_GetRevision(char *revision)
482 {GSM_Error err = GE_NONE;
483
484   if(!MB640_Revision) err = MB640_GetVersionInfo();
485   if(err == GE_NONE) strncpy(revision, MB640_Revision, 64);
486
487         return err;
488 }
489
490 GSM_Error       MB640_GetModel(char *model)
491 {GSM_Error err = GE_NONE;
492
493   if(!MB640_Model) err = MB640_GetVersionInfo();
494   if(err == GE_NONE) strncpy(model, MB640_Model, 64);
495
496         return err;
497 }
498
499 GSM_Error       MB640_GetMemoryStatus(GSM_MemoryStatus *Status)
500 {
501   switch(Status->MemoryType)
502   {
503     case GMT_ME:
504       Status->Used = 0;
505       Status->Free = 100;
506     break;
507     case GMT_LD:
508       Status->Used = 5;
509       Status->Free = 0;
510     break;
511     case GMT_ON:
512       Status->Used = 1;
513       Status->Free = 0;
514     break;
515     case GMT_SM:
516       Status->Used = 0;
517       Status->Free = 0;
518     break;
519     default: return (GE_NOTIMPLEMENTED);
520   }
521         return (GE_NONE);
522 }
523
524 GSM_Error       MB640_GetBitmap(GSM_Bitmap *Bitmap)
525 {int timeout;
526
527   switch(Bitmap->type)
528   {
529     case GSM_StartupLogo:
530     {u8  pkt[] = {0x0f, 0x60, 3, 0, 7, 0x3A, 0x7f, 0xf0, 0, 0, 0, 0};
531      int i;
532
533       for(i = 0; i < 6; i++)
534       {
535         pkt[9] = i;
536         MB640_PacketOK = false;
537         MB640_ACKOK    = false;
538         timeout        = 10;
539         while(!MB640_PacketOK)
540         {
541           if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
542           if(!--timeout || RequestTerminate)
543           {
544             return(GE_TIMEOUT);
545           }
546           usleep(100000);
547         }
548         memcpy(&Bitmap->bitmap[i * 84],&PacketData[18],84);
549       }
550       Bitmap->width  = 84;
551       Bitmap->height = 48;
552       Bitmap->size   = 84*48/8;
553     }
554     break;
555     default: return (GE_NOTIMPLEMENTED);
556   }
557         return (GE_NONE);
558 }
559
560 GSM_Error       MB640_SetBitmap(GSM_Bitmap *Bitmap)
561 {int timeout,i;
562
563   switch(Bitmap->type)
564   {
565     case GSM_StartupLogo:
566       {u8 pkt[98];
567
568         pkt[0]  = 0x10;
569         pkt[1]  = 0x08;
570         pkt[2]  = 0x03;
571         pkt[3]  = 0x00;
572         pkt[4]  = 0x07;
573         pkt[5]  = 0x3A;
574         pkt[6]  = 0x7F;
575         pkt[7]  = 0xF0;
576         pkt[8]  = 0x00;
577         pkt[10] = 0x00;
578         pkt[11] = 0x00;
579         pkt[12] = 0x00;
580         pkt[13] = 0x54;
581
582         for(i = 0; i < 6; i++)
583         {
584           pkt[9]  = i;
585           memcpy(&pkt[14],&Bitmap->bitmap[i * 84],84);
586
587           MB640_PacketOK = false;
588           MB640_ACKOK    = false;
589           timeout        = 10;
590           while(!MB640_PacketOK)
591           {
592             if(!MB640_ACKOK) MB640_SendPacket(pkt, sizeof(pkt));
593             if(!--timeout || RequestTerminate)
594             {
595               return(GE_TIMEOUT);
596             }
597             usleep(100000);
598           }
599         }
600       }
601     break;
602     default: return (GE_NOTIMPLEMENTED);
603   }
604   return (GE_NONE);
605 }
606
607 GSM_Error       MB640_Reset(unsigned char type)
608 {u8        pkt[] = { 0x43, 0x00, 0x00 };
609  int       timeout;
610
611   /* send packet */
612   MB640_PacketOK = false;
613   MB640_ACKOK    = false;
614   timeout        = 3;
615   while(!MB640_PacketOK)
616   {
617     if(!MB640_ACKOK) MB640_SendPacket(pkt, 4);
618     if(!--timeout) return (GE_TIMEOUT);
619     usleep(250000);
620   }
621   return (GE_NONE);
622 }
623
624 bool            MB640_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
625 {
626     return (false);
627 }
628
629         /* Everything from here down is internal to 640 code. */
630
631 /* Checksum calculation */
632 u8 MB640_GetChecksum( u8 * packet )
633 {u8           checksum = 0;
634  unsigned int i,len = packet[2];
635
636   if( packet[2] == 0x7F ) len = 4;   /* ACK packet length                 */
637   else                    len += 5;  /* Add sizes of header, command and  *
638                                       * packet_number to packet length    */
639   for( i = 0; i < len; i++ ) checksum ^= packet[i]; /* calculate checksum */
640   return checksum;
641 }
642
643 /* Handler called when characters received from serial port. 
644  * and process them. */
645 void MB640_SigHandler(int status)
646 {unsigned char        buffer[256],ack[5],b;
647  int                  i,res;
648  static unsigned int  Index = 0,
649                       Length = 5;
650  static unsigned char pkt[256];
651 #ifdef DEBUG
652  int                  j;
653 #endif
654
655   res = read(PortFD, buffer, 256);
656   if( res < 0 ) return;
657   for(i = 0; i < res ; i++)
658   {
659     b = buffer[i];
660     if(!Index && b != 0x00 && b != 0xE9)
661     {
662       /* something strange goes from phone. Just ignore it */
663 #ifdef DEBUG
664       fprintf( stdout, "Get [%02X %c]\n", b, b >= 0x20 ? b : '.' );
665 #endif /* DEBUG */
666       continue;
667     }
668     else
669     {
670       pkt[Index++] = b;
671       if(Index == 3) Length = (b == 0x7F) ? 5 : b + 6;
672       if(Index >= Length)
673       {
674         if(pkt[0] == 0xE9 && pkt[1] == 0x00) /* packet from phone */
675         {
676 #ifdef DEBUG
677           fprintf( stdout, _("Phone: ") );
678           for( j = 0; j < Length; j++ )
679           {
680             b = pkt[j];
681             fprintf( stdout, "[%02X %c]", b, b >= 0x20 ? b : '.' );
682           }
683           fprintf( stdout, "\n" );
684 #endif /* DEBUG */
685            /* ensure that we received valid packet */
686           if(pkt[Length - 1] == MB640_GetChecksum(pkt))
687           {
688             if(pkt[2] == 0x7F) /* acknowledge by phone */
689             {
690               /* Set ACKOK flag */
691               MB640_ACKOK    = true;
692               /* Increase TX packet number */
693               MB640_TXPacketNumber++;
694             }
695             else
696             {
697               /* Copy packet data  */
698               memcpy(PacketData,pkt,Length);
699               /* send acknowledge packet to phone */
700               usleep(1000);
701               ack[0] = 0x00;                     /* Construct the header.   */
702               ack[1] = pkt[0];                   /* Send back id            */
703               ack[2] = 0x7F;                     /* Set special size value  */
704               ack[3] = pkt[Length - 2];          /* Send back packet number */
705               ack[4] = MB640_GetChecksum( ack ); /* Set checksum            */
706 #ifdef DEBUG
707               fprintf( stdout, _("PC   : ") );
708               for( j = 0; j < 5; j++ )
709               {
710                 b = ack[j];
711                 fprintf( stdout, "[%02X %c]", b, b >= 0x20 ? b : '.' );
712               }
713               fprintf( stdout, "\n" );
714 #endif /* DEBUG */
715               if( write( PortFD, ack, 5 ) != 5 )
716               {
717                 perror( _("Write error!\n") );
718               }
719               /* Set validity flag */
720               MB640_PacketOK = true;
721             }
722           }
723         }
724         else
725         {
726           MB640_EchoOK = true;
727         }
728         /* Look for new packet */
729         Index  = 0;
730         Length = 5;
731       }
732     }
733   }
734 }
735
736 /* Called by initialisation code to open comm port in asynchronous mode. */
737 bool MB640_OpenSerial(void)
738 {
739   struct termios    new_termios;
740   struct sigaction  sig_io;
741   unsigned int      flags;
742
743 #ifdef DEBUG
744   fprintf(stdout, _("Setting MBUS communication...\n"));
745 #endif /* DEBUG */
746  
747   PortFD = open(PortDevice, O_RDWR | O_NOCTTY | O_NONBLOCK);
748   if ( PortFD < 0 )
749   { 
750     fprintf(stderr, "Failed to open %s ...\n", PortDevice);
751     return (false);
752   }
753
754 #ifdef DEBUG
755   fprintf(stdout, "%s opened...\n", PortDevice);
756 #endif /* DEBUG */
757
758   sig_io.sa_handler = MB640_SigHandler;
759   sig_io.sa_flags = 0;
760   sigaction (SIGIO, &sig_io, NULL);
761   /* Allow process/thread to receive SIGIO */
762   fcntl(PortFD, F_SETOWN, getpid());
763   /* Make filedescriptor asynchronous. */
764   fcntl(PortFD, F_SETFL, FASYNC);
765   /* Save old termios */
766   tcgetattr(PortFD, &old_termios);
767   /* set speed , 8bit, odd parity */
768   memset( &new_termios, 0, sizeof(new_termios) );
769   new_termios.c_cflag = B9600 | CS8 | CLOCAL | CREAD | PARODD | PARENB; 
770   new_termios.c_iflag = 0;
771   new_termios.c_lflag = 0;
772   new_termios.c_oflag = 0;
773   new_termios.c_cc[VMIN] = 1;
774   new_termios.c_cc[VTIME] = 0;
775   tcflush(PortFD, TCIFLUSH);
776   tcsetattr(PortFD, TCSANOW, &new_termios);
777   /* setting the RTS & DTR bit */
778   flags = TIOCM_DTR;
779   ioctl(PortFD, TIOCMBIC, &flags);
780   flags = TIOCM_RTS;
781   ioctl(PortFD, TIOCMBIS, &flags);
782 #ifdef DEBUG
783   ioctl(PortFD, TIOCMGET, &flags);
784   fprintf(stdout, _("DTR is %s.\n"), flags & TIOCM_DTR ? _("up") : _("down"));
785   fprintf(stdout, _("RTS is %s.\n"), flags & TIOCM_RTS ? _("up") : _("down"));
786   fprintf(stdout, "\n");
787 #endif /* DEBUG */
788   return (true);
789 }
790
791 GSM_Error MB640_SendPacket( u8 *buffer, u8 length )
792 {u8             pkt[256];
793  int            current = 0;
794
795   /* FIXME - we should check for the message length ... */
796   pkt[current++] = 0x00;                     /* Construct the header.      */
797   pkt[current++] = 0xE9;
798   pkt[current++] = length;                   /* Set data size              */
799   pkt[current++] = 0xE5;
800   memcpy( pkt + current, buffer, length );   /* Copy in data.              */
801   current += length;
802   pkt[current++] = MB640_TXPacketNumber;         /* Set packet number          */
803   pkt[current++] = MB640_GetChecksum( pkt ); /* Calculate and set checksum */
804 #ifdef DEBUG
805   {int i;
806    u8  b;
807     fprintf( stdout, _("PC   : ") );
808     for( i = 0; i < current; i++ )
809     {
810       b = pkt[i];
811       fprintf( stdout, "[%02X %c]", b, b > 0x20 ? b : '.' );
812     }
813     fprintf( stdout, "\n" );
814   }
815 #endif /* DEBUG */
816   /* Send it out... */
817   MB640_EchoOK = false;
818   if( write(PortFD, pkt, current) != current )
819   {
820     perror( _("Write error!\n") );
821     return (GE_INTERNALERROR);
822   }
823   /* wait for echo */
824   while( !MB640_EchoOK && current-- )
825   {
826     usleep(1000);
827   }
828   if( !MB640_EchoOK ) return (GE_TIMEOUT);
829   return (GE_NONE);
830 }
831
832
833         /* This is the main loop for the MB21 functions.  When MB21_Initialise
834            is called a thread is created to run this loop.  This loop is
835            exited when the application calls the MB21_Terminate function. */
836 void    MB640_ThreadLoop(void)
837 {
838         /* Do initialisation stuff */
839   if (MB640_OpenSerial() != true)
840   {
841     MB640_LinkOK = false;
842     while (!RequestTerminate)
843     {
844       usleep (100000);
845     }
846     return;
847   }
848   MB640_LinkOK = true;
849
850         while (!RequestTerminate) {
851                 usleep(100000);         /* Avoid becoming a "busy" loop. */
852         }
853 }
854
855
856 #endif