7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 1999, 2000 Hugh Blemings & Pavel JanÃk ml.
11 Released under the terms of the GNU GPL, see file COPYING for more details.
13 This code contains the main part of the 5160/6160 code.
16 Revision 1.1.1.2 2002/04/03 00:07:59 short
17 Found in "gnokii-working" directory, some November-patches version
19 Revision 1.29 2001/08/20 23:27:37 pkot
20 Add hardware shakehand to the link layer (Manfred Jonsson)
22 Revision 1.28 2001/06/28 00:28:45 pkot
23 Small docs updates (Pawel Kot)
30 #define __mbus_6160_c /* "Turn on" prototypes in mbus-6160.h */
39 #include <sys/types.h>
41 #include <sys/ioctl.h>
47 #include "gsm-common.h"
48 #include "mbus-6160.h"
50 #include "phones/nokia.h"
52 #define WRITEPHONE(a, b, c) device_write(b, c)
56 /* Global variables used by code in gsm-api.c to expose the
57 functions supported by this model of phone. */
60 GSM_Functions MB61_Functions = {
63 MB61_GetMemoryLocation,
64 MB61_WritePhonebookLocation,
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 */
133 /* Local variables */
135 bool RequestTerminate;
137 char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
138 u8 RequestSequenceNumber; /* 2-63 */
140 bool GotInitResponse;
143 enum MB61_RX_States RX_State;
144 enum MB61_Models ModelIdentified;
145 enum MB61_Responses ExpectedResponse;
146 enum MB61_Responses LatestResponse;
148 GSM_PhonebookEntry *CurrentPhonebookEntry;
149 GSM_Error CurrentPhonebookError;
152 u8 MessageDestination;
155 u8 MessageBuffer[MB61_MAX_RECEIVE_LENGTH];
157 u8 MessageSequenceNumber;
163 /* The following functions are made visible to gsm-api.c and friends. */
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))
173 RequestTerminate = false;
175 ModelIdentified = MB61_ModelUnknown;
176 ExpectedResponse = MB61_Response_Unknown;
177 CurrentPhonebookEntry = NULL;
178 CurrentPhonebookError = GE_NONE;
181 strncpy (PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
183 /* Create and start thread, */
184 rtn = pthread_create(&Thread, NULL, (void *) MB61_ThreadLoop, (void *)NULL);
186 if (rtn == EAGAIN || rtn == EINVAL) {
187 return (GE_INTERNALERROR);
194 /* Applications should call MB61_Terminate to shut down
195 the MB61 thread and close the serial port. */
196 void MB61_Terminate(void)
198 /* Request termination of thread */
199 RequestTerminate = true;
201 /* Now wait for thread to terminate. */
202 pthread_join(Thread, NULL);
204 /* Close serial port. */
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)
215 if (entry->MemoryType != GMT_ME) {
216 return (GE_INVALIDMEMORYTYPE);
219 timeout = 20; /* 2 seconds for command to complete */
221 /* Return if no link has been established. */
226 /* Process depending on model identified */
227 switch (ModelIdentified) {
230 if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
231 return (GE_INVALIDPHBOOKLOCATION);
233 CurrentPhonebookEntry = entry;
234 CurrentPhonebookError = GE_BUSY;
235 MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
236 MB61_TX_SendPhonebookReadRequest(entry->Location);
240 if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
241 return (GE_INVALIDPHBOOKLOCATION);
243 CurrentPhonebookEntry = entry;
244 CurrentPhonebookError = GE_BUSY;
245 MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
246 MB61_TX_SendPhonebookReadRequest(entry->Location);
250 if (entry->Location >= MAX_6185_PHONEBOOK_ENTRIES) {
251 return (GE_INVALIDPHBOOKLOCATION);
253 CurrentPhonebookEntry = entry;
254 CurrentPhonebookError = GE_BUSY;
255 MB61_SetExpectedResponse(MB61_Response_0x40_LongPhonebookRead);
256 MB61_TX_SendLongPhonebookReadRequest(entry->Location);
260 return(GE_NOTIMPLEMENTED);
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);
269 return (CurrentPhonebookError);
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)
279 if (entry->MemoryType != GMT_ME) {
280 return (GE_INVALIDMEMORYTYPE);
283 /* Return if no link has been established. */
288 /* Process depending on model identified */
289 switch (ModelIdentified) {
292 if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
293 return (GE_INVALIDPHBOOKLOCATION);
295 if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NAME_LENGTH) {
296 return (GE_PHBOOKNAMETOOLONG);
298 if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NUMBER_LENGTH) {
299 return (GE_PHBOOKNAMETOOLONG);
301 CurrentPhonebookError = GE_BUSY;
302 MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
303 MB61_TX_SendPhonebookWriteRequest(entry);
307 if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
308 return (GE_INVALIDPHBOOKLOCATION);
310 if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NAME_LENGTH) {
311 return (GE_PHBOOKNAMETOOLONG);
313 if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NUMBER_LENGTH) {
314 return (GE_PHBOOKNAMETOOLONG);
316 CurrentPhonebookError = GE_BUSY;
317 MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
318 MB61_TX_SendPhonebookWriteRequest(entry);
322 return (GE_NOTIMPLEMENTED);
326 return(GE_NOTIMPLEMENTED);
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);
335 return (CurrentPhonebookError);
339 bool MB61_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
344 /* Everything from here down is internal to 6160 code. */
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)
354 /* Initialise RX state machine. */
356 RX_State = MB61_RX_Sync;
359 /* Try to open serial port, if we fail we sit here and don't proceed
361 if (MB61_OpenSerial() != true) {
364 while (!RequestTerminate) {
370 /* Do initialisation sequence, sit here if it fails. */
371 if (MB61_InitialiseLink() != true) {
374 while (!RequestTerminate) {
380 /* Link is up OK so sit here twiddling our thumbs until
381 told to terminate. */
382 while (!RequestTerminate) {
383 if (idle_timer == 0) {
388 /*fprintf(stdout, ".");
392 usleep(100000); /* Avoid becoming a "busy" loop. */
395 /* Drop DTR and RTS lines before exiting */
396 device_setdtrrts(0, 0);
400 bool MB61_InitialiseLink(void)
402 unsigned char init_char[1] = {0x04};
404 fprintf(stdout, "Sending init...\n");
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 */
410 #define BASE_TIME (50000)
413 device_setdtrrts(0, 1);
416 /* RTS low for 250ms */
417 device_setdtrrts(0, 0);
418 usleep(5 * BASE_TIME);
420 /* RTS high, DTR high for 50ms */
421 device_setdtrrts(1, 1);
424 /* RTS low, DTR high for 50ms */
425 device_setdtrrts(1, 0);
428 /* RTS high, DTR high for 50ms */
429 device_setdtrrts(1, 1);
432 /* RTS low, DTR high for 50ms */
433 device_setdtrrts(1, 0);
436 /* RTS low, DTR low for 50ms */
437 device_setdtrrts(0, 0);
440 /* RTS low, DTR high for 50ms */
441 device_setdtrrts(1, 0);
444 /* RTS high, DTR high for 50ms */
445 device_setdtrrts(1, 1);
448 /* RTS low, DTR low for 50ms */
449 device_setdtrrts(0, 0);
452 /* leave RTS high, DTR low for duration of session. */
454 device_setdtrrts(0, 1);
459 /* Initialise sequence number used when sending messages
462 /* Send Initialisation message to phone. */
463 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
465 RequestSequenceNumber = 0x02;
466 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
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
474 fprintf(stdout, "Waiting for first response...\n");
477 if(MB61_WaitForExpectedResponse(100) == false) {
481 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
483 RequestSequenceNumber ++;
484 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
487 fprintf(stdout, "Waiting for second response...\n");
489 if(MB61_WaitForExpectedResponse(100) == false) {
494 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
495 MB61_TX_SendPhoneIDRequest();
496 if(MB61_WaitForExpectedResponse(300) == false) {
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... */
515 void MB61_SetExpectedResponse(enum MB61_Responses response)
517 LatestResponse = MB61_Response_Unknown;
518 ExpectedResponse = response;
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
526 bool MB61_WaitForExpectedResponse(int timeout)
531 while ((count > 0) && (LatestResponse != ExpectedResponse)) {
536 if (LatestResponse == ExpectedResponse) {
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)
551 /* If the message is from ADDR_PC ignore and don't process further. */
552 if (MessageSource == MSG_ADDR_PC) {
555 /* Leave this uncommented if you want all messages in raw form. */
556 //MB61_RX_DisplayMessage();
558 /* Switch on the basis of the message type byte */
559 switch (MessageCommand) {
562 if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
563 fprintf(stderr, _("Standard Ack write (0x40) failed!"));
566 if (ExpectedResponse == MB61_Response_0x40_PhonebookRead) {
567 MB61_RX_Handle0x40_PhonebookRead();
568 LatestResponse = MB61_Response_0x40_PhonebookRead;
572 if (ExpectedResponse == MB61_Response_0x40_WriteAcknowledge) {
573 LatestResponse = MB61_Response_0x40_WriteAcknowledge;
574 CurrentPhonebookError = GE_NONE;
579 /* 0xd0 messages are the response to
580 initialisation requests. */
582 if (ExpectedResponse == MB61_Response_0xD0_Init) {
583 LatestResponse = MB61_Response_0xD0_Init;
588 if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
589 fprintf(stderr, _("Standard Ack write (0xd2) failed!"));
591 if (ExpectedResponse == MB61_Response_0xD2_ID) {
592 MB61_RX_Handle0xD2_ID();
593 LatestResponse = MB61_Response_0xD2_ID;
595 if (ExpectedResponse == MB61_Response_0xD2_Version) {
596 MB61_RX_Handle0xD2_Version();
597 LatestResponse = MB61_Response_0xD2_Version;
602 /* Incoming 0x7f's are acks for commands we've sent. */
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!"));
613 fprintf(stdout, "Sent standard Ack for unknown %02x\n", MessageCommand);
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)
628 if (CurrentPhonebookEntry == NULL) {
629 CurrentPhonebookError = GE_INTERNALERROR;
633 /* First do number */
638 while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NUMBER_LENGTH)) {
639 CurrentPhonebookEntry->Number[j] = MessageBuffer[i];
642 if (MessageBuffer[i] == 0) {
646 CurrentPhonebookEntry->Number[j] = 0;
653 while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NAME_LENGTH)) {
654 CurrentPhonebookEntry->Name[j] = MessageBuffer[i];
657 if (MessageBuffer[i] == 0) {
661 CurrentPhonebookEntry->Name[j] = 0;
663 if ((strlen(CurrentPhonebookEntry->Number) != 0) ||
664 (strlen(CurrentPhonebookEntry->Name) != 0)) {
665 CurrentPhonebookEntry->Empty = false;
668 CurrentPhonebookEntry->Empty = true;
670 CurrentPhonebookEntry->Group = GSM_GROUPS_NOT_SUPPORTED;
673 CurrentPhonebookError = GE_NONE;
677 void MB61_RX_Handle0x40_LongPhonebookRead(void)
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)
693 if (strstr(MessageBuffer + 4, "NSW-1") != NULL) {
694 ModelIdentified = MB61_Model5160;
696 fprintf(stdout, "Identified as 5160\n");
700 if (strstr(MessageBuffer + 4, "NSW-3") != NULL) {
701 ModelIdentified = MB61_Model6160;
703 fprintf(stdout, "Identified as 6160\n");
707 if (strstr(MessageBuffer + 4, "NSD-3") != NULL) {
708 ModelIdentified = MB61_Model6185;
710 fprintf(stdout, "Identified as 6185\n");
715 fprintf(stdout, "Unknown model - please report dump below to hugh@linuxcare.com\n");
721 for (i = 4; i < MessageLength; i++) {
722 if (isprint(MessageBuffer[i])) {
723 fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
726 fprintf(stdout, "[%02x ]", MessageBuffer[i]);
728 if (((i - 3) % 16) == 0) {
729 fprintf(stdout, "\n");
740 void MB61_RX_Handle0xD2_Version(void)
747 void MB61_RX_DisplayMessage(void)
751 fprintf(stdout, "Dest:%02x Src:%02x Cmd:%02x Len:%d Seq:%02x Csum:%02x\n",
752 MessageDestination, MessageSource, MessageCommand, MessageLength,
753 MessageSequenceNumber, MessageCSum);
755 if (MessageLength == 0) {
759 fprintf(stdout, "Data: ");
761 for (i = 0; i < MessageLength; i++) {
762 if (isprint(MessageBuffer[i])) {
763 fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
766 fprintf(stdout, "[%02x ]", MessageBuffer[i]);
768 if (((i + 1) % 8) == 0) {
769 fprintf(stdout, "\n ");
772 fprintf(stdout, "\n");
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)
780 /* 7 - header and null terminators, 17 - number length,
782 u8 message[7 + 17 + 17];
787 name_length = strlen(entry->Name);
788 number_length = strlen(entry->Number);
790 /* Header plus two terminating nulls plus name/number themselves */
791 message_length = 7 + name_length + 1 + number_length + 1;
793 message[0] = 0x00; /* Header bytes, purpose not investigated */
800 message[6] = entry->Location;
802 strncpy(message + 7, entry->Number, 16);
804 strncpy(message + 8 + number_length, entry->Name, 16);
806 MB61_UpdateSequenceNumber();
807 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, message_length, message);
813 bool MB61_TX_SendPhonebookReadRequest(u8 entry)
815 u8 message[7] = {0x00, 0x01, 0x1f, 0x01, 0x04, 0x86, 0x01};
819 MB61_UpdateSequenceNumber();
820 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 7, message);
822 ExpectedResponse = MB61_Response_0x40_PhonebookRead;
827 /* 6185 requires a different phone book request apparently */
828 bool MB61_TX_SendLongPhonebookReadRequest(u8 entry)
830 u8 message[8] = {0x00, 0x00, 0x07, 0x11, 0x00, 0x10, 0x00, 0x00};
834 MB61_UpdateSequenceNumber();
835 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 8, message);
837 ExpectedResponse = MB61_Response_0x40_PhonebookRead;
843 void MB61_TX_SendPhoneIDRequest(void)
845 u8 message[5] = {0x00, 0x01, 0x00, 0x03, 0x00};
847 MB61_UpdateSequenceNumber();
848 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd1, RequestSequenceNumber, 5, message);
850 ExpectedResponse = MB61_Response_0xD2_ID;
854 void MB61_UpdateSequenceNumber(void)
856 RequestSequenceNumber ++;
857 if (RequestSequenceNumber > 63) {
858 RequestSequenceNumber = 2;
862 /* Not totally happy with this but it works for now. - HAB 20000602 */
863 bool MB61_TX_SendStandardAcknowledge(u8 sequence_number)
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;
875 /* Now calculate checksum over entire message
876 and append to message. */
878 for (count = 0; count < 5; count ++) {
879 checksum ^= out_buffer[count];
881 out_buffer[5] = checksum;
884 if (WRITEPHONE(PortFD, out_buffer, 6) != 6) {
885 perror(_("TX_SendMessage - write:"));
890 fprintf(stdout, "(Ack %02x) ", sequence_number);
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)
901 fprintf(stdout, "(%d)", RX_State);
906 /* Messages on the MBUS start with 0x1f. We use
907 this to "synchronise" with the incoming data
910 if (rx_byte == 0x1f) {
913 CalculatedCSum = rx_byte;
914 RX_State = MB61_RX_GetDestination;
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;
925 /* Next byte is the source of the message. */
926 case MB61_RX_GetSource:
927 MessageSource = rx_byte;
928 CalculatedCSum ^= rx_byte;
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;
937 RX_State = MB61_RX_Sync;
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;
953 RX_State = MB61_RX_GetMessage;
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;
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;
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;
979 if (BufferCount >= MB61_MAX_RECEIVE_LENGTH) {
980 RX_State = MB61_RX_Sync; /* Should be PANIC */
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;
989 /* Get checksum and if valid hand over to
990 dispatch message function */
991 case MB61_RX_GetCSum:
993 MessageCSum = rx_byte;
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();
1001 /* Checksum didn't match so ignore. */
1004 fprintf(stderr, _("CS Fail %02x != %02x"), MessageCSum, CalculatedCSum);
1005 MB61_RX_DisplayMessage();
1007 RX_State = MB61_RX_Sync;
1010 CalculatedCSum ^= rx_byte;
1017 /* Called by initialisation code to open comm port in
1018 asynchronous mode. */
1019 bool MB61_OpenSerial(void)
1022 struct sigaction sig_io;
1024 /* Set up and install handler before enabling async IO on port. */
1026 sig_io.sa_handler = MB61_SigHandler;
1027 sig_io.sa_flags = 0;
1028 sigaction (SIGIO, &sig_io, NULL);
1030 /* Open device MBUS uses 9600,O,1 */
1031 result = device_open(PortDevice, true, true, false, GCT_Serial);
1034 perror(_("Couldn't open MB61 device: "));
1037 fprintf(stdout, "Opened MB61 device\n");
1039 device_changespeed(9600);
1043 /* Handler called when characters received from serial port.
1044 calls state machine code to process it. */
1045 void MB61_SigHandler(int status)
1047 unsigned char buffer[255];
1050 res = device_read(buffer, 255);
1052 for (count = 0; count < res ; count ++) {
1053 MB61_RX_StateMachine(buffer[count]);
1056 if (isprint(buffer[count])) {
1057 fprintf(stdout, "<%02x%c>", buffer[count], buffer[count]);
1060 fprintf(stdout, "<%02x >", buffer[count]);
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)
1075 u8 out_buffer[MB61_MAX_TRANSMIT_LENGTH + 7];
1077 unsigned char checksum;
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"));
1087 //RX_State = MB61_RX_Sync; Hack.
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;
1097 /* Copy in data if any. */
1098 if (message_length != 0) {
1099 memcpy(out_buffer + 6, buffer, message_length);
1101 /* Copy in sequence number */
1102 out_buffer[message_length + 6] = sequence_byte;
1104 /* Now calculate checksum over entire message
1105 and append to message. */
1107 for (count = 0; count < message_length + 7; count ++) {
1108 checksum ^= out_buffer[count];
1110 out_buffer[message_length + 7] = checksum;
1112 /* Send it out... */
1113 if (WRITEPHONE(PortFD, out_buffer, message_length + 8) != message_length + 8) {
1114 perror(_("TX_SendMessage - write:"));
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]);
1124 fprintf(stdout, "{%02x }", out_buffer[count]);
1126 if (((count + 1) % 16) == 0) {
1127 fprintf(stdout, "\n");