Implemented connection type "tcp" (GCT_TCP), use <hostname>:<port> as "port"
[gnokii.git] / common / mbus-6160.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 code contains the main part of the 5160/6160 code.
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.29  2001/08/20 23:27:37  pkot
20   Add hardware shakehand to the link layer (Manfred Jonsson)
21
22   Revision 1.28  2001/06/28 00:28:45  pkot
23   Small docs updates (Pawel Kot)
24         
25
26 */
27
28 #ifndef WIN32
29
30 #define         __mbus_6160_c   /* "Turn on" prototypes in mbus-6160.h */
31
32 #include        <termios.h>
33 #include        <stdio.h>
34 #include        <stdlib.h>
35 #include        <unistd.h>
36 #include        <fcntl.h>
37 #include        <ctype.h>
38 #include        <signal.h>
39 #include        <sys/types.h>
40 #include        <sys/time.h>
41 #include        <sys/ioctl.h>
42 #include        <string.h>
43 #include        <pthread.h>
44 #include        <errno.h>
45
46 #include        "misc.h"
47 #include        "gsm-common.h"
48 #include        "mbus-6160.h"
49 #include        "device.h"
50 #include        "phones/nokia.h"
51
52 #define WRITEPHONE(a, b, c) device_write(b, c)
53
54 //#define       DEBUG
55
56         /* Global variables used by code in gsm-api.c to expose the
57            functions supported by this model of phone.  */
58 bool                                    MB61_LinkOK;
59
60 GSM_Functions                   MB61_Functions = {
61                 MB61_Initialise,
62                 MB61_Terminate,
63                 MB61_GetMemoryLocation,
64                 MB61_WritePhonebookLocation,
65                 UNIMPLEMENTED,
66                 UNIMPLEMENTED,
67                 UNIMPLEMENTED,
68                 UNIMPLEMENTED,
69                 UNIMPLEMENTED,
70                 UNIMPLEMENTED,
71                 UNIMPLEMENTED,
72                 UNIMPLEMENTED,
73                 UNIMPLEMENTED,
74                 UNIMPLEMENTED,
75                 UNIMPLEMENTED,
76                 UNIMPLEMENTED,
77                 UNIMPLEMENTED,
78                 UNIMPLEMENTED,
79                 UNIMPLEMENTED,
80                 UNIMPLEMENTED,
81                 UNIMPLEMENTED,
82                 UNIMPLEMENTED,
83                 UNIMPLEMENTED,
84                 PNOK_GetManufacturer,
85                 UNIMPLEMENTED,
86                 UNIMPLEMENTED,
87                 UNIMPLEMENTED,
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                 UNIMPLEMENTED,
102                 UNIMPLEMENTED,
103                 UNIMPLEMENTED,
104                 MB61_SendRLPFrame,
105                 UNIMPLEMENTED,
106                 UNIMPLEMENTED,
107                 UNIMPLEMENTED,
108                 UNIMPLEMENTED,
109                 UNIMPLEMENTED,
110                 UNIMPLEMENTED,
111                 UNIMPLEMENTED,
112                 UNIMPLEMENTED,
113                 UNIMPLEMENTED
114 };
115
116         /* FIXME - these are guesses only... */
117 GSM_Information                 MB61_Information = {
118                 "5160|6160|6185",               /* Models */
119                 4,                                              /* Max RF Level */
120                 0,                                              /* Min RF Level */
121                 GRF_Arbitrary,                  /* RF level units */
122                 4,                                              /* Max Battery Level */
123                 0,                                              /* Min Battery Level */
124                 GBU_Arbitrary,                  /* Battery level units */
125                 GDT_None,                               /* No date/time support */
126                 GDT_None,                               /* No alarm support */
127                 0,                                              /* Max alarms = 0 */
128                 0, 0,                   /* Startup logo size */
129                 0, 0,                   /* Op logo size */
130                 0, 0                    /* Caller logo size */
131 };
132
133         /* Local variables */
134 pthread_t                               Thread;
135 bool                                    RequestTerminate;
136 bool                                    MB61_LinkOK;
137 char                    PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
138 u8                                              RequestSequenceNumber; /* 2-63 */
139 int                                             PortFD;
140 bool                                    GotInitResponse;
141 bool                                    GotIDResponse;
142
143 enum MB61_RX_States     RX_State;
144 enum MB61_Models                ModelIdentified;
145 enum MB61_Responses             ExpectedResponse;
146 enum MB61_Responses             LatestResponse;
147
148 GSM_PhonebookEntry              *CurrentPhonebookEntry;
149 GSM_Error                               CurrentPhonebookError;
150
151 int                     MessageLength;
152 u8                      MessageDestination;
153 u8                      MessageSource;
154 u8                      MessageCommand;
155 u8                      MessageBuffer[MB61_MAX_RECEIVE_LENGTH];
156 u8                                              MessageCSum;
157 u8                                              MessageSequenceNumber;
158 int                     BufferCount;
159 u8                      CalculatedCSum;
160 int                                             ChecksumFails;
161
162
163         /* The following functions are made visible to gsm-api.c and friends. */
164
165         /* Initialise variables and state machine. */
166 GSM_Error   MB61_Initialise(char *port_device, char *initlength,
167                             GSM_ConnectionType connection,
168                             void (*rlp_callback)(RLP_F96Frame *frame))
169 {
170
171         int             rtn;
172
173         RequestTerminate = false;
174         MB61_LinkOK = false;
175         ModelIdentified = MB61_ModelUnknown;
176         ExpectedResponse = MB61_Response_Unknown;
177         CurrentPhonebookEntry = NULL;
178         CurrentPhonebookError = GE_NONE;
179
180
181     strncpy (PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
182
183                 /* Create and start thread, */
184         rtn = pthread_create(&Thread, NULL, (void *) MB61_ThreadLoop, (void *)NULL);
185
186     if (rtn == EAGAIN || rtn == EINVAL) {
187         return (GE_INTERNALERROR);
188     }
189
190         return (GE_NONE);
191
192 }
193
194         /* Applications should call MB61_Terminate to shut down
195            the MB61 thread and close the serial port. */
196 void            MB61_Terminate(void)
197 {
198                 /* Request termination of thread */
199         RequestTerminate = true;
200
201                 /* Now wait for thread to terminate. */
202         pthread_join(Thread, NULL);
203
204                 /* Close serial port. */
205         
206 }
207
208         /* Routine to get specifed phone book location.  Designed to 
209            be called by application.  Will block until location is
210            retrieved or a timeout/error occurs. */
211 GSM_Error       MB61_GetMemoryLocation(GSM_PhonebookEntry *entry)
212 {
213     int     timeout;
214
215     if (entry->MemoryType != GMT_ME) {
216         return (GE_INVALIDMEMORYTYPE);
217     }
218
219     timeout = 20;   /* 2 seconds for command to complete */
220
221         /* Return if no link has been established. */
222     if (!MB61_LinkOK) {
223         return GE_NOLINK;
224     }
225
226         /* Process depending on model identified */
227         switch (ModelIdentified) {
228
229                 case MB61_Model5160:
230                         if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
231                                 return (GE_INVALIDPHBOOKLOCATION);
232                         }
233                         CurrentPhonebookEntry = entry;
234                         CurrentPhonebookError = GE_BUSY;
235                         MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
236                         MB61_TX_SendPhonebookReadRequest(entry->Location);
237                         break;
238
239                 case MB61_Model6160:
240                         if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
241                                 return (GE_INVALIDPHBOOKLOCATION);
242                         }
243                         CurrentPhonebookEntry = entry;
244                         CurrentPhonebookError = GE_BUSY;
245                         MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
246                         MB61_TX_SendPhonebookReadRequest(entry->Location);
247                         break;
248
249                 case MB61_Model6185:
250                         if (entry->Location >= MAX_6185_PHONEBOOK_ENTRIES) {
251                                 return (GE_INVALIDPHBOOKLOCATION);
252                         }
253                         CurrentPhonebookEntry = entry;
254                         CurrentPhonebookError = GE_BUSY;
255                         MB61_SetExpectedResponse(MB61_Response_0x40_LongPhonebookRead);
256                         MB61_TX_SendLongPhonebookReadRequest(entry->Location);
257                         break;
258
259                 default:
260                         return(GE_NOTIMPLEMENTED);
261         }
262
263                 /* When response is received, data is copied into entry
264            by handler code or if error has occured, CurrentPhonebookEntry
265            is set accordingly. */
266         if (MB61_WaitForExpectedResponse(2000) != true) {
267                 return (GE_INTERNALERROR);
268         }
269         return (CurrentPhonebookError);
270
271 }
272
273         /* Routine to write phonebook location in phone. Designed to 
274            be called by application code.  Will block until location
275            is written or timeout occurs.  */
276 GSM_Error       MB61_WritePhonebookLocation(GSM_PhonebookEntry *entry)
277 {
278
279     if (entry->MemoryType != GMT_ME) {
280         return (GE_INVALIDMEMORYTYPE);
281     }
282
283         /* Return if no link has been established. */
284     if (!MB61_LinkOK) {
285         return GE_NOLINK;
286     }
287
288         /* Process depending on model identified */
289         switch (ModelIdentified) {
290
291                 case MB61_Model5160:
292                         if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
293                                 return (GE_INVALIDPHBOOKLOCATION);
294                         }
295                         if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NAME_LENGTH) {
296                                 return (GE_PHBOOKNAMETOOLONG);
297                         }
298                         if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NUMBER_LENGTH) {
299                                 return (GE_PHBOOKNAMETOOLONG);
300                         }
301                         CurrentPhonebookError = GE_BUSY;
302                         MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
303                         MB61_TX_SendPhonebookWriteRequest(entry);
304                         break;
305
306                 case MB61_Model6160:
307                         if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
308                                 return (GE_INVALIDPHBOOKLOCATION);
309                         }
310                         if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NAME_LENGTH) {
311                                 return (GE_PHBOOKNAMETOOLONG);
312                         }
313                         if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NUMBER_LENGTH) {
314                                 return (GE_PHBOOKNAMETOOLONG);
315                         }
316                         CurrentPhonebookError = GE_BUSY;
317                         MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
318                         MB61_TX_SendPhonebookWriteRequest(entry);
319                         break;
320
321                 case MB61_Model6185:
322                         return (GE_NOTIMPLEMENTED);
323                         break;
324
325                 default:
326                         return(GE_NOTIMPLEMENTED);
327         }
328
329                 /* When response is received, data is copied into entry
330            by handler code or if error has occured, CurrentPhonebookEntry
331            is set accordingly. */
332         if (MB61_WaitForExpectedResponse(2000) != true) {
333                 return (GE_INTERNALERROR);
334         }
335         return (CurrentPhonebookError);
336
337 }
338
339 bool            MB61_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
340 {
341     return (false);
342 }
343
344         /* Everything from here down is internal to 6160 code. */
345
346
347         /* This is the main loop for the MB61 functions.  When MB61_Initialise
348            is called a thread is created to run this loop.  This loop is
349            exited when the application calls the MB61_Terminate function. */
350 void    MB61_ThreadLoop(void)
351 {
352     int                 idle_timer;
353
354         /* Initialise RX state machine. */
355     BufferCount = 0;
356     RX_State = MB61_RX_Sync;
357     idle_timer = 0;
358
359         /* Try to open serial port, if we fail we sit here and don't proceed
360            to the main loop. */
361     if (MB61_OpenSerial() != true) {
362         MB61_LinkOK = false;
363         
364         while (!RequestTerminate) {
365             usleep (100000);
366         }
367         return;
368     }
369
370                 /* Do initialisation sequence, sit here if it fails. */
371         if (MB61_InitialiseLink() != true) {
372          MB61_LinkOK = false;
373         
374         while (!RequestTerminate) {
375             usleep (100000);
376         }
377         return;
378     }
379
380                 /* Link is up OK so sit here twiddling our thumbs until
381            told to terminate. */
382     while (!RequestTerminate) {
383         if (idle_timer == 0) {
384             idle_timer = 20;
385         }
386         else {
387             idle_timer --;
388                         /*fprintf(stdout, ".");
389                         fflush(stdout);*/
390         }
391
392         usleep(100000);     /* Avoid becoming a "busy" loop. */
393     }
394
395                 /* Drop DTR and RTS lines before exiting */
396     device_setdtrrts(0, 0);
397 }
398
399
400 bool    MB61_InitialiseLink(void)
401 {
402     unsigned char       init_char[1] = {0x04};
403
404     fprintf(stdout, "Sending init...\n");
405
406                 /* Need to "toggle" the dtr/rts lines in the right
407            sequence it seems for the interface to work. 
408                    Base time value is units of 50ms it seems */
409
410 #define BASE_TIME               (50000)
411
412                 /* Default state */
413     device_setdtrrts(0, 1);
414         sleep(1);
415
416                 /* RTS low for 250ms */
417     device_setdtrrts(0, 0);
418         usleep(5 * BASE_TIME);
419
420                 /* RTS high, DTR high for 50ms */
421     device_setdtrrts(1, 1);
422         usleep(BASE_TIME);
423
424                 /* RTS low, DTR high for 50ms */
425     device_setdtrrts(1, 0);
426         usleep(BASE_TIME);
427
428                 /* RTS high, DTR high for 50ms */
429     device_setdtrrts(1, 1);
430         usleep(BASE_TIME);
431
432                 /* RTS low, DTR high for 50ms */
433     device_setdtrrts(1, 0);
434         usleep(BASE_TIME);
435
436                 /* RTS low, DTR low for 50ms */
437     device_setdtrrts(0, 0);
438         usleep(BASE_TIME);
439
440                 /* RTS low, DTR high for 50ms */
441     device_setdtrrts(1, 0);
442         usleep(BASE_TIME);
443
444                 /* RTS high, DTR high for 50ms */
445     device_setdtrrts(1, 1);
446         usleep(BASE_TIME);
447
448                 /* RTS low, DTR low for 50ms */
449     device_setdtrrts(0, 0);
450         usleep(BASE_TIME);
451
452                 /* leave RTS high, DTR low for duration of session. */
453         usleep(BASE_TIME);
454     device_setdtrrts(0, 1);
455
456         sleep(1);
457
458
459         /* Initialise sequence number used when sending messages
460            to phone. */
461
462         /* Send Initialisation message to phone. */
463         MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
464
465     RequestSequenceNumber = 0x02;
466         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
467
468         /* We've now finished initialising things so sit in the loop
469            until told to do otherwise.  Loop doesn't do much other
470            than send periodic keepalive messages to phone.  This
471            loop will become more involved once we start doing 
472            fax/data calls. */
473
474         fprintf(stdout, "Waiting for first response...\n");
475         fflush(stdout);
476
477         if(MB61_WaitForExpectedResponse(100) == false) {
478                 return false;
479         }
480
481         MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
482
483     RequestSequenceNumber ++;
484         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
485
486
487         fprintf(stdout, "Waiting for second response...\n");
488         fflush(stdout);
489         if(MB61_WaitForExpectedResponse(100) == false) {
490                 return false;
491         }
492
493
494         MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
495         MB61_TX_SendPhoneIDRequest();
496         if(MB61_WaitForExpectedResponse(300) == false) {
497                 return false;
498         }
499
500         MB61_LinkOK = true;
501         return (true);
502
503 }
504
505         /* MB61_SetExpectedResponse
506            Used in combination with MB61_WaitForExpectedResponse, these
507        functions allow the MB61 code to specify what message it is expecting
508        a response to.  This becomes important as it appears that there is
509        no standard or unique character to identify incoming messages from
510        the phone.  A good example is the ID and Version responses which differ
511        only in their length and one of the bytes in the data portion of the
512        message.  It may be that once we understand more of the MBUS protocol
513        we can confirm that messages are unique... */
514
515 void    MB61_SetExpectedResponse(enum MB61_Responses response)
516 {
517         LatestResponse = MB61_Response_Unknown;
518         ExpectedResponse = response;
519 }
520
521         /* MB61_WaitForExpectedResponse
522        Allows code to wait a specified number of msecs
523        for the requested response before timing out.  Returns
524        true if expected response has been recieved, false in
525        case of timeout */
526 bool    MB61_WaitForExpectedResponse(int timeout)
527 {
528         int             count;
529
530         count = timeout;
531         while ((count > 0) && (LatestResponse != ExpectedResponse)) {
532                 count --;
533                 usleep(1000);
534         }
535
536         if (LatestResponse == ExpectedResponse) {
537                 return (true);
538         }
539
540         return (false);
541 }
542       
543
544     /* MB61_RX_DispatchMessage
545        Once we've received a message from the phone, the command/message
546        type byte is used to call an appropriate handler routine or
547        simply acknowledge the message as required. */
548 enum    MB61_RX_States MB61_RX_DispatchMessage(void)
549 {
550
551                                 /* If the message is from ADDR_PC ignore and don't process further. */
552                         if (MessageSource == MSG_ADDR_PC) {
553                         return MB61_RX_Sync;
554                         }
555                         /* Leave this uncommented if you want all messages in raw form. */
556                         //MB61_RX_DisplayMessage(); 
557
558                                 /* Switch on the basis of the message type byte */
559                         switch (MessageCommand) {
560
561                                 case 0x40:
562                                         if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
563                                                 fprintf(stderr, _("Standard Ack write (0x40) failed!"));
564                                         }
565
566                                         if (ExpectedResponse == MB61_Response_0x40_PhonebookRead) {
567                                                 MB61_RX_Handle0x40_PhonebookRead();
568                                                 LatestResponse = MB61_Response_0x40_PhonebookRead;
569                                                 break;
570                                         }
571
572                                         if (ExpectedResponse == MB61_Response_0x40_WriteAcknowledge) {
573                                                 LatestResponse = MB61_Response_0x40_WriteAcknowledge;
574                                                 CurrentPhonebookError = GE_NONE;
575                                                 break;
576                                         }
577                                         break;
578
579                                         /* 0xd0 messages are the response to
580                                            initialisation requests. */
581                                 case 0xd0:
582                                         if (ExpectedResponse == MB61_Response_0xD0_Init) {
583                                                 LatestResponse = MB61_Response_0xD0_Init;
584                                         }
585                                         break;
586
587                                 case 0xd2:
588                                         if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
589                                                 fprintf(stderr, _("Standard Ack write (0xd2) failed!"));
590                                         }
591                                         if (ExpectedResponse == MB61_Response_0xD2_ID) {
592                                                 MB61_RX_Handle0xD2_ID();
593                                         LatestResponse = MB61_Response_0xD2_ID;
594                                         }
595                                         if (ExpectedResponse == MB61_Response_0xD2_Version) {
596                                                 MB61_RX_Handle0xD2_Version();
597                                                 LatestResponse = MB61_Response_0xD2_Version;
598                                         }
599                                         break;
600
601
602                                         /* Incoming 0x7f's are acks for commands we've sent. */
603                                 case 0x7f:  break;
604
605                                         /* Here we attempt to acknowledge and display messages
606                                            we don't understand fully... The phone will send
607                                            the same message several (3-4) times before giving
608                                            up if no ack is received.  */
609                                 default:        MB61_RX_DisplayMessage(); 
610                                         if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
611                                                 fprintf(stderr, _("Standard Ack write failed!"));
612                                         }
613                                         fprintf(stdout, "Sent standard Ack for unknown %02x\n", MessageCommand);
614                         break;
615     }
616
617     return MB61_RX_Sync;
618 }
619
620         /* "Short" phonebook reads have 8 bytes of data (unknown/unstudied)
621        then a null terminated string for the number and then a null
622        terminated string which is the name. */
623 void    MB61_RX_Handle0x40_PhonebookRead(void)
624 {
625         int             i, j;
626         bool    got_null;
627
628         if (CurrentPhonebookEntry == NULL) {
629                 CurrentPhonebookError = GE_INTERNALERROR;
630                 return;
631         }
632
633                 /* First do number */
634         i = 8;
635         got_null = false;
636         j = 0;
637
638         while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NUMBER_LENGTH)) {
639                 CurrentPhonebookEntry->Number[j] = MessageBuffer[i];
640                 i++;
641                 j++;
642                 if (MessageBuffer[i] == 0) {
643                         got_null = true;
644                 }
645         }
646         CurrentPhonebookEntry->Number[j] = 0;
647
648                 /* Now name */
649         got_null = false;
650         j = 0;
651         i ++;
652
653         while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NAME_LENGTH)) {
654                 CurrentPhonebookEntry->Name[j] = MessageBuffer[i];
655                 i++;
656                 j++;
657                 if (MessageBuffer[i] == 0) {
658                         got_null = true;
659                 }
660         }
661         CurrentPhonebookEntry->Name[j] = 0;
662         
663         if ((strlen(CurrentPhonebookEntry->Number) != 0) ||
664             (strlen(CurrentPhonebookEntry->Name) != 0)) {
665                 CurrentPhonebookEntry->Empty = false;
666         }
667         else {
668                 CurrentPhonebookEntry->Empty = true;
669         }
670         CurrentPhonebookEntry->Group = GSM_GROUPS_NOT_SUPPORTED;        
671
672                 /* Done */
673         CurrentPhonebookError = GE_NONE;
674
675 }
676
677 void    MB61_RX_Handle0x40_LongPhonebookRead(void)
678 {
679
680
681 }
682
683
684
685         /* When we get an ID response back, we use it to set
686        model information for later and if in debug mode print it out. */
687 void    MB61_RX_Handle0xD2_ID(void) 
688 {
689 #ifdef DEBUG
690         int             i;
691 #endif
692
693         if (strstr(MessageBuffer + 4, "NSW-1") != NULL) {
694                 ModelIdentified = MB61_Model5160;
695 #ifdef DEBUG
696                 fprintf(stdout, "Identified as 5160\n");
697 #endif
698         }
699         else {
700                 if (strstr(MessageBuffer + 4, "NSW-3") != NULL) {
701                         ModelIdentified = MB61_Model6160;
702 #ifdef DEBUG
703                         fprintf(stdout, "Identified as 6160\n");
704 #endif
705                 }
706                 else {
707                         if (strstr(MessageBuffer + 4, "NSD-3") != NULL) {
708                                 ModelIdentified = MB61_Model6185;
709 #ifdef DEBUG
710                                 fprintf(stdout, "Identified as 6185\n");
711 #endif
712                         }
713                         else {
714 #ifdef DEBUG
715                                 fprintf(stdout, "Unknown model - please report dump below to hugh@linuxcare.com\n");
716 #endif
717                         }
718                 }
719         }
720 #ifdef DEBUG
721         for (i = 4; i < MessageLength; i++) {
722                 if (isprint(MessageBuffer[i])) {
723                         fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
724                 }
725                 else {
726                         fprintf(stdout, "[%02x ]", MessageBuffer[i]);
727                 }
728                 if (((i - 3) % 16) == 0) {
729                         fprintf(stdout, "\n");
730                 }
731         }       
732 #endif
733
734         
735 #ifdef DEBUG
736         fflush(stdout);
737 #endif
738
739 }
740 void    MB61_RX_Handle0xD2_Version(void) 
741 {
742
743
744 }
745
746
747 void    MB61_RX_DisplayMessage(void)
748 {
749         int             i;
750
751         fprintf(stdout, "Dest:%02x Src:%02x Cmd:%02x Len:%d Seq:%02x Csum:%02x\n", 
752                         MessageDestination, MessageSource, MessageCommand, MessageLength,
753                         MessageSequenceNumber, MessageCSum);
754
755         if (MessageLength == 0) {
756                 return;
757         }
758         else {
759                 fprintf(stdout, "Data: ");
760         }
761         for (i = 0; i < MessageLength; i++) {
762                 if (isprint(MessageBuffer[i])) {
763                         fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
764                 }
765                 else {
766                         fprintf(stdout, "[%02x ]", MessageBuffer[i]);
767                 }
768                 if (((i + 1) % 8) == 0) {
769                         fprintf(stdout, "\n      ");
770                 }
771         }
772         fprintf(stdout, "\n");
773
774 }
775
776         /* Higher level code does bounds checks for length of name/number
777        as well as entry number. */
778 GSM_Error       MB61_TX_SendPhonebookWriteRequest(GSM_PhonebookEntry *entry)
779 {
780                 /* 7 - header and null terminators, 17 - number length, 
781                    17 - name length. */
782         u8              message[7 + 17 + 17];
783         int             name_length;
784         int     number_length;
785         int             message_length;
786
787         name_length = strlen(entry->Name);
788         number_length = strlen(entry->Number);
789
790                 /* Header plus two terminating nulls plus name/number themselves */
791         message_length = 7 + name_length + 1 + number_length + 1;
792
793         message[0] = 0x00; /* Header bytes, purpose not investigated */
794         message[1] = 0x01; 
795         message[2] = 0x1f; 
796         message[3] = 0x01; 
797         message[4] = 0x04; 
798         message[5] = 0x87;      
799
800         message[6] = entry->Location; 
801
802         strncpy(message + 7, entry->Number, 16);
803
804         strncpy(message + 8 + number_length, entry->Name, 16);
805
806         MB61_UpdateSequenceNumber();
807         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, message_length, message);
808
809         return (GE_NONE);
810
811 }
812
813 bool            MB61_TX_SendPhonebookReadRequest(u8 entry)
814 {
815         u8              message[7] = {0x00, 0x01, 0x1f, 0x01, 0x04, 0x86, 0x01};
816
817         message[6] = entry;
818         
819         MB61_UpdateSequenceNumber();
820         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 7, message);
821
822         ExpectedResponse = MB61_Response_0x40_PhonebookRead;
823
824         return (true);
825 }
826
827         /* 6185 requires a different phone book request apparently */
828 bool            MB61_TX_SendLongPhonebookReadRequest(u8 entry)
829 {
830         u8              message[8] = {0x00, 0x00, 0x07, 0x11, 0x00, 0x10, 0x00, 0x00};
831
832         message[7] = entry;
833         
834         MB61_UpdateSequenceNumber();
835         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 8, message);
836
837         ExpectedResponse = MB61_Response_0x40_PhonebookRead;
838
839         return (true);
840 }
841
842
843 void            MB61_TX_SendPhoneIDRequest(void)
844 {
845         u8              message[5] = {0x00, 0x01, 0x00, 0x03, 0x00};
846         
847         MB61_UpdateSequenceNumber();
848         MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd1, RequestSequenceNumber, 5, message);
849
850         ExpectedResponse = MB61_Response_0xD2_ID;
851
852 }
853
854 void            MB61_UpdateSequenceNumber(void)
855 {
856         RequestSequenceNumber ++;
857         if (RequestSequenceNumber > 63) {
858                 RequestSequenceNumber = 2;
859         }
860 }
861
862         /* Not totally happy with this but it works for now. - HAB 20000602 */
863 bool            MB61_TX_SendStandardAcknowledge(u8 sequence_number)
864 {
865         u8              out_buffer[6];
866         u8              checksum;
867         int             count;
868
869         out_buffer[0] = 0x1f;
870         out_buffer[1] = MSG_ADDR_PHONE;
871         out_buffer[2] = MSG_ADDR_PC;
872         out_buffer[3] = 0x7f;
873         out_buffer[4] = sequence_number;
874
875         /* Now calculate checksum over entire message 
876            and append to message. */
877     checksum = 0;
878     for (count = 0; count < 5; count ++) {
879         checksum ^= out_buffer[count];
880     }
881     out_buffer[5] = checksum;
882
883         /* Send it out... */
884     if (WRITEPHONE(PortFD, out_buffer, 6) != 6) {
885         perror(_("TX_SendMessage - write:"));
886         return (false);
887     }
888
889 #ifdef  DEBUG
890         fprintf(stdout, "(Ack %02x) ", sequence_number);
891 #endif
892         
893     return (true);
894 }       
895             /* RX_State machine for receive handling.  Called once for each
896        character received from the phone/phone. */
897 void    MB61_RX_StateMachine(char rx_byte)
898 {
899
900 #ifdef  DEBUG
901         fprintf(stdout, "(%d)", RX_State);
902 #endif
903
904     switch (RX_State) {
905     
906                     /* Messages on the MBUS start with 0x1f.  We use
907                                            this to "synchronise" with the incoming data
908                        stream. */       
909         case MB61_RX_Sync:
910                 if (rx_byte == 0x1f) {
911
912                     BufferCount = 0;
913                     CalculatedCSum = rx_byte;
914                     RX_State = MB61_RX_GetDestination;
915                 }
916                 break;
917         
918                     /* Next byte is the destination of the message. */
919         case MB61_RX_GetDestination:
920                 MessageDestination = rx_byte;
921                 CalculatedCSum ^= rx_byte;
922                 RX_State = MB61_RX_GetSource;
923                 break;
924
925                     /* Next byte is the source of the message. */
926         case MB61_RX_GetSource:
927                 MessageSource = rx_byte;
928                 CalculatedCSum ^= rx_byte;
929
930                                         /* Sanity check these.  We make sure that the Source
931                        and destination are either PC/PHONE or PHONE/PC */
932                                 if (((MessageSource == MSG_ADDR_PC) && (MessageDestination == MSG_ADDR_PHONE)) ||
933                                    ((MessageSource == MSG_ADDR_PHONE) && (MessageDestination == MSG_ADDR_PC))) {
934                         RX_State = MB61_RX_GetCommand;
935                                 }
936                                 else {
937                                         RX_State = MB61_RX_Sync;
938                                 }
939                                 break;
940
941                     /* Next byte is the command type. */
942         case MB61_RX_GetCommand:
943                 MessageCommand = rx_byte;
944                 CalculatedCSum ^= rx_byte;
945                                         /* Command type 0x7f is an ack and is handled
946                                            differently in that it's length is known a priori */
947                                 if (MessageCommand != 0x7f) {
948                         RX_State = MB61_RX_GetLengthMSB;
949                         break;
950                                 }
951                                 else {
952                                         MessageLength = 0;
953                                         RX_State = MB61_RX_GetMessage;
954                                         break;
955                                 }
956
957                     /* Next is the most significant byte of message length. */
958         case MB61_RX_GetLengthMSB:
959                 MessageLength = rx_byte * 256;
960                 CalculatedCSum ^= rx_byte;
961                 RX_State = MB61_RX_GetLengthLSB;
962                 break;
963
964                     /* Next is the most significant byte of message length. */
965         case MB61_RX_GetLengthLSB:
966                 MessageLength += rx_byte;
967                 CalculatedCSum ^= rx_byte;
968                 RX_State = MB61_RX_GetMessage;
969                 break;
970
971                     /* Get each byte of the message.  We deliberately
972                        get one too many bytes so we get the sequence
973                        byte here as well. */
974         case MB61_RX_GetMessage:
975                 CalculatedCSum ^= rx_byte;
976                 MessageBuffer[BufferCount] = rx_byte;
977                 BufferCount ++;
978
979                 if (BufferCount >= MB61_MAX_RECEIVE_LENGTH) {
980                     RX_State = MB61_RX_Sync;        /* Should be PANIC */
981                 }
982                     /* If this is the last byte, it's the checksum */
983                 if (BufferCount > MessageLength) {
984                                         MessageSequenceNumber = rx_byte;
985                                         RX_State = MB61_RX_GetCSum;
986                                 }
987                                 break;
988
989                                         /* Get checksum and if valid hand over to 
990                                            dispatch message function */ 
991                 case MB61_RX_GetCSum:
992
993                 MessageCSum = rx_byte;
994
995                     /* Compare against calculated checksum. */
996                 if (MessageCSum == CalculatedCSum) {
997                     /* Got checksum, matches calculated one so 
998                        now pass to appropriate dispatch handler. */
999                     RX_State = MB61_RX_DispatchMessage();
1000                 }
1001                     /* Checksum didn't match so ignore. */
1002                 else {
1003                     ChecksumFails ++;
1004                     fprintf(stderr, _("CS Fail %02x != %02x"), MessageCSum, CalculatedCSum);
1005                     MB61_RX_DisplayMessage();
1006                     fflush(stderr);
1007                     RX_State = MB61_RX_Sync;
1008                 }
1009                     
1010                 CalculatedCSum ^= rx_byte;
1011                 break;
1012
1013         default:
1014     }
1015 }
1016
1017     /* Called by initialisation code to open comm port in
1018        asynchronous mode. */
1019 bool        MB61_OpenSerial(void)
1020 {
1021     int                     result;
1022     struct sigaction        sig_io;
1023
1024     /* Set up and install handler before enabling async IO on port. */
1025
1026     sig_io.sa_handler = MB61_SigHandler;
1027     sig_io.sa_flags = 0;
1028     sigaction (SIGIO, &sig_io, NULL);
1029
1030         /* Open device MBUS uses 9600,O,1  */
1031     result = device_open(PortDevice, true, true, false, GCT_Serial);
1032
1033     if (!result) {
1034         perror(_("Couldn't open MB61 device: "));
1035         return (false);
1036     }
1037         fprintf(stdout, "Opened MB61 device\n");
1038
1039     device_changespeed(9600);
1040     return (true);
1041 }
1042
1043     /* Handler called when characters received from serial port. 
1044        calls state machine code to process it. */
1045 void    MB61_SigHandler(int status)
1046 {
1047     unsigned char   buffer[255];
1048     int             count,res;
1049
1050     res = device_read(buffer, 255);
1051
1052     for (count = 0; count < res ; count ++) {
1053         MB61_RX_StateMachine(buffer[count]);
1054
1055 #ifdef          DEBUG
1056                 if (isprint(buffer[count])) {
1057                         fprintf(stdout, "<%02x%c>", buffer[count], buffer[count]);
1058                 }
1059                 else {
1060                         fprintf(stdout, "<%02x >", buffer[count]);
1061                 }
1062 #endif
1063
1064     }
1065         fflush(stdout);
1066 }
1067
1068
1069         /* Prepares the message header and sends it, prepends the
1070        message start byte (0x01) and other values according
1071        the value specified when called.  Calculates checksum
1072        and then sends the lot down the pipe... */
1073 int     MB61_TX_SendMessage(u8 destination, u8 source, u8 command, u8 sequence_byte, int message_length, u8 *buffer) 
1074 {
1075     u8                      out_buffer[MB61_MAX_TRANSMIT_LENGTH + 7];
1076     int                     count;
1077     unsigned char           checksum;
1078
1079         /* Check message isn't too long, once the necessary
1080            header and trailer bytes are included. */
1081     if ((message_length + 7) > MB61_MAX_TRANSMIT_LENGTH) {
1082         fprintf(stderr, _("TX_SendMessage - message too long!\n"));
1083
1084         return (false);
1085     }
1086
1087     //RX_State = MB61_RX_Sync;  Hack.
1088
1089         /* Now construct the message header. */
1090     out_buffer[0] = 0x1f;   /* Start of message indicator */
1091     out_buffer[1] = destination;
1092     out_buffer[2] = source;
1093     out_buffer[3] = command;
1094     out_buffer[4] = message_length >> 8;
1095         out_buffer[5] = message_length & 0xff;
1096
1097         /* Copy in data if any. */  
1098     if (message_length != 0) {
1099         memcpy(out_buffer + 6, buffer, message_length);
1100     }
1101             /* Copy in sequence number */
1102     out_buffer[message_length + 6] = sequence_byte;
1103
1104         /* Now calculate checksum over entire message 
1105            and append to message. */
1106     checksum = 0;
1107     for (count = 0; count < message_length + 7; count ++) {
1108         checksum ^= out_buffer[count];
1109     }
1110     out_buffer[message_length + 7] = checksum;
1111
1112         /* Send it out... */
1113     if (WRITEPHONE(PortFD, out_buffer, message_length + 8) != message_length + 8) {
1114         perror(_("TX_SendMessage - write:"));
1115         return (false);
1116     }
1117
1118 #ifdef DEBUG
1119         for (count = 0; count < message_length + 8; count++) {
1120                 if (isprint(out_buffer[count])) {
1121                         fprintf(stdout, "{%02x%c}", out_buffer[count], out_buffer[count]);
1122                 }
1123                 else {
1124                         fprintf(stdout, "{%02x }", out_buffer[count]);
1125                 }
1126                 if (((count + 1) % 16) == 0) {
1127                         fprintf(stdout, "\n");
1128                 }
1129         }       
1130         fflush(stdout);
1131 #endif
1132         
1133     return (true);
1134 }
1135
1136
1137
1138 #endif