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.1 2001/11/25 21:59:05 short
17 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
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,
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 */
134 /* Local variables */
136 bool RequestTerminate;
138 char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
139 u8 RequestSequenceNumber; /* 2-63 */
141 bool GotInitResponse;
144 enum MB61_RX_States RX_State;
145 enum MB61_Models ModelIdentified;
146 enum MB61_Responses ExpectedResponse;
147 enum MB61_Responses LatestResponse;
149 GSM_PhonebookEntry *CurrentPhonebookEntry;
150 GSM_Error CurrentPhonebookError;
153 u8 MessageDestination;
156 u8 MessageBuffer[MB61_MAX_RECEIVE_LENGTH];
158 u8 MessageSequenceNumber;
164 /* The following functions are made visible to gsm-api.c and friends. */
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))
174 RequestTerminate = false;
176 ModelIdentified = MB61_ModelUnknown;
177 ExpectedResponse = MB61_Response_Unknown;
178 CurrentPhonebookEntry = NULL;
179 CurrentPhonebookError = GE_NONE;
182 strncpy (PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
184 /* Create and start thread, */
185 rtn = pthread_create(&Thread, NULL, (void *) MB61_ThreadLoop, (void *)NULL);
187 if (rtn == EAGAIN || rtn == EINVAL) {
188 return (GE_INTERNALERROR);
195 /* Applications should call MB61_Terminate to shut down
196 the MB61 thread and close the serial port. */
197 void MB61_Terminate(void)
199 /* Request termination of thread */
200 RequestTerminate = true;
202 /* Now wait for thread to terminate. */
203 pthread_join(Thread, NULL);
205 /* Close serial port. */
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)
216 if (entry->MemoryType != GMT_ME) {
217 return (GE_INVALIDMEMORYTYPE);
220 timeout = 20; /* 2 seconds for command to complete */
222 /* Return if no link has been established. */
227 /* Process depending on model identified */
228 switch (ModelIdentified) {
231 if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
232 return (GE_INVALIDPHBOOKLOCATION);
234 CurrentPhonebookEntry = entry;
235 CurrentPhonebookError = GE_BUSY;
236 MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
237 MB61_TX_SendPhonebookReadRequest(entry->Location);
241 if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
242 return (GE_INVALIDPHBOOKLOCATION);
244 CurrentPhonebookEntry = entry;
245 CurrentPhonebookError = GE_BUSY;
246 MB61_SetExpectedResponse(MB61_Response_0x40_PhonebookRead);
247 MB61_TX_SendPhonebookReadRequest(entry->Location);
251 if (entry->Location >= MAX_6185_PHONEBOOK_ENTRIES) {
252 return (GE_INVALIDPHBOOKLOCATION);
254 CurrentPhonebookEntry = entry;
255 CurrentPhonebookError = GE_BUSY;
256 MB61_SetExpectedResponse(MB61_Response_0x40_LongPhonebookRead);
257 MB61_TX_SendLongPhonebookReadRequest(entry->Location);
261 return(GE_NOTIMPLEMENTED);
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);
270 return (CurrentPhonebookError);
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)
280 if (entry->MemoryType != GMT_ME) {
281 return (GE_INVALIDMEMORYTYPE);
284 /* Return if no link has been established. */
289 /* Process depending on model identified */
290 switch (ModelIdentified) {
293 if (entry->Location >= MAX_5160_PHONEBOOK_ENTRIES) {
294 return (GE_INVALIDPHBOOKLOCATION);
296 if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NAME_LENGTH) {
297 return (GE_PHBOOKNAMETOOLONG);
299 if (strlen(entry->Name) > MAX_5160_PHONEBOOK_NUMBER_LENGTH) {
300 return (GE_PHBOOKNAMETOOLONG);
302 CurrentPhonebookError = GE_BUSY;
303 MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
304 MB61_TX_SendPhonebookWriteRequest(entry);
308 if (entry->Location >= MAX_6160_PHONEBOOK_ENTRIES) {
309 return (GE_INVALIDPHBOOKLOCATION);
311 if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NAME_LENGTH) {
312 return (GE_PHBOOKNAMETOOLONG);
314 if (strlen(entry->Name) > MAX_616X_PHONEBOOK_NUMBER_LENGTH) {
315 return (GE_PHBOOKNAMETOOLONG);
317 CurrentPhonebookError = GE_BUSY;
318 MB61_SetExpectedResponse(MB61_Response_0x40_WriteAcknowledge);
319 MB61_TX_SendPhonebookWriteRequest(entry);
323 return (GE_NOTIMPLEMENTED);
327 return(GE_NOTIMPLEMENTED);
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);
336 return (CurrentPhonebookError);
340 bool MB61_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
345 /* Everything from here down is internal to 6160 code. */
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)
355 /* Initialise RX state machine. */
357 RX_State = MB61_RX_Sync;
360 /* Try to open serial port, if we fail we sit here and don't proceed
362 if (MB61_OpenSerial() != true) {
365 while (!RequestTerminate) {
371 /* Do initialisation sequence, sit here if it fails. */
372 if (MB61_InitialiseLink() != true) {
375 while (!RequestTerminate) {
381 /* Link is up OK so sit here twiddling our thumbs until
382 told to terminate. */
383 while (!RequestTerminate) {
384 if (idle_timer == 0) {
389 /*fprintf(stdout, ".");
393 usleep(100000); /* Avoid becoming a "busy" loop. */
396 /* Drop DTR and RTS lines before exiting */
397 device_setdtrrts(0, 0);
401 bool MB61_InitialiseLink(void)
403 unsigned char init_char[1] = {0x04};
405 fprintf(stdout, "Sending init...\n");
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 */
411 #define BASE_TIME (50000)
414 device_setdtrrts(0, 1);
417 /* RTS low for 250ms */
418 device_setdtrrts(0, 0);
419 usleep(5 * BASE_TIME);
421 /* RTS high, DTR high for 50ms */
422 device_setdtrrts(1, 1);
425 /* RTS low, DTR high for 50ms */
426 device_setdtrrts(1, 0);
429 /* RTS high, DTR high for 50ms */
430 device_setdtrrts(1, 1);
433 /* RTS low, DTR high for 50ms */
434 device_setdtrrts(1, 0);
437 /* RTS low, DTR low for 50ms */
438 device_setdtrrts(0, 0);
441 /* RTS low, DTR high for 50ms */
442 device_setdtrrts(1, 0);
445 /* RTS high, DTR high for 50ms */
446 device_setdtrrts(1, 1);
449 /* RTS low, DTR low for 50ms */
450 device_setdtrrts(0, 0);
453 /* leave RTS high, DTR low for duration of session. */
455 device_setdtrrts(0, 1);
460 /* Initialise sequence number used when sending messages
463 /* Send Initialisation message to phone. */
464 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
466 RequestSequenceNumber = 0x02;
467 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
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
475 fprintf(stdout, "Waiting for first response...\n");
478 if(MB61_WaitForExpectedResponse(100) == false) {
482 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
484 RequestSequenceNumber ++;
485 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd0, RequestSequenceNumber, 1, init_char);
488 fprintf(stdout, "Waiting for second response...\n");
490 if(MB61_WaitForExpectedResponse(100) == false) {
495 MB61_SetExpectedResponse(MB61_Response_0xD0_Init);
496 MB61_TX_SendPhoneIDRequest();
497 if(MB61_WaitForExpectedResponse(300) == false) {
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... */
516 void MB61_SetExpectedResponse(enum MB61_Responses response)
518 LatestResponse = MB61_Response_Unknown;
519 ExpectedResponse = response;
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
527 bool MB61_WaitForExpectedResponse(int timeout)
532 while ((count > 0) && (LatestResponse != ExpectedResponse)) {
537 if (LatestResponse == ExpectedResponse) {
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)
552 /* If the message is from ADDR_PC ignore and don't process further. */
553 if (MessageSource == MSG_ADDR_PC) {
556 /* Leave this uncommented if you want all messages in raw form. */
557 //MB61_RX_DisplayMessage();
559 /* Switch on the basis of the message type byte */
560 switch (MessageCommand) {
563 if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
564 fprintf(stderr, _("Standard Ack write (0x40) failed!"));
567 if (ExpectedResponse == MB61_Response_0x40_PhonebookRead) {
568 MB61_RX_Handle0x40_PhonebookRead();
569 LatestResponse = MB61_Response_0x40_PhonebookRead;
573 if (ExpectedResponse == MB61_Response_0x40_WriteAcknowledge) {
574 LatestResponse = MB61_Response_0x40_WriteAcknowledge;
575 CurrentPhonebookError = GE_NONE;
580 /* 0xd0 messages are the response to
581 initialisation requests. */
583 if (ExpectedResponse == MB61_Response_0xD0_Init) {
584 LatestResponse = MB61_Response_0xD0_Init;
589 if (MB61_TX_SendStandardAcknowledge(MessageSequenceNumber) != true) {
590 fprintf(stderr, _("Standard Ack write (0xd2) failed!"));
592 if (ExpectedResponse == MB61_Response_0xD2_ID) {
593 MB61_RX_Handle0xD2_ID();
594 LatestResponse = MB61_Response_0xD2_ID;
596 if (ExpectedResponse == MB61_Response_0xD2_Version) {
597 MB61_RX_Handle0xD2_Version();
598 LatestResponse = MB61_Response_0xD2_Version;
603 /* Incoming 0x7f's are acks for commands we've sent. */
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!"));
614 fprintf(stdout, "Sent standard Ack for unknown %02x\n", MessageCommand);
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)
629 if (CurrentPhonebookEntry == NULL) {
630 CurrentPhonebookError = GE_INTERNALERROR;
634 /* First do number */
639 while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NUMBER_LENGTH)) {
640 CurrentPhonebookEntry->Number[j] = MessageBuffer[i];
643 if (MessageBuffer[i] == 0) {
647 CurrentPhonebookEntry->Number[j] = 0;
654 while ((i < MessageLength) && (!got_null) && (j < GSM_MAX_PHONEBOOK_NAME_LENGTH)) {
655 CurrentPhonebookEntry->Name[j] = MessageBuffer[i];
658 if (MessageBuffer[i] == 0) {
662 CurrentPhonebookEntry->Name[j] = 0;
664 if ((strlen(CurrentPhonebookEntry->Number) != 0) ||
665 (strlen(CurrentPhonebookEntry->Name) != 0)) {
666 CurrentPhonebookEntry->Empty = false;
669 CurrentPhonebookEntry->Empty = true;
671 CurrentPhonebookEntry->Group = GSM_GROUPS_NOT_SUPPORTED;
674 CurrentPhonebookError = GE_NONE;
678 void MB61_RX_Handle0x40_LongPhonebookRead(void)
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)
694 if (strstr(MessageBuffer + 4, "NSW-1") != NULL) {
695 ModelIdentified = MB61_Model5160;
697 fprintf(stdout, "Identified as 5160\n");
701 if (strstr(MessageBuffer + 4, "NSW-3") != NULL) {
702 ModelIdentified = MB61_Model6160;
704 fprintf(stdout, "Identified as 6160\n");
708 if (strstr(MessageBuffer + 4, "NSD-3") != NULL) {
709 ModelIdentified = MB61_Model6185;
711 fprintf(stdout, "Identified as 6185\n");
716 fprintf(stdout, "Unknown model - please report dump below to hugh@linuxcare.com\n");
722 for (i = 4; i < MessageLength; i++) {
723 if (isprint(MessageBuffer[i])) {
724 fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
727 fprintf(stdout, "[%02x ]", MessageBuffer[i]);
729 if (((i - 3) % 16) == 0) {
730 fprintf(stdout, "\n");
741 void MB61_RX_Handle0xD2_Version(void)
748 void MB61_RX_DisplayMessage(void)
752 fprintf(stdout, "Dest:%02x Src:%02x Cmd:%02x Len:%d Seq:%02x Csum:%02x\n",
753 MessageDestination, MessageSource, MessageCommand, MessageLength,
754 MessageSequenceNumber, MessageCSum);
756 if (MessageLength == 0) {
760 fprintf(stdout, "Data: ");
762 for (i = 0; i < MessageLength; i++) {
763 if (isprint(MessageBuffer[i])) {
764 fprintf(stdout, "[%02x%c]", MessageBuffer[i], MessageBuffer[i]);
767 fprintf(stdout, "[%02x ]", MessageBuffer[i]);
769 if (((i + 1) % 8) == 0) {
770 fprintf(stdout, "\n ");
773 fprintf(stdout, "\n");
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)
781 /* 7 - header and null terminators, 17 - number length,
783 u8 message[7 + 17 + 17];
788 name_length = strlen(entry->Name);
789 number_length = strlen(entry->Number);
791 /* Header plus two terminating nulls plus name/number themselves */
792 message_length = 7 + name_length + 1 + number_length + 1;
794 message[0] = 0x00; /* Header bytes, purpose not investigated */
801 message[6] = entry->Location;
803 strncpy(message + 7, entry->Number, 16);
805 strncpy(message + 8 + number_length, entry->Name, 16);
807 MB61_UpdateSequenceNumber();
808 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, message_length, message);
814 bool MB61_TX_SendPhonebookReadRequest(u8 entry)
816 u8 message[7] = {0x00, 0x01, 0x1f, 0x01, 0x04, 0x86, 0x01};
820 MB61_UpdateSequenceNumber();
821 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 7, message);
823 ExpectedResponse = MB61_Response_0x40_PhonebookRead;
828 /* 6185 requires a different phone book request apparently */
829 bool MB61_TX_SendLongPhonebookReadRequest(u8 entry)
831 u8 message[8] = {0x00, 0x00, 0x07, 0x11, 0x00, 0x10, 0x00, 0x00};
835 MB61_UpdateSequenceNumber();
836 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0x40, RequestSequenceNumber, 8, message);
838 ExpectedResponse = MB61_Response_0x40_PhonebookRead;
844 void MB61_TX_SendPhoneIDRequest(void)
846 u8 message[5] = {0x00, 0x01, 0x00, 0x03, 0x00};
848 MB61_UpdateSequenceNumber();
849 MB61_TX_SendMessage(MSG_ADDR_PHONE, MSG_ADDR_PC, 0xd1, RequestSequenceNumber, 5, message);
851 ExpectedResponse = MB61_Response_0xD2_ID;
855 void MB61_UpdateSequenceNumber(void)
857 RequestSequenceNumber ++;
858 if (RequestSequenceNumber > 63) {
859 RequestSequenceNumber = 2;
863 /* Not totally happy with this but it works for now. - HAB 20000602 */
864 bool MB61_TX_SendStandardAcknowledge(u8 sequence_number)
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;
876 /* Now calculate checksum over entire message
877 and append to message. */
879 for (count = 0; count < 5; count ++) {
880 checksum ^= out_buffer[count];
882 out_buffer[5] = checksum;
885 if (WRITEPHONE(PortFD, out_buffer, 6) != 6) {
886 perror(_("TX_SendMessage - write:"));
891 fprintf(stdout, "(Ack %02x) ", sequence_number);
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)
902 fprintf(stdout, "(%d)", RX_State);
907 /* Messages on the MBUS start with 0x1f. We use
908 this to "synchronise" with the incoming data
911 if (rx_byte == 0x1f) {
914 CalculatedCSum = rx_byte;
915 RX_State = MB61_RX_GetDestination;
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;
926 /* Next byte is the source of the message. */
927 case MB61_RX_GetSource:
928 MessageSource = rx_byte;
929 CalculatedCSum ^= rx_byte;
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;
938 RX_State = MB61_RX_Sync;
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;
954 RX_State = MB61_RX_GetMessage;
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;
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;
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;
980 if (BufferCount >= MB61_MAX_RECEIVE_LENGTH) {
981 RX_State = MB61_RX_Sync; /* Should be PANIC */
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;
990 /* Get checksum and if valid hand over to
991 dispatch message function */
992 case MB61_RX_GetCSum:
994 MessageCSum = rx_byte;
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();
1002 /* Checksum didn't match so ignore. */
1005 fprintf(stderr, _("CS Fail %02x != %02x"), MessageCSum, CalculatedCSum);
1006 MB61_RX_DisplayMessage();
1008 RX_State = MB61_RX_Sync;
1011 CalculatedCSum ^= rx_byte;
1018 /* Called by initialisation code to open comm port in
1019 asynchronous mode. */
1020 bool MB61_OpenSerial(void)
1023 struct sigaction sig_io;
1025 /* Set up and install handler before enabling async IO on port. */
1027 sig_io.sa_handler = MB61_SigHandler;
1028 sig_io.sa_flags = 0;
1029 sigaction (SIGIO, &sig_io, NULL);
1031 /* Open device MBUS uses 9600,O,1 */
1032 result = device_open(PortDevice, true, true, false, GCT_Serial);
1035 perror(_("Couldn't open MB61 device: "));
1038 fprintf(stdout, "Opened MB61 device\n");
1040 device_changespeed(9600);
1044 /* Handler called when characters received from serial port.
1045 calls state machine code to process it. */
1046 void MB61_SigHandler(int status)
1048 unsigned char buffer[255];
1051 res = device_read(buffer, 255);
1053 for (count = 0; count < res ; count ++) {
1054 MB61_RX_StateMachine(buffer[count]);
1057 if (isprint(buffer[count])) {
1058 fprintf(stdout, "<%02x%c>", buffer[count], buffer[count]);
1061 fprintf(stdout, "<%02x >", buffer[count]);
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)
1076 u8 out_buffer[MB61_MAX_TRANSMIT_LENGTH + 7];
1078 unsigned char checksum;
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"));
1088 //RX_State = MB61_RX_Sync; Hack.
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;
1098 /* Copy in data if any. */
1099 if (message_length != 0) {
1100 memcpy(out_buffer + 6, buffer, message_length);
1102 /* Copy in sequence number */
1103 out_buffer[message_length + 6] = sequence_byte;
1105 /* Now calculate checksum over entire message
1106 and append to message. */
1108 for (count = 0; count < message_length + 7; count ++) {
1109 checksum ^= out_buffer[count];
1111 out_buffer[message_length + 7] = checksum;
1113 /* Send it out... */
1114 if (WRITEPHONE(PortFD, out_buffer, message_length + 8) != message_length + 8) {
1115 perror(_("TX_SendMessage - write:"));
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]);
1125 fprintf(stdout, "{%02x }", out_buffer[count]);
1127 if (((count + 1) % 16) == 0) {
1128 fprintf(stdout, "\n");