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