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 file provides an API for accessing functions on the 6110 and similar
14 phones. See README for more details on supported mobile phones.
16 The various routines are called FB61 (whatever) as a concatenation of FBUS
20 Revision 1.1.1.1 2001/11/25 21:59:03 short
21 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
23 Revision 1.136 2001/08/20 23:27:37 pkot
24 Add hardware shakehand to the link layer (Manfred Jonsson)
26 Revision 1.135 2001/08/09 12:34:33 pkot
27 3330 and 6250 support - I have no idea if it does work (mygnokii)
29 Revision 1.134 2001/06/10 11:24:57 machek
30 Kill "slash star" inside comment.
32 Revision 1.133 2001/03/19 23:43:46 pkot
33 Solaris/ *BSD '#if defined' cleanup
35 Revision 1.132 2001/03/13 01:23:17 pkot
36 Windows updates (Manfred Jonsson)
38 Revision 1.131 2001/03/13 01:21:38 pkot
39 *BSD updates (Bert Driehuis)
41 Revision 1.130 2001/02/28 21:30:52 machek
42 Return data in GBF_Arbitrary if we can't handle units requested.
44 Revision 1.129 2001/02/21 19:56:55 chris
45 More fiddling with the directory layout
47 Revision 1.128 2001/02/17 22:40:48 chris
50 Revision 1.127 2001/02/06 21:15:34 chris
51 Preliminary irda support for 7110 etc. Not well tested!
53 Revision 1.126 2001/02/06 14:35:55 pkot
54 Few more cleanups on authentication
56 Revision 1.125 2001/02/03 23:56:12 chris
57 Start of work on irda support (now we just need fbus-irda.c!)
58 Proper unicode support in 7110 code (from pkot)
60 Revision 1.124 2001/02/01 15:17:27 pkot
61 Fixed --identify and added Manfred's manufacturer patch
63 Revision 1.123 2001/01/31 12:49:00 pkot
64 Many cleanups in fbus-6110 code.
65 3210/3310 really work now.
67 Revision 1.122 2001/01/23 15:32:35 chris
68 Pavel's 'break' and 'static' corrections.
69 Work on logos for 7110.
71 Revision 1.121 2001/01/15 17:00:45 pkot
72 Initial keypress sequence support. Disable compilation warning
74 Revision 1.120 2001/01/14 22:46:56 chris
75 Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
77 Revision 1.119 2001/01/10 16:32:16 pkot
78 Documentation updates.
79 FreeBSD fix for 3810 code.
80 Added possibility for deleting SMS just after reading it in gnokii.
84 Revision 1.118 2001/01/08 15:11:36 pkot
85 Documentation updates.
86 Fixed some bugs and removed FIXMEs.
87 We need to move some stuff from configure.in to aclocal.m4
89 Revision 1.117 2000/12/21 15:13:46 pkot
90 Fixed functions converting ascii to and from PDU
92 Revision 1.116 2000/12/19 16:27:16 pkot
93 Added 'static' word to variable declarations in common/fbus-6110.c and Makefile fix. (thanks to Pavel Machek)
97 /* "Turn on" prototypes in fbus-6110.h */
101 /* System header files */
110 #include "win32/winserial.h"
115 #define WRITEPHONE(a, b, c) WriteCommBlock(b, c)
116 #define sleep(x) Sleep((x) * 1000)
117 #define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
118 extern HANDLE hPhone;
122 #define WRITEPHONE(a, b, c) device_write(b, c)
128 #include <sys/ioctl.h>
129 #include <sys/types.h>
130 #include <sys/time.h>
134 #include "devices/unixserial.h"
138 /* Various header file */
142 #include "gsm-common.h"
143 #include "fbus-6110.h"
144 #include "fbus-6110-auth.h"
145 #include "gsm-ringtones.h"
146 #include "gsm-networks.h"
147 #include "phones/generic.h"
148 #include "phones/nokia.h"
150 /* Global variables used by code in gsm-api.c to expose the functions
151 supported by this model of phone. */
156 /* fd opened in device.c */
157 extern int device_portfd;
162 void FB61_InitializeLink();
166 /* Here we initialise model specific functions. */
168 GSM_Functions FB61_Functions = {
171 FB61_GetMemoryLocation,
172 FB61_WritePhonebookLocation,
175 FB61_GetMemoryStatus,
180 FB61_DeleteSMSMessage,
184 FB61_GetBatteryLevel,
186 FB61_GetDisplayStatus,
187 FB61_EnterSecurityCode,
188 FB61_GetSecurityCodeStatus,
192 PNOK_GetManufacturer,
199 FB61_GetIncomingCallNr,
201 FB61_GetCalendarNote,
202 FB61_WriteCalendarNote,
203 FB61_DeleteCalendarNote,
215 FB61_EnableDisplayOutput,
216 FB61_DisableDisplayOutput,
217 FB61_EnableCellBroadcast,
218 FB61_DisableCellBroadcast,
219 FB61_ReadCellBroadcast,
225 /* Mobile phone information */
227 GSM_Information FB61_Information = {
228 "6110|6130|6150|6190|5110|5130|5190|3210|3310|3330", /* Supported models */
229 4, /* Max RF Level */
230 0, /* Min RF Level */
231 GRF_Arbitrary, /* RF level units */
232 4, /* Max Battery Level */
233 0, /* Min Battery Level */
234 GBU_Arbitrary, /* Battery level units */
235 GDT_DateTime, /* Have date/time support */
236 GDT_TimeOnly, /* Alarm supports time only */
237 1, /* Only one alarm available */
238 48, 84, /* Startup logo size */
239 14, 72, /* Op logo size */
240 14, 72 /* Caller logo size */
243 unsigned char GSM_Default_Alphabet[] = {
245 /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
246 /* Characters in hex position 10, [12 to 1a] and 24 are not present on
247 latin1 charset, so we cannot reproduce on the screen, however they are
248 greek symbol not present even on my Nokia */
250 '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec,
251 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
252 '?', '_', '?', '?', '?', '?', '?', '?',
253 '?', '?', '?', '?', 0xc6, 0xe6, 0xdf, 0xc9,
254 ' ', '!', '\"', '#', 0xa4, '%', '&', '\'',
255 '(', ')', '*', '+', ',', '-', '.', '/',
256 '0', '1', '2', '3', '4', '5', '6', '7',
257 '8', '9', ':', ';', '<', '=', '>', '?',
258 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
259 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
260 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
261 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
262 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
263 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
264 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
265 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0
268 const char *FB61_MemoryType_String [] = {
281 /* Local variables */
284 char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
286 /* This is the connection type used in gnokii. */
288 GSM_ConnectionType CurrentConnectionType;
292 u8 MessageBuffer[FB61_MAX_RECEIVE_LENGTH * 6];
295 u8 MessageType, MessageDestination, MessageSource, MessageUnknown;
296 u8 MessagesSent=0, AcksReceived=0;
298 /* Magic bytes from the phone. */
300 unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
301 GSM_Error CurrentMagicError = GE_BUSY;
303 enum FB61_RX_States RX_State;
304 bool RX_Multiple = false;
306 u8 RequestSequenceNumber = 0x00;
307 bool RequestTerminate;
308 bool DisableKeepalive = false;
310 u8 CallSequenceNumber; /* Used to disconnect the call */
321 /* Local variables used by get/set phonebook entry code. Buffer is used as a
322 source or destination for phonebook data and other functions... Error is
323 set to GE_NONE by calling function, set to GE_COMPLETE or an error code by
324 handler routines as appropriate. */
326 static GSM_PhonebookEntry *CurrentPhonebookEntry;
327 static GSM_Error CurrentPhonebookError;
329 static GSM_SpeedDial *CurrentSpeedDialEntry;
330 static GSM_Error CurrentSpeedDialError;
332 static GSM_SMSMessage *CurrentSMSMessage;
333 static GSM_Error CurrentSMSMessageError;
334 static int CurrentSMSPointer;
336 static GSM_MemoryStatus *CurrentMemoryStatus;
337 static GSM_Error CurrentMemoryStatusError;
339 static GSM_NetworkInfo *CurrentNetworkInfo = NULL;
340 static GSM_Error CurrentNetworkInfoError;
342 static GSM_SMSStatus *CurrentSMSStatus;
343 static GSM_Error CurrentSMSStatusError;
345 static GSM_MessageCenter *CurrentMessageCenter;
346 static GSM_Error CurrentMessageCenterError;
348 static int *CurrentSecurityCodeStatus;
349 static GSM_Error CurrentSecurityCodeError;
351 static GSM_DateTime *CurrentDateTime;
352 static GSM_Error CurrentDateTimeError;
354 static GSM_DateTime *CurrentAlarm;
355 static GSM_Error CurrentAlarmError;
357 static GSM_CalendarNote *CurrentCalendarNote;
358 static GSM_Error CurrentCalendarNoteError;
360 static GSM_Error CurrentSetDateTimeError;
361 static GSM_Error CurrentSetAlarmError;
363 static int CurrentRFLevel,
367 static int DisplayStatus;
368 static GSM_Error DisplayStatusError;
370 static char *CurrentNetmonitor;
371 static GSM_Error CurrentNetmonitorError;
373 static GSM_Bitmap *GetBitmap=NULL;
374 static GSM_Error GetBitmapError;
376 static GSM_Error SetBitmapError;
378 static GSM_Profile *CurrentProfile;
379 static GSM_Error CurrentProfileError;
381 static GSM_Error CurrentDisplayOutputError;
383 static GSM_CBMessage *CurrentCBMessage;
384 static GSM_Error CurrentCBError;
386 static GSM_Error CurrentPhoneInfoError;
388 static unsigned char IMEI[FB61_MAX_IMEI_LENGTH];
389 static unsigned char Revision[FB61_MAX_REVISION_LENGTH];
390 static unsigned char Model[FB61_MAX_MODEL_LENGTH];
392 static char CurrentIncomingCall[20] = " ";
394 /* Pointer to callback function in user code to be called when RLP frames
397 void (*RLP_RXCallback)(RLP_F96Frame *frame);
399 /* Pointer to a callback function used to return changes to a calls status */
400 /* This saves unreliable polling */
401 void (*CallPassup)(char c);
404 /* called repeatedly from a separate thread */
405 void FB61_KeepAliveProc()
407 if (!DisableKeepalive)
408 FB61_TX_SendStatusRequest();
413 /* Initialise variables and state machine. */
415 GSM_Error FB61_Initialise(char *port_device, char *initlength,
416 GSM_ConnectionType connection,
417 void (*rlp_callback)(RLP_F96Frame *frame))
421 RequestTerminate = false;
423 RLP_RXCallback = rlp_callback;
426 strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
428 InitLength = atoi(initlength);
429 if (!strcmp(initlength, "default") || (InitLength == 0)) {
430 InitLength = 250; /* This is the usual value, lower may work. */
433 CurrentConnectionType = connection;
435 /* Create and start main thread. */
438 DisableKeepalive = true;
439 rtn = ! OpenConnection(PortDevice, FB61_RX_StateMachine, FB61_KeepAliveProc);
441 FB61_InitializeLink(); /* makes more sense to do this in 'this' thread */
442 DisableKeepalive = false;
445 rtn = pthread_create(&Thread, NULL, (void *)FB61_ThreadLoop, (void *)NULL);
449 return (GE_INTERNALERROR);
455 /* thread for handling incoming data */
456 void FB61_SelectLoop()
460 struct timeval timeout;
463 FD_SET(device_portfd, &readfds);
464 /* set timeout to 15 seconds */
467 while (!RequestTerminate) {
468 err = select(device_portfd + 1, &readfds, NULL, NULL, &timeout);
469 /* call singal handler to process incoming data */
470 if ( err > 0 ) FB61_SigHandler(0);
471 else if (err == -1) perror("Error in SelectLoop");
477 /* This function send the status request to the phone. */
479 GSM_Error FB61_TX_SendStatusRequest(void)
481 /* The status request is of the type 0x04. It's subtype is 0x01. If you have
482 another subtypes and it's meaning - just inform Pavel, please. */
483 unsigned char request[] = {FB61_FRAME_HEADER, 0x01};
484 FB61_TX_SendMessage(4, 0x04, request);
488 /* This function translates GMT_MemoryType to FB61_MEMORY_xx */
490 int FB61_GetMemoryType(GSM_MemoryType memory_type)
493 switch (memory_type) {
494 case GMT_MT: result = FB61_MEMORY_MT; break;
495 case GMT_ME: result = FB61_MEMORY_ME; break;
496 case GMT_SM: result = FB61_MEMORY_SM; break;
497 case GMT_FD: result = FB61_MEMORY_FD; break;
498 case GMT_ON: result = FB61_MEMORY_ON; break;
499 case GMT_EN: result = FB61_MEMORY_EN; break;
500 case GMT_DC: result = FB61_MEMORY_DC; break;
501 case GMT_RC: result = FB61_MEMORY_RC; break;
502 case GMT_MC: result = FB61_MEMORY_MC; break;
503 default: result = FB61_MEMORY_XX; break;
508 /* This function is used to get storage status from the phone. It currently
509 supports two different memory areas - internal and SIM. */
512 wait_on(volatile GSM_Error *what, int timeout)
515 while (timeout && (*what == GE_BUSY)) {
523 #define WAIT_ON(x, y) \
525 GSM_Error res = wait_on(x, y); \
526 if (res != GE_NONE) \
530 #define WAIT_ON1(x, y) \
532 GSM_Error res = wait_on(x, y); \
533 if (res != GE_NONE) \
537 static GSM_Error FB61_GetPhoneInfo()
539 unsigned char req[] = { FB61_FRAME_HEADER, 0x03, 0x00 };
540 FB61_TX_SendMessage(5, 0xd1, req);
541 return (wait_on(&CurrentPhoneInfoError, 20));
544 GSM_Error FB61_AnswerCall(char s)
546 unsigned char req0[] = { FB61_FRAME_HEADER, 0x42,0x05,0x01,0x07, 0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
547 0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80};
548 unsigned char req[] = { FB61_FRAME_HEADER, 0x06, 0x00, 0x00};
550 dprintf("Answering call %d\n\r",s);
551 FB61_TX_SendMessage(sizeof(req0), 0x01, req0);
553 FB61_TX_SendMessage(sizeof(req), 0x01, req);
554 return (wait_on(&CurrentPhoneInfoError, 20));
557 GSM_Error FB61_GetMemoryStatus(GSM_MemoryStatus *Status)
559 unsigned char req[] = { FB61_FRAME_HEADER, 0x07 /* MemoryStatus request */, 0x00 /* MemoryType */ };
560 CurrentMemoryStatus = Status;
561 req[4] = FB61_GetMemoryType(Status->MemoryType);
562 FB61_TX_SendMessage(5, 0x03, req);
563 return wait_on(&CurrentMemoryStatusError, 20);
566 GSM_Error FB61_GetNetworkInfo(GSM_NetworkInfo *NetworkInfo)
568 unsigned char req[] = { FB61_FRAME_HEADER, 0x70 };
569 CurrentNetworkInfo = NetworkInfo;
570 FB61_TX_SendMessage(4, 0x0a, req);
571 return wait_on(&CurrentNetworkInfoError, 20);
574 GSM_Error FB61_EnableDisplayOutput(void)
576 unsigned char req[] = { FB61_FRAME_HEADER, 0x53, 0x01};
577 FB61_TX_SendMessage(5, 0x0d, req);
578 return wait_on(&CurrentDisplayOutputError, 20);
581 GSM_Error FB61_DisableDisplayOutput(void)
583 unsigned char req[] = { FB61_FRAME_HEADER, 0x53, 0x02};
584 FB61_TX_SendMessage(5, 0x0d, req);
585 return wait_on(&CurrentDisplayOutputError, 20);
588 GSM_Error FB61_GetProfile(GSM_Profile *Profile)
591 /* Hopefully is 64 larger as FB38_MAX* / FB61_MAX* */
593 unsigned char name_req[] = { FB61_FRAME_HEADER, 0x1a, 0x00};
594 unsigned char feat_req[] = { FB61_FRAME_HEADER, 0x13, 0x01, 0x00, 0x00};
596 CurrentProfile = Profile;
598 name_req[4] = Profile->Number;
599 feat_req[5] = Profile->Number;
600 FB61_TX_SendMessage(5, 0x05, name_req);
602 WAIT_ON(&CurrentProfileError, 20);
604 for (i = 0x00; i <= 0x09; i++) {
605 CurrentProfileError = GE_BUSY;
607 FB61_TX_SendMessage(7, 0x05, feat_req);
608 WAIT_ON(&CurrentProfileError, 20);
611 if (Profile->DefaultName > -1)
613 while (FB61_GetModel(model) != GE_NONE)
617 /*FIX ME: It should be set for N5130 and 3210 too*/
618 if (!strcmp(model,"NSE-1")) {
619 switch (Profile->DefaultName) {
620 case 0x00: sprintf(Profile->Name, "Personal"); break;
621 case 0x01: sprintf(Profile->Name, "Car"); break;
622 case 0x02: sprintf(Profile->Name, "Headset"); break;
623 default: sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName); break;
626 switch (Profile->DefaultName) {
627 case 0x00: sprintf(Profile->Name, "General"); break;
628 case 0x01: sprintf(Profile->Name, "Silent"); break;
629 case 0x02: sprintf(Profile->Name, "Meeting"); break;
630 case 0x03: sprintf(Profile->Name, "Outdoor"); break;
631 case 0x04: sprintf(Profile->Name, "Pager"); break;
632 case 0x05: sprintf(Profile->Name, "Car"); break;
633 case 0x06: sprintf(Profile->Name, "Headset"); break;
634 default: sprintf(Profile->Name, "Unknown (%i)", Profile->DefaultName); break;
641 GSM_Error FB61_SetProfile(GSM_Profile *Profile)
644 unsigned char name_req[40] = { FB61_FRAME_HEADER, 0x1c, 0x01, 0x03, 0x00, 0x00, 0x00};
645 unsigned char feat_req[] = { FB61_FRAME_HEADER, 0x10, 0x01, 0x00, 0x00, 0x00};
647 name_req[7] = Profile->Number;
648 name_req[8] = strlen(Profile->Name);
649 name_req[6] = name_req[8] + 2;
651 for (i = 0; i < name_req[8]; i++)
652 name_req[9 + i] = Profile->Name[i];
654 FB61_TX_SendMessage(name_req[8] + 9, 0x05, name_req);
655 WAIT_ON(&CurrentProfileError, 30);
657 feat_req[5] = Profile->Number;
658 for (i = 0x00; i <= 0x09; i++) {
660 switch (feat_req[6]) {
661 case 0x00: feat_req[7] = Profile->KeypadTone; break;
662 case 0x01: feat_req[7] = Profile->Lights; break;
663 case 0x02: feat_req[7] = Profile->CallAlert; break;
664 case 0x03: feat_req[7] = Profile->Ringtone; break;
665 case 0x04: feat_req[7] = Profile->Volume; break;
666 case 0x05: feat_req[7] = Profile->MessageTone; break;
667 case 0x06: feat_req[7] = Profile->Vibration; break;
668 case 0x07: feat_req[7] = Profile->WarningTone; break;
669 case 0x08: feat_req[7] = Profile->CallerGroups; break;
670 case 0x09: feat_req[7] = Profile->AutomaticAnswer; break;
673 FB61_TX_SendMessage(8, 0x05, feat_req);
674 WAIT_ON(&CurrentProfileError, 20);
680 bool FB61_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
682 u8 req[60] = { 0x00, 0xd9 };
683 /* Discontinuos transmission (DTX). See section 5.6 of GSM 04.22 version 7.0.1. */
685 if (out_dtx) req[1] = 0x01;
686 memcpy(req + 2, (u8 *) frame, 32);
687 return (FB61_TX_SendFrame(32, 0xf0, req));
691 GSM_Error FB61_GetCalendarNote(GSM_CalendarNote *CalendarNote)
693 unsigned char req[5] = { FB61_FRAME_HEADER, 0x66, 0x00 };
694 req[4] = CalendarNote->Location;
695 CurrentCalendarNote = CalendarNote;
696 CurrentCalendarNoteError = GE_BUSY;
697 FB61_TX_SendMessage(5, 0x13, req);
698 return wait_on(&CurrentCalendarNoteError, 20);
701 GSM_Error FB61_WriteCalendarNote(GSM_CalendarNote *CalendarNote)
703 unsigned char req[200] = { FB61_FRAME_HEADER,
705 0x00, /* Length of the rest of the frame. */
706 0x00, /* The type of calendar note */
707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
712 req[7] = CalendarNote->Type;
714 req[8] = CalendarNote->Time.Year / 256;
715 req[9] = CalendarNote->Time.Year % 256;
716 req[10] = CalendarNote->Time.Month;
717 req[11] = CalendarNote->Time.Day;
718 req[12] = CalendarNote->Time.Hour;
719 req[13] = CalendarNote->Time.Minute;
720 req[14] = CalendarNote->Time.Timezone;
722 if (CalendarNote->Alarm.Year) {
723 req[15] = CalendarNote->Alarm.Year / 256;
724 req[16] = CalendarNote->Alarm.Year % 256;
725 req[17] = CalendarNote->Alarm.Month;
726 req[18] = CalendarNote->Alarm.Day;
727 req[19] = CalendarNote->Alarm.Hour;
728 req[20] = CalendarNote->Alarm.Minute;
729 req[21] = CalendarNote->Alarm.Timezone;
732 req[22] = strlen(CalendarNote->Text);
736 for (i=0; i<strlen(CalendarNote->Text); i++)
737 req[current++] = CalendarNote->Text[i];
739 req[current++] = strlen(CalendarNote->Phone);
741 for (i=0; i<strlen(CalendarNote->Phone); i++)
742 req[current++] = CalendarNote->Phone[i];
744 CurrentCalendarNote = CalendarNote;
745 CurrentCalendarNoteError = GE_BUSY;
747 FB61_TX_SendMessage(current, 0x13, req);
748 return wait_on(&CurrentCalendarNoteError, 20);
751 GSM_Error FB61_DeleteCalendarNote(GSM_CalendarNote *CalendarNote)
753 unsigned char req[] = { FB61_FRAME_HEADER, 0x68, 0x00 };
754 req[4] = CalendarNote->Location;
755 CurrentCalendarNoteError = GE_BUSY;
756 FB61_TX_SendMessage(5, 0x13, req);
757 return wait_on(&CurrentCalendarNoteError, 20);
760 /* Init ir for win32 is made in winserial.c */
763 void FB61_InitIR(void)
766 unsigned char init_char = FB61_SYNC_BYTE;
767 unsigned char end_init_char = FB61_IR_END_INIT_BYTE;
769 for ( i = 0; i < 32; i++ )
770 device_write(&init_char, 1);
772 device_write(&end_init_char, 1);
776 bool FB61_InitIR115200(void)
779 u8 connect_seq[] = {FB61_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
784 struct timeval timeout;
790 /* send the connection sequence to phone */
791 FB61_TX_SendMessage(7, 0x02, connect_seq);
793 /* Wait for 1 sec. */
797 PortFD = device_getfd();
801 FD_SET(PortFD, &ready);
802 no_timeout = select(PortFD + 1, &ready, NULL, NULL, &timeout);
803 if ( FD_ISSET(PortFD, &ready) ) {
804 nr_read = read(PortFD, in_buffer, 1);
805 if ( nr_read >= 1 ) {
806 for (i = 0; i < nr_read; i++) {
807 if ( in_buffer[i] == FB61_IR_FRAME_ID ) {
820 dprintf(_("Timeout in IR-mode\n"));
829 /* This function is used to open the IR connection with the phone. */
831 bool FB61_OpenIR(void)
840 struct sigaction sig_io;
842 /* Set up and install handler before enabling async IO on port. */
844 sig_io.sa_handler = FB61_SigHandler;
846 sigaction (SIGIO, &sig_io, NULL);
851 result = device_open(PortDevice, false, true, false, GCT_Infrared);
854 perror(_("Couldn't open FB61 infrared device"));
859 /* create a thread to handle incoming data from mobile phone */
860 rtn = pthread_create(&selThread, NULL, (void*)FB61_SelectLoop, (void*)NULL);
861 if (rtn != 0) return false;
864 device_changespeed(9600);
866 device_changespeed(115200);
867 ret = FB61_InitIR115200();
869 for ( i = 0; i < 4 ; i++) {
871 device_changespeed(9600);
873 device_changespeed(115200);
874 ret = FB61_InitIR115200();
882 static void FB61_Authentication()
884 unsigned char connect1[] = {FB61_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
885 unsigned char connect2[] = {FB61_FRAME_HEADER, 0x20, 0x02};
886 unsigned char connect3[] = {FB61_FRAME_HEADER, 0x0d, 0x01, 0x00, 0x02};
887 unsigned char connect4[] = {FB61_FRAME_HEADER, 0x10};
889 unsigned char magic_connect[] = {FB61_FRAME_HEADER,
892 /* The real magic goes here ... These bytes are filled in with the
893 external function FB61_GetNokiaAuth(). */
895 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
898 /* NOKIA&GNOKII Accessory */
900 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x26, 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x20,
901 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79,
903 0x00, 0x00, 0x00, 0x00};
905 usleep(100); FB61_GetPhoneInfo(); usleep(100);
907 if (*Model && (GetPhoneModel(Model)->flags & PM_AUTHENTICATION)) {
908 FB61_TX_SendMessage(7, 0x02, connect1);
909 usleep(100); FB61_TX_SendMessage(5, 0x02, connect2);
910 usleep(100); FB61_TX_SendMessage(7, 0x02, connect3);
911 usleep(100); FB61_TX_SendMessage(4, 0x64, connect4);
913 WAIT_ON1(&CurrentMagicError, 50);
915 FB61_GetNokiaAuth(IMEI, MagicBytes, magic_connect+4);
917 FB61_TX_SendMessage(45, 0x64, magic_connect);
923 /* This is the main loop for the FB61 functions. When FB61_Initialise is
924 called a thread is created to run this loop. This loop is exited when the
925 application calls the FB61_Terminate function. */
926 void FB61_ThreadLoop(void)
928 unsigned char init_char = 0x55;
929 int count, idle_timer;
931 CurrentPhonebookEntry = NULL;
933 if ( CurrentConnectionType == GCT_Infrared ) {
934 dprintf(_("Starting IR mode...!\n"));
935 if (FB61_OpenIR() != true) {
937 while (!RequestTerminate)
942 } else { /* CurrentConnectionType == GCT_Serial */
944 /* Try to open serial port, if we fail we sit here and don't proceed to the
947 if (FB61_OpenSerial() != true) {
950 /* Fail so sit here till calling code works out there is a problem. */
952 while (!RequestTerminate)
959 /* Initialise link with phone or what have you */
961 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
964 for (count = 0; count < InitLength; count ++) {
966 WRITEPHONE(PortFD, &init_char, 1);
969 FB61_TX_SendStatusRequest();
971 FB61_Authentication();
973 /* FIXME: we should implement better support for ringtones and the utility
976 // FB61_SendRingtoneRTTTL("/tmp/barbie.txt");
980 /* Now enter main loop */
982 while (!RequestTerminate) {
983 if (idle_timer == 0) {
984 /* Dont send keepalive and status packets when doing other transactions. */
985 if (!DisableKeepalive) FB61_TX_SendStatusRequest();
990 usleep(100000); /* Avoid becoming a "busy" loop. */
996 void FB61_InitializeLink()
1001 unsigned char init_char = 0x55;
1003 unsigned char end_init_char = 0xc1;
1005 /* Daxer Added for infared support */
1006 if ( CurrentConnectionType == GCT_Infrared ) {
1007 dcb.DCBlength = sizeof(DCB);
1009 GetCommState(hPhone, &dcb);
1010 dcb.BaudRate = CBR_9600;
1011 SetCommState(hPhone, &dcb);
1014 /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
1017 for (count = 0; count < 32; count ++) {
1019 WRITEPHONE(PortFD, &init_char, 1);
1022 WRITEPHONE(PortFD, &end_init_char, 1);
1024 if ( CurrentConnectionType == GCT_Infrared ) {
1025 dcb.BaudRate = CBR_115200;
1026 SetCommState(hPhone, &dcb);
1029 FB61_TX_SendStatusRequest();
1031 FB61_Authentication();
1035 /* Applications should call FB61_Terminate to shut down the FB61 thread and
1036 close the serial port. */
1038 void FB61_Terminate(void)
1040 /* Request termination of thread */
1041 RequestTerminate = true;
1044 /* Now wait for thread to terminate. */
1045 pthread_join(Thread, NULL);
1047 /* Close serial port. */
1055 #define ByteMask ((1 << Bits) - 1)
1057 int UnpackEightBitsToSeven(int offset, int in_length, int out_length,
1058 unsigned char *input, unsigned char *output)
1060 unsigned char *OUT = output; /* Current pointer to the output buffer */
1061 unsigned char *IN = input; /* Current pointer to the input buffer */
1062 unsigned char Rest = 0x00;
1065 Bits = offset ? offset : 7;
1067 while ((IN - input) < in_length) {
1069 *OUT = ((*IN & ByteMask) << (7 - Bits)) | Rest;
1072 /* If we don't start from 0th bit, we shouldn't go to the
1073 next char. Under *OUT we have now 0 and under Rest -
1074 _first_ part of the char. */
1075 if ((IN != input) || (Bits == 7)) OUT++;
1078 if ((OUT - output) >= out_length) break;
1080 /* After reading 7 octets we have read 7 full characters but
1081 we have 7 bits as well. This is the next character */
1092 return OUT - output;
1095 unsigned char GetAlphabetValue(unsigned char value)
1099 if (value == '?') return 0x3f;
1101 for (i = 0 ; i < 128 ; i++)
1102 if (GSM_Default_Alphabet[i] == value)
1105 return 0x3f; /* '?' */
1108 int PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output)
1110 unsigned char *OUT = output; /* Current pointer to the output buffer */
1111 unsigned char *IN = input; /* Current pointer to the input buffer */
1112 int Bits; /* Number of bits directly copied to
1113 the output buffer */
1114 Bits = (7 + offset) % 8;
1116 /* If we don't begin with 0th bit, we will write only a part of the
1123 while ((IN - input) < strlen(input)) {
1124 unsigned char Byte = GetAlphabetValue(*IN);
1126 *OUT = Byte >> (7 - Bits);
1127 /* If we don't write at 0th bit of the octet, we should write
1128 a second part of the previous octet */
1130 *(OUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
1134 if (Bits == -1) Bits = 7;
1139 return (OUT - output);
1142 GSM_Error FB61_GetRFLevel(GSM_RFUnits *units, float *level)
1144 /* FIXME - these values are from 3810 code, may be incorrect. Map from
1145 values returned in status packet to the the values returned by the AT+CSQ
1147 float csq_map[5] = {0, 8, 16, 24, 31};
1151 CurrentRFLevel = -1;
1153 FB61_TX_SendStatusRequest();
1155 /* Wait for timeout or other error. */
1157 while (timeout && (CurrentRFLevel == -1)) {
1159 return (GE_TIMEOUT);
1163 /* Make copy in case it changes. */
1164 rf_level = CurrentRFLevel;
1169 /* Now convert between the different units we support. */
1171 /* Arbitrary units. */
1172 if (*units == GRF_Arbitrary) {
1178 if (*units == GRF_CSQ) {
1181 *level = csq_map[rf_level];
1183 *level = 99; /* Unknown/undefined */
1188 *units = GRF_Arbitrary;
1193 GSM_Error FB61_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
1198 CurrentBatteryLevel = -1;
1200 FB61_TX_SendStatusRequest();
1202 /* Wait for timeout or other error. */
1203 while (timeout && (CurrentBatteryLevel == -1)) {
1205 return (GE_TIMEOUT);
1209 /* Take copy in case it changes. */
1210 batt_level = CurrentBatteryLevel;
1212 if (batt_level != -1) {
1213 /* Only units we handle at present are GBU_Arbitrary */
1214 *units = GBU_Arbitrary;
1215 *level = batt_level;
1217 } else return (GE_NOLINK);
1220 GSM_Error FB61_GetPowerSource(GSM_PowerSource *source)
1223 CurrentPowerSource=-1;
1225 FB61_TX_SendStatusRequest();
1227 /* Wait for timeout or other error. */
1228 while (timeout && (CurrentPowerSource == -1)) {
1230 return (GE_TIMEOUT);
1234 if (CurrentPowerSource != -1) {
1235 *source = CurrentPowerSource;
1237 } else return (GE_NOLINK);
1240 GSM_Error FB61_GetDisplayStatus(int *Status)
1242 unsigned char req[4]={ FB61_FRAME_HEADER, 0x51 };
1243 FB61_TX_SendMessage(4, 0x0d, req);
1244 WAIT_ON(&DisplayStatusError, 10);
1245 *Status = DisplayStatus;
1249 GSM_Error FB61_DialVoice(char *Number)
1251 unsigned char req[64] = {FB61_FRAME_HEADER, 0x01};
1252 unsigned char req_end[] = {0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
1255 req[4] = strlen(Number);
1256 for(i = 0; i < strlen(Number) ; i++)
1257 req[5+i] = Number[i];
1258 memcpy(req + 5 + strlen(Number), req_end, 10);
1259 FB61_TX_SendMessage(13 + strlen(Number), 0x01, req);
1264 /* Dial a data call - type specifies request to use:
1265 type 0 should normally be used
1266 type 1 should be used when calling a digital line - corresponds to ats35=0
1267 Maybe one day we'll know what they mean!
1270 GSM_Error FB61_DialData(char *Number, char type, void (* callpassup)(char c))
1272 unsigned char req[100] = { FB61_FRAME_HEADER, 0x01 };
1273 unsigned char *req_end;
1274 unsigned char req_end0[] = { 0x01, /* make a data call = type 0x01 */
1275 0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
1276 0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00 };
1277 unsigned char req_end1[] = { 0x01,
1278 0x02,0x01,0x05,0x81,0x01,0x00,0x00,0x01,0x02,0x0a,
1279 0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
1280 0x88,0x90,0x21,0x48,0x40,0xbb };
1281 unsigned char req2[] = { FB61_FRAME_HEADER, 0x42,0x05,0x01,
1282 0x07,0xa2,0xc8,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
1283 0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80,0x01,0x60 };
1284 unsigned char req3[] = { FB61_FRAME_HEADER, 0x42,0x05,0x01,
1285 0x07,0xa2,0x88,0x81,0x21,0x15,0x63,0xa8,0x00,0x00,
1286 0x07,0xa3,0xb8,0x81,0x20,0x15,0x63,0x80 };
1287 unsigned char req4[] = { FB61_FRAME_HEADER, 0x42,0x05,0x81,
1288 0x07,0xa1,0x88,0x89,0x21,0x15,0x63,0xa0,0x00,0x06,
1289 0x88,0x90,0x21,0x48,0x40,0xbb,0x07,0xa3,0xb8,0x81,
1290 0x20,0x15,0x63,0x80 };
1295 CallPassup=callpassup;
1300 size = sizeof(req_end0);
1303 FB61_TX_SendMessage(sizeof(req3), 0x01, req3);
1304 FB61_TX_SendMessage(sizeof(req4), 0x01, req4);
1306 size = sizeof(req_end1);
1308 case -1: /* Just used to set the call passup */
1313 size = sizeof(req_end0);
1317 req[4] = strlen(Number);
1319 for(i = 0; i < strlen(Number) ; i++)
1320 req[5+i] = Number[i];
1322 memcpy(req + 5 + strlen(Number), req_end, size);
1324 FB61_TX_SendMessage(5 + size + strlen(Number), 0x01, req);
1325 if (type != 1) FB61_TX_SendMessage(26, 0x01, req2);
1330 GSM_Error FB61_GetIncomingCallNr(char *Number)
1332 if (*CurrentIncomingCall != ' ') {
1333 strcpy(Number, CurrentIncomingCall);
1335 } else return GE_BUSY;
1338 GSM_Error FB61_CancelCall(void)
1340 unsigned char req[] = { FB61_FRAME_HEADER, 0x08, 0x00, 0x85};
1342 req[4] = CallSequenceNumber;
1343 FB61_TX_SendMessage(6, 0x01, req);
1348 GSM_Error FB61_EnterSecurityCode(GSM_SecurityCode SecurityCode)
1350 unsigned char req[15] = { FB61_FRAME_HEADER, 0x0a /* Enter code request. */, 0x00 /* Type of the entered code. */ };
1352 req[4] = SecurityCode.Type;
1353 for (i = 0; i < strlen(SecurityCode.Code); i++)
1354 req[5+i] = SecurityCode.Code[i];
1355 req[5+strlen(SecurityCode.Code)] = 0x00;
1356 req[6+strlen(SecurityCode.Code)] = 0x00;
1357 FB61_TX_SendMessage(7+strlen(SecurityCode.Code), 0x08, req);
1358 return wait_on(&CurrentSecurityCodeError, 20);
1361 GSM_Error FB61_GetSecurityCodeStatus(int *Status)
1363 unsigned char req[4] = { FB61_FRAME_HEADER, 0x07 };
1364 CurrentSecurityCodeStatus=Status;
1365 FB61_TX_SendMessage(4, 0x08, req);
1366 return wait_on(&CurrentSecurityCodeError, 20);
1369 GSM_Error FB61_GetDateTime(GSM_DateTime *date_time)
1371 unsigned char req[] = {FB61_FRAME_HEADER, 0x62};
1372 CurrentDateTime = date_time;
1373 FB61_TX_SendMessage(4, 0x11, req);
1374 return wait_on(&CurrentDateTimeError, 5);
1377 GSM_Error FB61_GetAlarm(int alarm_number, GSM_DateTime *date_time)
1379 unsigned char req[] = {FB61_FRAME_HEADER, 0x6d};
1380 CurrentAlarm = date_time;
1381 FB61_TX_SendMessage(4, 0x11, req);
1382 return wait_on(&CurrentAlarmError, 5);
1385 /* This function sends to the mobile phone a request for the SMS Center */
1387 GSM_Error FB61_GetSMSCenter(GSM_MessageCenter *MessageCenter)
1389 unsigned char req[10] = { FB61_FRAME_HEADER, 0x33, 0x64, 0x00 /* SMS Center Number. */ };
1390 req[5] = MessageCenter->No;
1391 CurrentMessageCenter = MessageCenter;
1392 FB61_TX_SendMessage(6, 0x02, req);
1393 return wait_on(&CurrentMessageCenterError, 10);
1396 /* This function set the SMS Center profile on the phone. */
1398 GSM_Error FB61_SetSMSCenter(GSM_MessageCenter *MessageCenter)
1400 unsigned char req[64] = { FB61_FRAME_HEADER, 0x30, 0x64,
1401 0x00, /* SMS Center Number. */
1402 0x00, /* Unknown. */
1403 0x00, /* SMS Message Format. */
1404 0x00, /* Unknown. */
1405 0x00, /* Validity. */
1406 0,0,0,0,0,0,0,0,0,0,0,0, /* Unknown. */
1407 0,0,0,0,0,0,0,0,0,0,0,0 /* Message Center Number. */
1408 /* Message Center Name. */
1410 req[5] = MessageCenter->No;
1411 req[7] = MessageCenter->Format;
1412 req[9] = MessageCenter->Validity;
1414 req[22] = SemiOctetPack(MessageCenter->Number, req+23);
1415 if (req[22] % 2) req[22]++;
1416 req[22] = req[22] / 2 + 1;
1418 sprintf(req+34, "%s", MessageCenter->Name);
1420 CurrentMessageCenter = MessageCenter;
1421 CurrentMessageCenterError = GE_BUSY;
1423 FB61_TX_SendMessage(35+strlen(MessageCenter->Name), 0x02, req);
1424 return wait_on(&CurrentMessageCenterError,20);
1427 GSM_Error FB61_GetSMSStatus(GSM_SMSStatus *Status)
1429 unsigned char req[] = {FB61_FRAME_HEADER, 0x36, 0x64};
1430 CurrentSMSStatus = Status;
1431 FB61_TX_SendMessage(5, 0x14, req);
1432 return wait_on(&CurrentSMSStatusError,20);
1435 GSM_Error FB61_GetIMEI(char *imei)
1438 strncpy (imei, IMEI, FB61_MAX_IMEI_LENGTH);
1440 } else return (GE_TRYAGAIN);
1443 GSM_Error FB61_GetRevision(char *revision)
1446 strncpy (revision, Revision, FB61_MAX_REVISION_LENGTH);
1448 } else return (GE_TRYAGAIN);
1451 GSM_Error FB61_GetModel(char *model)
1454 strncpy (model, Model, FB61_MAX_MODEL_LENGTH);
1456 } else return (GE_TRYAGAIN);
1459 GSM_Error FB61_SetDateTime(GSM_DateTime *date_time)
1461 unsigned char req[] = { FB61_FRAME_HEADER,
1462 0x60, /* set-time subtype */
1463 0x01, 0x01, 0x07, /* unknown */
1464 0x00, 0x00, /* Year (0x07cf = 1999) */
1465 0x00, 0x00, /* Month Day */
1466 0x00, 0x00, /* Hours Minutes */
1467 0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
1469 req[7] = date_time->Year / 256;
1470 req[8] = date_time->Year % 256;
1471 req[9] = date_time->Month;
1472 req[10] = date_time->Day;
1473 req[11] = date_time->Hour;
1474 req[12] = date_time->Minute;
1476 FB61_TX_SendMessage(14, 0x11, req);
1477 return wait_on(&CurrentSetDateTimeError, 20);
1480 /* FIXME: we should also allow to set the alarm off :-) */
1482 GSM_Error FB61_SetAlarm(int alarm_number, GSM_DateTime *date_time)
1484 unsigned char req[] = { FB61_FRAME_HEADER,
1485 0x6b, /* set-alarm subtype */
1486 0x01, 0x20, 0x03, /* unknown */
1487 0x02, /* should be alarm on/off, but it don't works */
1488 0x00, 0x00, /* Hours Minutes */
1489 0x00 /* Unknown, but not seconds - try 59 and wait 1 sec. */
1491 req[8] = date_time->Hour;
1492 req[9] = date_time->Minute;
1494 FB61_TX_SendMessage(11, 0x11, req);
1495 return wait_on(&CurrentSetAlarmError, 20);
1498 /* Routine to get specifed phone book location. Designed to be called by
1499 application. Will block until location is retrieved or a timeout/error
1502 GSM_Error FB61_GetMemoryLocation(GSM_PhonebookEntry *entry)
1504 unsigned char req[] = {FB61_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
1506 CurrentPhonebookEntry = entry;
1507 req[4] = FB61_GetMemoryType(entry->MemoryType);
1508 req[5] = entry->Location;
1509 FB61_TX_SendMessage(7, 0x03, req);
1510 return wait_on(&CurrentPhonebookError, 20);
1513 /* Routine to write phonebook location in phone. Designed to be called by
1514 application code. Will block until location is written or timeout
1517 GSM_Error FB61_WritePhonebookLocation(GSM_PhonebookEntry *entry)
1519 unsigned char req[128] = { FB61_FRAME_HEADER, 0x04, 0x00, 0x00 };
1520 int i = 0, current = 0;
1522 req[4] = FB61_GetMemoryType(entry->MemoryType);
1523 req[5] = entry->Location;
1525 req[6] = strlen(entry->Name);
1529 for (i = 0; i<strlen(entry->Name); i++)
1530 req[current+i] = entry->Name[i];
1532 current += strlen(entry->Name);
1534 req[current++] = strlen(entry->Number);
1536 for (i = 0; i < strlen(entry->Number); i++)
1537 req[current+i] = entry->Number[i];
1539 current += strlen(entry->Number);
1541 /* Jano: This allow to save 14 characters name into SIM memory, when
1542 No Group is selected. */
1544 if (entry->Group == 5)
1545 req[current++] = 0xff;
1547 req[current++] = entry->Group;
1549 FB61_TX_SendMessage(current, 3, req);
1550 return wait_on(&CurrentPhonebookError, 50);
1553 GSM_Error FB61_NetMonitor(unsigned char mode, char *Screen)
1555 unsigned char req1[] = { 0x00, 0x01, 0x64, 0x01 };
1556 unsigned char req2[] = { 0x00, 0x01, 0x7e, 0x00 };
1558 CurrentNetmonitor = Screen;
1559 FB61_TX_SendMessage(4, 0x40, req1);
1561 FB61_TX_SendMessage(4, 0x40, req2);
1562 return wait_on(&CurrentNetmonitorError, 20);
1565 GSM_Error FB61_SendDTMF(char *String)
1567 unsigned char req[64] = { FB61_FRAME_HEADER, 0x50, 0x00 /* Length of DTMF string. */ };
1568 u8 length=strlen(String);
1571 sprintf(req+5, "%s", String);
1572 FB61_TX_SendMessage(5+length, 0x01, req);
1576 GSM_Error FB61_GetSpeedDial(GSM_SpeedDial *entry)
1578 unsigned char req[10] = { FB61_FRAME_HEADER, 0x16, 0x00 /* The number of speed dial. */ };
1579 CurrentSpeedDialEntry = entry;
1580 req[4] = entry->Number;
1581 FB61_TX_SendMessage(5, 0x03, req);
1582 return wait_on(&CurrentSpeedDialError, 20);
1585 GSM_Error FB61_SetSpeedDial(GSM_SpeedDial *entry)
1587 unsigned char req[7] = { FB61_FRAME_HEADER, 0x19, 0x00 /* Number */, 0x00 /* Memory Type */, 0x00 /* Location */ };
1588 req[4] = entry->Number;
1589 req[5] = entry->MemoryType;
1590 req[6] = entry->Location;
1591 FB61_TX_SendMessage(7, 0x03, req);
1592 return wait_on(&CurrentSpeedDialError, 20);
1595 GSM_Error FB61_GetSMSMessage(GSM_SMSMessage *message)
1597 unsigned char req[10] = { FB61_FRAME_HEADER, 0x07, 0x02 /* Unknown */, 0x00 /* Location */, 0x01, 0x64};
1600 /* State machine code writes data to these variables when it comes in. */
1602 CurrentSMSMessage = message;
1603 CurrentSMSMessageError = GE_BUSY;
1604 req[5] = message->Location;
1605 FB61_TX_SendMessage(8, 0x02, req);
1607 while (timeout && (CurrentSMSMessageError == GE_BUSY || CurrentSMSMessageError == GE_SMSWAITING)) {
1609 return (GE_TIMEOUT);
1612 return (CurrentSMSMessageError);
1615 GSM_Error FB61_DeleteSMSMessage(GSM_SMSMessage *message)
1617 unsigned char req[] = {FB61_FRAME_HEADER, 0x0a, 0x02, 0x00};
1618 CurrentSMSMessageError = GE_BUSY;
1619 req[5] = message->Location;
1620 FB61_TX_SendMessage(6, 0x14, req);
1621 return wait_on(&CurrentSMSMessageError, 50);
1624 /* This function implements packing of numbers (SMS Center number and
1625 destination number) for SMS sending function. */
1627 int SemiOctetPack(char *Number, unsigned char *Output)
1629 unsigned char *IN = Number; /* Pointer to the input number */
1630 unsigned char *OUT = Output; /* Pointer to the output */
1631 int count = 0; /* This variable is used to notify us about count of already
1634 /* The first byte in the Semi-octet representation of the address field is
1635 the Type-of-Address. This field is described in the official GSM
1636 specification 03.40 version 5.3.0, section 9.1.2.5, page 33. We support
1637 only international and unknown number. */
1640 *OUT++ = GNT_INTERNATIONAL; /* International number */
1642 } else *OUT++ = GNT_UNKNOWN; /* Unknown number */
1644 /* The next field is the number. It is in semi-octet representation - see
1645 GSM scpecification 03.40 version 5.3.0, section 9.1.2.3, page 31. */
1649 *OUT = *OUT | ((*IN - '0') << 4);
1657 /* We should also fill in the most significant bits of the last byte with
1658 0x0f (1111 binary) if the number is represented with odd number of
1664 return (2 * (OUT - Output - 1) - 1);
1667 return (2 * (OUT - Output - 1));
1670 /* The second argument is the size of the data in octets,
1671 excluding User Data Header - important only for 8bit data */
1672 GSM_Error FB61_SendSMSMessage(GSM_SMSMessage *SMS, int data_size)
1676 unsigned char req[256] = {
1678 0x01, 0x02, 0x00, /* SMS send request*/
1679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* SMS center, the rest is unused */
1680 0x11, /* 0 - TP-Reply-Path (9.2.3.17)
1681 0 - TP-TP-User-Data-Header-Indicator (9.2.3.23)
1682 x - TP-Status-Report-Request (9.2.3.5)
1683 0 - no delivery report (default for gnokii)
1684 1 - request for delivry report
1685 xx - TP validity period (9.2.3.3, see also 9.2.3.12)
1687 10 - relative format (default for gnokii)
1688 01 - enhanced format
1689 11 - absolute format
1690 no support for this field yet
1691 0 - TP-Reject-Duplicates (9.2.3.25)
1692 01 - TP-Message-Type-Indicator (9.2.3.1) - SMS_SUBMIT */
1693 0x00, /* TP-Message-Reference (9.2.3.6) */
1694 0x00, /* TP-Protocol-Identifier (9.2.3.9) */
1695 0x00, /* TP-Data-Coding-Scheme (9.2.3.10, GSM 03.38) */
1696 0x00, /* TP-User-Data-Length (9.2.3.16) */
1697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* destination */
1698 0xa9, /* SMS validity: b0=1h 47=6h a7=24h a9=72h ad=1week */
1699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1704 /* First of all we should get SMSC number */
1705 if (SMS->MessageCenter.No) {
1706 error = FB61_GetSMSCenter(&SMS->MessageCenter);
1707 if (error != GE_NONE)
1709 SMS->MessageCenter.No = 0;
1711 dprintf(_("Sending SMS to %s via message center %s\n"), SMS->Destination, SMS->MessageCenter.Number);
1714 /* offset - length of the user data header */
1715 offset = 1 + SMS->UDH[0];
1716 /* we copy the udh and set the mask for the indicator */
1717 memcpy(req + 42, SMS->UDH, offset);
1721 /* such messages should be sent as concatenated */
1722 if (strlen(SMS->MessageText) > GSM_MAX_SMS_LENGTH)
1723 return(GE_SMSTOOLONG);
1726 /* size is the length of the data in octets including udh */
1728 - integer representation of the number od octets within the user data when UD is coded using 8bit data
1729 - the sum of the number of septets in UDH including any padding and number of septets in UD in other case
1732 /* offset now denotes UDH length */
1733 if (SMS->EightBit) {
1734 memcpy(req + 42 + offset, SMS->MessageText, data_size);
1735 SMS->Length = size = data_size + offset;
1736 /* the mask for the 8-bit data */
1739 size = PackSevenBitsToEight((7-offset)%7, SMS->MessageText, req + 42 + offset);
1741 SMS->Length = (offset*8 + ((7-offset)%7)) / 7 + strlen(SMS->MessageText);
1744 req[22] = SMS->Length;
1746 CurrentSMSMessageError=GE_BUSY;
1748 req[6] = SemiOctetPack(SMS->MessageCenter.Number, req+7);
1749 if (req[6] % 2) req[6]++;
1751 req[6] = req[6] / 2 + 1;
1753 /* Mask for request for delivery report from SMSC */
1754 if (SMS->Type == GST_DR) req[18] |= 0x20;
1757 switch (SMS->Class) {
1758 case 0: req[21] |= 0xf0; break;
1759 case 1: req[21] |= 0xf1; break;
1760 case 2: req[21] |= 0xf2; break;
1761 case 3: req[21] |= 0xf3; break;
1765 /* Mask for compression */
1766 /* FIXME: support for compression */
1768 /* if (SMS->Compression) req[21] = req[21] | 0x20; */
1770 req[23] = SemiOctetPack(SMS->Destination, req+24);
1772 /* TP-Validity Period handling */
1774 /* FIXME: error-checking for correct Validity - it should not be bigger then
1775 63 weeks and smaller then 5minutes. We should also test intervals because
1776 the SMS->Validity to TP-VP is not continuos. I think that the simplest
1777 solution will be an array of correct values. We should parse it and if we
1778 find the closest TP-VP value we should use it. Or is it good to take
1779 closest smaller TP-VP as we do now? I think it is :-) */
1781 /* 5 minutes intervals up to 12 hours = 720 minutes */
1782 if (SMS->Validity <= 720)
1783 req[35] = (unsigned char) (SMS->Validity/5)-1;
1785 /* 30 minutes intervals up to 1 day */
1786 else if ((SMS->Validity > 720) && (SMS->Validity <= 1440))
1787 req[35] = (unsigned char) ((SMS->Validity-720)/30)+143;
1789 /* 1 day intervals up to 30 days */
1790 else if ((SMS->Validity > 1440) && (SMS->Validity <= 43200))
1791 req[35] = (unsigned char) (SMS->Validity/1440)+166;
1793 /* 1 week intervals up to 63 weeks */
1794 else if ((SMS->Validity > 43200) && (SMS->Validity <= 635040))
1795 req[35] = (unsigned char) (SMS->Validity/10080)+192;
1797 FB61_TX_SendMessage(42+size, 0x02, req);
1798 return wait_on(&CurrentSMSMessageError, 70);
1801 GSM_Error FB61_SaveSMSMessage(GSM_SMSMessage *SMS)
1803 unsigned char req[256] = {
1805 0x04, 0x05, 0x02, 0x00, 0x02, /* SMS save request*/
1806 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* SMS center, the rest is unused */
1807 0x11, /* 0 - TP-Reply-Path (9.2.3.17)
1808 0 - TP-TP-User-Data-Header-Indicator (9.2.3.23)
1809 x - TP-Status-Report-Request (9.2.3.5)
1810 0 - no delivery report (default for gnokii)
1811 1 - request for delivry report
1812 xx - TP validity period (9.2.3.3, see also 9.2.3.12)
1814 10 - relative format (default for gnokii)
1815 01 - enhanced format
1816 11 - absolute format
1817 no support for this field yet
1818 0 - TP-Reject-Duplicates (9.2.3.25)
1819 01 - TP-Message-Type-Indicator (9.2.3.1) - SMS_SUBMIT */
1820 0x00, /* TP-Message-Reference (9.2.3.6) */
1821 0x00, /* TP-Protocol-Identifier (9.2.3.9) */
1822 0x00, /* TP-Data-Coding-Scheme (9.2.3.10, GSM 03.38) */
1823 0x00, /* TP-User-Data-Length (9.2.3.16) */
1824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* destination */
1825 0xa9, /* SMS validity: b0=1h 47=6h a7=24h a9=72h ad=1week */
1826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1831 if (SMS->Status == GSS_NOTSENTREAD)
1835 req[6] = SMS->Location;
1838 /* such messages should be sent as concatenated */
1839 if (strlen(SMS->MessageText) > GSM_MAX_SMS_LENGTH)
1840 return(GE_SMSTOOLONG);
1842 /* size is the length of the data in octets including udh */
1844 - integer representation of the number od octets within the user data when UD is coded using 8bit data
1845 - the sum of the number of septets in UDH including any padding and number of septets in UD in other case
1848 /* offset now denotes UDH length */
1849 size = PackSevenBitsToEight((7-offset)%7, SMS->MessageText, req + 44 + offset);
1851 SMS->Length = (offset*8 + ((7-offset)%7)) / 7 + strlen(SMS->MessageText);
1853 req[24] = SMS->Length;
1854 FB61_TX_SendMessage(44+size, 0x14, req);
1855 return wait_on(&CurrentSMSMessageError, 70);
1858 /* Enable and disable Cell Broadcasting */
1860 GSM_Error FB61_EnableCellBroadcast(void)
1862 unsigned char req[] = {FB61_FRAME_HEADER, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01};
1863 CurrentCBError = GE_BUSY;
1865 CurrentCBMessage = (GSM_CBMessage *)malloc(sizeof (GSM_CBMessage));
1866 CurrentCBMessage->Channel = 0;
1867 CurrentCBMessage->New = false;
1868 strcpy (CurrentCBMessage->Message,"");
1869 FB61_TX_SendMessage(10, 0x02, req);
1870 return wait_on(&CurrentCBError, 20);
1873 GSM_Error FB61_DisableCellBroadcast(void) /* Should work, but not tested fully */
1875 unsigned char req[] = {FB61_FRAME_HEADER, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*VERIFY*/
1876 FB61_TX_SendMessage(10, 0x02, req);
1877 return wait_on(&CurrentCBError, 20);
1880 GSM_Error FB61_ReadCellBroadcast(GSM_CBMessage *Message)
1882 if (CurrentCBMessage != NULL) {
1883 if (CurrentCBMessage->New == true) {
1884 Message->Channel = CurrentCBMessage->Channel;
1885 strcpy(Message->Message,CurrentCBMessage->Message);
1886 CurrentCBMessage->New = false;
1890 return (GE_NONEWCBRECEIVED);
1893 /* Send a bitmap or welcome-note */
1895 GSM_Error FB61_SetBitmap(GSM_Bitmap *Bitmap)
1897 unsigned char req[600] = { FB61_FRAME_HEADER };
1901 switch (Bitmap->type) {
1902 case GSM_WelcomeNoteText:
1903 req[count++] = 0x18;
1904 req[count++] = 0x01; /* Only one block */
1905 req[count++] = 0x02; /* Welcome text */
1906 req[count++] = textlen = strlen(Bitmap->text);
1907 memcpy(req+count, Bitmap->text, textlen);
1910 FB61_TX_SendMessage(count, 0x05, req);
1913 case GSM_DealerNoteText:
1914 req[count++] = 0x18;
1915 req[count++] = 0x01; /* Only one block */
1916 req[count++] = 0x03; /* Dealer Welcome Note */
1917 req[count++] = textlen = strlen(Bitmap->text);
1918 memcpy(req+count, Bitmap->text, textlen);
1921 FB61_TX_SendMessage(count, 0x05, req);
1924 case GSM_StartupLogo:
1925 req[count++] = 0x18;
1926 req[count++] = 0x01; /* Only one block */
1927 req[count++] = 0x01;
1928 req[count++] = Bitmap->height;
1929 req[count++] = Bitmap->width;
1930 memcpy(req+count, Bitmap->bitmap, Bitmap->size);
1931 count += Bitmap->size;
1932 FB61_TX_SendMessage(count, 0x05, req);
1935 case GSM_OperatorLogo:
1936 req[count++] = 0x30; /* Store Op Logo */
1937 req[count++] = 0x01; /* Location */
1938 req[count++] = ((Bitmap->netcode[1] & 0x0f) << 4) | (Bitmap->netcode[0] & 0x0f);
1939 req[count++] = 0xf0 | (Bitmap->netcode[2] & 0x0f);
1940 req[count++] = ((Bitmap->netcode[5] & 0x0f) << 4) | (Bitmap->netcode[4] & 0x0f);
1941 req[count++] = (Bitmap->size+4) >> 8;
1942 req[count++] = (Bitmap->size+4)%0xff;
1943 req[count++] = 0x00; /* Infofield */
1944 req[count++] = Bitmap->width;
1945 req[count++] = Bitmap->height;
1946 req[count++] = 0x01; /* Just BW */
1947 memcpy(req+count, Bitmap->bitmap, Bitmap->size);
1948 FB61_TX_SendMessage(count+Bitmap->size, 0x05, req);
1951 case GSM_CallerLogo:
1952 req[count++] = 0x13;
1953 req[count++] = Bitmap->number;
1954 req[count++] = strlen(Bitmap->text);
1955 memcpy(req+count, Bitmap->text, req[count-1]);
1956 count += req[count-1];
1957 req[count++]= Bitmap->ringtone;
1958 req[count++]= 0x01; /* Graphic on. You can use other values as well:
1961 0x02 - View Graphics
1962 0x03 - Send Graphics
1964 You can even set it higher but Nokia phones (my
1965 6110 at least) will not show you the name of this
1966 item in menu ;-)) Nokia is really joking here. */
1967 req[count++] = (Bitmap->size + 4) >> 8;
1968 req[count++] = (Bitmap->size + 4) % 0xff;
1969 req[count++] = 0x00; /* Future extensions! */
1970 req[count++] = Bitmap->width;
1971 req[count++] = Bitmap->height;
1972 req[count++] = 0x01; /* Just BW */
1973 memcpy(req+count, Bitmap->bitmap, Bitmap->size);
1974 FB61_TX_SendMessage(count+Bitmap->size, 0x03, req);
1977 case GSM_PictureImage:
1978 return (GE_NOTIMPLEMENTED);
1984 return wait_on(&SetBitmapError, 70);
1987 /* Get a bitmap from the phone */
1989 GSM_Error FB61_GetBitmap(GSM_Bitmap *Bitmap)
1991 unsigned char req[10] = { FB61_FRAME_HEADER };
1996 GetBitmapError = GE_BUSY;
1998 /* This is needed to avoid the packet being interrupted */
1999 /* Remove when multipacket code is implemented fully */
2001 DisableKeepalive = true;
2003 while (timeout && (MessagesSent != AcksReceived)) {
2008 /* We'll assume that nothing more will be received after 1 sec */
2010 MessagesSent = AcksReceived;
2012 switch (GetBitmap->type) {
2013 case GSM_StartupLogo:
2014 req[count++] = 0x16;
2015 FB61_TX_SendMessage(count, 0x05, req);
2017 case GSM_WelcomeNoteText:
2018 req[count++] = 0x16;
2019 FB61_TX_SendMessage(count, 0x05, req);
2021 case GSM_DealerNoteText:
2022 req[count++] = 0x16;
2023 FB61_TX_SendMessage(count, 0x05, req);
2025 case GSM_OperatorLogo:
2026 req[count++] = 0x33;
2027 req[count++] = 0x01; /* Location 1 */
2028 FB61_TX_SendMessage(count, 0x05, req);
2030 case GSM_CallerLogo:
2031 req[count++] = 0x10;
2032 req[count++] = Bitmap->number;
2033 FB61_TX_SendMessage(count, 0x03, req);
2039 /* 5secs for the command to complete */
2041 WAIT_ON(&GetBitmapError, 50);
2043 DisableKeepalive = false;
2045 return (GetBitmapError);
2049 GSM_Error FB61_SetRingTone(GSM_Ringtone *ringtone)
2051 char package[GSM_MAX_RINGTONE_PACKAGE_LENGTH+10] =
2052 { 0x0c, 0x01, /* FBUS RingTone header */
2053 /* Next bytes are from Smart Messaging Specification version 2.0.0 */
2054 0x06, /* User Data Header Length */
2055 0x05, /* IEI FIXME: What is this? */
2056 0x04, /* IEDL FIXME: What is this? */
2057 0x15, 0x81, /* Destination port */
2058 0x15, 0x81 /* Originator port, only
2062 int size = GSM_MAX_RINGTONE_PACKAGE_LENGTH;
2063 GSM_PackRingtone(ringtone, package+9, &size);
2064 package[size+9] = 0x01;
2065 FB61_TX_SendMessage((size+10), 0x12, package);
2069 GSM_Error FB61_SendRingTone(GSM_Ringtone *ringtone, char *dest)
2074 int size = GSM_MAX_RINGTONE_PACKAGE_LENGTH;
2075 char Package[GSM_MAX_RINGTONE_PACKAGE_LENGTH];
2077 0x06, /* User Data Header Length */
2080 0x15, 0x81, /* Destination port */
2081 0x15, 0x81 /* Originator port, only
2086 /* Default settings for SMS message:
2087 - no delivery report
2093 - set UserDataHeaderIndicator
2098 SMS.Compression = false;
2099 SMS.EightBit = true;
2100 SMS.MessageCenter.No = 1;
2101 SMS.Validity = 4320; /* 4320 minutes == 72 hours */
2103 SMS.UDHType = GSM_RingtoneUDH;
2105 strcpy(SMS.Destination, dest);
2106 GSM_PackRingtone(ringtone, Package, &size);
2107 memcpy(SMS.UDH, udh, 7);
2108 memcpy(SMS.MessageText, Package, size);
2110 /* Send the message. */
2111 error = FB61_SendSMSMessage(&SMS, size);
2113 if (error == GE_SMSSENDOK) dprintf(_("Send succeeded!\n"));
2114 else dprintf(_("SMS Send failed (error=%d)\n"), error);
2119 GSM_Error FB61_Reset(unsigned char type)
2121 unsigned char req[4] = { 0x00,0x01,0x64,0x03 };
2123 FB61_TX_SendMessage(4, 0x40, req);
2129 void FB61_DumpSerial(void)
2132 unsigned int Flags=0;
2134 PortFD = device_getfd();
2135 ioctl(PortFD, TIOCMGET, &Flags);
2137 dprintf(_("Serial flags dump:\n"));
2138 dprintf(_("DTR is %s.\n"), Flags&TIOCM_DTR?_("up"):_("down"));
2139 dprintf(_("RTS is %s.\n"), Flags&TIOCM_RTS?_("up"):_("down"));
2140 dprintf(_("CAR is %s.\n"), Flags&TIOCM_CAR?_("up"):_("down"));
2141 dprintf(_("CTS is %s.\n"), Flags&TIOCM_CTS?_("up"):_("down"));
2145 /* This functions set up the Nokia DAU-9P MBus Cable NSE-3 which is probably
2146 dual MBUS/FBUS to FBUS communication. If we skip this step we can
2147 communicate with the phone, but the phone sends us some garbagge (0x18 0x00
2150 This was brought to my attention by people with original cable. My cable is
2151 FBUS only so I borrow the original cable from my friend and solve
2152 it. Thanks to Cobus, Juan and people on the mailing list.
2156 The data suite cable has some electronics built into the connector. This of
2157 course needs a power supply of some sorts to operate properly.
2159 In this case power is drawn off the handshaking lines of the PC. DTR has to
2160 be set and RTS have to be cleared, thus if you use a terminal program (that
2161 does not set the handshaking lines to these conditions) you will get weird
2162 results. It will not set them like this since if Request To Send (RTS) is
2163 not set the other party will not send any data (in hardware handshaking)
2164 and if DTS is not set (handshaking = none) the cable will not receive
2167 /* FIXME: In this function we use ioctls - can people with different OSes than
2168 my (Linux) tell me if it works for them? */
2170 void FB61_SetFBUS(void)
2174 dprintf(_("Setting FBUS communication...\n"));
2177 /* clearing the RTS bit and setting the DTR bit*/
2178 device_setdtrrts(1, 0);
2185 /* Called by initialisation code to open comm port in asynchronous mode. */
2187 bool FB61_OpenSerial(void)
2194 struct sigaction sig_io;
2196 /* Set up and install handler before enabling async IO on port. */
2198 sig_io.sa_handler = FB61_SigHandler;
2199 sig_io.sa_flags = 0;
2200 sigaction (SIGIO, &sig_io, NULL);
2205 result = device_open(PortDevice, false, true, false, GCT_Serial);
2208 perror(_("Couldn't open FB61 device"));
2213 /* create a thread to handle incoming data from mobile phone */
2214 rtn = pthread_create(&selThread, NULL, (void*)FB61_SelectLoop, (void*)NULL);
2215 if (rtn != 0) return false;
2218 device_changespeed(115200);
2223 void FB61_SigHandler(int status)
2225 unsigned char buffer[255];
2227 res = device_read(buffer, 255);
2228 for (count = 0; count < res ; count ++)
2229 FB61_RX_StateMachine(buffer[count]);
2233 char *FB61_GetBCDNumber(u8 *Number)
2235 static char Buffer[20] = "";
2237 /* This is the length of BCD coded number */
2238 int length = Number[0];
2241 if (Number[1] == 0x91) sprintf(Buffer, "+");
2242 else Buffer[0] = '\0';
2244 for (count = 0; count < length-1; count++) {
2246 Digit = Number[count+2] & 0x0f;
2247 if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
2248 Digit = Number[count+2] >> 4;
2249 if (Digit < 10) sprintf(Buffer, "%s%d", Buffer, Digit);
2255 char *FB61_GetPackedDateTime(u8 *Number)
2257 static char Buffer[20] = "";
2259 sprintf(Buffer, "%d%d-", Number[0] & 0xf, Number[0] >> 4);
2260 sprintf(Buffer, "%s%d%d-", Buffer, Number[1] & 0xf, Number[1] >> 4);
2261 sprintf(Buffer, "%s%d%d ", Buffer, Number[2] & 0xf, Number[2] >> 4);
2262 sprintf(Buffer, "%s%d%d:", Buffer, Number[3] & 0xf, Number[3] >> 4);
2263 sprintf(Buffer, "%s%d%d:", Buffer, Number[4] & 0xf, Number[4] >> 4);
2264 sprintf(Buffer, "%s%d%d", Buffer, Number[5] & 0xf, Number[5] >> 4);
2269 enum FB61_RX_States FB61_RX_DispatchMessage(void)
2271 int i, tmp, count, offset, off, length;
2272 unsigned char output[160];
2275 if (RX_Multiple) return FB61_RX_Sync;
2278 /* Do not debug Ack and RLP frames to detail. */
2280 if (MessageType != FB61_FRTYPE_ACK && MessageType != 0xf1)
2281 FB61_RX_DisplayMessage();
2284 /* Switch on the basis of the message type byte */
2285 switch (MessageType) {
2286 case 0x01: /* Call information */
2287 switch (MessageBuffer[3]) {
2288 /* Unknown message - it has been seen after the 0x07 message (call
2289 answered). Probably it has similar meaning. If you can solve
2290 this - just mail me. Pavel JanÃk ml.
2292 The message looks like this:
2300 Phone: [01 ][08 ][00 ] is the header of the frame
2302 [03 ] is the call message subtype
2304 [05 ] is the call sequence number
2308 [00 ][01 ][03 ][02 ][91][00] are unknown but has been
2309 seen in the Incoming call message (just after the
2310 caller's name from the phonebook). But never change
2311 between phone calls :-(
2314 case 0x02: /* This may mean sequence number of 'just made' call - CK */
2315 dprintf(_("Message: Call message, type 0x02:"));
2316 dprintf(_(" Exact meaning not known yet, sorry :-(\n"));
2319 case 0x03: /* Possibly call OK */
2320 /* JD: I think that this means "call in progress" (incomming or outgoing) */
2321 dprintf(_("Message: Call message, type 0x03:"));
2322 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2323 dprintf(_(" Exact meaning not known yet, sorry :-(\n"));
2324 CallSequenceNumber = MessageBuffer[4];
2325 CurrentIncomingCall[0] = 'D';
2326 if (CallPassup) CallPassup('D');
2329 /* Remote end has gone away before you answer the call. Probably your
2330 mother-in-law or banker (which is worse?) ... */
2332 dprintf(_("Message: Remote end hang up.\n"));
2333 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2334 CurrentIncomingCall[0] = ' ';
2335 if (CallPassup) CallPassup(' ');
2338 case 0x05: /* Incoming call alert */
2339 dprintf(_("Message: Incoming call alert:\n"));
2340 /* We can have more then one call ringing - we can distinguish between
2342 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2343 dprintf(_(" Number: "));
2344 count = MessageBuffer[6];
2345 for (tmp = 0; tmp < count; tmp++)
2346 dprintf("%c", MessageBuffer[7+tmp]);
2348 dprintf(_(" Name: "));
2349 for (tmp = 0; tmp < MessageBuffer[7+count]; tmp++)
2350 dprintf("%c", MessageBuffer[8+count+tmp]);
2352 count = MessageBuffer[6];
2353 CurrentIncomingCall[0] = 0;
2354 for (tmp = 0; tmp < count; tmp++)
2355 sprintf(CurrentIncomingCall, "%s%c", CurrentIncomingCall, MessageBuffer[7+tmp]);
2356 if (CallPassup) CallPassup(MessageBuffer[4]);
2359 /* Call answered. Probably your girlfriend...*/
2361 dprintf(_("Message: Call answered.\n"));
2362 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2365 /* Call ended. Girlfriend is girlfriend, but time is money :-) */
2367 dprintf(_("Message: Call ended by your phone.\n"));
2368 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2371 /* This message has been seen with the message of subtype 0x09
2372 after I hang the call.
2379 Phone: [01 ][08 ][00 ][0a ][04 ][87 ][01 ][42B][1a ][c2 ]
2381 What is the meaning of 87? Can you spell some magic light into
2386 case 0x0a: /* Probably means call over - CK */
2387 dprintf(_("Message: Call message, type 0x0a:"));
2388 dprintf(_(" Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2389 dprintf(_(" Exact meaning not known yet, sorry :-(\n"));
2391 CurrentIncomingCall[0] = ' ';
2392 if (CallPassup) CallPassup(' ');
2396 dprintf(_("Message: Unknown message of type 0x01\n"));
2404 switch (MessageBuffer[3]) {
2405 case 0x02: /* SMS message correctly sent to the network */
2406 dprintf(_("Message: SMS Message correctly sent.\n"));
2407 CurrentSMSMessageError = GE_SMSSENDOK;
2410 case 0x03: /* SMS message send to the network failed */
2411 dprintf(_("Message: Sending SMS Message failed.\n"));
2412 CurrentSMSMessageError = GE_SMSSENDFAILED;
2416 dprintf(_("Message: SMS Message Received\n"));
2417 dprintf(_(" SMS center number: %s\n"), FB61_GetBCDNumber(MessageBuffer+7));
2419 MessageBuffer[23] = (MessageBuffer[23]+1)/2+1;
2421 dprintf(_(" Remote number: %s\n"), FB61_GetBCDNumber(MessageBuffer+23));
2422 dprintf(_(" Date: %s\n"), FB61_GetPackedDateTime(MessageBuffer+35));
2423 dprintf(_(" SMS: "));
2425 tmp = UnpackEightBitsToSeven(0, MessageLength - 42 - 2, MessageBuffer[22], MessageBuffer + 42, output);
2427 for (i = 0; i < tmp; i++) dprintf("%c", GSM_Default_Alphabet[output[i]]);
2433 dprintf(_("Message: Cell Broadcast enabled/disabled successfully.\n"));
2434 CurrentCBError = GE_NONE;
2438 CurrentCBMessage->Channel = MessageBuffer[7];
2439 CurrentCBMessage->New = true;
2440 tmp=UnpackEightBitsToSeven(0, 82, 82, MessageBuffer+10, output);
2442 dprintf(_("Message: CB received.\n")); fflush (stdout);
2443 dprintf(_("Message: channel number %i\n"),MessageBuffer[7]);
2444 for (i=0; i<tmp;i++)
2445 dprintf("%c", GSM_Default_Alphabet[output[i]]);
2448 for (i = 0; i < tmp; i++)
2449 CurrentCBMessage->Message[i] = GSM_Default_Alphabet[output[i]];
2455 dprintf(_("Message: SMS Center correctly set.\n"));
2456 CurrentMessageCenterError = GE_NONE;
2461 CurrentMessageCenter->No = MessageBuffer[4];
2462 CurrentMessageCenter->Format = MessageBuffer[6];
2463 CurrentMessageCenter->Validity = MessageBuffer[8];
2464 sprintf(CurrentMessageCenter->Name, "%s", MessageBuffer+33);
2465 sprintf(CurrentMessageCenter->Number, "%s", FB61_GetBCDNumber(MessageBuffer+21));
2467 dprintf(_("Message: SMS Center received:\n"));
2468 dprintf(_(" %d. SMS Center name is %s\n"), CurrentMessageCenter->No, CurrentMessageCenter->Name);
2469 dprintf(_(" SMS Center number is %s\n"), CurrentMessageCenter->Number);
2470 dprintf(_(" SMS Center message format is "));
2472 switch (CurrentMessageCenter->Format) {
2473 case GSMF_Text: dprintf(_("Text")); break;
2474 case GSMF_Paging: dprintf(_("Paging")); break;
2475 case GSMF_Fax: dprintf(_("Fax")); break;
2476 case GSMF_Email: dprintf(_("Email")); break;
2477 default: dprintf(_("Unknown")); break;
2482 dprintf(_(" SMS Center message validity is "));
2484 switch (CurrentMessageCenter->Validity) {
2485 case GSMV_1_Hour: dprintf(_("1 hour")); break;
2486 case GSMV_6_Hours: dprintf(_("6 hours")); break;
2487 case GSMV_24_Hours: dprintf(_("24 hours")); break;
2488 case GSMV_72_Hours: dprintf(_("72 hours")); break;
2489 case GSMV_1_Week: dprintf(_("1 week")); break;
2490 case GSMV_Max_Time: dprintf(_("Maximum time")); break;
2491 default: dprintf(_("Unknown")); break;
2494 CurrentMessageCenterError = GE_NONE;
2498 /* Nokia 6110 has support for three SMS centers with numbers 1, 2 and
2499 3. Each request for SMS Center without one of these numbers
2501 dprintf(_("Message: SMS Center error received:\n"));
2502 dprintf(_(" The request for SMS Center failed.\n"));
2504 /* FIXME: appropriate error. */
2505 CurrentMessageCenterError = GE_INTERNALERROR;
2509 dprintf(_("Unknown message!\n"));
2515 /* Phonebook handling */
2519 switch (MessageBuffer[3]) {
2523 CurrentPhonebookEntry->Empty = true;
2525 count = MessageBuffer[5];
2526 dprintf(_("Message: Phonebook entry received:\n"));
2527 dprintf(_(" Name: "));
2528 for (tmp = 0; tmp < count; tmp++)
2529 dprintf("%c", MessageBuffer[6+tmp]);
2532 memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
2533 CurrentPhonebookEntry->Name[count] = 0x00;
2534 CurrentPhonebookEntry->Empty = false;
2537 count = MessageBuffer[6+count];
2539 dprintf(_(" Number: "));
2540 for (tmp = 0; tmp < count; tmp++)
2541 dprintf("%c", MessageBuffer[i+tmp]);
2544 memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
2545 CurrentPhonebookEntry->Number[count] = 0x00;
2546 CurrentPhonebookEntry->Group = MessageBuffer[i+count];
2548 CurrentPhonebookEntry->Date.Year = MessageBuffer[i+count+2] * 256 + MessageBuffer[i+count+3];
2549 CurrentPhonebookEntry->Date.Month = MessageBuffer[i+count+4];
2550 CurrentPhonebookEntry->Date.Day = MessageBuffer[i+count+5];
2551 CurrentPhonebookEntry->Date.Hour = MessageBuffer[i+count+6];
2552 CurrentPhonebookEntry->Date.Minute = MessageBuffer[i+count+7];
2553 CurrentPhonebookEntry->Date.Second = MessageBuffer[i+count+8];
2555 dprintf(_(" Date: "));
2556 dprintf("%02u-%02u-%04u\n", CurrentPhonebookEntry->Date.Day, CurrentPhonebookEntry->Date.Month, CurrentPhonebookEntry->Date.Year);
2557 dprintf(_(" Time: "));
2558 dprintf("%02u-%02u-%02u\n", CurrentPhonebookEntry->Date.Hour, CurrentPhonebookEntry->Date.Minute, CurrentPhonebookEntry->Date.Second);
2560 /* Signal no error to calling code. */
2562 CurrentPhonebookError = GE_NONE;
2567 dprintf(_("Message: Phonebook read entry error received:\n"));
2568 switch (MessageBuffer[4]) {
2570 dprintf(_(" Invalid memory type!\n"));
2571 CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
2574 dprintf(_(" Unknown error!\n"));
2575 CurrentPhonebookError = GE_INTERNALERROR;
2581 dprintf(_("Message: Phonebook written correctly.\n"));
2582 CurrentPhonebookError = GE_NONE;
2586 switch (MessageBuffer[4]) {
2588 /* FIXME: other errors? When I send the phonebook with index of 350 it
2589 still report error 0x7d :-( */
2592 dprintf(_("Message: Phonebook not written - name is too long.\n"));
2593 CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
2597 dprintf(_(" Unknown error!\n"));
2598 CurrentPhonebookError = GE_INTERNALERROR;
2605 dprintf(_("Message: Memory status received:\n"));
2606 dprintf(_(" Memory Type: %s\n"), FB61_MemoryType_String[MessageBuffer[4]]);
2607 dprintf(_(" Used: %d\n"), MessageBuffer[6]);
2608 dprintf(_(" Free: %d\n"), MessageBuffer[5]);
2609 CurrentMemoryStatus->Used = MessageBuffer[6];
2610 CurrentMemoryStatus->Free = MessageBuffer[5];
2611 CurrentMemoryStatusError = GE_NONE;
2615 switch (MessageBuffer[4]) {
2617 dprintf(_("Message: Memory status error, phone is probably powered off.\n"));
2618 CurrentMemoryStatusError = GE_TIMEOUT;
2622 dprintf(_("Message: Memory status error, memory type not supported by phone model.\n"));
2623 CurrentMemoryStatusError = GE_INTERNALERROR;
2627 dprintf(_("Message: Memory status error, waiting for security code.\n"));
2628 CurrentMemoryStatusError = GE_INVALIDSECURITYCODE;
2632 dprintf(_("Message: Unknown Memory status error, subtype (MessageBuffer[4]) = %02x\n"),MessageBuffer[4]);
2638 case 0x11: /* Get group data */
2640 /* [ID],[name_len],[name].,[ringtone],[graphicon],[lenhi],[lenlo],[bitmap] */
2642 if (GetBitmap != NULL) {
2643 count = MessageBuffer[5];
2644 memcpy(GetBitmap->text, MessageBuffer+6, count);
2645 GetBitmap->text[count] = 0;
2647 dprintf(_("Message: Caller group logo etc.\n"));
2648 dprintf(_("Caller group name: %s\n"), GetBitmap->text);
2651 GetBitmap->ringtone = MessageBuffer[count++];
2653 GetBitmap->size = MessageBuffer[count++]<<8;
2654 GetBitmap->size += MessageBuffer[count++];
2656 GetBitmap->width = MessageBuffer[count++];
2657 GetBitmap->height = MessageBuffer[count++];
2659 tmp = GetBitmap->height * GetBitmap->width / 8;
2660 if (GetBitmap->size > tmp) GetBitmap->size = tmp;
2661 memcpy(GetBitmap->bitmap, MessageBuffer+count, GetBitmap->size);
2662 GetBitmapError = GE_NONE;
2665 dprintf(_("Message: Caller group data received but not requested!\n"));
2669 case 0x12: /* Get group data error */
2670 GetBitmapError = GE_UNKNOWN;
2671 dprintf(_("Message: Error attempting to get caller group data.\n"));
2674 case 0x14: /* Set group data OK */
2675 SetBitmapError = GE_NONE;
2676 dprintf(_("Message: Caller group data set correctly.\n"));
2679 case 0x15: /* Set group data error */
2680 SetBitmapError = GE_UNKNOWN;
2681 dprintf(_("Message: Error attempting to set caller group data\n"));
2685 CurrentSpeedDialEntry->MemoryType = MessageBuffer[4];
2686 CurrentSpeedDialEntry->Location = MessageBuffer[5];
2687 dprintf(_("Message: Speed dial entry received:\n"));
2688 dprintf(_(" Location: %d\n"), CurrentSpeedDialEntry->Location);
2689 dprintf(_(" MemoryType: %s\n"), FB61_MemoryType_String[CurrentSpeedDialEntry->MemoryType]);
2690 dprintf(_(" Number: %d\n"), CurrentSpeedDialEntry->Number);
2691 CurrentSpeedDialError = GE_NONE;
2695 dprintf(_("Message: Speed dial entry error\n"));
2696 CurrentSpeedDialError = GE_INVALIDSPEEDDIALLOCATION;
2700 dprintf(_("Message: Speed dial entry set.\n"));
2701 CurrentSpeedDialError = GE_NONE;
2705 dprintf(_("Message: Speed dial entry setting error.\n"));
2706 CurrentSpeedDialError = GE_INVALIDSPEEDDIALLOCATION;
2710 dprintf(_("Message: Unknown message of type 0x03\n"));
2719 switch (MessageBuffer[3]) {
2721 dprintf(_("Message: Phone status received:\n"));
2722 dprintf(_(" Mode: "));
2723 switch (MessageBuffer[4]) {
2724 case 0x01: dprintf(_("registered within the network\n")); break;
2725 /* I was really amazing why is there a hole in the type of 0x02, now I
2727 case 0x02: dprintf(_("call in progress\n")); /* ringing or already answered call */ break;
2728 case 0x03: dprintf(_("waiting for security code\n")); break;
2729 case 0x04: dprintf(_("powered off\n")); break;
2730 default: dprintf(_("unknown\n")); break;
2732 dprintf(_(" Power source: "));
2733 switch (MessageBuffer[7]) {
2734 case 0x01: dprintf(_("AC/DC\n")); break;
2735 case 0x02: dprintf(_("battery\n")); break;
2736 default: dprintf(_("unknown\n")); break;
2738 dprintf(_(" Battery Level: %d\n"), MessageBuffer[8]);
2739 dprintf(_(" Signal strength: %d\n"), MessageBuffer[5]);
2741 CurrentRFLevel = MessageBuffer[5];
2742 CurrentBatteryLevel = MessageBuffer[8];
2743 CurrentPowerSource = MessageBuffer[7];
2747 dprintf(_("Message: Unknown message of type 0x04\n"));
2753 /* Startup Logo, Operator Logo and Profiles. */
2756 switch (MessageBuffer[3]) {
2757 case 0x11: /* Profile feature change result */
2758 dprintf(_("Message: Profile feature change result.\n"));
2759 CurrentProfileError = GE_NONE;
2762 case 0x14: /* Profile feature */
2763 switch (MessageBuffer[6]) {
2765 CurrentProfile->KeypadTone = MessageBuffer[8];
2768 CurrentProfile->Lights = MessageBuffer[8];
2771 CurrentProfile->CallAlert = MessageBuffer[8];
2774 CurrentProfile->Ringtone = MessageBuffer[8];
2777 CurrentProfile->Volume = MessageBuffer[8];
2780 CurrentProfile->MessageTone = MessageBuffer[8];
2783 CurrentProfile->Vibration = MessageBuffer[8];
2786 CurrentProfile->WarningTone = MessageBuffer[8];
2789 CurrentProfile->CallerGroups = MessageBuffer[8];
2792 CurrentProfile->AutomaticAnswer = MessageBuffer[8];
2796 CurrentProfileError = GE_NONE;
2799 case 0x17: /* Startup Logo */
2800 dprintf(_("Message: Startup Logo, welcome note and dealer welcome note received.\n"));
2801 if (GetBitmap != NULL) {
2804 for (tmp = 0; tmp < MessageBuffer[4]; tmp++){
2805 switch (MessageBuffer[count++]) {
2807 if (GetBitmap->type == GSM_StartupLogo) {
2808 GetBitmap->height = MessageBuffer[count++];
2809 GetBitmap->width = MessageBuffer[count++];
2810 GetBitmap->size = GetBitmap->height * GetBitmap->width / 8;
2811 length = GetBitmap->size;
2812 memcpy(GetBitmap->bitmap, MessageBuffer + count, length);
2814 length = MessageBuffer[count++];
2815 length = length * MessageBuffer[count++] / 8;
2818 dprintf(_("Startup logo supported - "));
2819 if (length != 0) dprintf(_("currently set\n"));
2820 else dprintf(_("currently empty\n"));
2821 if (GetBitmap->type == GSM_StartupLogo) supported = true;
2824 length = MessageBuffer[count];
2825 if (GetBitmap->type == GSM_WelcomeNoteText) {
2826 memcpy(GetBitmap->text, MessageBuffer + count + 1, length);
2827 GetBitmap->text[length] = 0;
2829 dprintf(_("Startup Text supported - "));
2831 dprintf(_("currently set to \""));
2832 for (i = 0; i < length; i++) dprintf(_("%c"), MessageBuffer[count+1+i]);
2835 dprintf(_("currently empty\n"));
2837 count += length + 1;
2838 if (GetBitmap->type == GSM_WelcomeNoteText) supported = true;
2841 length = MessageBuffer[count];
2842 if (GetBitmap->type == GSM_DealerNoteText) {
2843 memcpy(GetBitmap->text, MessageBuffer + count + 1, length);
2844 GetBitmap->text[length] = 0;
2846 dprintf(_("Dealer Welcome supported - "));
2848 dprintf(_("currently set to \""));
2849 for (i = 0;i < length; i++) dprintf(_("%c"), MessageBuffer[count+1+i]);
2851 } else dprintf(_("currently empty\n"));
2852 count += length + 1;
2853 if (GetBitmap->type==GSM_DealerNoteText) supported = true;
2857 if (supported) GetBitmapError = GE_NONE;
2858 else GetBitmapError = GE_NOTSUPPORTED;
2859 } else dprintf(_("Message: Startup logo received but not requested!\n"));
2862 case 0x19: /* Set startup OK */
2863 SetBitmapError = GE_NONE;
2864 dprintf(_("Message: Startup logo, welcome note or dealer welcome note correctly set.\n"));
2867 case 0x1b: /* Incoming profile name */
2868 if (MessageBuffer[9] == 0x00)
2869 CurrentProfile->DefaultName = MessageBuffer[8];
2871 CurrentProfile->DefaultName = -1;
2872 sprintf(CurrentProfile->Name, MessageBuffer + 10, MessageBuffer[9]);
2873 CurrentProfile->Name[MessageBuffer[9]] = '\0';
2875 CurrentProfileError = GE_NONE;
2878 case 0x1d: /* Profile name set result */
2879 CurrentProfileError = GE_NONE;
2882 case 0x31: /* Set Operator Logo OK */
2883 dprintf(_("Message: Operator logo correctly set.\n"));
2884 SetBitmapError = GE_NONE;
2887 case 0x32: /* Set Operator Logo Error */
2888 SetBitmapError = GE_UNKNOWN;
2889 dprintf(_("Message: Error setting operator logo!\n"));
2892 case 0x34: /* Operator Logo */
2893 /* [location],[netcode x 3],[lenhi],[lenlo],[bitmap] */
2894 if (GetBitmap != NULL) {
2895 count = 5; /* Location ignored. */
2896 /* Network code is stored as 0xBA 0xXC 0xED ("ABC DE"). */
2897 GetBitmap->netcode[0] = '0' + (MessageBuffer[count] & 0x0f);
2898 GetBitmap->netcode[1] = '0' + (MessageBuffer[count++] >> 4);
2899 GetBitmap->netcode[2] = '0' + (MessageBuffer[count++] & 0x0f);
2900 GetBitmap->netcode[3] = ' ';
2901 GetBitmap->netcode[4] = '0' + (MessageBuffer[count] & 0x0f);
2902 GetBitmap->netcode[5] = '0' + (MessageBuffer[count++] >> 4);
2903 GetBitmap->netcode[6] = 0;
2904 dprintf(_("Message: Operator Logo for %s (%s) network received.\n"),
2906 GSM_GetNetworkName(GetBitmap->netcode));
2907 GetBitmap->size = MessageBuffer[count++] << 8;
2908 GetBitmap->size += MessageBuffer[count++];
2910 GetBitmap->width = MessageBuffer[count++];
2911 GetBitmap->height = MessageBuffer[count++];
2913 tmp = GetBitmap->height * GetBitmap->width / 8;
2914 if (GetBitmap->size > tmp) GetBitmap->size = tmp;
2915 memcpy(GetBitmap->bitmap, MessageBuffer + count, GetBitmap->size);
2916 GetBitmapError = GE_NONE;
2918 else dprintf(_("Message: Operator logo received but not requested!\n"));
2921 case 0x35: /* Get op logo error */
2922 dprintf(_("Message: Error getting operator logo!\n"));
2923 GetBitmapError = GE_UNKNOWN;
2928 /* Security code requests */
2931 switch(MessageBuffer[3]) {
2933 *CurrentSecurityCodeStatus = MessageBuffer[4];
2934 dprintf(_("Message: Security Code status received: "));
2935 switch(*CurrentSecurityCodeStatus) {
2936 case GSCT_SecurityCode: dprintf(_("waiting for Security Code.\n")); break;
2937 case GSCT_Pin: dprintf(_("waiting for PIN.\n")); break;
2938 case GSCT_Pin2: dprintf(_("waiting for PIN2.\n")); break;
2939 case GSCT_Puk: dprintf(_("waiting for PUK.\n")); break;
2940 case GSCT_Puk2: dprintf(_("waiting for PUK2.\n")); break;
2941 case GSCT_None: dprintf(_("nothing to enter.\n")); break;
2942 default: dprintf(_("Unknown!\n")); break;
2944 CurrentSecurityCodeError = GE_NONE;
2948 dprintf(_("Message: Security code accepted.\n"));
2949 CurrentSecurityCodeError = GE_NONE;
2953 dprintf(_("Message: Security code is wrong. You're not my big owner :-)\n"));
2954 CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2964 switch (MessageBuffer[3]) {
2966 /* Make sure we are expecting NetworkInfo frame */
2967 if (CurrentNetworkInfo && CurrentNetworkInfoError == GE_BUSY) {
2968 sprintf(CurrentNetworkInfo->NetworkCode, "%x%x%x %x%x", MessageBuffer[14] & 0x0f, MessageBuffer[14] >>4, MessageBuffer[15] & 0x0f, MessageBuffer[16] & 0x0f, MessageBuffer[16] >> 4);
2969 sprintf(CurrentNetworkInfo->CellID, "%02x%02x", MessageBuffer[10], MessageBuffer[11]);
2970 sprintf(CurrentNetworkInfo->LAC, "%02x%02x", MessageBuffer[12], MessageBuffer[13]);
2972 dprintf(_("Message: Network information:\n"));
2974 dprintf(_(" CellID: %s\n"), CurrentNetworkInfo->CellID);
2975 dprintf(_(" LAC: %s\n"), CurrentNetworkInfo->LAC);
2976 dprintf(_(" Network code: %s\n"), CurrentNetworkInfo->NetworkCode);
2977 dprintf(_(" Network name: %s (%s)\n"),
2978 GSM_GetNetworkName(CurrentNetworkInfo->NetworkCode),
2979 GSM_GetCountryName(CurrentNetworkInfo->NetworkCode));
2980 dprintf(_(" Status: "));
2982 switch (MessageBuffer[8]) {
2983 case 0x01: dprintf(_("home network selected")); break;
2984 case 0x02: dprintf(_("roaming network")); break;
2985 case 0x03: dprintf(_("requesting network")); break;
2986 case 0x04: dprintf(_("not registered in the network")); break;
2987 default: dprintf(_("unknown")); break;
2992 dprintf(_(" Network selection: %s\n"), MessageBuffer[9] == 1 ? _("manual") : _("automatic"));
2994 CurrentNetworkInfoError = GE_NONE;
2998 dprintf(_("Message: Unknown message of type 0x0a\n"));
3004 /* Display status. */
3007 switch(MessageBuffer[3]) {
3009 dprintf("%i %i ", MessageBuffer[6], MessageBuffer[5]);
3010 for (i = 0; i < MessageBuffer[7]; i++)
3011 dprintf("%c", MessageBuffer[9+(i*2)]);
3016 for (i = 0; i < MessageBuffer[4]; i++)
3017 if (MessageBuffer[2*i+6] == 2)
3018 DisplayStatus |= 1 << (MessageBuffer[2*i+5] - 1);
3020 DisplayStatus &= (0xff - (1 << (MessageBuffer[2*i+5] - 1)));
3021 dprintf(_("Call in progress: %s\n"), DisplayStatus & (1 << DS_Call_In_Progress) ? "on" : "off");
3022 dprintf(_("Unknown: %s\n"), DisplayStatus & (1 << DS_Unknown) ? "on" : "off");
3023 dprintf(_("Unread SMS: %s\n"), DisplayStatus & (1 << DS_Unread_SMS) ? "on" : "off");
3024 dprintf(_("Voice call: %s\n"), DisplayStatus & (1 << DS_Voice_Call) ? "on" : "off");
3025 dprintf(_("Fax call active: %s\n"), DisplayStatus & (1 << DS_Fax_Call) ? "on" : "off");
3026 dprintf(_("Data call active: %s\n"), DisplayStatus & (1 << DS_Data_Call) ? "on" : "off");
3027 dprintf(_("Keyboard lock: %s\n"), DisplayStatus & (1 << DS_Keyboard_Lock) ? "on" : "off");
3028 dprintf(_("SMS storage full: %s\n"), DisplayStatus & (1 << DS_SMS_Storage_Full) ? "on" : "off");
3029 DisplayStatusError = GE_NONE;
3033 if (MessageBuffer[5] == 1) {
3034 dprintf(_("Display output successfully disabled/enabled.\n"));
3035 CurrentDisplayOutputError = GE_NONE;
3040 dprintf(_("Unknown message of type 0x0d.\n"));
3045 /* Phone Clock and Alarm */
3048 switch (MessageBuffer[3]) {
3050 switch (MessageBuffer[4]) {
3052 dprintf(_("Message: Date and time set correctly\n"));
3053 CurrentSetDateTimeError = GE_NONE;
3057 dprintf(_("Message: Date and time set error\n"));
3058 CurrentSetDateTimeError = GE_INVALIDDATETIME;
3064 CurrentDateTime->Year = 256 * MessageBuffer[8] + MessageBuffer[9];
3065 CurrentDateTime->Month = MessageBuffer[10];
3066 CurrentDateTime->Day = MessageBuffer[11];
3068 CurrentDateTime->Hour = MessageBuffer[12];
3069 CurrentDateTime->Minute = MessageBuffer[13];
3070 CurrentDateTime->Second = MessageBuffer[14];
3072 dprintf(_("Message: Date and time\n"));
3073 dprintf(_(" Time: %02d:%02d:%02d\n"), CurrentDateTime->Hour, CurrentDateTime->Minute, CurrentDateTime->Second);
3074 dprintf(_(" Date: %4d/%02d/%02d\n"), CurrentDateTime->Year, CurrentDateTime->Month, CurrentDateTime->Day);
3076 CurrentDateTimeError = GE_NONE;
3080 switch (MessageBuffer[4]) {
3082 dprintf(_("Message: Alarm set correctly\n"));
3083 CurrentSetAlarmError = GE_NONE;
3087 dprintf(_("Message: Date and time set error\n"));
3088 CurrentSetAlarmError = GE_INVALIDDATETIME;
3094 dprintf(_("Message: Alarm\n"));
3095 dprintf(_(" Alarm: %02d:%02d\n"), MessageBuffer[9], MessageBuffer[10]);
3096 dprintf(_(" Alarm is %s\n"), (MessageBuffer[8] == 2) ? _("on") : _("off"));
3098 CurrentAlarm->Hour = MessageBuffer[9];
3099 CurrentAlarm->Minute = MessageBuffer[10];
3100 CurrentAlarm->Second = 0;
3101 CurrentAlarm->AlarmEnabled = (MessageBuffer[8] == 2);
3102 CurrentAlarmError = GE_NONE;
3106 dprintf(_("Message: Unknown message of type 0x11\n"));
3111 /* Calendar notes handling */
3114 switch (MessageBuffer[3]) {
3116 switch(MessageBuffer[4]) {
3117 case 0x01: /* This message is also sent when the user enters the new entry on keypad */
3118 dprintf(_("Message: Calendar note write succesfull!\n"));
3119 CurrentCalendarNoteError = GE_NONE;
3122 dprintf(_("Message: Calendar note write failed!\n"));
3123 CurrentCalendarNoteError = GE_INTERNALERROR;
3126 dprintf(_("Message: Calendar note write failed!\n"));
3127 CurrentCalendarNoteError = GE_INTERNALERROR;
3130 dprintf(_("Unknown message of type 0x13 and subtype 0x65\n"));
3138 switch (MessageBuffer[4]) {
3142 CurrentCalendarNote->Type = MessageBuffer[8];
3144 CurrentCalendarNote->Time.Year = 256 * MessageBuffer[9] + MessageBuffer[10];
3145 CurrentCalendarNote->Time.Month = MessageBuffer[11];
3146 CurrentCalendarNote->Time.Day = MessageBuffer[12];
3148 CurrentCalendarNote->Time.Hour = MessageBuffer[13];
3149 CurrentCalendarNote->Time.Minute = MessageBuffer[14];
3150 CurrentCalendarNote->Time.Second = MessageBuffer[15];
3152 CurrentCalendarNote->Alarm.Year = 256 * MessageBuffer[16] + MessageBuffer[17];
3153 CurrentCalendarNote->Alarm.Month = MessageBuffer[18];
3154 CurrentCalendarNote->Alarm.Day = MessageBuffer[19];
3156 CurrentCalendarNote->Alarm.Hour = MessageBuffer[20];
3157 CurrentCalendarNote->Alarm.Minute = MessageBuffer[21];
3158 CurrentCalendarNote->Alarm.Second = MessageBuffer[22];
3160 memcpy(CurrentCalendarNote->Text, MessageBuffer + 24, MessageBuffer[23]);
3161 CurrentCalendarNote->Text[MessageBuffer[23]] = 0;
3163 if (CurrentCalendarNote->Type == GCN_CALL) {
3164 memcpy(CurrentCalendarNote->Phone,MessageBuffer + 24 + MessageBuffer[23] + 1,MessageBuffer[24+MessageBuffer[23]]);
3165 CurrentCalendarNote->Phone[MessageBuffer[24+MessageBuffer[23]]] = 0;
3168 dprintf(_("Message: Calendar note received.\n"));
3169 dprintf(_(" Date: %d-%02d-%02d\n"), CurrentCalendarNote->Time.Year,
3170 CurrentCalendarNote->Time.Month,
3171 CurrentCalendarNote->Time.Day);
3172 dprintf(_(" Time: %02d:%02d:%02d\n"), CurrentCalendarNote->Time.Hour,
3173 CurrentCalendarNote->Time.Minute,
3174 CurrentCalendarNote->Time.Second);
3176 /* Some messages do not have alarm set up */
3178 if (CurrentCalendarNote->Alarm.Year != 0) {
3179 dprintf(_(" Alarm date: %d-%02d-%02d\n"), CurrentCalendarNote->Alarm.Year,
3180 CurrentCalendarNote->Alarm.Month,
3181 CurrentCalendarNote->Alarm.Day);
3182 dprintf(_(" Alarm time: %02d:%02d:%02d\n"), CurrentCalendarNote->Alarm.Hour,
3183 CurrentCalendarNote->Alarm.Minute,
3184 CurrentCalendarNote->Alarm.Second);
3187 dprintf(_(" Type: %d\n"), CurrentCalendarNote->Type);
3188 dprintf(_(" Text: %s\n"), CurrentCalendarNote->Text);
3189 if (CurrentCalendarNote->Type == GCN_CALL)
3190 dprintf(_(" Phone: %s\n"), CurrentCalendarNote->Phone);
3191 CurrentCalendarNoteError = GE_NONE;
3195 dprintf(_("Message: Calendar note not available\n"));
3196 CurrentCalendarNoteError = GE_INVALIDCALNOTELOCATION;
3200 dprintf(_("Message: Calendar note error\n"));
3201 CurrentCalendarNoteError = GE_INTERNALERROR;
3207 switch (MessageBuffer[4]) {
3208 /* This message is also sent when the user deletes an old entry on
3209 keypad or moves an old entry somewhere (there is also `write'
3212 dprintf(_("Message: Calendar note deleted\n"));
3213 CurrentCalendarNoteError = GE_NONE;
3216 dprintf(_("Message: Calendar note can't be deleted\n"));
3217 CurrentCalendarNoteError = GE_INVALIDCALNOTELOCATION;
3220 dprintf(_("Message: Calendar note deleting error\n"));
3221 CurrentCalendarNoteError = GE_INTERNALERROR;
3228 /* Jano will probably implement something similar to IncomingCall
3229 notification for easy integration into xgnokii */
3230 dprintf(_("Message: Calendar Alarm active\n"));
3231 dprintf(_(" Item number: %d\n"), MessageBuffer[4]);
3235 dprintf(_("Message: Unknown message of type 0x13\n"));
3241 /* SMS Messages frame received */
3244 switch (MessageBuffer[3]) {
3246 switch (MessageBuffer[7]) {
3248 CurrentSMSMessage->Type = GST_MT;
3252 CurrentSMSMessage->Type = GST_DR;
3256 CurrentSMSMessage->Type = GST_MO;
3260 CurrentSMSMessage->Type = GST_UN;
3261 offset = 4; /* ??? */
3265 /* Field Short Message Status - MessageBuffer[4] seems not to be
3266 compliant with GSM 07.05 spec.
3267 Meaning Nokia protocol GMS spec
3268 ----------------------------------------------------
3269 MO Sent 0x05 0x07 or 0x01
3270 MO Not sent 0x07 0x06 or 0x00
3271 MT Read 0x01 0x05 or 0x01
3272 MT Not read 0x03 0x04 or 0x00
3273 ----------------------------------------------------
3274 See GSM 07.05 section 2.5.2.6 and correct me if I'm wrong.
3278 if (MessageBuffer[4] & 0x02)
3279 CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3281 CurrentSMSMessage->Status = GSS_SENTREAD;
3284 if (MessageBuffer[20] & 0x40) {
3285 switch (MessageBuffer[40+offset]) {
3286 case 0x00: /* concatenated messages */
3287 dprintf(_("Concatenated message!!!\n"));
3288 CurrentSMSMessage->UDHType = GSM_ConcatenatedMessages;
3289 if (MessageBuffer[41+offset] != 0x03) {
3290 /* should be some error */
3293 case 0x05: /* logos */
3294 switch (MessageBuffer[43+offset]) {
3296 CurrentSMSMessage->UDHType = GSM_OpLogo;
3299 CurrentSMSMessage->UDHType = GSM_CallerIDLogo;
3306 /* Skip user data header when reading data */
3307 off = (MessageBuffer[39+offset] + 1);
3308 for (i = 0; i < off; i++)
3309 CurrentSMSMessage->UDH[i] = MessageBuffer[39+offset+i];
3311 CurrentSMSMessage->UDHType = GSM_NoUDH;
3314 MessageBuffer[20+offset] = (MessageBuffer[20+offset]+1)/2+1;
3316 dprintf(_("Number: %d\n"), MessageBuffer[6]);
3317 switch (CurrentSMSMessage->Type) {
3319 dprintf(_("Message: Outbox message (mobile originated)\n"));
3320 if (CurrentSMSMessage->Status)
3321 dprintf(_("Sent\n"));
3323 dprintf(_("Not sent\n"));
3327 dprintf(_("Message: Received SMS (mobile terminated)\n"));
3328 if (CurrentSMSMessage->Type == GST_DR)
3329 dprintf(_("Delivery Report\n"));
3330 if (CurrentSMSMessage->Type == GST_UN)
3331 dprintf(_("Unknown type\n"));
3333 if (CurrentSMSMessage->Status)
3334 dprintf(_("Read\n"));
3336 dprintf(_("Not read\n"));
3338 dprintf(_(" Date: %s "), FB61_GetPackedDateTime(MessageBuffer + 32 + offset));
3340 if (MessageBuffer[38+offset]) {
3341 if (MessageBuffer[38+offset] & 0x08)
3346 dprintf(_("%02d00"), (10 * (MessageBuffer[38+offset] & 0x07) + (MessageBuffer[38+offset] >> 4)) / 4);
3350 if (CurrentSMSMessage->Type == GST_DR) {
3351 dprintf(_(" SMSC response date: %s "), FB61_GetPackedDateTime(MessageBuffer + 39 + offset));
3352 if (MessageBuffer[45+offset]) {
3353 if (MessageBuffer[45+offset] & 0x08)
3358 dprintf(_("%02d00"),(10 * (MessageBuffer[45+offset] & 0x07) + (MessageBuffer[45+offset] >> 4)) / 4);
3362 dprintf(_(" SMS center number: %s\n"), FB61_GetBCDNumber(MessageBuffer + 8));
3363 dprintf(_(" Remote number: %s\n"), FB61_GetBCDNumber(MessageBuffer + 20 + offset));
3367 /* In Outbox messages fields:
3371 are not filled in, so we ignore it.
3373 if (CurrentSMSMessage->Type != GST_MO) {
3374 CurrentSMSMessage->Time.Year = 10 * (MessageBuffer[32+offset] & 0x0f) + (MessageBuffer[32+offset] >> 4);
3375 CurrentSMSMessage->Time.Month = 10 * (MessageBuffer[33+offset] & 0x0f) + (MessageBuffer[33+offset] >> 4);
3376 CurrentSMSMessage->Time.Day = 10 * (MessageBuffer[34+offset] & 0x0f) + (MessageBuffer[34+offset] >> 4);
3377 CurrentSMSMessage->Time.Hour = 10 * (MessageBuffer[35+offset] & 0x0f) + (MessageBuffer[35+offset] >> 4);
3378 CurrentSMSMessage->Time.Minute = 10 * (MessageBuffer[36+offset] & 0x0f) + (MessageBuffer[36+offset] >> 4);
3379 CurrentSMSMessage->Time.Second = 10 * (MessageBuffer[37+offset] & 0x0f) + (MessageBuffer[37+offset] >> 4);
3380 CurrentSMSMessage->Time.Timezone = (10 * (MessageBuffer[38+offset] & 0x07) + (MessageBuffer[38+offset] >> 4)) / 4;
3381 if (MessageBuffer[38+offset] & 0x08)
3382 CurrentSMSMessage->Time.Timezone = -CurrentSMSMessage->Time.Timezone;
3383 strcpy(CurrentSMSMessage->Sender, FB61_GetBCDNumber(MessageBuffer + 20 + offset));
3384 strcpy(CurrentSMSMessage->MessageCenter.Number, FB61_GetBCDNumber(MessageBuffer + 8));
3387 if (CurrentSMSMessage->Type != GST_DR) {
3389 if ((MessageBuffer[18+offset] & 0xf4) == 0xf4) {
3390 CurrentSMSMessage->EightBit = true;
3391 tmp=CurrentSMSMessage->Length=MessageBuffer[19+offset];
3393 memcpy(output, MessageBuffer - 39 - offset - 2, tmp - offset);
3396 CurrentSMSMessage->EightBit = false;
3397 CurrentSMSMessage->Length=MessageBuffer[19+offset] - (off * 8 + ((7-off)%7)) / 7;
3399 tmp=UnpackEightBitsToSeven((7-off)%7, MessageLength - 39 - offset - 2, CurrentSMSMessage->Length, MessageBuffer + 39 + offset, output);
3401 for (i = 0; i < tmp;i++) {
3402 dprintf("%c", GSM_Default_Alphabet[output[i]]);
3403 CurrentSMSMessage->MessageText[i] = GSM_Default_Alphabet[output[i]];
3405 } else { /* CurrentSMSMessage->Type == GST_DR (Delivery Report) */
3406 /* SMSC Response time */
3407 CurrentSMSMessage->SMSCTime.Year = 10 * (MessageBuffer[39+offset] & 0x0f) + (MessageBuffer[39+offset] >> 4);
3408 CurrentSMSMessage->SMSCTime.Month = 10 * (MessageBuffer[40+offset] & 0x0f) + (MessageBuffer[40+offset] >> 4);
3409 CurrentSMSMessage->SMSCTime.Day = 10 * (MessageBuffer[41+offset] & 0x0f) + (MessageBuffer[41+offset] >> 4);
3410 CurrentSMSMessage->SMSCTime.Hour = 10 * (MessageBuffer[42+offset] & 0x0f) + (MessageBuffer[42+offset] >> 4);
3411 CurrentSMSMessage->SMSCTime.Minute = 10 * (MessageBuffer[43+offset] & 0x0f) + (MessageBuffer[43+offset] >> 4);
3412 CurrentSMSMessage->SMSCTime.Second = 10 * (MessageBuffer[44+offset] & 0x0f) + (MessageBuffer[44+offset] >> 4);
3413 CurrentSMSMessage->SMSCTime.Timezone = (10 * (MessageBuffer[45+offset] & 0x07) + (MessageBuffer[45+offset] >> 4)) / 4;
3414 if (MessageBuffer[45+offset] & 0x08) CurrentSMSMessage->SMSCTime.Timezone = -CurrentSMSMessage->SMSCTime.Timezone;
3415 if (MessageBuffer[22] < 0x03) {
3416 strcpy(CurrentSMSMessage->MessageText, _("Delivered"));
3417 switch (MessageBuffer[22]) {
3419 dprintf(_("SM received by the SME"));
3422 dprintf(_("SM forwarded by the SC to the SME but the SC is unable to confirm delivery"));
3425 dprintf(_("SM replaced by the SC"));
3428 CurrentSMSMessage->Length = tmp = 10;
3429 } else if (MessageBuffer[22] & 0x40) {
3431 strcpy(CurrentSMSMessage->MessageText, _("Failed"));
3433 /* more detailed reason only for debug */
3435 if (MessageBuffer[22] & 0x20) {
3436 dprintf(_("Temporary error, SC is not making any more transfer attempts\n"));
3438 switch (MessageBuffer[22]) {
3440 dprintf(_("Congestion"));
3443 dprintf(_("SME busy"));
3446 dprintf(_("No response from SME"));
3449 dprintf(_("Service rejected"));
3452 dprintf(_("Quality of service not aviable"));
3455 dprintf(_("Error in SME"));
3458 dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3462 dprintf(_("Permanent error, SC is not making any more transfer attempts\n"));
3463 switch (MessageBuffer[22]) {
3465 dprintf(_("Remote procedure error"));
3468 dprintf(_("Incompatibile destination"));
3471 dprintf(_("Connection rejected by SME"));
3474 dprintf(_("Not obtainable"));
3477 dprintf(_("Quality of service not aviable"));
3480 dprintf(_("No internetworking available"));
3483 dprintf(_("SM Validity Period Expired"));
3486 dprintf(_("SM deleted by originating SME"));
3489 dprintf(_("SM Deleted by SC Administration"));
3492 dprintf(_("SM does not exist"));
3495 dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3499 CurrentSMSMessage->Length = tmp = 6;
3500 } else if (MessageBuffer[22] & 0x20) {
3501 strcpy(CurrentSMSMessage->MessageText, _("Pending"));
3503 /* more detailed reason only for debug */
3504 dprintf(_("Temporary error, SC still trying to transfer SM\n"));
3505 switch (MessageBuffer[22]) {
3507 dprintf(_("Congestion"));
3510 dprintf(_("SME busy"));
3513 dprintf(_("No response from SME"));
3516 dprintf(_("Service rejected"));
3519 dprintf(_("Quality of service not aviable"));
3522 dprintf(_("Error in SME"));
3525 dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3528 CurrentSMSMessage->Length = tmp = 7;
3530 strcpy(CurrentSMSMessage->MessageText, _("Unknown"));
3532 /* more detailed reason only for debug */
3533 dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3534 CurrentSMSMessage->Length = tmp = 8;
3538 CurrentSMSMessage->MessageText[CurrentSMSMessage->Length] = 0;
3540 CurrentSMSPointer = tmp;
3542 CurrentSMSMessage->MemoryType = MessageBuffer[5];
3543 CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3545 /* Signal no error to calling code. */
3547 CurrentSMSMessageError = GE_NONE;
3552 dprintf(_("Message stored at %d\n"), MessageBuffer[5]);
3553 CurrentSMSMessageError = GE_NONE;
3557 dprintf(_("SMS saving failed\n"));
3558 switch (MessageBuffer[4]) {
3560 dprintf(_(" All locations busy.\n"));
3561 CurrentSMSMessageError = GE_MEMORYFULL;
3564 dprintf(_(" Invalid location!\n"));
3565 CurrentSMSMessageError = GE_INVALIDSMSLOCATION;
3568 dprintf(_(" Unknown error.\n"));
3569 CurrentSMSMessageError = GE_UNKNOWN;
3575 /* We have requested invalid or empty location. */
3576 dprintf(_("Message: SMS reading failed.\n"));
3577 switch (MessageBuffer[4]) {
3579 dprintf(_(" Invalid location!\n"));
3580 CurrentSMSMessageError = GE_INVALIDSMSLOCATION;
3583 dprintf(_(" Empty SMS location.\n"));
3584 CurrentSMSMessageError = GE_EMPTYSMSLOCATION;
3589 case 0x0b: /* successful delete */
3590 dprintf(_("Message: SMS deleted successfully.\n"));
3591 CurrentSMSMessageError = GE_NONE;
3595 dprintf(_("Message: SMS Status Received\n"));
3596 dprintf(_(" The number of messages: %d\n"), MessageBuffer[10]);
3597 dprintf(_(" Unread messages: %d\n"), MessageBuffer[11]);
3598 CurrentSMSStatus->UnRead = MessageBuffer[11];
3599 CurrentSMSStatus->Number = MessageBuffer[10];
3600 CurrentSMSStatusError = GE_NONE;
3604 dprintf(_("Message: SMS Status error, probably not authorized by PIN\n"));
3605 CurrentSMSStatusError = GE_INTERNALERROR;
3609 CurrentSMSStatusError = GE_INTERNALERROR;
3616 /* Internal phone functions? */
3620 switch(MessageBuffer[2]) {
3624 switch(MessageBuffer[3]) {
3626 dprintf(_("Message: Netmonitor correctly set.\n"));
3627 CurrentNetmonitorError = GE_NONE;
3630 dprintf(_("Message: Netmonitor menu %d received:\n"), MessageBuffer[3]);
3631 dprintf("%s\n", MessageBuffer + 4);
3632 strcpy(CurrentNetmonitor, MessageBuffer + 4);
3633 CurrentNetmonitorError = GE_NONE;
3640 dprintf(_("Unknown message of type 0x40.\n"));
3645 /* Mobile phone identification */
3648 #if defined WIN32 || !defined HAVE_SNPRINTF
3649 sprintf(IMEI, "%s", MessageBuffer + 9);
3650 sprintf(Model, "%s", MessageBuffer + 25);
3651 sprintf(Revision, "SW%s, HW%s", MessageBuffer + 44, MessageBuffer + 39);
3653 snprintf(IMEI, FB61_MAX_IMEI_LENGTH, "%s", MessageBuffer + 9);
3654 snprintf(Model, FB61_MAX_MODEL_LENGTH, "%s", MessageBuffer + 25);
3655 snprintf(Revision, FB61_MAX_REVISION_LENGTH, "SW%s, HW%s", MessageBuffer + 44, MessageBuffer + 39);
3658 dprintf(_("Message: Mobile phone identification received:\n"));
3659 dprintf(_(" IMEI: %s\n"), IMEI);
3660 dprintf(_(" Model: %s\n"), Model);
3661 dprintf(_(" Production Code: %s\n"), MessageBuffer + 31);
3662 dprintf(_(" HW: %s\n"), MessageBuffer + 39);
3663 dprintf(_(" Firmware: %s\n"), MessageBuffer + 44);
3665 /* These bytes are probably the source of the "Accessory not connected"
3666 messages on the phone when trying to emulate NCDS... I hope....
3667 UPDATE: of course, now we have the authentication algorithm. */
3669 dprintf(_(" Magic bytes: %02x %02x %02x %02x\n"), MessageBuffer[50], MessageBuffer[51], MessageBuffer[52], MessageBuffer[53]);
3671 MagicBytes[0] = MessageBuffer[50];
3672 MagicBytes[1] = MessageBuffer[51];
3673 MagicBytes[2] = MessageBuffer[52];
3674 MagicBytes[3] = MessageBuffer[53];
3675 CurrentMagicError = GE_NONE;
3678 /***** Acknowlegment of our frames. *****/
3680 dprintf(_("[Received Ack of type %02x, seq: %2x]\n"), MessageBuffer[0], MessageBuffer[1]);
3685 /***** Power on message. *****/
3687 dprintf(_("Message: The phone is powered on - seq 1.\n"));
3690 /***** Phone info. *****/
3692 #if defined WIN32 || !defined HAVE_SNPRINTF
3693 sprintf(Model, "%s", MessageBuffer + 21);
3694 sprintf(Revision, "SW%s", MessageBuffer + 5);
3696 snprintf(Model, FB61_MAX_MODEL_LENGTH, "%s", MessageBuffer + 21);
3697 Model[FB61_MAX_MODEL_LENGTH-1] = 0;
3698 snprintf(Revision, FB61_MAX_SW_LENGTH, "SW%s", MessageBuffer + 5);
3699 Revision[FB61_MAX_SW_LENGTH-1] = 0;
3701 dprintf(_("Phone info:\n%s\n"), MessageBuffer + 4);
3702 CurrentPhoneInfoError = GE_NONE;
3705 /***** RLP frame received. *****/
3707 FB61_RX_HandleRLPMessage();
3710 /***** Power on message. *****/
3712 dprintf(_("Message: The phone is powered on - seq 2.\n"));
3715 /***** Unknown message *****/
3716 /* If you think that you know the exact meaning of other messages - please
3719 dprintf(_("Message: Unknown message.\n"));
3722 return FB61_RX_Sync;
3725 /* RX_State machine for receive handling. Called once for each character
3726 received from the phone/phone. */
3728 void FB61_RX_StateMachine(char rx_byte)
3730 static int checksum[2];
3732 static struct _timeb time_now, time_last;
3733 static struct timeval time_diff;
3735 static struct timeval time_now, time_last, time_diff;
3738 /* XOR the byte with the current checksum */
3739 checksum[BufferCount&1] ^= rx_byte;
3743 /* Messages from the phone start with an 0x1e (cable) or 0x1c (IR).
3744 We use this to "synchronise" with the incoming data stream. However,
3745 if we see something else, we assume we have lost sync and we require
3746 a gap of at least 5ms before we start looking again. This is because
3747 the data part of the frame could contain a byte which looks like the
3750 case FB61_RX_Discarding:
3751 gettimeofday(&time_now, NULL);
3752 timersub(&time_now, &time_last, &time_diff);
3753 if (time_diff.tv_sec == 0 && time_diff.tv_usec < 5000) {
3754 time_last = time_now; /* no gap seen, continue discarding */
3757 /* else fall through to... */
3761 if ( CurrentConnectionType == GCT_Infrared ) {
3762 if (rx_byte == FB61_IR_FRAME_ID) {
3764 if (RX_Multiple == false) BufferCount = 0;
3765 else BufferCount = MessageLength - 2;
3766 RX_State = FB61_RX_GetDestination;
3768 /* Initialize checksums. */
3769 checksum[0] = FB61_IR_FRAME_ID;
3772 /* Lost frame sync */
3773 RX_State = FB61_RX_Discarding;
3774 gettimeofday(&time_last, NULL);
3776 } else { /* CurrentConnectionType == GCT_Serial */
3777 if (rx_byte == FB61_FRAME_ID) {
3779 if (RX_Multiple == false) BufferCount = 0;
3780 else BufferCount = MessageLength - 2;
3781 RX_State = FB61_RX_GetDestination;
3783 /* Initialize checksums. */
3784 checksum[0] = FB61_FRAME_ID;
3787 /* Lost frame sync */
3788 RX_State = FB61_RX_Discarding;
3789 gettimeofday(&time_last, NULL);
3795 case FB61_RX_GetDestination:
3797 MessageDestination = rx_byte;
3798 RX_State = FB61_RX_GetSource;
3800 /* When there is a checksum error and things get out of sync we have to manage to resync */
3801 /* If doing a data call at the time, finding a 0x1e etc is really quite likely in the data stream */
3802 /* Then all sorts of horrible things happen because the packet length etc is wrong... */
3803 /* Therefore we test here for a destination of 0x0c and return to the top if it is not */
3805 if (rx_byte != 0x0c) {
3806 RX_State = FB61_RX_Sync;
3807 dprintf("The fbus stream is out of sync - expected 0x0c, got %2x\n",rx_byte);
3811 case FB61_RX_GetSource:
3812 MessageSource = rx_byte;
3813 RX_State = FB61_RX_GetType;
3815 /* Source should be 0x00 */
3817 if (rx_byte != 0x00) {
3818 RX_State = FB61_RX_Sync;
3819 dprintf("The fbus stream is out of sync - expected 0x00, got %2x\n",rx_byte);
3823 case FB61_RX_GetType:
3824 if ((RX_Multiple == true) && (MessageType != rx_byte)) {
3825 dprintf(_("Interrupted MultiFrame-Message - Ignoring it !!!\n"));
3826 dprintf(_("Please report it ...\n"));
3828 RX_Multiple = false;
3831 MessageType = rx_byte;
3832 RX_State = FB61_RX_GetUnknown;
3835 case FB61_RX_GetUnknown:
3836 MessageUnknown = rx_byte;
3837 RX_State = FB61_RX_GetLength;
3840 case FB61_RX_GetLength:
3841 if (RX_Multiple == true)
3842 MessageLength = MessageLength - 2 + rx_byte;
3844 MessageLength = rx_byte;
3845 RX_State = FB61_RX_GetMessage;
3848 case FB61_RX_GetMessage:
3849 MessageBuffer[BufferCount] = rx_byte;
3851 if (BufferCount > FB61_MAX_RECEIVE_LENGTH*6) {
3852 dprintf(_("FB61: Message buffer overun - resetting\n"));
3853 RX_Multiple = false;
3854 RX_State = FB61_RX_Sync;
3858 /* If this is the last byte, it's the checksum. */
3860 if (BufferCount == MessageLength + (MessageLength % 2) + 2) {
3861 /* Is the checksum correct? */
3862 if (checksum[0] == checksum[1]) {
3863 /* We do not want to send ACK of ACKs and ACK of RLP frames. */
3865 if (MessageType != FB61_FRTYPE_ACK && MessageType != 0xf1) {
3866 FB61_TX_SendAck(MessageType, MessageBuffer[MessageLength-1] & 0x0f);
3867 if ((MessageLength > 1) && (MessageBuffer[MessageLength-2] != 0x01))
3870 RX_Multiple = false;
3873 FB61_RX_DispatchMessage();
3877 dprintf(_("Bad checksum!\n"));
3878 RX_Multiple = false; /* Just to be sure! */
3881 RX_State = FB61_RX_Sync;
3887 /* This function is used for parsing the RLP frame into fields. */
3889 enum FB61_RX_States FB61_RX_HandleRLPMessage(void)
3895 /* We do not need RLP frame parsing to be done when we do not have callback
3898 if (RLP_RXCallback == NULL)
3899 return (FB61_RX_Sync);
3901 /* Anybody know the official meaning of the first two bytes?
3902 Nokia 6150 sends junk frames starting D9 01, and real frames starting
3903 D9 00. We'd drop the junk frames anyway because the FCS is bad, but
3904 it's tidier to do it here. We still need to call the callback function
3905 to give it a chance to handle timeouts and/or transmit a frame */
3907 if (MessageBuffer[0] == 0xd9 && MessageBuffer[1] == 0x01)
3910 /* Nokia uses 240 bit frame size of RLP frames as per GSM 04.22
3911 specification, so Header consists of 16 bits (2 bytes). See section 4.1
3912 of the specification. */
3914 frame.Header[0] = MessageBuffer[2];
3915 frame.Header[1] = MessageBuffer[3];
3917 /* Next 200 bits (25 bytes) contain the Information. We store the
3918 information in the Data array. */
3920 for (count = 0; count < 25; count ++)
3921 frame.Data[count] = MessageBuffer[4 + count];
3923 /* The last 24 bits (3 bytes) contain FCS. */
3925 frame.FCS[0] = MessageBuffer[29];
3926 frame.FCS[1] = MessageBuffer[30];
3927 frame.FCS[2] = MessageBuffer[31];
3929 /* Here we pass the frame down in the input stream. */
3931 RLP_RXCallback(valid ? &frame : NULL);
3933 return (FB61_RX_Sync);
3936 char *FB61_PrintDevice(int Device)
3941 case FB61_DEVICE_PHONE:
3944 case FB61_DEVICE_PC:
3948 return _("Unknown");
3953 /* FB61_RX_DisplayMessage is called when a message we don't know about is
3954 received so that the user can see what is going back and forth, and perhaps
3955 shed some more light/explain another message type! */
3957 void FB61_RX_DisplayMessage(void)
3962 dprintf(_("Msg Dest: %s\n"), FB61_PrintDevice(MessageDestination));
3963 dprintf(_("Msg Source: %s\n"), FB61_PrintDevice(MessageSource));
3964 dprintf(_("Msg Type: %02x\n"), MessageType);
3965 dprintf(_("Msg Unknown: %02x\n"), MessageUnknown);
3966 dprintf(_("Msg Len: %02x\nPhone: "), MessageLength);
3968 for (count = 0; count < MessageLength + (MessageLength % 2) + 2; count ++)
3969 if (isprint(MessageBuffer[count]))
3970 dprintf("[%02x%c]", MessageBuffer[count], MessageBuffer[count]);
3972 dprintf("[%02x ]", MessageBuffer[count]);
3978 /* Prepares the message header and sends it, prepends the message start byte
3979 (0x1e) and other values according the value specified when called.
3980 Calculates checksum and then sends the lot down the pipe... */
3982 int FB61_TX_SendFrame(u8 message_length, u8 message_type, u8 *buffer)
3984 u8 out_buffer[FB61_MAX_TRANSMIT_LENGTH + 5];
3985 int count, current = 0;
3986 unsigned char checksum;
3988 /* FIXME - we should check for the message length ... */
3990 /* Now construct the message header. */
3992 if (CurrentConnectionType == GCT_Infrared)
3993 out_buffer[current++] = FB61_IR_FRAME_ID; /* Start of the IR frame indicator */
3994 else /* CurrentConnectionType == GCT_Serial */
3995 out_buffer[current++] = FB61_FRAME_ID; /* Start of the frame indicator */
3997 out_buffer[current++] = FB61_DEVICE_PHONE; /* Destination */
3998 out_buffer[current++] = FB61_DEVICE_PC; /* Source */
3999 out_buffer[current++] = message_type; /* Type */
4000 out_buffer[current++] = 0; /* Unknown */
4001 out_buffer[current++] = message_length; /* Length */
4003 /* Copy in data if any. */
4005 if (message_length != 0) {
4006 memcpy(out_buffer + current, buffer, message_length);
4007 current += message_length;
4010 /* If the message length is odd we should add pad byte 0x00 */
4011 if (message_length % 2)
4012 out_buffer[current++] = 0x00;
4014 /* Now calculate checksums over entire message and append to message. */
4019 for (count = 0; count < current; count += 2)
4020 checksum ^= out_buffer[count];
4022 out_buffer[current++] = checksum;
4027 for (count = 1; count < current; count += 2)
4028 checksum ^= out_buffer[count];
4030 out_buffer[current++] = checksum;
4033 for (count = 0; count < current; count++)
4034 dprintf("%02x:", out_buffer[count]);
4037 /* Send it out... */
4039 if (WRITEPHONE(PortFD, out_buffer, current) != current)
4042 if(message_type != 0x7f)
4048 int FB61_TX_SendMessage(u16 message_length, u8 message_type, u8 *buffer)
4050 u8 seqnum, frame_buffer[FB61_MAX_CONTENT_LENGTH + 2];
4051 u8 nom, lml; /* number of messages, last message len */
4054 seqnum = 0x40 + RequestSequenceNumber;
4055 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
4057 if (message_length > FB61_MAX_CONTENT_LENGTH) {
4059 nom = (message_length + FB61_MAX_CONTENT_LENGTH - 1)
4060 / FB61_MAX_CONTENT_LENGTH;
4061 lml = message_length - ((nom - 1) * FB61_MAX_CONTENT_LENGTH);
4063 for (i = 0; i < nom - 1; i++) {
4065 memcpy(frame_buffer, buffer + (i * FB61_MAX_CONTENT_LENGTH),
4066 FB61_MAX_CONTENT_LENGTH);
4067 frame_buffer[FB61_MAX_CONTENT_LENGTH] = nom - i;
4068 frame_buffer[FB61_MAX_CONTENT_LENGTH + 1] = seqnum;
4070 FB61_TX_SendFrame(FB61_MAX_CONTENT_LENGTH + 2, message_type,
4073 seqnum = RequestSequenceNumber;
4074 RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
4077 memcpy(frame_buffer, buffer + ((nom - 1) * FB61_MAX_CONTENT_LENGTH), lml);
4078 frame_buffer[lml] = 0x01;
4079 frame_buffer[lml + 1] = seqnum;
4080 FB61_TX_SendFrame(lml + 2, message_type, frame_buffer);
4084 memcpy(frame_buffer, buffer, message_length);
4085 frame_buffer[message_length] = 0x01;
4086 frame_buffer[message_length + 1] = seqnum;
4087 FB61_TX_SendFrame(message_length + 2, message_type, frame_buffer);
4093 int FB61_TX_SendAck(u8 message_type, u8 message_seq)
4095 unsigned char request[2];
4096 request[0] = message_type;
4097 request[1] = message_seq;
4098 dprintf(_("[Sending Ack of type %02x, seq: %x]\n"), message_type, message_seq);
4099 return FB61_TX_SendFrame(2, FB61_FRTYPE_ACK, request);