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