\r\n -> \n
[gnokii.git] / common / fbus-6110.c
1 /*
2
3   $Id$
4   
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 1999, 2000 Hugh Blemings & Pavel Janík ml.
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   This file provides an API for accessing functions on the 6110 and similar
14   phones. See README for more details on supported mobile phones.
15
16   The various routines are called FB61 (whatever) as a concatenation of FBUS
17   and 6110.
18
19   $Log$
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
22
23   Revision 1.136  2001/08/20 23:27:37  pkot
24   Add hardware shakehand to the link layer (Manfred Jonsson)
25
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)
28
29   Revision 1.134  2001/06/10 11:24:57  machek
30   Kill "slash star" inside comment.
31
32   Revision 1.133  2001/03/19 23:43:46  pkot
33   Solaris/ *BSD '#if defined' cleanup
34
35   Revision 1.132  2001/03/13 01:23:17  pkot
36   Windows updates (Manfred Jonsson)
37
38   Revision 1.131  2001/03/13 01:21:38  pkot
39   *BSD updates (Bert Driehuis)
40
41   Revision 1.130  2001/02/28 21:30:52  machek
42   Return data in GBF_Arbitrary if we can't handle units requested.
43
44   Revision 1.129  2001/02/21 19:56:55  chris
45   More fiddling with the directory layout
46
47   Revision 1.128  2001/02/17 22:40:48  chris
48   ATA support
49
50   Revision 1.127  2001/02/06 21:15:34  chris
51   Preliminary irda support for 7110 etc.  Not well tested!
52
53   Revision 1.126  2001/02/06 14:35:55  pkot
54   Few more cleanups on authentication
55
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)
59
60   Revision 1.124  2001/02/01 15:17:27  pkot
61   Fixed --identify and added Manfred's manufacturer patch
62
63   Revision 1.123  2001/01/31 12:49:00  pkot
64   Many cleanups in fbus-6110 code.
65   3210/3310 really work now.
66
67   Revision 1.122  2001/01/23 15:32:35  chris
68   Pavel's 'break' and 'static' corrections.
69   Work on logos for 7110.
70
71   Revision 1.121  2001/01/15 17:00:45  pkot
72   Initial keypress sequence support. Disable compilation warning
73
74   Revision 1.120  2001/01/14 22:46:56  chris
75   Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
76
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.
81   2110 code updates.
82   Many cleanups.
83
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
88
89   Revision 1.117  2000/12/21 15:13:46  pkot
90   Fixed functions converting ascii to and from PDU
91
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)
94
95 */
96
97 /* "Turn on" prototypes in fbus-6110.h */
98
99 #define __fbus_6110_c 
100
101 /* System header files */
102
103 #include <stdio.h>
104 #include <string.h>
105 #include <stdlib.h>
106  
107 #ifdef WIN32
108
109 #include <windows.h>
110 #include "win32/winserial.h"
111
112 #undef IN
113 #undef OUT
114
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;
119
120 #else
121
122 #define WRITEPHONE(a, b, c) device_write(b, c)
123 #include <unistd.h>
124 #include <termios.h>
125 #include <fcntl.h>
126 #include <ctype.h>
127 #include <signal.h>
128 #include <sys/ioctl.h>
129 #include <sys/types.h>
130 #include <sys/time.h>
131 #include <pthread.h>
132 #include <errno.h>
133 #include "device.h"
134 #include "devices/unixserial.h"
135
136 #endif
137
138 /* Various header file */
139
140 #include "config.h"
141 #include "misc.h"
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"
149
150 /* Global variables used by code in gsm-api.c to expose the functions
151    supported by this model of phone. */
152
153 bool FB61_LinkOK;
154
155 #if __unices__
156 /* fd opened in device.c */
157 extern int device_portfd;
158 #endif
159
160 #ifdef WIN32
161
162 void FB61_InitializeLink();
163
164 #endif
165
166 /* Here we initialise model specific functions. */
167
168 GSM_Functions FB61_Functions = {
169         FB61_Initialise,
170         FB61_Terminate,
171         FB61_GetMemoryLocation,
172         FB61_WritePhonebookLocation,
173         FB61_GetSpeedDial,
174         FB61_SetSpeedDial,
175         FB61_GetMemoryStatus,
176         FB61_GetSMSStatus,
177         FB61_GetSMSCenter,
178         FB61_SetSMSCenter,
179         FB61_GetSMSMessage,
180         FB61_DeleteSMSMessage,
181         FB61_SendSMSMessage,
182         FB61_SaveSMSMessage,
183         FB61_GetRFLevel,
184         FB61_GetBatteryLevel,
185         FB61_GetPowerSource,
186         FB61_GetDisplayStatus,
187         FB61_EnterSecurityCode,
188         FB61_GetSecurityCodeStatus,
189         FB61_GetIMEI,
190         FB61_GetRevision,
191         FB61_GetModel,
192         PNOK_GetManufacturer,
193         FB61_GetDateTime,
194         FB61_SetDateTime,
195         FB61_GetAlarm,
196         FB61_SetAlarm,
197         FB61_DialVoice,
198         FB61_DialData,
199         FB61_GetIncomingCallNr,
200         FB61_GetNetworkInfo,
201         FB61_GetCalendarNote,
202         FB61_WriteCalendarNote,
203         FB61_DeleteCalendarNote,
204         FB61_NetMonitor,
205         FB61_SendDTMF,
206         FB61_GetBitmap,
207         FB61_SetBitmap,
208         FB61_SetRingTone,
209         FB61_SendRingTone,
210         FB61_Reset,
211         FB61_GetProfile,
212         FB61_SetProfile,
213         FB61_SendRLPFrame,
214         FB61_CancelCall,
215         FB61_EnableDisplayOutput,
216         FB61_DisableDisplayOutput,
217         FB61_EnableCellBroadcast,
218         FB61_DisableCellBroadcast,
219         FB61_ReadCellBroadcast,
220         UNIMPLEMENTED,
221         UNIMPLEMENTED,
222         FB61_AnswerCall
223 };
224
225 /* Mobile phone information */
226
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 */
241 };
242
243 unsigned char GSM_Default_Alphabet[] = {
244
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 */
249
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
266 };
267
268 const char *FB61_MemoryType_String [] = {
269         "",     /* 0x00 */
270         "MT", /* 0x01 */
271         "ME", /* 0x02 */
272         "SM", /* 0x03 */
273         "FD", /* 0x04 */
274         "ON", /* 0x05 */
275         "EN", /* 0x06 */
276         "DC", /* 0x07 */
277         "RC", /* 0x08 */
278         "MC", /* 0x09 */
279 };
280
281 /* Local variables */
282
283
284 char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
285
286 /* This is the connection type used in gnokii. */
287
288 GSM_ConnectionType CurrentConnectionType;
289
290 int BufferCount;
291
292 u8 MessageBuffer[FB61_MAX_RECEIVE_LENGTH * 6];
293
294 u16 MessageLength;
295 u8 MessageType, MessageDestination, MessageSource, MessageUnknown;
296 u8 MessagesSent=0, AcksReceived=0;
297
298 /* Magic bytes from the phone. */
299
300 unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
301 GSM_Error CurrentMagicError = GE_BUSY;
302
303 enum FB61_RX_States RX_State;
304 bool RX_Multiple = false;
305
306 u8        RequestSequenceNumber = 0x00;
307 bool      RequestTerminate;
308 bool      DisableKeepalive = false;
309 int       InitLength;
310 u8        CallSequenceNumber; /* Used to disconnect the call */
311
312 #ifndef WIN32
313
314 pthread_t Thread;
315 # if __unices__
316 pthread_t selThread;
317 # endif
318
319 #endif
320
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. */
325                                    
326 static GSM_PhonebookEntry *CurrentPhonebookEntry;
327 static GSM_Error          CurrentPhonebookError;
328
329 static GSM_SpeedDial      *CurrentSpeedDialEntry;
330 static GSM_Error          CurrentSpeedDialError;
331
332 static GSM_SMSMessage     *CurrentSMSMessage;
333 static GSM_Error          CurrentSMSMessageError;
334 static int                CurrentSMSPointer;
335
336 static GSM_MemoryStatus   *CurrentMemoryStatus;
337 static GSM_Error          CurrentMemoryStatusError;
338
339 static GSM_NetworkInfo    *CurrentNetworkInfo = NULL;
340 static GSM_Error          CurrentNetworkInfoError;
341
342 static GSM_SMSStatus      *CurrentSMSStatus;
343 static GSM_Error          CurrentSMSStatusError;
344
345 static GSM_MessageCenter  *CurrentMessageCenter;
346 static GSM_Error          CurrentMessageCenterError;
347
348 static int                *CurrentSecurityCodeStatus;
349 static GSM_Error          CurrentSecurityCodeError;
350
351 static GSM_DateTime       *CurrentDateTime;
352 static GSM_Error          CurrentDateTimeError;
353
354 static GSM_DateTime       *CurrentAlarm;
355 static GSM_Error          CurrentAlarmError;
356
357 static GSM_CalendarNote   *CurrentCalendarNote;
358 static GSM_Error          CurrentCalendarNoteError;
359
360 static GSM_Error          CurrentSetDateTimeError;
361 static GSM_Error          CurrentSetAlarmError;
362
363 static int                CurrentRFLevel,
364         CurrentBatteryLevel,
365         CurrentPowerSource;
366
367 static int                DisplayStatus;
368 static GSM_Error          DisplayStatusError;
369
370 static char               *CurrentNetmonitor;
371 static GSM_Error          CurrentNetmonitorError;
372
373 static GSM_Bitmap         *GetBitmap=NULL;
374 static GSM_Error          GetBitmapError;
375
376 static GSM_Error          SetBitmapError;
377
378 static GSM_Profile        *CurrentProfile;
379 static GSM_Error          CurrentProfileError;
380
381 static GSM_Error          CurrentDisplayOutputError;
382
383 static GSM_CBMessage      *CurrentCBMessage;
384 static GSM_Error          CurrentCBError;
385
386 static GSM_Error          CurrentPhoneInfoError;
387
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];
391
392 static char               CurrentIncomingCall[20] = " ";
393
394 /* Pointer to callback function in user code to be called when RLP frames
395    are received. */
396
397 void               (*RLP_RXCallback)(RLP_F96Frame *frame);
398
399 /* Pointer to a callback function used to return changes to a calls status */
400 /* This saves unreliable polling */
401 void (*CallPassup)(char c);
402
403 #ifdef WIN32
404 /* called repeatedly from a separate thread */
405 void FB61_KeepAliveProc()
406 {
407         if (!DisableKeepalive)
408                 FB61_TX_SendStatusRequest();
409         Sleep(2000);
410 }
411 #endif
412
413 /* Initialise variables and state machine. */
414
415 GSM_Error FB61_Initialise(char *port_device, char *initlength,
416                           GSM_ConnectionType connection,
417                           void (*rlp_callback)(RLP_F96Frame *frame))
418 {
419         int rtn;
420
421         RequestTerminate = false;
422         FB61_LinkOK = false;
423         RLP_RXCallback = rlp_callback;
424         CallPassup = NULL;
425
426         strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
427
428         InitLength = atoi(initlength);
429         if (!strcmp(initlength, "default") || (InitLength == 0)) {
430                 InitLength = 250;       /* This is the usual value, lower may work. */
431         }
432
433         CurrentConnectionType = connection;
434
435         /* Create and start main thread. */
436
437 #ifdef WIN32
438         DisableKeepalive = true;
439         rtn = ! OpenConnection(PortDevice, FB61_RX_StateMachine, FB61_KeepAliveProc);
440         if (rtn == 0) {
441                 FB61_InitializeLink(); /* makes more sense to do this in 'this' thread */
442                 DisableKeepalive = false;
443         }
444 #else
445         rtn = pthread_create(&Thread, NULL, (void *)FB61_ThreadLoop, (void *)NULL);
446 #endif
447
448         if (rtn != 0)
449                 return (GE_INTERNALERROR);
450
451         return (GE_NONE);
452 }
453
454 #if __unices__
455 /* thread for handling incoming data */
456 void FB61_SelectLoop()
457 {
458         int err;
459         fd_set readfds;
460         struct timeval timeout;
461
462         FD_ZERO(&readfds);
463         FD_SET(device_portfd, &readfds);
464         /* set timeout to 15 seconds */
465         timeout.tv_sec=15;
466         timeout.tv_usec=0;
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");
472         }
473 }
474 #endif
475
476   
477 /* This function send the status request to the phone. */
478
479 GSM_Error FB61_TX_SendStatusRequest(void)
480 {
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);
485         return (GE_NONE);
486 }
487
488 /* This function translates GMT_MemoryType to FB61_MEMORY_xx */
489
490 int FB61_GetMemoryType(GSM_MemoryType memory_type)
491 {
492         int result;
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;
504         }
505         return (result);
506 }
507
508 /* This function is used to get storage status from the phone. It currently
509    supports two different memory areas - internal and SIM. */
510
511 static GSM_Error 
512 wait_on(volatile GSM_Error *what, int timeout)
513 {
514         *what = GE_BUSY;
515         while (timeout && (*what == GE_BUSY)) {
516                 if (!--timeout)
517                         return GE_TIMEOUT;
518                 usleep(100000);
519         }
520         return *what;
521 }
522
523 #define WAIT_ON(x, y) \
524         { \
525                 GSM_Error res = wait_on(x, y); \
526                 if (res != GE_NONE) \
527                         return res; \
528         }
529
530 #define WAIT_ON1(x, y) \
531         { \
532                 GSM_Error res = wait_on(x, y); \
533                 if (res != GE_NONE) \
534                         return; \
535         }
536
537 static GSM_Error FB61_GetPhoneInfo()
538 {
539         unsigned char req[] = { FB61_FRAME_HEADER, 0x03, 0x00 };
540         FB61_TX_SendMessage(5, 0xd1, req);
541         return (wait_on(&CurrentPhoneInfoError, 20));
542 }
543
544 GSM_Error FB61_AnswerCall(char s)
545 {
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};
549         req[4]=s;
550         dprintf("Answering call %d\n\r",s);
551         FB61_TX_SendMessage(sizeof(req0), 0x01, req0);
552         sleep(1);
553         FB61_TX_SendMessage(sizeof(req), 0x01, req);
554         return (wait_on(&CurrentPhoneInfoError, 20));
555 }
556
557 GSM_Error FB61_GetMemoryStatus(GSM_MemoryStatus *Status)
558 {
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);
564 }
565
566 GSM_Error FB61_GetNetworkInfo(GSM_NetworkInfo *NetworkInfo)
567 {
568         unsigned char req[] = { FB61_FRAME_HEADER, 0x70 };
569         CurrentNetworkInfo = NetworkInfo;
570         FB61_TX_SendMessage(4, 0x0a, req);
571         return wait_on(&CurrentNetworkInfoError, 20);
572 }
573
574 GSM_Error FB61_EnableDisplayOutput(void)
575 {
576         unsigned char req[] = { FB61_FRAME_HEADER, 0x53, 0x01};
577         FB61_TX_SendMessage(5, 0x0d, req);
578         return wait_on(&CurrentDisplayOutputError, 20);
579 }
580  
581 GSM_Error FB61_DisableDisplayOutput(void)
582 {
583         unsigned char req[] = { FB61_FRAME_HEADER, 0x53, 0x02};
584         FB61_TX_SendMessage(5, 0x0d, req);
585         return wait_on(&CurrentDisplayOutputError, 20);
586 }
587
588 GSM_Error FB61_GetProfile(GSM_Profile *Profile)
589 {
590         int i;
591         /* Hopefully is 64 larger as FB38_MAX* / FB61_MAX* */
592         char model[64];
593         unsigned char name_req[] = { FB61_FRAME_HEADER, 0x1a, 0x00};
594         unsigned char feat_req[] = { FB61_FRAME_HEADER, 0x13, 0x01, 0x00, 0x00};
595
596         CurrentProfile = Profile;
597
598         name_req[4] = Profile->Number;
599         feat_req[5] = Profile->Number;
600         FB61_TX_SendMessage(5, 0x05, name_req);
601
602         WAIT_ON(&CurrentProfileError, 20);
603
604         for (i = 0x00; i <= 0x09; i++) {
605                 CurrentProfileError = GE_BUSY;
606                 feat_req[6] = i;
607                 FB61_TX_SendMessage(7, 0x05, feat_req);
608                 WAIT_ON(&CurrentProfileError, 20);
609         }
610
611         if (Profile->DefaultName > -1)
612         {
613                 while (FB61_GetModel(model)  != GE_NONE)
614                         sleep(1);
615
616                 /*For N5110*/
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;
624                         }
625                 } else {
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;
635                         }
636                 }
637         }
638         return (GE_NONE);
639 }
640
641 GSM_Error FB61_SetProfile(GSM_Profile *Profile)
642 {
643         int i;
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};
646
647         name_req[7] = Profile->Number;
648         name_req[8] = strlen(Profile->Name);
649         name_req[6] = name_req[8] + 2;
650
651         for (i = 0; i < name_req[8]; i++)
652                 name_req[9 + i] = Profile->Name[i];
653
654         FB61_TX_SendMessage(name_req[8] + 9, 0x05, name_req);
655         WAIT_ON(&CurrentProfileError, 30);
656
657         feat_req[5] = Profile->Number;
658         for (i = 0x00; i <= 0x09; i++) {
659                 feat_req[6] = 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;
671                 }
672
673                 FB61_TX_SendMessage(8, 0x05, feat_req);
674                 WAIT_ON(&CurrentProfileError, 20);
675         }
676
677         return (GE_NONE);
678 }
679
680 bool FB61_SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
681 {
682         u8 req[60] = { 0x00, 0xd9 };
683         /* Discontinuos transmission (DTX).  See section 5.6 of GSM 04.22 version 7.0.1. */
684        
685         if (out_dtx) req[1] = 0x01;
686         memcpy(req + 2, (u8 *) frame, 32);
687         return (FB61_TX_SendFrame(32, 0xf0, req));
688 }
689
690
691 GSM_Error FB61_GetCalendarNote(GSM_CalendarNote *CalendarNote)
692 {
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);
699 }
700
701 GSM_Error FB61_WriteCalendarNote(GSM_CalendarNote *CalendarNote)
702 {
703         unsigned char req[200] = { FB61_FRAME_HEADER,
704                                    0x64, 0x01, 0x10,
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
709         };
710         int i, current;
711
712         req[7] = CalendarNote->Type;
713
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;
721
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;
730         }
731
732         req[22] = strlen(CalendarNote->Text);
733
734         current = 23;
735
736         for (i=0; i<strlen(CalendarNote->Text); i++)
737                 req[current++] = CalendarNote->Text[i];
738
739         req[current++] = strlen(CalendarNote->Phone);
740
741         for (i=0; i<strlen(CalendarNote->Phone); i++)
742                 req[current++] = CalendarNote->Phone[i];
743
744         CurrentCalendarNote = CalendarNote;
745         CurrentCalendarNoteError = GE_BUSY;
746
747         FB61_TX_SendMessage(current, 0x13, req);
748         return wait_on(&CurrentCalendarNoteError, 20);
749 }
750
751 GSM_Error FB61_DeleteCalendarNote(GSM_CalendarNote *CalendarNote)
752 {
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);
758 }
759
760 /* Init ir for win32 is made in winserial.c */
761 #ifndef WIN32
762
763 void FB61_InitIR(void)
764 {
765         int i;
766         unsigned char init_char     = FB61_SYNC_BYTE;
767         unsigned char end_init_char = FB61_IR_END_INIT_BYTE;
768   
769         for ( i = 0; i < 32; i++ )
770                 device_write(&init_char, 1);
771
772         device_write(&end_init_char, 1);
773         usleep(100000);
774 }
775
776 bool FB61_InitIR115200(void)
777 {
778         int PortFD;
779         u8 connect_seq[] = {FB61_FRAME_HEADER, 0x0d, 0x00, 0x00, 0x02};
780
781         bool ret         = true;
782         u8 nr_read       = 0;
783         u8 in_buffer[255];
784         struct timeval timeout;
785         fd_set ready;
786         int no_timeout   = 0;
787         int i;
788         int done         = 0;
789
790         /* send the connection sequence to phone */
791         FB61_TX_SendMessage(7, 0x02, connect_seq);
792
793         /* Wait for 1 sec. */
794         timeout.tv_sec  = 1;
795         timeout.tv_usec = 0;
796
797         PortFD = device_getfd();
798
799         do {
800                 FD_ZERO(&ready);
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 ) {
808                                                 done = 1;
809                                                 ret = true;
810                                                 break;
811                                         }
812                                 }
813                         } else {
814                                 done = 1;
815                                 ret = false;
816                         }
817                 }
818
819                 if (!no_timeout) {
820                         dprintf(_("Timeout in IR-mode\n"));
821                         done = 1;
822                         ret = false;
823                 }
824         } while (!done);
825   
826         return (ret);
827 }
828
829 /* This function is used to open the IR connection with the phone. */
830
831 bool FB61_OpenIR(void)
832 {
833         int result;
834         bool ret = false;
835         u8 i = 0;
836
837 #if __unices__
838         int rtn;
839 #else
840         struct sigaction sig_io;  
841
842         /* Set up and install handler before enabling async IO on port. */
843   
844         sig_io.sa_handler = FB61_SigHandler;
845         sig_io.sa_flags = 0;
846         sigaction (SIGIO, &sig_io, NULL);
847 #endif
848
849         /* Open device. */
850   
851         result = device_open(PortDevice, false, true, false, GCT_Infrared);
852
853         if (!result) {
854                 perror(_("Couldn't open FB61 infrared device"));
855                 return false;
856         }
857
858 #if __unices__
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;
862 #endif
863
864         device_changespeed(9600);
865         FB61_InitIR();
866         device_changespeed(115200);
867         ret = FB61_InitIR115200();
868         if (!ret) {
869                 for ( i = 0; i < 4 ; i++) {
870                         usleep (500000);
871                         device_changespeed(9600);
872                         FB61_InitIR();
873                         device_changespeed(115200);
874                         ret = FB61_InitIR115200();
875                         if (ret) break;
876                 }
877         }
878   
879         return (ret);
880 }
881
882 static void FB61_Authentication()
883 {
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};
888
889         unsigned char magic_connect[] = {FB61_FRAME_HEADER,
890                                          0x12,
891
892                                          /* The real magic goes here ... These bytes are filled in with the
893                                             external function FB61_GetNokiaAuth(). */
894
895                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
896                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
897
898                                          /* NOKIA&GNOKII Accessory */
899
900                                          0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x26, 0x4e, 0x4f, 0x4b, 0x49, 0x41, 0x20,
901                                          0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x79,
902   
903                                          0x00, 0x00, 0x00, 0x00};
904
905         usleep(100); FB61_GetPhoneInfo(); usleep(100);
906
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);
912
913                 WAIT_ON1(&CurrentMagicError, 50);
914
915                 FB61_GetNokiaAuth(IMEI, MagicBytes, magic_connect+4);
916
917                 FB61_TX_SendMessage(45, 0x64, magic_connect);
918         }
919
920         return;
921 }
922
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)
927 {
928         unsigned char init_char = 0x55;
929         int count, idle_timer;
930
931         CurrentPhonebookEntry = NULL;  
932
933         if ( CurrentConnectionType == GCT_Infrared ) {
934                 dprintf(_("Starting IR mode...!\n"));
935                 if (FB61_OpenIR() != true) {
936                         FB61_LinkOK = false;
937                         while (!RequestTerminate)
938                                 usleep (100000);
939                         return;
940                 }
941
942         } else { /* CurrentConnectionType == GCT_Serial */
943
944                 /* Try to open serial port, if we fail we sit here and don't proceed to the
945                    main loop. */
946    
947                 if (FB61_OpenSerial() != true) {
948                         FB61_LinkOK = false;
949       
950                         /* Fail so sit here till calling code works out there is a problem. */
951       
952                         while (!RequestTerminate)
953                                 usleep (100000);
954       
955                         return;
956                 }
957         }
958
959         /* Initialise link with phone or what have you */
960
961         /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
962            empirical. */
963
964         for (count = 0; count < InitLength; count ++) {
965                 usleep(100);
966                 WRITEPHONE(PortFD, &init_char, 1);
967         }
968
969         FB61_TX_SendStatusRequest();
970
971         FB61_Authentication();
972
973         /* FIXME: we should implement better support for ringtones and the utility
974            to set ringtones. */
975
976         // FB61_SendRingtoneRTTTL("/tmp/barbie.txt");
977
978         idle_timer = 0;
979
980         /* Now enter main loop */
981
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();
986                         idle_timer = 20;
987                 } else
988                         idle_timer--;
989
990                 usleep(100000);         /* Avoid becoming a "busy" loop. */
991         }
992 }
993 #endif /* WIN32 */
994
995 #ifdef WIN32
996 void FB61_InitializeLink()
997 {
998         int count;
999         DCB        dcb;
1000
1001         unsigned char init_char = 0x55;
1002         /* Daxer */
1003         unsigned char end_init_char = 0xc1;
1004
1005         /* Daxer Added for infared support */
1006         if ( CurrentConnectionType == GCT_Infrared ) {
1007                 dcb.DCBlength = sizeof(DCB);
1008
1009                 GetCommState(hPhone, &dcb);
1010                 dcb.BaudRate = CBR_9600;
1011                 SetCommState(hPhone, &dcb);
1012         }
1013
1014         /* Send init string to phone, this is a bunch of 0x55 characters. Timing is
1015            empirical. */
1016
1017         for (count = 0; count < 32; count ++) {
1018                 usleep(100);
1019                 WRITEPHONE(PortFD, &init_char, 1);
1020         }
1021
1022         WRITEPHONE(PortFD, &end_init_char, 1);
1023
1024         if ( CurrentConnectionType == GCT_Infrared ) {
1025                 dcb.BaudRate = CBR_115200;
1026                 SetCommState(hPhone, &dcb);
1027         }
1028  
1029         FB61_TX_SendStatusRequest();
1030
1031         FB61_Authentication();
1032 }
1033 #endif
1034
1035 /* Applications should call FB61_Terminate to shut down the FB61 thread and
1036    close the serial port. */
1037
1038 void FB61_Terminate(void)
1039 {
1040         /* Request termination of thread */
1041         RequestTerminate = true;
1042
1043 #ifndef WIN32
1044         /* Now wait for thread to terminate. */
1045         pthread_join(Thread, NULL);
1046
1047         /* Close serial port. */
1048         device_close();
1049
1050 #else
1051         CloseConnection();
1052 #endif
1053 }
1054
1055 #define ByteMask ((1 << Bits) - 1)
1056
1057 int UnpackEightBitsToSeven(int offset, int in_length, int out_length,
1058                            unsigned char *input, unsigned char *output)
1059 {
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;
1063         int Bits;
1064
1065         Bits = offset ? offset : 7;
1066
1067         while ((IN - input) < in_length) {
1068
1069                 *OUT = ((*IN & ByteMask) << (7 - Bits)) | Rest;
1070                 Rest = *IN >> Bits;
1071
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++;
1076                 IN++;
1077
1078                 if ((OUT - output) >= out_length) break;
1079
1080                 /* After reading 7 octets we have read 7 full characters but
1081                    we have 7 bits as well. This is the next character */
1082                 if (Bits == 1) {
1083                         *OUT = Rest;
1084                         OUT++;
1085                         Bits = 7;
1086                         Rest = 0x00;
1087                 } else {
1088                         Bits--;
1089                 }
1090         }
1091
1092         return OUT - output;
1093 }
1094
1095 unsigned char GetAlphabetValue(unsigned char value)
1096 {
1097         unsigned char i;
1098   
1099         if (value == '?') return 0x3f;
1100   
1101         for (i = 0 ; i < 128 ; i++)
1102                 if (GSM_Default_Alphabet[i] == value)
1103                         return i;
1104
1105         return 0x3f; /* '?' */
1106 }
1107
1108 int PackSevenBitsToEight(int offset, unsigned char *input, unsigned char *output)
1109 {
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;
1115
1116         /* If we don't begin with 0th bit, we will write only a part of the
1117            first octet */
1118         if (offset) {
1119                 *OUT = 0x00;
1120                 OUT++;
1121         }
1122
1123         while ((IN - input) < strlen(input)) {
1124                 unsigned char Byte = GetAlphabetValue(*IN);
1125
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 */
1129                 if (Bits != 7)
1130                         *(OUT-1) |= (Byte & ((1 << (7-Bits)) - 1)) << (Bits+1);
1131
1132                 Bits--;
1133
1134                 if (Bits == -1) Bits = 7;
1135                 else OUT++;
1136
1137                 IN++;
1138         }
1139         return (OUT - output);
1140 }
1141
1142 GSM_Error FB61_GetRFLevel(GSM_RFUnits *units, float *level)
1143 {
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
1146            command. */
1147         float   csq_map[5] = {0, 8, 16, 24, 31};
1148         int timeout = 10;
1149         int rf_level;
1150
1151         CurrentRFLevel = -1;
1152
1153         FB61_TX_SendStatusRequest();
1154
1155         /* Wait for timeout or other error. */
1156
1157         while (timeout && (CurrentRFLevel == -1)) {
1158                 if (!--timeout)
1159                         return (GE_TIMEOUT);
1160                 usleep (100000);
1161         }
1162
1163         /* Make copy in case it changes. */
1164         rf_level = CurrentRFLevel;
1165
1166         if (rf_level == -1)
1167                 return (GE_NOLINK);
1168
1169   /* Now convert between the different units we support. */
1170
1171   /* Arbitrary units. */
1172         if (*units == GRF_Arbitrary) {
1173                 *level = rf_level;
1174                 return (GE_NONE);
1175         }
1176
1177         /* CSQ units. */
1178         if (*units == GRF_CSQ) {
1179
1180                 if (rf_level <= 4)
1181                         *level = csq_map[rf_level];
1182                 else
1183                         *level = 99; /* Unknown/undefined */
1184
1185                 return (GE_NONE);
1186         }
1187
1188         *units = GRF_Arbitrary;
1189         *level = rf_level;
1190         return (GE_NONE);
1191 }
1192
1193 GSM_Error FB61_GetBatteryLevel(GSM_BatteryUnits *units, float *level)
1194 {
1195         int timeout = 10;
1196         int batt_level;
1197
1198         CurrentBatteryLevel = -1;
1199
1200         FB61_TX_SendStatusRequest();
1201
1202         /* Wait for timeout or other error. */
1203         while (timeout && (CurrentBatteryLevel == -1)) {
1204                 if (!--timeout)
1205                         return (GE_TIMEOUT);
1206                 usleep (100000);
1207         }
1208
1209         /* Take copy in case it changes. */
1210         batt_level = CurrentBatteryLevel;
1211
1212         if (batt_level != -1) {
1213                 /* Only units we handle at present are GBU_Arbitrary */
1214                 *units = GBU_Arbitrary;
1215                 *level = batt_level;
1216                 return (GE_NONE);
1217         } else return (GE_NOLINK);
1218 }
1219
1220 GSM_Error FB61_GetPowerSource(GSM_PowerSource *source)
1221 {
1222         int timeout = 10;
1223         CurrentPowerSource=-1;
1224
1225         FB61_TX_SendStatusRequest();
1226
1227         /* Wait for timeout or other error. */
1228         while (timeout && (CurrentPowerSource == -1)) {
1229                 if (!--timeout)
1230                         return (GE_TIMEOUT);
1231                 usleep (100000);
1232         }
1233
1234         if (CurrentPowerSource != -1) {
1235                 *source = CurrentPowerSource;
1236                 return (GE_NONE);
1237         } else return (GE_NOLINK);
1238 }
1239
1240 GSM_Error FB61_GetDisplayStatus(int *Status)
1241 {
1242         unsigned char req[4]={ FB61_FRAME_HEADER, 0x51 };
1243         FB61_TX_SendMessage(4, 0x0d, req);
1244         WAIT_ON(&DisplayStatusError, 10);
1245         *Status = DisplayStatus;
1246         return (GE_NONE);
1247 }
1248
1249 GSM_Error FB61_DialVoice(char *Number)
1250 {
1251         unsigned char req[64] = {FB61_FRAME_HEADER, 0x01};
1252         unsigned char req_end[] = {0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
1253         int i = 0;
1254
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);
1260
1261         return(GE_NONE);
1262 }
1263
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!
1268 */
1269
1270 GSM_Error FB61_DialData(char *Number, char type, void (* callpassup)(char c))
1271 {
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 };
1291
1292         int i = 0;
1293         u8 size;
1294
1295         CallPassup=callpassup;
1296
1297         switch (type) {
1298         case 0:
1299                 req_end = req_end0;
1300                 size = sizeof(req_end0);
1301                 break;
1302         case 1:
1303                 FB61_TX_SendMessage(sizeof(req3), 0x01, req3);
1304                 FB61_TX_SendMessage(sizeof(req4), 0x01, req4);
1305                 req_end = req_end1;
1306                 size = sizeof(req_end1);
1307                 break;
1308         case -1:   /* Just used to set the call passup */
1309                 return GE_NONE;
1310                 break;
1311         default:
1312                 req_end = req_end0;
1313                 size = sizeof(req_end0);
1314                 break;
1315         }
1316
1317         req[4] = strlen(Number);
1318
1319         for(i = 0; i < strlen(Number) ; i++)
1320                 req[5+i] = Number[i];
1321
1322         memcpy(req + 5 + strlen(Number), req_end, size);
1323
1324         FB61_TX_SendMessage(5 + size + strlen(Number), 0x01, req);
1325         if (type != 1) FB61_TX_SendMessage(26, 0x01, req2);
1326
1327         return (GE_NONE);
1328 }
1329
1330 GSM_Error FB61_GetIncomingCallNr(char *Number)
1331 {
1332         if (*CurrentIncomingCall != ' ') {
1333                 strcpy(Number, CurrentIncomingCall);
1334                 return GE_NONE;
1335         } else return GE_BUSY;
1336 }
1337
1338 GSM_Error FB61_CancelCall(void)
1339 {
1340         unsigned char req[] = { FB61_FRAME_HEADER, 0x08, 0x00, 0x85};
1341   
1342         req[4] = CallSequenceNumber;
1343         FB61_TX_SendMessage(6, 0x01, req);
1344   
1345         return GE_NONE;
1346 }  
1347   
1348 GSM_Error FB61_EnterSecurityCode(GSM_SecurityCode SecurityCode)
1349 {
1350         unsigned char req[15] = { FB61_FRAME_HEADER, 0x0a /* Enter code request. */, 0x00 /* Type of the entered code. */ };
1351         int i = 0;
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);
1359 }
1360
1361 GSM_Error FB61_GetSecurityCodeStatus(int *Status)
1362 {
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);
1367 }
1368
1369 GSM_Error FB61_GetDateTime(GSM_DateTime *date_time)
1370 {
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);
1375 }
1376
1377 GSM_Error FB61_GetAlarm(int alarm_number, GSM_DateTime *date_time)
1378 {
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);
1383 }
1384
1385 /* This function sends to the mobile phone a request for the SMS Center */
1386
1387 GSM_Error FB61_GetSMSCenter(GSM_MessageCenter *MessageCenter)
1388 {
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);
1394 }
1395
1396 /* This function set the SMS Center profile on the phone. */
1397
1398 GSM_Error FB61_SetSMSCenter(GSM_MessageCenter *MessageCenter)
1399 {
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. */
1409         };
1410         req[5] = MessageCenter->No;
1411         req[7] = MessageCenter->Format;
1412         req[9] = MessageCenter->Validity;
1413
1414         req[22] = SemiOctetPack(MessageCenter->Number, req+23);
1415         if (req[22] % 2) req[22]++;
1416         req[22] = req[22] / 2 + 1;
1417
1418         sprintf(req+34, "%s", MessageCenter->Name);
1419
1420         CurrentMessageCenter = MessageCenter;
1421         CurrentMessageCenterError = GE_BUSY;
1422
1423         FB61_TX_SendMessage(35+strlen(MessageCenter->Name), 0x02, req);
1424         return wait_on(&CurrentMessageCenterError,20);
1425 }
1426
1427 GSM_Error FB61_GetSMSStatus(GSM_SMSStatus *Status)
1428 {
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);
1433 }
1434
1435 GSM_Error FB61_GetIMEI(char *imei)
1436 {
1437         if (*IMEI) {
1438                 strncpy (imei, IMEI, FB61_MAX_IMEI_LENGTH);
1439                 return (GE_NONE);
1440         } else return (GE_TRYAGAIN);
1441 }
1442
1443 GSM_Error FB61_GetRevision(char *revision)
1444 {
1445         if (*Revision) {
1446                 strncpy (revision, Revision, FB61_MAX_REVISION_LENGTH);
1447                 return (GE_NONE);
1448         } else return (GE_TRYAGAIN);
1449 }
1450
1451 GSM_Error FB61_GetModel(char *model)
1452 {
1453         if (*Model) {
1454                 strncpy (model, Model, FB61_MAX_MODEL_LENGTH);
1455                 return (GE_NONE);
1456         } else return (GE_TRYAGAIN);
1457 }
1458
1459 GSM_Error FB61_SetDateTime(GSM_DateTime *date_time)
1460 {
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. */
1468         };
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;
1475
1476         FB61_TX_SendMessage(14, 0x11, req);
1477         return wait_on(&CurrentSetDateTimeError, 20);
1478 }
1479
1480 /* FIXME: we should also allow to set the alarm off :-) */
1481
1482 GSM_Error FB61_SetAlarm(int alarm_number, GSM_DateTime *date_time)
1483 {
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. */
1490         };
1491         req[8] = date_time->Hour;
1492         req[9] = date_time->Minute;
1493
1494         FB61_TX_SendMessage(11, 0x11, req);
1495         return wait_on(&CurrentSetAlarmError, 20);
1496 }
1497
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
1500    occurs. */
1501
1502 GSM_Error FB61_GetMemoryLocation(GSM_PhonebookEntry *entry)
1503 {
1504         unsigned char req[] = {FB61_FRAME_HEADER, 0x01, 0x00, 0x00, 0x00};
1505
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);
1511 }
1512
1513 /* Routine to write phonebook location in phone. Designed to be called by
1514    application code. Will block until location is written or timeout
1515    occurs. */
1516
1517 GSM_Error FB61_WritePhonebookLocation(GSM_PhonebookEntry *entry)
1518 {
1519         unsigned char req[128] = { FB61_FRAME_HEADER, 0x04, 0x00, 0x00 };
1520         int i = 0, current = 0;
1521
1522         req[4] = FB61_GetMemoryType(entry->MemoryType);
1523         req[5] = entry->Location;
1524
1525         req[6] = strlen(entry->Name);
1526
1527         current = 7;
1528
1529         for (i = 0; i<strlen(entry->Name); i++)
1530                 req[current+i] = entry->Name[i];
1531
1532         current += strlen(entry->Name);
1533
1534         req[current++] = strlen(entry->Number);
1535
1536         for (i = 0; i < strlen(entry->Number); i++)
1537                 req[current+i] = entry->Number[i];
1538
1539         current += strlen(entry->Number);
1540
1541         /* Jano: This allow to save 14 characters name into SIM memory, when
1542            No Group is selected. */
1543
1544         if (entry->Group == 5)
1545                 req[current++] = 0xff;
1546         else
1547                 req[current++] = entry->Group;
1548
1549         FB61_TX_SendMessage(current, 3, req);
1550         return wait_on(&CurrentPhonebookError, 50);
1551 }
1552
1553 GSM_Error FB61_NetMonitor(unsigned char mode, char *Screen)
1554 {
1555         unsigned char req1[] = { 0x00, 0x01, 0x64, 0x01 };
1556         unsigned char req2[] = { 0x00, 0x01, 0x7e, 0x00 };
1557
1558         CurrentNetmonitor = Screen;
1559         FB61_TX_SendMessage(4, 0x40, req1);
1560         req2[3] = mode;
1561         FB61_TX_SendMessage(4, 0x40, req2);
1562         return wait_on(&CurrentNetmonitorError, 20);
1563 }
1564
1565 GSM_Error FB61_SendDTMF(char *String)
1566 {
1567         unsigned char req[64] = { FB61_FRAME_HEADER, 0x50, 0x00 /* Length of DTMF string. */ };
1568         u8 length=strlen(String);
1569
1570         req[4] = length;
1571         sprintf(req+5, "%s", String);
1572         FB61_TX_SendMessage(5+length, 0x01, req);
1573         return (GE_NONE);
1574 }
1575
1576 GSM_Error FB61_GetSpeedDial(GSM_SpeedDial *entry)
1577 {
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);
1583 }
1584
1585 GSM_Error FB61_SetSpeedDial(GSM_SpeedDial *entry)
1586 {
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);
1593 }
1594
1595 GSM_Error FB61_GetSMSMessage(GSM_SMSMessage *message)
1596 {
1597         unsigned char req[10] = { FB61_FRAME_HEADER, 0x07, 0x02 /* Unknown */, 0x00 /* Location */, 0x01, 0x64};
1598         int timeout = 60;
1599
1600         /* State machine code writes data to these variables when it comes in. */
1601
1602         CurrentSMSMessage = message;
1603         CurrentSMSMessageError = GE_BUSY;
1604         req[5] = message->Location;
1605         FB61_TX_SendMessage(8, 0x02, req);
1606
1607         while (timeout && (CurrentSMSMessageError == GE_BUSY || CurrentSMSMessageError == GE_SMSWAITING)) {
1608                 if (!--timeout)
1609                         return (GE_TIMEOUT);
1610                 usleep (100000);
1611         }
1612         return (CurrentSMSMessageError);
1613 }
1614
1615 GSM_Error FB61_DeleteSMSMessage(GSM_SMSMessage *message)
1616 {
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);
1622 }
1623
1624 /* This function implements packing of numbers (SMS Center number and
1625    destination number) for SMS sending function. */
1626
1627 int SemiOctetPack(char *Number, unsigned char *Output)
1628 {
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
1632                           packed numbers. */
1633
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. */
1638   
1639         if (*IN == '+') {
1640                 *OUT++ = GNT_INTERNATIONAL; /* International number */
1641                 IN++;
1642         } else *OUT++ = GNT_UNKNOWN; /* Unknown number */
1643
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. */
1646
1647         while (*IN) {
1648                 if (count & 0x01) {
1649                         *OUT = *OUT | ((*IN - '0') << 4);
1650                         OUT++;
1651                 }
1652                 else
1653                         *OUT = *IN - '0';
1654                 count++; IN++;
1655         }
1656
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
1659            digits. */
1660
1661         if (count & 0x01) {
1662                 *OUT=*OUT | 0xf0;
1663                 OUT++;
1664                 return (2 * (OUT - Output - 1) - 1);
1665         }
1666
1667         return (2 * (OUT - Output - 1));
1668 }
1669
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)
1673 {
1674         GSM_Error error;
1675
1676         unsigned char req[256] = {
1677                 FB61_FRAME_HEADER,
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)
1686                           00 - not present
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
1700         };
1701
1702         int size, offset;
1703
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)
1708                         return error;
1709                 SMS->MessageCenter.No = 0;
1710         }
1711         dprintf(_("Sending SMS to %s via message center %s\n"), SMS->Destination, SMS->MessageCenter.Number);
1712
1713         if (SMS->UDHType) {
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);
1718                 req[18] |= 0x40;
1719         } else {
1720                 offset = 0;
1721                 /* such messages should be sent as concatenated */
1722                 if (strlen(SMS->MessageText) > GSM_MAX_SMS_LENGTH)
1723                         return(GE_SMSTOOLONG);
1724         }
1725
1726         /* size is the length of the data in octets including udh */
1727         /* SMS->Length is:
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
1730         */
1731   
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 */
1737                 req[21] |= 0xf4;
1738         } else {
1739                 size = PackSevenBitsToEight((7-offset)%7, SMS->MessageText, req + 42 + offset);
1740                 size += offset;
1741                 SMS->Length = (offset*8 + ((7-offset)%7)) / 7 + strlen(SMS->MessageText);
1742         }
1743
1744         req[22] = SMS->Length;
1745
1746         CurrentSMSMessageError=GE_BUSY;
1747
1748         req[6] = SemiOctetPack(SMS->MessageCenter.Number, req+7);
1749         if (req[6] % 2) req[6]++;
1750
1751         req[6] = req[6] / 2 + 1;
1752
1753         /* Mask for request for delivery report from SMSC */
1754         if (SMS->Type == GST_DR) req[18] |= 0x20;
1755  
1756         /* Message Class */
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;
1762         default: break;
1763         }
1764   
1765         /* Mask for compression */
1766         /* FIXME: support for compression */
1767         /* See GSM 03.42 */
1768 /*  if (SMS->Compression) req[21] = req[21] | 0x20; */
1769
1770         req[23] = SemiOctetPack(SMS->Destination, req+24);
1771
1772         /* TP-Validity Period handling */
1773
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 :-) */
1780
1781         /* 5 minutes intervals up to 12 hours = 720 minutes */
1782         if (SMS->Validity <= 720)
1783                 req[35] = (unsigned char) (SMS->Validity/5)-1;
1784
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;
1788
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;
1792
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;
1796
1797         FB61_TX_SendMessage(42+size, 0x02, req);
1798         return wait_on(&CurrentSMSMessageError, 70);
1799 }
1800
1801 GSM_Error FB61_SaveSMSMessage(GSM_SMSMessage *SMS)
1802 {
1803         unsigned char req[256] = {
1804                 FB61_FRAME_HEADER,
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)
1813                           00 - not present
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
1827         };
1828
1829         int size, offset;
1830
1831         if (SMS->Status == GSS_NOTSENTREAD)
1832                 req[4] |= 0x02;
1833
1834         if (SMS->Location)
1835                 req[6] = SMS->Location;
1836
1837         offset = 0;
1838         /* such messages should be sent as concatenated */
1839         if (strlen(SMS->MessageText) > GSM_MAX_SMS_LENGTH)
1840                 return(GE_SMSTOOLONG);
1841
1842         /* size is the length of the data in octets including udh */
1843         /* SMS->Length is:
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
1846         */
1847   
1848         /* offset now denotes UDH length */
1849         size = PackSevenBitsToEight((7-offset)%7, SMS->MessageText, req + 44 + offset);
1850         size += offset;
1851         SMS->Length = (offset*8 + ((7-offset)%7)) / 7 + strlen(SMS->MessageText);
1852
1853         req[24] = SMS->Length;
1854         FB61_TX_SendMessage(44+size, 0x14, req);
1855         return wait_on(&CurrentSMSMessageError, 70);
1856 }
1857
1858 /* Enable and disable Cell Broadcasting */
1859
1860 GSM_Error FB61_EnableCellBroadcast(void)
1861 {
1862         unsigned char req[] = {FB61_FRAME_HEADER, 0x20, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01};
1863         CurrentCBError = GE_BUSY;
1864
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);
1871 }
1872
1873 GSM_Error FB61_DisableCellBroadcast(void) /* Should work, but not tested fully */
1874 {
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);
1878 }
1879
1880 GSM_Error FB61_ReadCellBroadcast(GSM_CBMessage *Message)
1881 {
1882         if (CurrentCBMessage != NULL) {
1883                 if (CurrentCBMessage->New == true) {
1884                         Message->Channel = CurrentCBMessage->Channel;
1885                         strcpy(Message->Message,CurrentCBMessage->Message);
1886                         CurrentCBMessage->New = false;
1887                         return (GE_NONE);
1888                 }
1889         }
1890         return (GE_NONEWCBRECEIVED);
1891 }
1892
1893 /* Send a bitmap or welcome-note */
1894
1895 GSM_Error FB61_SetBitmap(GSM_Bitmap *Bitmap)
1896 {
1897         unsigned char req[600] = { FB61_FRAME_HEADER };
1898         u16 count = 3;
1899         u8 textlen;
1900
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);
1908       
1909                 count += textlen;
1910                 FB61_TX_SendMessage(count, 0x05, req);
1911                 break;
1912
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);
1919       
1920                 count += textlen;
1921                 FB61_TX_SendMessage(count, 0x05, req);
1922                 break;
1923
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);
1933                 break;
1934
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);
1949                 break;
1950
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:
1959                                         0x00 - Off
1960                                         0x01 - On
1961                                         0x02 - View Graphics
1962                                         0x03 - Send Graphics
1963                                         0x04 - Send via IR
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);
1975                 break;
1976
1977         case GSM_PictureImage:
1978                 return (GE_NOTIMPLEMENTED);
1979                 break;
1980
1981         case GSM_None:
1982                 break;
1983         }
1984         return wait_on(&SetBitmapError, 70);
1985 }
1986
1987 /* Get a bitmap from the phone */
1988
1989 GSM_Error FB61_GetBitmap(GSM_Bitmap *Bitmap)
1990 {
1991         unsigned char req[10] = { FB61_FRAME_HEADER };
1992         u8 count = 3;
1993         int timeout = 10;
1994
1995         GetBitmap = Bitmap;
1996         GetBitmapError = GE_BUSY;
1997  
1998         /* This is needed to avoid the packet being interrupted */
1999         /* Remove when multipacket code is implemented fully */
2000
2001         DisableKeepalive = true;
2002
2003         while (timeout && (MessagesSent != AcksReceived)) {
2004                 usleep(100000);
2005                 timeout--;
2006         }
2007
2008         /* We'll assume that nothing more will be received after 1 sec */
2009
2010         MessagesSent = AcksReceived;
2011
2012         switch (GetBitmap->type) {
2013         case GSM_StartupLogo:
2014                 req[count++] = 0x16;
2015                 FB61_TX_SendMessage(count, 0x05, req);
2016                 break;
2017         case GSM_WelcomeNoteText:
2018                 req[count++] = 0x16;
2019                 FB61_TX_SendMessage(count, 0x05, req);
2020                 break;
2021         case GSM_DealerNoteText:
2022                 req[count++] = 0x16;
2023                 FB61_TX_SendMessage(count, 0x05, req);
2024                 break;  
2025         case GSM_OperatorLogo:
2026                 req[count++] = 0x33;
2027                 req[count++] = 0x01; /* Location 1 */
2028                 FB61_TX_SendMessage(count, 0x05, req);
2029                 break;
2030         case GSM_CallerLogo:
2031                 req[count++] = 0x10;
2032                 req[count++] = Bitmap->number;
2033                 FB61_TX_SendMessage(count, 0x03, req);
2034                 break;
2035         default:
2036                 break;
2037         }
2038
2039         /* 5secs for the command to complete */
2040   
2041         WAIT_ON(&GetBitmapError, 50);
2042
2043         DisableKeepalive = false;
2044         GetBitmap = NULL;
2045         return (GetBitmapError);
2046 }
2047
2048
2049 GSM_Error FB61_SetRingTone(GSM_Ringtone *ringtone)
2050 {
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
2059                          to fill in the two
2060                          bytes :-) */
2061         };
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);
2066         return (GE_NONE);
2067 }
2068
2069 GSM_Error FB61_SendRingTone(GSM_Ringtone *ringtone, char *dest)
2070 {
2071         GSM_SMSMessage SMS;
2072         GSM_Error error;
2073
2074         int size = GSM_MAX_RINGTONE_PACKAGE_LENGTH;
2075         char Package[GSM_MAX_RINGTONE_PACKAGE_LENGTH];
2076         char udh[] = {
2077                 0x06,       /* User Data Header Length */
2078                 0x05,       /* IEI */
2079                 0x04,       /* IEDL */
2080                 0x15, 0x81, /* Destination port */
2081                 0x15, 0x81  /* Originator port, only
2082                                to fill in the two
2083                                bytes :-) */
2084         };
2085
2086         /* Default settings for SMS message:
2087            - no delivery report
2088            - Class Message 1
2089            - no compression
2090            - 8 bit data
2091            - SMSC no. 1
2092            - validity 3 days
2093            - set UserDataHeaderIndicator
2094         */
2095
2096         SMS.Type = GST_MO;
2097         SMS.Class = 1;
2098         SMS.Compression = false;
2099         SMS.EightBit = true;
2100         SMS.MessageCenter.No = 1;
2101         SMS.Validity = 4320; /* 4320 minutes == 72 hours */
2102
2103         SMS.UDHType = GSM_RingtoneUDH;
2104
2105         strcpy(SMS.Destination, dest);
2106         GSM_PackRingtone(ringtone, Package, &size);
2107         memcpy(SMS.UDH, udh, 7);
2108         memcpy(SMS.MessageText, Package, size);
2109
2110         /* Send the message. */
2111         error = FB61_SendSMSMessage(&SMS, size);
2112
2113         if (error == GE_SMSSENDOK) dprintf(_("Send succeeded!\n"));
2114         else dprintf(_("SMS Send failed (error=%d)\n"), error);
2115
2116         return (GE_NONE);
2117 }
2118
2119 GSM_Error FB61_Reset(unsigned char type)
2120 {
2121         unsigned char req[4] = { 0x00,0x01,0x64,0x03 };
2122         req[3] = type;
2123         FB61_TX_SendMessage(4, 0x40, req);
2124         return (GE_NONE);
2125 }
2126
2127 #ifndef WIN32
2128
2129 void FB61_DumpSerial(void)
2130 {
2131         int PortFD;
2132         unsigned int Flags=0;
2133
2134         PortFD = device_getfd();
2135         ioctl(PortFD, TIOCMGET, &Flags);
2136
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"));
2142         dprintf("\n");
2143 }
2144
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
2148    ...).
2149
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.
2153
2154    Colin wrote:
2155
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.
2158
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
2165    power. */
2166
2167 /* FIXME: In this function we use ioctls - can people with different OSes than
2168    my (Linux) tell me if it works for them? */
2169
2170 void FB61_SetFBUS(void)
2171 {
2172 #ifdef DEBUG
2173         FB61_DumpSerial();  
2174         dprintf(_("Setting FBUS communication...\n"));
2175 #endif
2176
2177         /* clearing the RTS bit and setting the DTR bit*/
2178         device_setdtrrts(1, 0);
2179
2180 #ifdef DEBUG
2181         FB61_DumpSerial();  
2182 #endif /* DEBUG */
2183 }
2184
2185 /* Called by initialisation code to open comm port in asynchronous mode. */
2186
2187 bool FB61_OpenSerial(void)
2188 {
2189         int result;
2190   
2191 #if __unices__
2192         int rtn;
2193 #else
2194         struct sigaction sig_io;
2195
2196         /* Set up and install handler before enabling async IO on port. */
2197
2198         sig_io.sa_handler = FB61_SigHandler;
2199         sig_io.sa_flags = 0;
2200         sigaction (SIGIO, &sig_io, NULL);
2201 #endif
2202
2203         /* Open device. */
2204
2205         result = device_open(PortDevice, false, true, false, GCT_Serial);
2206
2207         if (!result) {
2208                 perror(_("Couldn't open FB61 device"));
2209                 return false;
2210         }
2211
2212 #if __unices__
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;
2216 #endif
2217
2218         device_changespeed(115200);
2219         FB61_SetFBUS();
2220         return (true);
2221 }
2222
2223 void FB61_SigHandler(int status)
2224 {
2225         unsigned char buffer[255];
2226         int count, res;
2227         res = device_read(buffer, 255);
2228         for (count = 0; count < res ; count ++)
2229                 FB61_RX_StateMachine(buffer[count]);
2230 }
2231 #endif /* WIN32 */
2232
2233 char *FB61_GetBCDNumber(u8 *Number) 
2234 {
2235         static char Buffer[20] = "";
2236
2237         /* This is the length of BCD coded number */
2238         int length = Number[0];
2239         int count;
2240
2241         if (Number[1] == 0x91) sprintf(Buffer, "+");
2242         else Buffer[0] = '\0';
2243
2244         for (count = 0; count < length-1; count++) {
2245                 int Digit;
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);
2250         }
2251
2252         return Buffer;
2253 }
2254
2255 char *FB61_GetPackedDateTime(u8 *Number)
2256 {
2257         static char Buffer[20] = "";
2258
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);
2265   
2266         return Buffer;
2267 }
2268
2269 enum FB61_RX_States FB61_RX_DispatchMessage(void)
2270 {
2271         int i, tmp, count, offset, off, length;
2272         unsigned char output[160];
2273         bool supported;
2274
2275         if (RX_Multiple) return FB61_RX_Sync;
2276
2277 #ifdef DEBUG
2278         /* Do not debug Ack and RLP frames to detail. */
2279
2280         if (MessageType != FB61_FRTYPE_ACK && MessageType != 0xf1)
2281                 FB61_RX_DisplayMessage();
2282 #endif /* DEBUG */
2283
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.
2291
2292                            The message looks like this:
2293
2294                            Msg Destination: PC
2295                            Msg Source: Phone
2296                            Msg Type: 01
2297                            Msg Unknown: 00
2298                            Msg Len: 0e
2299
2300                            Phone: [01 ][08 ][00 ] is the header of the frame
2301
2302                            [03 ] is the call message subtype
2303
2304                            [05 ] is the call sequence number
2305
2306                            [05 ] unknown 
2307
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 :-(
2312                         */
2313
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"));
2317                         break;
2318
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');
2327                         break;
2328
2329                         /* Remote end has gone away before you answer the call.  Probably your
2330                            mother-in-law or banker (which is worse?) ... */
2331                 case 0x04:
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(' ');
2336                         break;
2337
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
2341                            them */
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]);
2347                         dprintf("\n");
2348                         dprintf(_("   Name: "));
2349                         for (tmp = 0; tmp < MessageBuffer[7+count]; tmp++)
2350                                 dprintf("%c", MessageBuffer[8+count+tmp]);
2351                         dprintf("\n");
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]);
2357                         break;
2358
2359                         /* Call answered. Probably your girlfriend...*/
2360                 case 0x07:
2361                         dprintf(_("Message: Call answered.\n"));
2362                         dprintf(_("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2363                         break;
2364
2365                         /* Call ended. Girlfriend is girlfriend, but time is money :-) */
2366                 case 0x09:
2367                         dprintf(_("Message: Call ended by your phone.\n"));
2368                         dprintf(_("   Sequence nr. of the call: %d\n"), MessageBuffer[4]);
2369                         break;
2370
2371                         /* This message has been seen with the message of subtype 0x09
2372                            after I hang the call.
2373
2374                            Msg Destination: PC
2375                            Msg Source: Phone
2376                            Msg Type: 01
2377                            Msg Unknown: 00
2378                            Msg Len: 08
2379                            Phone: [01 ][08 ][00 ][0a ][04 ][87 ][01 ][42B][1a ][c2 ]
2380
2381                            What is the meaning of 87? Can you spell some magic light into
2382                            this issue?
2383
2384                         */
2385
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"));
2390
2391                         CurrentIncomingCall[0] = ' ';
2392                         if (CallPassup) CallPassup(' ');
2393                         break;
2394
2395                 default:
2396                         dprintf(_("Message: Unknown message of type 0x01\n"));
2397                         break;
2398                 }
2399                 break;
2400
2401                 /* SMS handling */
2402
2403         case 0x02:
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;
2408                         break;
2409
2410                 case 0x03: /* SMS message send to the network failed */
2411                         dprintf(_("Message: Sending SMS Message failed.\n"));
2412                         CurrentSMSMessageError = GE_SMSSENDFAILED;
2413                         break;
2414
2415                 case 0x10:
2416                         dprintf(_("Message: SMS Message Received\n"));
2417                         dprintf(_("   SMS center number: %s\n"), FB61_GetBCDNumber(MessageBuffer+7));
2418
2419                         MessageBuffer[23] = (MessageBuffer[23]+1)/2+1;
2420
2421                         dprintf(_("   Remote number: %s\n"), FB61_GetBCDNumber(MessageBuffer+23));
2422                         dprintf(_("   Date: %s\n"), FB61_GetPackedDateTime(MessageBuffer+35));
2423                         dprintf(_("   SMS: "));
2424
2425                         tmp = UnpackEightBitsToSeven(0, MessageLength - 42 - 2, MessageBuffer[22], MessageBuffer + 42, output);
2426
2427                         for (i = 0; i < tmp; i++) dprintf("%c", GSM_Default_Alphabet[output[i]]);
2428
2429                         dprintf("\n");
2430                         break;
2431
2432                 case 0x21:
2433                         dprintf(_("Message: Cell Broadcast enabled/disabled successfully.\n"));
2434                         CurrentCBError = GE_NONE;
2435                         break;
2436
2437                 case 0x23:
2438                         CurrentCBMessage->Channel = MessageBuffer[7];
2439                         CurrentCBMessage->New = true;
2440                         tmp=UnpackEightBitsToSeven(0, 82, 82, MessageBuffer+10, output);
2441
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]]);
2446
2447                         dprintf("\n");
2448                         for (i = 0; i < tmp; i++)
2449                                 CurrentCBMessage->Message[i] = GSM_Default_Alphabet[output[i]];
2450
2451                         break;
2452
2453   
2454                 case 0x31:
2455                         dprintf(_("Message: SMS Center correctly set.\n"));
2456                         CurrentMessageCenterError = GE_NONE;
2457                         break;
2458
2459                 case 0x34:
2460
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));
2466
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 "));
2471
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;
2478                         }
2479
2480                         dprintf("\n");
2481
2482                         dprintf(_("   SMS Center message validity is "));
2483
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;
2492                         }
2493                         dprintf("\n");
2494                         CurrentMessageCenterError = GE_NONE;
2495                         break;
2496
2497                 case 0x35:
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
2500                            fail. */
2501                         dprintf(_("Message: SMS Center error received:\n"));
2502                         dprintf(_("   The request for SMS Center failed.\n"));
2503
2504                         /* FIXME: appropriate error. */
2505                         CurrentMessageCenterError = GE_INTERNALERROR;
2506                         break;  
2507
2508                 default:
2509                         dprintf(_("Unknown message!\n"));
2510                         break;
2511                 }
2512
2513                 break;
2514
2515                 /* Phonebook handling */
2516
2517         case 0x03:
2518
2519                 switch (MessageBuffer[3]) {
2520
2521                 case 0x02:
2522
2523                         CurrentPhonebookEntry->Empty = true;
2524
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]);
2530                         dprintf("\n");
2531
2532                         memcpy(CurrentPhonebookEntry->Name, MessageBuffer + 6, count);
2533                         CurrentPhonebookEntry->Name[count] = 0x00;
2534                         CurrentPhonebookEntry->Empty = false;
2535
2536                         i = 7 + count;
2537                         count = MessageBuffer[6+count];
2538
2539                         dprintf(_("   Number: "));
2540                         for (tmp = 0; tmp < count; tmp++)
2541                                 dprintf("%c", MessageBuffer[i+tmp]);
2542                         dprintf("\n");
2543
2544                         memcpy(CurrentPhonebookEntry->Number, MessageBuffer + i, count);
2545                         CurrentPhonebookEntry->Number[count] = 0x00;
2546                         CurrentPhonebookEntry->Group = MessageBuffer[i+count];
2547       
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];
2554
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);
2559
2560                         /* Signal no error to calling code. */
2561
2562                         CurrentPhonebookError = GE_NONE;
2563
2564                         break;
2565
2566                 case 0x03:
2567                         dprintf(_("Message: Phonebook read entry error received:\n"));
2568                         switch (MessageBuffer[4]) {
2569                         case 0x7d:
2570                                 dprintf(_("   Invalid memory type!\n"));
2571                                 CurrentPhonebookError = GE_INVALIDMEMORYTYPE;
2572                                 break;
2573                         default:
2574                                 dprintf(_("   Unknown error!\n"));
2575                                 CurrentPhonebookError = GE_INTERNALERROR;
2576                                 break;
2577                         }
2578                         break;
2579
2580                 case 0x05:
2581                         dprintf(_("Message: Phonebook written correctly.\n"));
2582                         CurrentPhonebookError = GE_NONE;
2583                         break;
2584
2585                 case 0x06:
2586                         switch (MessageBuffer[4]) {
2587
2588                                 /* FIXME: other errors? When I send the phonebook with index of 350 it
2589                                    still report error 0x7d :-( */
2590
2591                         case 0x7d:
2592                                 dprintf(_("Message: Phonebook not written - name is too long.\n"));
2593                                 CurrentPhonebookError = GE_PHBOOKNAMETOOLONG;
2594                                 break;
2595
2596                         default:
2597                                 dprintf(_("   Unknown error!\n"));
2598                                 CurrentPhonebookError = GE_INTERNALERROR;
2599                                 break;
2600                         }
2601
2602                         break;
2603
2604                 case 0x08:
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;
2612                         break;
2613
2614                 case 0x09:
2615                         switch (MessageBuffer[4]) {
2616                         case 0x6f:
2617                                 dprintf(_("Message: Memory status error, phone is probably powered off.\n"));
2618                                 CurrentMemoryStatusError = GE_TIMEOUT;
2619                                 break;
2620
2621                         case 0x7d:
2622                                 dprintf(_("Message: Memory status error, memory type not supported by phone model.\n"));
2623                                 CurrentMemoryStatusError = GE_INTERNALERROR;
2624                                 break;
2625
2626                         case 0x8d:
2627                                 dprintf(_("Message: Memory status error, waiting for security code.\n"));
2628                                 CurrentMemoryStatusError = GE_INVALIDSECURITYCODE;
2629                                 break;
2630
2631                         default:
2632                                 dprintf(_("Message: Unknown Memory status error, subtype (MessageBuffer[4]) = %02x\n"),MessageBuffer[4]);
2633                                 break;
2634                         }
2635
2636                         break;
2637     
2638                 case 0x11:   /* Get group data */
2639       
2640                         /* [ID],[name_len],[name].,[ringtone],[graphicon],[lenhi],[lenlo],[bitmap] */
2641  
2642                         if (GetBitmap != NULL) {
2643                                 count = MessageBuffer[5];
2644                                 memcpy(GetBitmap->text, MessageBuffer+6, count);
2645                                 GetBitmap->text[count] = 0;
2646
2647                                 dprintf(_("Message: Caller group logo etc.\n"));
2648                                 dprintf(_("Caller group name: %s\n"), GetBitmap->text);
2649
2650                                 count += 6;
2651                                 GetBitmap->ringtone = MessageBuffer[count++];
2652                                 count++;
2653                                 GetBitmap->size = MessageBuffer[count++]<<8;
2654                                 GetBitmap->size += MessageBuffer[count++];
2655                                 count++;
2656                                 GetBitmap->width = MessageBuffer[count++];
2657                                 GetBitmap->height = MessageBuffer[count++];
2658                                 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;
2663                         }
2664                         else {
2665                                 dprintf(_("Message: Caller group data received but not requested!\n"));
2666                         }
2667                         break;
2668
2669                 case 0x12:   /* Get group data error */
2670                         GetBitmapError = GE_UNKNOWN;   
2671                         dprintf(_("Message: Error attempting to get caller group data.\n"));
2672                         break;
2673       
2674                 case 0x14:   /* Set group data OK */
2675                         SetBitmapError = GE_NONE;      
2676                         dprintf(_("Message: Caller group data set correctly.\n"));
2677                         break;
2678
2679                 case 0x15:   /* Set group data error */
2680                         SetBitmapError = GE_UNKNOWN;      
2681                         dprintf(_("Message: Error attempting to set caller group data\n"));
2682                         break;  
2683
2684                 case 0x17:
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;
2692                         break;
2693
2694                 case 0x18:
2695                         dprintf(_("Message: Speed dial entry error\n"));
2696                         CurrentSpeedDialError = GE_INVALIDSPEEDDIALLOCATION;
2697                         break;
2698
2699                 case 0x1a:
2700                         dprintf(_("Message: Speed dial entry set.\n"));
2701                         CurrentSpeedDialError = GE_NONE;
2702                         break;
2703
2704                 case 0x1b:
2705                         dprintf(_("Message: Speed dial entry setting error.\n"));
2706                         CurrentSpeedDialError = GE_INVALIDSPEEDDIALLOCATION;
2707                         break;
2708
2709                 default:
2710                         dprintf(_("Message: Unknown message of type 0x03\n"));
2711                         break;
2712                 }
2713
2714                 break;
2715
2716                 /* Phone status */
2717           
2718         case 0x04:
2719                 switch (MessageBuffer[3]) {
2720                 case 0x02:
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
2726                                    know... */
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;
2731                         }
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;
2737                         }
2738                         dprintf(_("   Battery Level: %d\n"), MessageBuffer[8]);
2739                         dprintf(_("   Signal strength: %d\n"), MessageBuffer[5]);
2740
2741                         CurrentRFLevel = MessageBuffer[5];
2742                         CurrentBatteryLevel = MessageBuffer[8];
2743                         CurrentPowerSource = MessageBuffer[7];
2744                         break;
2745
2746                 default:
2747                         dprintf(_("Message: Unknown message of type 0x04\n"));
2748                         break;
2749                 }
2750
2751                 break;
2752   
2753                 /* Startup Logo, Operator Logo and Profiles. */
2754
2755         case 0x05:
2756                 switch (MessageBuffer[3]) {
2757                 case 0x11:   /* Profile feature change result */
2758                         dprintf(_("Message: Profile feature change result.\n"));
2759                         CurrentProfileError = GE_NONE;
2760                         break;
2761
2762                 case 0x14:   /* Profile feature */
2763                         switch (MessageBuffer[6]) {
2764                         case 0x00:
2765                                 CurrentProfile->KeypadTone = MessageBuffer[8];
2766                                 break;
2767                         case 0x01:
2768                                 CurrentProfile->Lights = MessageBuffer[8];
2769                                 break;
2770                         case 0x02:
2771                                 CurrentProfile->CallAlert = MessageBuffer[8];
2772                                 break;
2773                         case 0x03:
2774                                 CurrentProfile->Ringtone = MessageBuffer[8];
2775                                 break;
2776                         case 0x04:
2777                                 CurrentProfile->Volume = MessageBuffer[8];
2778                                 break;
2779                         case 0x05:
2780                                 CurrentProfile->MessageTone = MessageBuffer[8];
2781                                 break;
2782                         case 0x06:
2783                                 CurrentProfile->Vibration = MessageBuffer[8];
2784                                 break;
2785                         case 0x07:
2786                                 CurrentProfile->WarningTone = MessageBuffer[8];
2787                                 break;
2788                         case 0x08:
2789                                 CurrentProfile->CallerGroups = MessageBuffer[8];
2790                                 break;
2791                         case 0x09:
2792                                 CurrentProfile->AutomaticAnswer = MessageBuffer[8];
2793                                 break;
2794                         }
2795
2796                         CurrentProfileError = GE_NONE;
2797                         break;
2798
2799                 case 0x17:   /* Startup Logo */
2800                         dprintf(_("Message: Startup Logo, welcome note and dealer welcome note received.\n"));
2801                         if (GetBitmap != NULL) {
2802                                 supported = false;
2803                                 count = 5;
2804                                 for (tmp = 0; tmp < MessageBuffer[4]; tmp++){
2805                                         switch (MessageBuffer[count++]) {
2806                                         case 0x01:
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);
2813                                                 } else {
2814                                                         length = MessageBuffer[count++];
2815                                                         length = length * MessageBuffer[count++] / 8;
2816                                                 }
2817                                                 count += length;
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;
2822                                                 break;
2823                                         case 0x02:
2824                                                 length = MessageBuffer[count];
2825                                                 if (GetBitmap->type == GSM_WelcomeNoteText) {
2826                                                         memcpy(GetBitmap->text, MessageBuffer + count + 1, length);
2827                                                         GetBitmap->text[length] = 0;
2828                                                 }
2829                                                 dprintf(_("Startup Text supported - "));
2830                                                 if (length != 0) {
2831                                                         dprintf(_("currently set to \""));
2832                                                         for (i = 0; i < length; i++) dprintf(_("%c"), MessageBuffer[count+1+i]);
2833                                                         dprintf(_("\"\n"));
2834                                                 } else {
2835                                                         dprintf(_("currently empty\n"));
2836                                                 }
2837                                                 count += length + 1;
2838                                                 if (GetBitmap->type == GSM_WelcomeNoteText) supported = true;
2839                                                 break;
2840                                         case 0x03:
2841                                                 length = MessageBuffer[count];
2842                                                 if (GetBitmap->type == GSM_DealerNoteText) {
2843                                                         memcpy(GetBitmap->text, MessageBuffer + count + 1, length);
2844                                                         GetBitmap->text[length] = 0;
2845                                                 }
2846                                                 dprintf(_("Dealer Welcome supported - "));
2847                                                 if (length != 0) {
2848                                                         dprintf(_("currently set to \""));
2849                                                         for (i = 0;i < length; i++) dprintf(_("%c"), MessageBuffer[count+1+i]);
2850                                                         dprintf(_("\"\n"));
2851                                                 } else dprintf(_("currently empty\n"));
2852                                                 count += length + 1;
2853                                                 if (GetBitmap->type==GSM_DealerNoteText) supported = true;
2854                                                 break;
2855                                         }
2856                                 }
2857                                 if (supported) GetBitmapError = GE_NONE;
2858                                 else GetBitmapError = GE_NOTSUPPORTED;
2859                         } else dprintf(_("Message: Startup logo received but not requested!\n"));
2860                         break;
2861
2862                 case 0x19:   /* Set startup OK */
2863                         SetBitmapError = GE_NONE;
2864                         dprintf(_("Message: Startup logo, welcome note or dealer welcome note correctly set.\n"));
2865                         break;      
2866
2867                 case 0x1b:   /* Incoming profile name */
2868                         if (MessageBuffer[9] == 0x00)
2869                                 CurrentProfile->DefaultName = MessageBuffer[8];
2870                         else {
2871                                 CurrentProfile->DefaultName = -1;
2872                                 sprintf(CurrentProfile->Name, MessageBuffer + 10, MessageBuffer[9]);
2873                                 CurrentProfile->Name[MessageBuffer[9]] = '\0';
2874                         }
2875                         CurrentProfileError = GE_NONE;
2876                         break;
2877
2878                 case 0x1d:   /* Profile name set result */
2879                         CurrentProfileError = GE_NONE;
2880                         break;
2881
2882                 case 0x31:   /* Set Operator Logo OK */
2883                         dprintf(_("Message: Operator logo correctly set.\n"));
2884                         SetBitmapError = GE_NONE;      
2885                         break;
2886       
2887                 case 0x32:   /* Set Operator Logo Error */
2888                         SetBitmapError = GE_UNKNOWN;
2889                         dprintf(_("Message: Error setting operator logo!\n"));
2890                         break;
2891
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"),
2905                                         GetBitmap->netcode,
2906                                         GSM_GetNetworkName(GetBitmap->netcode));
2907                                 GetBitmap->size = MessageBuffer[count++] << 8;
2908                                 GetBitmap->size += MessageBuffer[count++];
2909                                 count++;
2910                                 GetBitmap->width = MessageBuffer[count++];
2911                                 GetBitmap->height = MessageBuffer[count++];
2912                                 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;
2917                         }
2918                         else dprintf(_("Message: Operator logo received but not requested!\n"));
2919                         break;
2920       
2921                 case 0x35:  /* Get op logo error */
2922                         dprintf(_("Message: Error getting operator logo!\n"));
2923                         GetBitmapError = GE_UNKNOWN; 
2924                         break;
2925                 }
2926                 break;
2927
2928                 /* Security code requests */
2929
2930         case 0x08:
2931                 switch(MessageBuffer[3]) {
2932                 case 0x08:
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;
2943                         }
2944                         CurrentSecurityCodeError = GE_NONE;
2945                         break;
2946
2947                 case 0x0b:
2948                         dprintf(_("Message: Security code accepted.\n"));
2949                         CurrentSecurityCodeError = GE_NONE;
2950                         break;
2951
2952                 default:
2953                         dprintf(_("Message: Security code is wrong. You're not my big owner :-)\n"));
2954                         CurrentSecurityCodeError = GE_INVALIDSECURITYCODE;
2955                         break;
2956                 }
2957
2958                 break;
2959
2960                 /* Network Info */
2961
2962         case 0x0a:
2963
2964                 switch (MessageBuffer[3]) {
2965                 case 0x71:
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]);
2971
2972                                 dprintf(_("Message: Network information:\n"));
2973
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: "));
2981
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;
2988                                 }
2989
2990                                 dprintf("\n");
2991
2992                                 dprintf(_("   Network selection: %s\n"), MessageBuffer[9] == 1 ? _("manual") : _("automatic"));
2993                         }
2994                         CurrentNetworkInfoError = GE_NONE;
2995                         break;
2996
2997                 default:
2998                         dprintf(_("Message: Unknown message of type 0x0a\n"));
2999                         break;
3000                 }
3001
3002                 break;
3003
3004                 /* Display status. */
3005
3006         case 0x0d:
3007                 switch(MessageBuffer[3]) {
3008                 case 0x50:
3009                         dprintf("%i %i ", MessageBuffer[6], MessageBuffer[5]);
3010                         for (i = 0; i < MessageBuffer[7]; i++)
3011                                 dprintf("%c", MessageBuffer[9+(i*2)]);
3012                         dprintf("\n");
3013                         break;
3014  
3015                 case 0x52:
3016                         for (i = 0; i < MessageBuffer[4]; i++)
3017                                 if (MessageBuffer[2*i+6] == 2)
3018                                         DisplayStatus |= 1 << (MessageBuffer[2*i+5] - 1);
3019                                 else
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;
3030                         break;
3031       
3032                 case 0x54:
3033                         if (MessageBuffer[5] == 1) {
3034                                 dprintf(_("Display output successfully disabled/enabled.\n"));
3035                                 CurrentDisplayOutputError = GE_NONE;
3036                         }
3037                         break;
3038       
3039                 default:
3040                         dprintf(_("Unknown message of type 0x0d.\n"));
3041                         break;
3042                 }
3043                 break;
3044
3045                 /* Phone Clock and Alarm */
3046
3047         case 0x11:
3048                 switch (MessageBuffer[3]) {
3049                 case 0x61:
3050                         switch (MessageBuffer[4]) {
3051                         case 0x01:
3052                                 dprintf(_("Message: Date and time set correctly\n"));
3053                                 CurrentSetDateTimeError = GE_NONE;
3054                                 break;
3055       
3056                         default:
3057                                 dprintf(_("Message: Date and time set error\n"));
3058                                 CurrentSetDateTimeError = GE_INVALIDDATETIME;
3059                                 break;
3060                         }
3061                         break;
3062
3063                 case 0x63:
3064                         CurrentDateTime->Year = 256 * MessageBuffer[8] + MessageBuffer[9];
3065                         CurrentDateTime->Month = MessageBuffer[10];
3066                         CurrentDateTime->Day = MessageBuffer[11];
3067
3068                         CurrentDateTime->Hour = MessageBuffer[12];
3069                         CurrentDateTime->Minute = MessageBuffer[13];
3070                         CurrentDateTime->Second = MessageBuffer[14];
3071
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);
3075
3076                         CurrentDateTimeError = GE_NONE;
3077                         break;
3078
3079                 case 0x6c:
3080                         switch (MessageBuffer[4]) {
3081                         case 0x01:
3082                                 dprintf(_("Message: Alarm set correctly\n"));
3083                                 CurrentSetAlarmError = GE_NONE;
3084                                 break;
3085       
3086                         default:
3087                                 dprintf(_("Message: Date and time set error\n"));
3088                                 CurrentSetAlarmError = GE_INVALIDDATETIME;
3089                                 break;
3090                         }
3091                         break;
3092
3093                 case 0x6e:
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"));
3097
3098                         CurrentAlarm->Hour = MessageBuffer[9];
3099                         CurrentAlarm->Minute = MessageBuffer[10];
3100                         CurrentAlarm->Second = 0;
3101                         CurrentAlarm->AlarmEnabled = (MessageBuffer[8] == 2);
3102                         CurrentAlarmError = GE_NONE;
3103                         break;
3104
3105                 default:
3106                         dprintf(_("Message: Unknown message of type 0x11\n"));
3107                         break;
3108                 }
3109                 break;
3110
3111                 /* Calendar notes handling */
3112
3113         case 0x13:
3114                 switch (MessageBuffer[3]) {
3115                 case 0x65:
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;
3120                                 break;
3121                         case 0x73:
3122                                 dprintf(_("Message: Calendar note write failed!\n"));
3123                                 CurrentCalendarNoteError = GE_INTERNALERROR;
3124                                 break;
3125                         case 0x7d:
3126                                 dprintf(_("Message: Calendar note write failed!\n"));
3127                                 CurrentCalendarNoteError = GE_INTERNALERROR;
3128                                 break;
3129                         default:
3130                                 dprintf(_("Unknown message of type 0x13 and subtype 0x65\n"));
3131                                 break;
3132                         }
3133     
3134                         break;
3135
3136                 case 0x67:
3137
3138                         switch (MessageBuffer[4]) {
3139
3140                         case 0x01:
3141       
3142                                 CurrentCalendarNote->Type = MessageBuffer[8];
3143
3144                                 CurrentCalendarNote->Time.Year = 256 * MessageBuffer[9] + MessageBuffer[10];
3145                                 CurrentCalendarNote->Time.Month = MessageBuffer[11];
3146                                 CurrentCalendarNote->Time.Day = MessageBuffer[12];
3147
3148                                 CurrentCalendarNote->Time.Hour = MessageBuffer[13];
3149                                 CurrentCalendarNote->Time.Minute = MessageBuffer[14];
3150                                 CurrentCalendarNote->Time.Second = MessageBuffer[15];
3151
3152                                 CurrentCalendarNote->Alarm.Year = 256 * MessageBuffer[16] + MessageBuffer[17];
3153                                 CurrentCalendarNote->Alarm.Month = MessageBuffer[18];
3154                                 CurrentCalendarNote->Alarm.Day = MessageBuffer[19];
3155
3156                                 CurrentCalendarNote->Alarm.Hour = MessageBuffer[20];
3157                                 CurrentCalendarNote->Alarm.Minute = MessageBuffer[21];
3158                                 CurrentCalendarNote->Alarm.Second = MessageBuffer[22];
3159
3160                                 memcpy(CurrentCalendarNote->Text, MessageBuffer + 24, MessageBuffer[23]);
3161                                 CurrentCalendarNote->Text[MessageBuffer[23]] = 0;
3162
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;
3166                                 }
3167
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);
3175
3176                                 /* Some messages do not have alarm set up */
3177
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);
3185                                 }
3186
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;
3192                                 break;
3193
3194                         case 0x93:
3195                                 dprintf(_("Message: Calendar note not available\n"));
3196                                 CurrentCalendarNoteError = GE_INVALIDCALNOTELOCATION;
3197                                 break;
3198
3199                         default:
3200                                 dprintf(_("Message: Calendar note error\n"));
3201                                 CurrentCalendarNoteError = GE_INTERNALERROR;
3202                                 break;
3203                         }
3204                         break;
3205
3206                 case 0x69:
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'
3210                                    message). */
3211                         case 0x01:
3212                                 dprintf(_("Message: Calendar note deleted\n"));
3213                                 CurrentCalendarNoteError = GE_NONE;
3214                                 break;
3215                         case 0x93:
3216                                 dprintf(_("Message: Calendar note can't be deleted\n"));
3217                                 CurrentCalendarNoteError = GE_INVALIDCALNOTELOCATION;
3218                                 break;
3219                         default:
3220                                 dprintf(_("Message: Calendar note deleting error\n"));
3221                                 CurrentCalendarNoteError = GE_INTERNALERROR;
3222                                 break;
3223                         }
3224
3225                         break;
3226
3227                 case 0x6a:
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]);
3232                         break;
3233
3234                 default:
3235                         dprintf(_("Message: Unknown message of type 0x13\n"));
3236                         break;
3237                 }
3238
3239                 break;
3240
3241                 /* SMS Messages frame received */
3242
3243         case 0x14:
3244                 switch (MessageBuffer[3]) {
3245                 case 0x08:
3246                         switch (MessageBuffer[7]) {
3247                         case 0x00:
3248                                 CurrentSMSMessage->Type = GST_MT;
3249                                 offset = 4;
3250                                 break;
3251                         case 0x01:
3252                                 CurrentSMSMessage->Type = GST_DR;
3253                                 offset = 3;
3254                                 break;
3255                         case 0x02:
3256                                 CurrentSMSMessage->Type = GST_MO;
3257                                 offset = 5;
3258                                 break;
3259                         default:
3260                                 CurrentSMSMessage->Type = GST_UN;
3261                                 offset = 4; /* ??? */
3262                                 break;
3263                         }
3264
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.
3275          
3276                            Pawel Kot */
3277
3278                         if (MessageBuffer[4] & 0x02)
3279                                 CurrentSMSMessage->Status = GSS_NOTSENTREAD;
3280                         else
3281                                 CurrentSMSMessage->Status = GSS_SENTREAD;
3282
3283                         off = 0;
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 */
3291                                         }
3292                                         break;
3293                                 case 0x05: /* logos */
3294                                         switch (MessageBuffer[43+offset]) {
3295                                         case 0x82:
3296                                                 CurrentSMSMessage->UDHType = GSM_OpLogo;
3297                                                 break;
3298                                         case 0x83:
3299                                                 CurrentSMSMessage->UDHType = GSM_CallerIDLogo;
3300                                                 break;
3301                                         }
3302                                         break;
3303                                 default:
3304                                         break;
3305                                 }
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];
3310                         } else {
3311                                 CurrentSMSMessage->UDHType = GSM_NoUDH;
3312                         }
3313       
3314                         MessageBuffer[20+offset] = (MessageBuffer[20+offset]+1)/2+1;
3315
3316                         dprintf(_("Number: %d\n"), MessageBuffer[6]);
3317                         switch (CurrentSMSMessage->Type) {
3318                         case GST_MO:
3319                                 dprintf(_("Message: Outbox message (mobile originated)\n"));
3320                                 if (CurrentSMSMessage->Status)
3321                                         dprintf(_("Sent\n"));
3322                                 else
3323                                         dprintf(_("Not sent\n"));
3324                                 break;
3325
3326                         default:
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"));
3332
3333                                 if (CurrentSMSMessage->Status)
3334                                         dprintf(_("Read\n"));
3335                                 else
3336                                         dprintf(_("Not read\n"));
3337
3338                                 dprintf(_("   Date: %s "), FB61_GetPackedDateTime(MessageBuffer + 32 + offset));
3339
3340                                 if (MessageBuffer[38+offset]) {
3341                                         if (MessageBuffer[38+offset] & 0x08)
3342                                                 dprintf("-");
3343                                         else
3344                                                 dprintf("+");
3345
3346                                         dprintf(_("%02d00"), (10 * (MessageBuffer[38+offset] & 0x07) + (MessageBuffer[38+offset] >> 4)) / 4);
3347                                 }
3348                                 dprintf("\n");
3349
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)
3354                                                         dprintf("-");
3355                                                 else
3356                                                         dprintf("+");
3357
3358                                                 dprintf(_("%02d00"),(10 * (MessageBuffer[45+offset] & 0x07) + (MessageBuffer[45+offset] >> 4)) / 4);
3359                                         }
3360                                         dprintf("\n");
3361                                 }
3362                                 dprintf(_("   SMS center number: %s\n"), FB61_GetBCDNumber(MessageBuffer + 8));
3363                                 dprintf(_("   Remote number: %s\n"), FB61_GetBCDNumber(MessageBuffer + 20 + offset));
3364                                 break;
3365                         }
3366
3367                         /* In Outbox messages fields:
3368                            - datetime
3369                            - sender
3370                            - message center
3371                            are not filled in, so we ignore it.
3372                         */
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));
3385                         }
3386
3387                         if (CurrentSMSMessage->Type != GST_DR) {
3388                                 /* 8bit SMS */
3389                                 if ((MessageBuffer[18+offset] & 0xf4) == 0xf4) {
3390                                         CurrentSMSMessage->EightBit = true;
3391                                         tmp=CurrentSMSMessage->Length=MessageBuffer[19+offset];
3392                                         offset += off;
3393                                         memcpy(output, MessageBuffer - 39 - offset - 2, tmp - offset);
3394                                         /* 7bit SMS */
3395                                 } else {
3396                                         CurrentSMSMessage->EightBit = false;
3397                                         CurrentSMSMessage->Length=MessageBuffer[19+offset] - (off * 8 + ((7-off)%7)) / 7;
3398                                         offset += off;
3399                                         tmp=UnpackEightBitsToSeven((7-off)%7, MessageLength - 39 - offset - 2, CurrentSMSMessage->Length, MessageBuffer + 39 + offset, output);
3400                                 }
3401                                 for (i = 0; i < tmp;i++) {
3402                                         dprintf("%c", GSM_Default_Alphabet[output[i]]);
3403                                         CurrentSMSMessage->MessageText[i] = GSM_Default_Alphabet[output[i]];
3404                                 }
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]) {
3418                                         case 0x00:
3419                                                 dprintf(_("SM received by the SME"));
3420                                                 break;
3421                                         case 0x01:
3422                                                 dprintf(_("SM forwarded by the SC to the SME but the SC is unable to confirm delivery"));
3423                                                 break;
3424                                         case 0x02:
3425                                                 dprintf(_("SM replaced by the SC"));
3426                                                 break;
3427                                         }
3428                                         CurrentSMSMessage->Length = tmp = 10;
3429                                 } else if (MessageBuffer[22] & 0x40) {
3430
3431                                         strcpy(CurrentSMSMessage->MessageText, _("Failed"));
3432
3433                                         /* more detailed reason only for debug */
3434
3435                                         if (MessageBuffer[22] & 0x20) {
3436                                                 dprintf(_("Temporary error, SC is not making any more transfer attempts\n"));
3437
3438                                                 switch (MessageBuffer[22]) {
3439                                                 case 0x60:
3440                                                         dprintf(_("Congestion"));
3441                                                         break;
3442                                                 case 0x61:
3443                                                         dprintf(_("SME busy"));
3444                                                         break;
3445                                                 case 0x62:
3446                                                         dprintf(_("No response from SME"));
3447                                                         break;
3448                                                 case 0x63:
3449                                                         dprintf(_("Service rejected"));
3450                                                         break;
3451                                                 case 0x64:
3452                                                         dprintf(_("Quality of service not aviable"));
3453                                                         break;
3454                                                 case 0x65:
3455                                                         dprintf(_("Error in SME"));
3456                                                         break;
3457                                                 default:
3458                                                         dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3459                                                         break;
3460                                                 }
3461                                         } else {
3462                                                 dprintf(_("Permanent error, SC is not making any more transfer attempts\n"));
3463                                                 switch (MessageBuffer[22]) {
3464                                                 case 0x40:
3465                                                         dprintf(_("Remote procedure error"));
3466                                                         break;
3467                                                 case 0x41:
3468                                                         dprintf(_("Incompatibile destination"));
3469                                                         break;
3470                                                 case 0x42:
3471                                                         dprintf(_("Connection rejected by SME"));
3472                                                         break;
3473                                                 case 0x43:
3474                                                         dprintf(_("Not obtainable"));
3475                                                         break;
3476                                                 case 0x44:
3477                                                         dprintf(_("Quality of service not aviable"));
3478                                                         break;
3479                                                 case 0x45:
3480                                                         dprintf(_("No internetworking available"));
3481                                                         break;
3482                                                 case 0x46:
3483                                                         dprintf(_("SM Validity Period Expired"));
3484                                                         break;
3485                                                 case 0x47:
3486                                                         dprintf(_("SM deleted by originating SME"));
3487                                                         break;
3488                                                 case 0x48:
3489                                                         dprintf(_("SM Deleted by SC Administration"));
3490                                                         break;
3491                                                 case 0x49:
3492                                                         dprintf(_("SM does not exist"));
3493                                                         break;
3494                                                 default:
3495                                                         dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3496                                                         break;
3497                                                 }
3498                                         }
3499                                         CurrentSMSMessage->Length = tmp = 6;
3500                                 } else if (MessageBuffer[22] & 0x20) {
3501                                         strcpy(CurrentSMSMessage->MessageText, _("Pending"));
3502
3503                                         /* more detailed reason only for debug */
3504                                         dprintf(_("Temporary error, SC still trying to transfer SM\n"));
3505                                         switch (MessageBuffer[22]) {
3506                                         case 0x20:
3507                                                 dprintf(_("Congestion"));
3508                                                 break;
3509                                         case 0x21:
3510                                                 dprintf(_("SME busy"));
3511                                                 break;
3512                                         case 0x22:
3513                                                 dprintf(_("No response from SME"));
3514                                                 break;
3515                                         case 0x23:
3516                                                 dprintf(_("Service rejected"));
3517                                                 break;
3518                                         case 0x24:
3519                                                 dprintf(_("Quality of service not aviable"));
3520                                                 break;
3521                                         case 0x25:
3522                                                 dprintf(_("Error in SME"));
3523                                                 break;
3524                                         default:
3525                                                 dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3526                                                 break;
3527                                         }
3528                                         CurrentSMSMessage->Length = tmp = 7;
3529                                 } else {
3530                                         strcpy(CurrentSMSMessage->MessageText, _("Unknown"));
3531
3532                                         /* more detailed reason only for debug */
3533                                         dprintf(_("Reserved/Specific to SC: %x"), MessageBuffer[22]);
3534                                         CurrentSMSMessage->Length = tmp = 8;
3535                                 }
3536                         }
3537
3538                         CurrentSMSMessage->MessageText[CurrentSMSMessage->Length] = 0;
3539
3540                         CurrentSMSPointer = tmp;
3541       
3542                         CurrentSMSMessage->MemoryType = MessageBuffer[5];
3543                         CurrentSMSMessage->MessageNumber = MessageBuffer[6];
3544  
3545                         /* Signal no error to calling code. */
3546
3547                         CurrentSMSMessageError = GE_NONE;
3548                         dprintf("\n");
3549                         break;
3550     
3551                 case 0x05:
3552                         dprintf(_("Message stored at %d\n"), MessageBuffer[5]);
3553                         CurrentSMSMessageError = GE_NONE;
3554                         break;
3555
3556                 case 0x06:
3557                         dprintf(_("SMS saving failed\n"));
3558                         switch (MessageBuffer[4]) {
3559                         case 0x02:
3560                                 dprintf(_("   All locations busy.\n"));
3561                                 CurrentSMSMessageError = GE_MEMORYFULL;
3562                                 break;
3563                         case 0x03:
3564                                 dprintf(_("   Invalid location!\n"));
3565                                 CurrentSMSMessageError = GE_INVALIDSMSLOCATION;
3566                                 break;
3567                         default:
3568                                 dprintf(_("   Unknown error.\n"));
3569                                 CurrentSMSMessageError = GE_UNKNOWN;
3570                                 break;
3571                         }
3572                         break;
3573
3574                 case 0x09:
3575                         /* We have requested invalid or empty location. */
3576                         dprintf(_("Message: SMS reading failed.\n"));
3577                         switch (MessageBuffer[4]) {
3578                         case 0x02:
3579                                 dprintf(_("   Invalid location!\n"));
3580                                 CurrentSMSMessageError = GE_INVALIDSMSLOCATION;
3581                                 break;
3582                         case 0x07:
3583                                 dprintf(_("   Empty SMS location.\n"));
3584                                 CurrentSMSMessageError = GE_EMPTYSMSLOCATION;
3585                                 break;
3586                         }
3587                         break;
3588
3589                 case 0x0b:      /* successful delete */
3590                         dprintf(_("Message: SMS deleted successfully.\n"));
3591                         CurrentSMSMessageError = GE_NONE;       
3592                         break;
3593
3594                 case 0x37:
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;
3601                         break;
3602
3603                 case 0x38:
3604                         dprintf(_("Message: SMS Status error, probably not authorized by PIN\n"));
3605                         CurrentSMSStatusError = GE_INTERNALERROR;
3606                         break;
3607           
3608                 default:
3609                         CurrentSMSStatusError = GE_INTERNALERROR;
3610                         break;
3611       
3612                 }
3613                 break;
3614
3615
3616                 /* Internal phone functions? */
3617
3618         case 0x40:
3619
3620                 switch(MessageBuffer[2]) {
3621
3622                 case 0x7e:
3623
3624                         switch(MessageBuffer[3]) {
3625                         case 0x00:
3626                                 dprintf(_("Message: Netmonitor correctly set.\n"));
3627                                 CurrentNetmonitorError = GE_NONE;
3628                                 break;
3629                         default:
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;
3634                                 break;
3635                         }
3636
3637                         break;
3638
3639                 default:
3640                         dprintf(_("Unknown message of type 0x40.\n"));
3641                         break;
3642                 }
3643                 break;
3644         
3645                 /* Mobile phone identification */
3646
3647         case 0x64:
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);
3652 #else
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);
3656 #endif
3657
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);
3664
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. */
3668
3669                 dprintf(_("   Magic bytes: %02x %02x %02x %02x\n"), MessageBuffer[50], MessageBuffer[51], MessageBuffer[52], MessageBuffer[53]);
3670
3671                 MagicBytes[0] = MessageBuffer[50];
3672                 MagicBytes[1] = MessageBuffer[51];
3673                 MagicBytes[2] = MessageBuffer[52];
3674                 MagicBytes[3] = MessageBuffer[53];
3675                 CurrentMagicError = GE_NONE;
3676                 break;
3677
3678                 /***** Acknowlegment of our frames. *****/
3679         case 0x7f:
3680                 dprintf(_("[Received Ack of type %02x, seq: %2x]\n"), MessageBuffer[0], MessageBuffer[1]);
3681                 AcksReceived++;
3682                 FB61_LinkOK = true;
3683                 break;
3684
3685                 /***** Power on message. *****/
3686         case 0xd0:
3687                 dprintf(_("Message: The phone is powered on - seq 1.\n"));
3688                 break;
3689
3690                 /***** Phone info. *****/
3691         case 0xd2:
3692 #if defined WIN32 || !defined HAVE_SNPRINTF
3693                 sprintf(Model, "%s", MessageBuffer + 21);
3694                 sprintf(Revision, "SW%s", MessageBuffer + 5);
3695 #else
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;
3700 #endif
3701                 dprintf(_("Phone info:\n%s\n"), MessageBuffer + 4);
3702                 CurrentPhoneInfoError = GE_NONE;
3703                 break;
3704
3705                 /***** RLP frame received. *****/
3706         case 0xf1:
3707                 FB61_RX_HandleRLPMessage();
3708                 break;
3709
3710                 /***** Power on message. *****/
3711         case 0xf4:
3712                 dprintf(_("Message: The phone is powered on - seq 2.\n"));
3713                 break;
3714
3715                 /***** Unknown message *****/
3716                 /* If you think that you know the exact meaning of other messages - please
3717                    let us know. */
3718         default:
3719                 dprintf(_("Message: Unknown message.\n"));
3720                 break;
3721         }
3722         return FB61_RX_Sync;
3723 }
3724
3725 /* RX_State machine for receive handling.  Called once for each character
3726    received from the phone/phone. */
3727
3728 void FB61_RX_StateMachine(char rx_byte)
3729 {
3730         static int checksum[2];
3731 #ifdef WIN32
3732         static struct _timeb time_now, time_last;
3733         static struct timeval time_diff;
3734 #else
3735         static struct timeval time_now, time_last, time_diff;
3736 #endif
3737
3738         /* XOR the byte with the current checksum */
3739         checksum[BufferCount&1] ^= rx_byte;
3740
3741         switch (RX_State) {
3742         
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
3748                    sync byte */
3749
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 */
3755                         break;
3756                 }
3757                 /* else fall through to... */
3758
3759         case FB61_RX_Sync:
3760
3761                 if ( CurrentConnectionType == GCT_Infrared ) {
3762                         if (rx_byte == FB61_IR_FRAME_ID) {
3763
3764                                 if (RX_Multiple == false) BufferCount = 0;
3765                                 else BufferCount = MessageLength - 2;
3766                                 RX_State = FB61_RX_GetDestination;
3767         
3768                                 /* Initialize checksums. */
3769                                 checksum[0] = FB61_IR_FRAME_ID;
3770                                 checksum[1] = 0;
3771                         } else {
3772                                 /* Lost frame sync */
3773                                 RX_State = FB61_RX_Discarding;
3774                                 gettimeofday(&time_last, NULL);
3775                         }
3776                 } else { /* CurrentConnectionType == GCT_Serial */
3777                         if (rx_byte == FB61_FRAME_ID) {
3778
3779                                 if (RX_Multiple == false) BufferCount = 0;
3780                                 else BufferCount = MessageLength - 2;
3781                                 RX_State = FB61_RX_GetDestination;
3782         
3783                                 /* Initialize checksums. */
3784                                 checksum[0] = FB61_FRAME_ID;
3785                                 checksum[1] = 0;
3786                         } else {
3787                                 /* Lost frame sync */
3788                                 RX_State = FB61_RX_Discarding;
3789                                 gettimeofday(&time_last, NULL);
3790                         }
3791                 }
3792     
3793                 break;
3794
3795         case FB61_RX_GetDestination:
3796
3797                 MessageDestination = rx_byte;
3798                 RX_State = FB61_RX_GetSource;
3799
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 */
3804     
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);
3808                 }
3809                 break;
3810
3811         case FB61_RX_GetSource:
3812                 MessageSource = rx_byte;
3813                 RX_State = FB61_RX_GetType;
3814
3815                 /* Source should be 0x00 */
3816     
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);
3820                 }
3821                 break;
3822
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"));
3827                         BufferCount = 0;
3828                         RX_Multiple = false;
3829                 }
3830
3831                 MessageType = rx_byte;
3832                 RX_State = FB61_RX_GetUnknown;
3833                 break;
3834
3835         case FB61_RX_GetUnknown:
3836                 MessageUnknown = rx_byte;
3837                 RX_State = FB61_RX_GetLength;
3838                 break;
3839     
3840         case FB61_RX_GetLength:
3841                 if (RX_Multiple == true)
3842                         MessageLength = MessageLength - 2 + rx_byte;
3843                 else
3844                         MessageLength = rx_byte;
3845                 RX_State = FB61_RX_GetMessage;
3846                 break;
3847     
3848         case FB61_RX_GetMessage:
3849                 MessageBuffer[BufferCount] = rx_byte;
3850                 BufferCount++;
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;
3855                         break;
3856                 }
3857
3858                 /* If this is the last byte, it's the checksum. */
3859
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. */
3864
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))
3868                                                 RX_Multiple = true;
3869                                         else
3870                                                 RX_Multiple = false;
3871                                 }
3872
3873                                 FB61_RX_DispatchMessage();
3874
3875                         }
3876                         else {
3877                                 dprintf(_("Bad checksum!\n"));
3878                                 RX_Multiple = false;    /* Just to be sure! */
3879                         }
3880
3881                         RX_State = FB61_RX_Sync;
3882                 }
3883                 break;
3884         }
3885 }
3886
3887 /* This function is used for parsing the RLP frame into fields. */
3888
3889 enum FB61_RX_States FB61_RX_HandleRLPMessage(void)
3890 {
3891         RLP_F96Frame frame;
3892         int count;
3893         int valid = true;
3894
3895         /* We do not need RLP frame parsing to be done when we do not have callback
3896            specified. */
3897     
3898         if (RLP_RXCallback == NULL)
3899                 return (FB61_RX_Sync);
3900
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 */
3906
3907         if (MessageBuffer[0] == 0xd9 && MessageBuffer[1] == 0x01)
3908                 valid = false;
3909
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. */
3913     
3914         frame.Header[0] = MessageBuffer[2];
3915         frame.Header[1] = MessageBuffer[3];
3916
3917         /* Next 200 bits (25 bytes) contain the Information. We store the
3918            information in the Data array. */
3919
3920         for (count = 0; count < 25; count ++)
3921                 frame.Data[count] = MessageBuffer[4 + count];
3922
3923         /* The last 24 bits (3 bytes) contain FCS. */
3924
3925         frame.FCS[0] = MessageBuffer[29];
3926         frame.FCS[1] = MessageBuffer[30];
3927         frame.FCS[2] = MessageBuffer[31];
3928
3929         /* Here we pass the frame down in the input stream. */
3930     
3931         RLP_RXCallback(valid ? &frame : NULL);
3932
3933         return (FB61_RX_Sync);
3934 }
3935
3936 char *FB61_PrintDevice(int Device)
3937 {
3938
3939         switch (Device) {
3940
3941         case FB61_DEVICE_PHONE:
3942                 return _("Phone");
3943
3944         case FB61_DEVICE_PC:
3945                 return _("PC");
3946
3947         default:
3948                 return _("Unknown");
3949                 break;
3950         }
3951 }
3952
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! */
3956         
3957 void FB61_RX_DisplayMessage(void)
3958 {
3959 #ifdef DEBUG
3960
3961         int count;
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);
3967
3968         for (count = 0; count < MessageLength + (MessageLength % 2) + 2; count ++)
3969                 if (isprint(MessageBuffer[count]))
3970                         dprintf("[%02x%c]", MessageBuffer[count], MessageBuffer[count]);
3971                 else
3972                         dprintf("[%02x ]", MessageBuffer[count]);
3973
3974         dprintf("\n");
3975 #endif /* DEBUG */
3976 }
3977
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... */
3981
3982 int FB61_TX_SendFrame(u8 message_length, u8 message_type, u8 *buffer)
3983 {
3984         u8 out_buffer[FB61_MAX_TRANSMIT_LENGTH + 5];
3985         int count, current = 0;
3986         unsigned char   checksum;
3987
3988         /* FIXME - we should check for the message length ... */
3989
3990         /* Now construct the message header. */
3991
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 */
3996
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 */
4002
4003         /* Copy in data if any. */      
4004         
4005         if (message_length != 0) {
4006                 memcpy(out_buffer + current, buffer, message_length);
4007                 current += message_length;
4008         }
4009
4010         /* If the message length is odd we should add pad byte 0x00 */
4011         if (message_length % 2)
4012                 out_buffer[current++] = 0x00;
4013
4014         /* Now calculate checksums over entire message and append to message. */
4015
4016         /* Odd bytes */
4017
4018         checksum = 0;
4019         for (count = 0; count < current; count += 2)
4020                 checksum ^= out_buffer[count];
4021
4022         out_buffer[current++] = checksum;
4023
4024         /* Even bytes */
4025
4026         checksum = 0;
4027         for (count = 1; count < current; count += 2)
4028                 checksum ^= out_buffer[count];
4029
4030         out_buffer[current++] = checksum;
4031
4032         dprintf(_("PC: "));
4033         for (count = 0; count < current; count++)
4034                 dprintf("%02x:", out_buffer[count]);
4035         dprintf("\n");
4036
4037         /* Send it out... */
4038   
4039         if (WRITEPHONE(PortFD, out_buffer, current) != current)
4040                 return (false);
4041
4042         if(message_type != 0x7f)
4043                 MessagesSent++;
4044
4045         return (true);
4046 }
4047
4048 int FB61_TX_SendMessage(u16 message_length, u8 message_type, u8 *buffer)
4049 {
4050         u8 seqnum, frame_buffer[FB61_MAX_CONTENT_LENGTH + 2];
4051         u8 nom, lml;  /* number of messages, last message len */
4052         int i;
4053
4054         seqnum = 0x40 + RequestSequenceNumber;
4055         RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;
4056
4057         if (message_length > FB61_MAX_CONTENT_LENGTH) {
4058
4059                 nom = (message_length + FB61_MAX_CONTENT_LENGTH - 1)
4060                         / FB61_MAX_CONTENT_LENGTH;
4061                 lml = message_length - ((nom - 1) * FB61_MAX_CONTENT_LENGTH);
4062
4063                 for (i = 0; i < nom - 1; i++) {
4064
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;
4069
4070                         FB61_TX_SendFrame(FB61_MAX_CONTENT_LENGTH + 2, message_type,
4071                                           frame_buffer);
4072
4073                         seqnum = RequestSequenceNumber;
4074                         RequestSequenceNumber = (RequestSequenceNumber + 1) & 0x07;    
4075                 }
4076
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);
4081
4082         }
4083         else {
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);
4088         }
4089
4090         return (true);
4091 }
4092
4093 int FB61_TX_SendAck(u8 message_type, u8 message_seq)
4094 {
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);
4100 }
4101
4102