Found in "gnokii-working" directory, some November-patches version
[gnokii.git] / common / phones / nk7110.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) 2000 Hugh Blemings & Pavel Janík ml.
10   Copytight (C) 2000 Chris Kemp
11
12   Released under the terms of the GNU GPL, see file COPYING for more details.
13
14   This file provides functions specific to the 7110 series. 
15   See README for more details on supported mobile phones.
16
17   The various routines are called P7110_(whatever).
18
19   $Log$
20   Revision 1.1.1.5  2002/04/03 00:08:10  short
21   Found in "gnokii-working" directory, some November-patches version
22
23   Revision 1.15  2001/11/08 16:47:48  pkot
24   Start fiddling with 7110 and SMS
25
26   Revision 1.14  2001/09/09 21:45:49  machek
27   Cleanups from Ladislav Michl <ladis@psi.cz>:
28
29   *) do *not* internationalize debug messages
30
31   *) some whitespace fixes, do not use //
32
33   *) break is unneccessary after return
34
35   Revision 1.13  2001/08/16 23:59:32  pkot
36   Fixed (hopefully) timezone mismash (Sheldon Hearn)
37
38   Revision 1.12  2001/08/09 12:34:34  pkot
39   3330 and 6250 support - I have no idea if it does work (mygnokii)
40
41   Revision 1.11  2001/07/05 10:54:53  pkot
42   Solaris 2.7 fixes - should be harmless for other OSes (Michael Wiedmann)
43
44   Revision 1.10  2001/06/27 23:52:49  pkot
45   7110/6210 updates (Marian Jancar)
46
47   Revision 1.9  2001/06/10 23:49:49  pkot
48   Small fixes to hide compilation warnings and allow gnokii.c to compile
49
50   Revision 1.8  2001/05/24 20:47:30  chris
51   More updating of 7110 code and some of xgnokii_lowlevel changed over.
52
53   Revision 1.7  2001/05/07 16:24:04  pkot
54   DLR-3P temporary fix. How should I do it better?
55
56   Revision 1.6  2001/03/23 13:40:24  chris
57   Pavel's patch and a few fixes.
58
59   Revision 1.5  2001/03/22 16:17:06  chris
60   Tidy-ups and fixed gnokii/Makefile and gnokii/ChangeLog which I somehow corrupted.
61
62   Revision 1.4  2001/03/21 23:36:06  chris
63   Added the statemachine
64   This will break gnokii --identify and --monitor except for 6210/7110
65
66   Revision 1.3  2001/03/13 01:24:03  pkot
67   Code cleanup - no warnings during compilation
68
69   Revision 1.2  2001/03/13 01:23:18  pkot
70   Windows updates (Manfred Jonsson)
71
72   Revision 1.1  2001/02/21 19:57:07  chris
73   More fiddling with the directory layout
74
75   Revision 1.1  2001/02/16 14:29:53  chris
76   Restructure of common/.  Fixed a problem in fbus-phonet.c
77   Lots of dprintfs for Marcin
78   Any size xpm can now be loaded (eg for 7110 startup logos)
79   nk7110 code detects 7110/6210 and alters startup logo size to suit
80   Moved Marcin's extended phonebook code into gnokii.c
81
82   Revision 1.7  2001/02/06 21:15:35  chris
83   Preliminary irda support for 7110 etc.  Not well tested!
84
85   Revision 1.6  2001/02/03 23:56:15  chris
86   Start of work on irda support (now we just need fbus-irda.c!)
87   Proper unicode support in 7110 code (from pkot)
88
89   Revision 1.5  2001/02/01 15:17:31  pkot
90   Fixed --identify and added Manfred's manufacturer patch
91
92   Revision 1.4  2001/01/29 17:14:42  chris
93   dprintf now in misc.h (and fiddling with 7110 code)
94
95   Revision 1.3  2001/01/23 15:32:41  chris
96   Pavel's 'break' and 'static' corrections.
97   Work on logos for 7110.
98
99   Revision 1.2  2001/01/17 02:54:54  chris
100   More 7110 work.  Use with care! (eg it is not possible to delete phonebook entries)
101   I can now edit my phonebook in xgnokii but it is 'work in progress'.
102
103   Revision 1.1  2001/01/14 22:46:59  chris
104   Preliminary 7110 support (dlr9 only) and the beginnings of a new structure
105
106
107 */
108
109 #include <string.h>
110 #include <stdlib.h>
111 #include <ctype.h>
112
113 #define __phones_nk7110_c  /* Turn on prototypes in phones/nk7110.h */
114 #include "misc.h"
115 #include "gsm-common.h"
116 #include "phones/generic.h"
117 #include "phones/nk7110.h"
118 #include "links/fbus.h"
119 #include "links/fbus-phonet.h"
120 #include "phones/nokia.h"
121 #include "gsm-encoding.h"
122
123 #ifdef WIN32
124 #define snprintf _snprintf
125 #endif
126
127 /* Some globals */
128
129 static GSM_IncomingFunctionType P7110_IncomingFunctions[] = {
130         { P7110_MSG_FOLDER,     P7110_IncomingFolder },
131         { P7110_MSG_SMS,        P7110_IncomingSMS },
132         { P7110_MSG_PHONEBOOK,  P7110_IncomingPhonebook },
133         { P7110_MSG_NETSTATUS,  P7110_IncomingNetwork },
134         { P7110_MSG_CALENDAR,   P7110_IncomingCalendar },
135         { P7110_MSG_BATTERY,    P7110_IncomingBattLevel },
136         { P7110_MSG_CLOCK,      P7110_IncomingClock },
137         { P7110_MSG_IDENTITY,   P7110_Incoming0x1b },
138         { P7110_MSG_STLOGO,     P7110_IncomingStartup },
139         { 0, NULL }
140 };
141
142 GSM_Phone phone_nokia_7110 = {
143         P7110_IncomingFunctions,
144         PGEN_IncomingDefault,
145         /* Mobile phone information */
146         {
147                 "7110|6210|6250", /* Supported models */
148                 7,                     /* Max RF Level */
149                 0,                     /* Min RF Level */
150                 GRF_Percentage,        /* RF level units */
151                 7,                     /* Max Battery Level */
152                 0,                     /* Min Battery Level */
153                 GBU_Percentage,        /* Battery level units */
154                 GDT_DateTime,          /* Have date/time support */
155                 GDT_TimeOnly,            /* Alarm supports time only */
156                 1,                     /* Alarms available - FIXME */
157                 60, 96,                /* Startup logo size - 7110 is fixed at init*/
158                 21, 78,                /* Op logo size */
159                 14, 72                 /* Caller logo size */
160         },
161         P7110_Functions
162 };
163
164 /* FIXME - a little macro would help here... */
165
166 static GSM_Error P7110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
167 {
168         switch (op) {
169         case GOP_Init:
170                 return P7110_Initialise(state);
171         case GOP_GetModel:
172                 return P7110_GetModel(data, state);
173         case GOP_GetRevision:
174                 return P7110_GetRevision(data, state);
175         case GOP_GetImei:
176                 return P7110_GetIMEI(data, state);
177         case GOP_Identify:
178                 return P7110_Identify(data, state);
179         case GOP_GetBatteryLevel:
180                 return P7110_GetBatteryLevel(data, state);
181         case GOP_GetRFLevel:
182                 return P7110_GetRFLevel(data, state);
183         case GOP_GetMemoryStatus:
184                 return P7110_GetMemoryStatus(data, state);
185         case GOP_GetBitmap:
186                 return P7110_GetBitmap(data, state);
187         case GOP_SetBitmap:
188                 return P7110_SetBitmap(data, state);
189         case GOP_ReadPhonebook:
190                 return P7110_ReadPhonebook(data, state);
191         case GOP_WritePhonebook:
192                 return P7110_WritePhonebookLocation(data, state);
193         case GOP_GetNetworkInfo:
194                 return P7110_GetNetworkInfo(data, state);
195         case GOP_GetSpeedDial:
196                 return P7110_GetSpeedDial(data, state);
197         case GOP_GetSMSCenter:
198                 return P7110_GetSMSCenter(data, state);
199         case GOP_GetDateTime:
200                 return P7110_GetClock(P7110_SUBCLO_GET_DATE, data, state);
201         case GOP_GetAlarm:
202                 return P7110_GetClock(P7110_SUBCLO_GET_ALARM, data, state);
203         case GOP_GetCalendarNote:
204                 return P7110_GetCalendarNote(data, state);
205         case GOP_GetSMS:
206                 return P7110_GetSMS(data, state);
207 /* I'm not suer yet if folder functions will be shared or local
208         case GOP_GetSMSFolders:
209                 return P7110_GetSMSFolders(data, state);
210         case GOP_GetSMSFolderStatus:
211         return P7110_GetSMSFolderStatus(data, state);*/
212         default:
213                 return GE_NOTIMPLEMENTED;
214         }
215 }
216
217 /* LinkOK is always true for now... */
218 bool P7110_LinkOK = true;
219
220 /* Initialise is the only function allowed to 'use' state */
221 static GSM_Error P7110_Initialise(GSM_Statemachine *state)
222 {
223         GSM_Data data;
224         char model[10];
225         GSM_Error err;
226         int try = 0, connected = 0;
227
228         /* Copy in the phone info */
229         memcpy(&(state->Phone), &phone_nokia_7110, sizeof(GSM_Phone));
230
231         while (!connected) {
232                 switch (state->Link.ConnectionType) {
233                 case GCT_Serial:
234                         if (try > 1) return GE_NOTSUPPORTED;
235                         err = FBUS_Initialise(&(state->Link), state);
236                         break;
237                 case GCT_Infrared:
238                 case GCT_Irda:
239                         if (try > 0) return GE_NOTSUPPORTED;
240                         err = PHONET_Initialise(&(state->Link), state);
241                         break;
242                 default:
243                         return GE_NOTSUPPORTED;
244                         break;
245                 }
246
247                 if (err != GE_NONE) {
248                         dprintf("Error in link initialisation\n");
249                         try++;
250                         continue;
251                 }
252
253                 SM_Initialise(state);
254
255                 /* Now test the link and get the model */
256                 GSM_DataClear(&data);
257                 data.Model = model;
258                 if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) try++;
259                 else connected = 1;
260         }
261         /* Check for 7110 and alter the startup logo size */
262         if (strcmp(model, "NSE-5") == 0) {
263                 state->Phone.Info.StartupLogoH = 65;
264                 dprintf("7110 detected - startup logo height set to 65\n");
265         }
266         return GE_NONE;
267 }
268
269 static GSM_Error P7110_GetModel(GSM_Data *data, GSM_Statemachine *state)
270 {
271         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
272   
273         dprintf("Getting model...\n");
274         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
275         return SM_Block(state, data, 0x1b);
276 }
277
278 static GSM_Error P7110_GetRevision(GSM_Data *data, GSM_Statemachine *state)
279 {
280         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
281   
282         dprintf("Getting revision...\n");
283         if (SM_SendMessage(state, 6, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
284         return SM_Block(state, data, 0x1b);
285 }
286
287 static GSM_Error P7110_GetIMEI(GSM_Data *data, GSM_Statemachine *state)
288 {
289         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
290   
291         dprintf("Getting imei...\n");
292         if (SM_SendMessage(state, 4, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
293         return SM_Block(state, data, 0x1b);
294 }
295
296 static GSM_Error P7110_GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
297 {
298         unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
299
300         dprintf("Getting battery level...\n");
301         if (SM_SendMessage(state, 4, 0x17, req) != GE_NONE) return GE_NOTREADY;
302         return SM_Block(state, data, 0x17);
303 }
304
305 static GSM_Error P7110_IncomingBattLevel(int messagetype, unsigned char *message, int length, GSM_Data *data)
306 {
307         switch (message[3]) {
308         case 0x03:
309                 if (data->BatteryLevel) { 
310                         *(data->BatteryUnits) = GBU_Percentage;
311                         *(data->BatteryLevel) = message[5];
312                         dprintf("Battery level %f\n",*(data->BatteryLevel));
313                 }
314                 return GE_NONE;
315                 break;
316         default:
317                 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
318                 return GE_UNKNOWN;
319                 break;
320         }
321 }
322
323 static GSM_Error P7110_GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
324 {
325         unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
326
327         dprintf("Getting rf level...\n");
328         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
329         return SM_Block(state, data, 0x0a);
330 }
331
332 static GSM_Error P7110_GetNetworkInfo(GSM_Data *data, GSM_Statemachine *state)
333 {
334         unsigned char req[] = {FBUS_FRAME_HEADER, 0x70};
335
336         dprintf("Getting Network Info...\n");
337         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
338         return SM_Block(state, data, 0x0a);
339 }
340
341 static GSM_Error P7110_IncomingNetwork(int messagetype, unsigned char *message, int length, GSM_Data *data)
342 {
343         unsigned char *blockstart;
344         int i;
345         
346         switch (message[3]) {
347         case 0x71:
348                 blockstart = message + 6;
349                 for (i = 0; i < message[4]; i++) {
350                         switch (blockstart[0]) {
351                         case 0x01:  /* Operator details */
352                                 /* Network code is stored as 0xBA 0xXC 0xED ("ABC DE"). */
353                                 if (data->NetworkInfo) {
354                                         /* Is this correct? */
355                                         data->NetworkInfo->CellID[0]=blockstart[4];
356                                         data->NetworkInfo->CellID[1]=blockstart[5];
357                                         data->NetworkInfo->LAC[0]=blockstart[6];
358                                         data->NetworkInfo->LAC[1]=blockstart[7];
359                                         data->NetworkInfo->NetworkCode[0] = '0' + (blockstart[8] & 0x0f);
360                                         data->NetworkInfo->NetworkCode[1] = '0' + (blockstart[8] >> 4);
361                                         data->NetworkInfo->NetworkCode[2] = '0' + (blockstart[9] & 0x0f);
362                                         data->NetworkInfo->NetworkCode[3] = ' ';
363                                         data->NetworkInfo->NetworkCode[4] = '0' + (blockstart[10] & 0x0f);
364                                         data->NetworkInfo->NetworkCode[5] = '0' + (blockstart[10] >> 4);
365                                         data->NetworkInfo->NetworkCode[6] = 0;
366                                 }
367                                 if (data->Bitmap) {
368                                         data->Bitmap->netcode[0] = '0' + (blockstart[8] & 0x0f);
369                                         data->Bitmap->netcode[1] = '0' + (blockstart[8] >> 4);
370                                         data->Bitmap->netcode[2] = '0' + (blockstart[9] & 0x0f);
371                                         data->Bitmap->netcode[3] = ' ';
372                                         data->Bitmap->netcode[4] = '0' + (blockstart[10] & 0x0f);
373                                         data->Bitmap->netcode[5] = '0' + (blockstart[10] >> 4);
374                                         data->Bitmap->netcode[6] = 0;
375                                         dprintf("Operator %s ",data->Bitmap->netcode);
376                                 }
377                                 break;
378                         case 0x04: /* Logo */
379                                 if (data->Bitmap) {
380                                         dprintf("Op logo received ok ");
381                                         data->Bitmap->type = GSM_OperatorLogo;
382                                         data->Bitmap->size = blockstart[5]; /* Probably + [4]<<8 */
383                                         data->Bitmap->height = blockstart[3];
384                                         data->Bitmap->width = blockstart[2];
385                                         memcpy(data->Bitmap->bitmap, blockstart + 8, data->Bitmap->size);
386                                         dprintf("Logo (%dx%d) ", data->Bitmap->height, data->Bitmap->width);
387                                 }
388                                 break;
389                         default:
390                                 dprintf("Unknown operator block %d\n", blockstart[0]);
391                                 break;
392                         }
393                         blockstart += blockstart[1];
394                 }
395                 return GE_NONE;
396                 break;
397         case 0x82:
398                 if (data->RFLevel) { 
399                         *(data->RFUnits) = GRF_Percentage;
400                         *(data->RFLevel) = message[4];
401                         dprintf("RF level %f\n",*(data->RFLevel));
402                 }
403                 return GE_NONE;
404                 break;
405         case 0xa4:
406                 dprintf("Op Logo Set OK\n");
407                 return GE_NONE;
408         default:
409                 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
410                 return GE_UNKNOWN;
411                 break;
412         }
413 }
414
415 static GSM_Error P7110_GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
416 {
417         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
418       
419         dprintf("Getting memory status...\n");
420         req[5] = GetMemoryType(data->MemoryStatus->MemoryType);
421         if (SM_SendMessage(state, 6, 0x03, req) != GE_NONE) return GE_NOTREADY;
422         return SM_Block(state, data, 0x03);
423 }
424
425 static GSM_Error P7110_IncomingPhonebook(int messagetype, unsigned char *message, int length, GSM_Data *data)
426 {
427         unsigned char *blockstart;
428         unsigned char blocks;
429         unsigned char subblockcount;
430         char *str;
431         int i;
432         GSM_SubPhonebookEntry* subEntry = NULL;
433
434         PGEN_DebugMessage(messagetype, message, length);
435
436         switch (message[3]) {
437         case 0x04:  /* Get status response */
438                 if (data->MemoryStatus) {
439                         if (message[5] != 0xff) {
440                                 data->MemoryStatus->Used = (message[16] << 8) + message[17];
441                                 data->MemoryStatus->Free = ((message[14] << 8) + message[15]) - data->MemoryStatus->Used;
442                                 dprintf("Memory status - location = %d\n", (message[8] << 8) + message[9]);
443                                 return GE_NONE;
444                         } else {
445                                 dprintf("Unknown error getting mem status\n");
446                                 return GE_NOTIMPLEMENTED;
447                                 
448                         }
449                 }
450                 return GE_NONE;
451                 break;
452         case 0x08:  /* Read Memory response */
453                 if (data->PhonebookEntry) {
454                         data->PhonebookEntry->Empty = true;
455                         data->PhonebookEntry->Group = 0;
456                         data->PhonebookEntry->Name[0] = '\0';
457                         data->PhonebookEntry->Number[0] = '\0';
458                         data->PhonebookEntry->SubEntriesCount = 0;
459                         data->PhonebookEntry->Date.Year = 0;
460                         data->PhonebookEntry->Date.Month = 0;
461                         data->PhonebookEntry->Date.Day = 0;
462                         data->PhonebookEntry->Date.Hour = 0;
463                         data->PhonebookEntry->Date.Minute = 0;
464                         data->PhonebookEntry->Date.Second = 0;
465                 }
466                 if (message[6] == 0x0f) { // not found
467                         if (message[10] == 0x34 || message[10] == 0x33 || message[10] == 0x30) {
468                                 dprintf("Invalid caller location\n");
469                                 return GE_INVALIDPHBOOKLOCATION;
470                         } else {
471                                 dprintf("Unknown error getting phonebook\n");
472                                 return GE_NOTIMPLEMENTED;
473                         }
474                 }
475                 dprintf("Received phonebook info\n");
476                 blocks     = message[17];        
477                 blockstart = message + 18;
478                 subblockcount = 0;
479            
480                 for (i = 0; i < blocks; i++) {
481                         if (data->PhonebookEntry)
482                                 subEntry = &data->PhonebookEntry->SubEntries[subblockcount];
483                         switch(blockstart[0]) {
484                         case P7110_ENTRYTYPE_POINTER:   /* Pointer */
485                                 switch (message[11]) {  /* Memory type */
486                                 case P7110_MEMORY_SPEEDDIALS:   /* Speed dial numbers */
487                                         if ((data != NULL) && (data->SpeedDial != NULL)) {
488                                                 data->SpeedDial->Location = (((unsigned int)blockstart[6]) << 8) + blockstart[7];
489                                                 switch(blockstart[8]) {
490                                                 case 0x05:
491                                                         data->SpeedDial->MemoryType = GMT_ME;
492                                                         str = "phone";
493                                                         break;
494                                                 case 0x06:
495                                                         str = "SIM";
496                                                         data->SpeedDial->MemoryType = GMT_SM;
497                                                         break;
498                                                 default:
499                                                         str = "unknown";
500                                                         data->SpeedDial->MemoryType = GMT_XX;
501                                                         break;
502                                                 }
503                                         }
504                                         
505                                         dprintf("Speed dial pointer: %i in %s\n", data->SpeedDial->Location, str);
506                                         
507                                         break;
508                                 default:
509                                         /* FIXME: is it possible? */
510                                         dprintf("Wrong memory type(?)\n");
511                                         break;
512                                 }
513                                 
514                                 break;
515                         case P7110_ENTRYTYPE_NAME:      /* Name */
516                                 if (data->Bitmap) {
517                                         DecodeUnicode(data->Bitmap->text, (blockstart + 6), blockstart[5] / 2);
518                                         dprintf("Name: %s\n", data->Bitmap->text);
519                                 } else if (data->PhonebookEntry) {
520                                         DecodeUnicode(data->PhonebookEntry->Name, (blockstart + 6), blockstart[5] / 2);
521                                         data->PhonebookEntry->Empty = false;
522                                         dprintf("   Name: %s\n", data->PhonebookEntry->Name);
523                                 }
524                                 break;
525                         case P7110_ENTRYTYPE_EMAIL:
526                         case P7110_ENTRYTYPE_POSTAL:
527                         case P7110_ENTRYTYPE_NOTE:
528                                 if (data->PhonebookEntry) {
529                                         subEntry->EntryType   = blockstart[0];
530                                         subEntry->NumberType  = 0;
531                                         subEntry->BlockNumber = blockstart[4];
532                                         DecodeUnicode(subEntry->data.Number, (blockstart + 6), blockstart[5] / 2);
533                                         dprintf("   Type: %d (%02x)\n", subEntry->EntryType, subEntry->EntryType);
534                                         dprintf("   Text: %s\n", subEntry->data.Number);
535                                         subblockcount++;
536                                         data->PhonebookEntry->SubEntriesCount++;
537                                 }
538                                 break;
539                         case P7110_ENTRYTYPE_NUMBER:
540                                 if (data->PhonebookEntry) {
541                                         subEntry->EntryType   = blockstart[0];
542                                         subEntry->NumberType  = blockstart[5];
543                                         subEntry->BlockNumber = blockstart[4];
544                                         DecodeUnicode(subEntry->data.Number, (blockstart + 10), blockstart[9] / 2);
545                                         if (!subblockcount) strcpy(data->PhonebookEntry->Number, subEntry->data.Number);
546                                         dprintf("   Type: %d (%02x)\n", subEntry->NumberType, subEntry->NumberType);
547                                         dprintf(" Number: %s\n", subEntry->data.Number);                                        
548                                         subblockcount++;
549                                         data->PhonebookEntry->SubEntriesCount++;
550                                 }
551                                 break;
552                         case P7110_ENTRYTYPE_RINGTONE:  /* Ringtone */
553                                 if (data->Bitmap) {
554                                         data->Bitmap->ringtone = blockstart[5];
555                                         dprintf("Ringtone no. %d\n", data->Bitmap->ringtone);
556                                 }
557                                 break;
558                         case P7110_ENTRYTYPE_DATE:
559                                 if (data->PhonebookEntry) {
560                                         subEntry->EntryType=blockstart[0];
561                                         subEntry->NumberType=blockstart[5];
562                                         subEntry->BlockNumber=blockstart[4];
563                                         subEntry->data.Date.Year=(blockstart[6] << 8) + blockstart[7];
564                                         subEntry->data.Date.Month  = blockstart[8];
565                                         subEntry->data.Date.Day    = blockstart[9];
566                                         subEntry->data.Date.Hour   = blockstart[10];
567                                         subEntry->data.Date.Minute = blockstart[11];
568                                         subEntry->data.Date.Second = blockstart[12];
569                                         dprintf("   Date: %02u.%02u.%04u\n", subEntry->data.Date.Day,
570                                                 subEntry->data.Date.Month, subEntry->data.Date.Year);
571                                         dprintf("   Time: %02u:%02u:%02u\n", subEntry->data.Date.Hour,
572                                                 subEntry->data.Date.Minute, subEntry->data.Date.Second);
573                                         subblockcount++;
574                                 }
575                                 break;
576                         case P7110_ENTRYTYPE_LOGO:      /* Caller group logo */
577                                 if (data->Bitmap) {
578                                         data->Bitmap->width = blockstart[5];
579                                         data->Bitmap->height = blockstart[6];
580                                         data->Bitmap->size = (data->Bitmap->width * data->Bitmap->height) / 8;
581                                         memcpy(data->Bitmap->bitmap, blockstart + 10, data->Bitmap->size);
582                                         dprintf("Bitmap\n");
583                                 }
584                                 break;
585                         case P7110_ENTRYTYPE_LOGOSWITCH:/* Logo on/off */
586                                 break;
587                         case P7110_ENTRYTYPE_GROUP:     /* Caller group number */
588                                 if (data->PhonebookEntry) {
589                                         data->PhonebookEntry->Group = blockstart[5] - 1;
590                                         dprintf("   Group: %d\n", data->PhonebookEntry->Group);
591                                 }
592                                 break;
593                         default:
594                                 dprintf("Unknown phonebook block %02x\n", blockstart[0]);
595                                 break;
596                         }
597                         blockstart += blockstart[3];
598                 }
599                 return GE_NONE;
600                 break;
601         case 0x0c:
602                 switch (message[6]) {
603                 case 0x3d: return GE_PHBOOKWRITEFAILED; break;
604                 case 0x3e: return GE_PHBOOKWRITEFAILED; break;
605                 default: return GE_NONE; break; 
606                 }
607                 break;  
608         default:
609                 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
610                 return GE_UNKNOWN;
611                 break;
612         }
613 }
614
615 /* Just as an example.... */
616 /* But note that both requests are the same type which isn't very 'proper' */ 
617 static GSM_Error P7110_Identify(GSM_Data *data, GSM_Statemachine *state)
618 {
619         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
620         unsigned char req2[] = {FBUS_FRAME_HEADER, 0x03, 0x01, 0x32};
621   
622         dprintf("Identifying...\n");
623         if (SM_SendMessage(state, 4, 0x1b, req) != GE_NONE) return GE_NOTREADY;
624         if (SM_SendMessage(state, 6, 0x1b, req2) != GE_NONE) return GE_NOTREADY;
625         SM_WaitFor(state, data, 0x1b);
626         SM_Block(state, data, 0x1b); /* waits for all requests - returns req2 error */
627         SM_GetError(state, 0x1b);
628         
629         /* Check that we are back at state Initialised */
630         if (SM_Loop(state,0)!=Initialised) return GE_UNKNOWN;
631         return GE_NONE;
632 }
633
634 static GSM_Error P7110_Incoming0x1b(int messagetype, unsigned char *message, int length, GSM_Data *data)
635 {
636         switch (message[3]) {
637         case 02:
638                 if (data->Imei) { 
639                         snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
640                         dprintf("Received imei %s\n",data->Imei);
641                 }
642                 return GE_NONE;
643                 break;
644         case 04:
645                 if (data->Model) { 
646                         snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
647                         dprintf("Received model %s\n",data->Model);
648                 }
649                 if (data->Revision) { 
650                         snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
651                         dprintf("Received revision %s\n",data->Revision);
652                 }
653                 return GE_NONE;
654                 break;
655         default:
656                 dprintf("Unknown subtype of type 0x1b (%d)\n", message[3]);
657                 return GE_UNKNOWN;
658                 break;
659         }
660 }
661
662
663 /* handle messages of type 0x14 (SMS Handling, Folders, Logos.. */
664 static GSM_Error P7110_IncomingFolder(int messagetype, unsigned char *message, int length, GSM_Data *data)
665 {
666 #if 0
667         int off, offset;
668         int wc,i,j,tmp=0;
669         switch (message[3]) {
670         /* getfolders */
671         case 0x7B:
672                 i = 5;
673                 data->SMSFolders->number = message[4];
674                 dprintf("Message: %d SMS Folders received:\n", data->SMSFolders->number);
675       
676                 for (j = 0; j < message[4]; j++) {
677                         strcpy(data->SMSFolders->Folder[j].Name, "               ");
678                         data->SMSFolders->FoldersID[j] = message[i];
679                         dprintf("Folder Index: %d", data->SMSFolders->FoldersID[j]);
680                         i = i + 2;
681                         dprintf("   Folder name: ");
682                         tmp = 0;
683                         while ((message[i] != 0x00) & (message[i+1] == 0x00)) {
684                                 wc = message[i] | (message[i+1] << 8);
685                                 data->SMSFolders->Folder[j].Name[tmp] = DecodeWithUnicodeAlphabet(wc);
686                                 dprintf("%c", data->SMSFolders->Folder[j].Name[tmp]);
687                                 tmp++;
688                                 i = i + 2;
689                         }
690                         dprintf("\n");
691                         tmp = 0;
692                         i = i + 1;
693                 }
694                 break;
695
696         /* getfolderstatus */
697         case 0x6C:
698                 dprintf("Message: SMS Folder status received: \n" );
699                 data->OneSMSFolder->number = (message[5] * 256) + message[5];
700                 dprintf("Message: Number of Entries: %i\n" , data->OneSMSFolder->number);
701                 dprintf("Message: IDs of Entries : ");
702                 for (i=0;i<message[4]*256+message[5];i++) {
703                         data->OneSMSFolder->locations[i]=message[6+(i*2)]*256+message[(i*2)+7];
704                         dprintf("%d, ", data->OneSMSFolder->locations[i]);
705                 }
706                 dprintf("\n");
707                 break;
708
709         /* getsms */    
710         case 0x08:
711                 for (i = 0; i < length-2; i ++)
712                         if (isprint(message[i]))
713                                 dprintf("[%02x%c]", message[i], message[i]);
714                         else
715                                 dprintf("[%02x ]", message[i]);
716                 dprintf("\n");
717
718                 dprintf("Message: Getting SMS  %i " , data->SMSMessage->Location);
719                 dprintf("in Folder  %i\n", data->SMSMessage->Destination);
720                 if (message[5] != data->SMSMessage->Destination) {
721                         dprintf("Invalid SMS location (Folder)\n");
722                         return GE_INVALIDSMSLOCATION;
723                 }
724                 if ((message[6] * 256 + message[7]) != data->SMSMessage->Location) {
725                         dprintf("Invalid SMS location (ID)\n");
726                         return GE_INVALIDSMSLOCATION;
727                 }
728
729                 /* Status see nk7110.txt */
730                 data->SMSMessage->Status = message[4];
731
732                 if (message[8]==0x01) data->SMSMessage->Type = SMS_Deliver_Report;
733                 offset=4;
734                 if (data->SMSMessage->Status == SMS_MO_SENT) offset=5;
735                 off = 0;
736                 if (message[9+12] & 0x40) { /* UDH header available */
737
738                         off = (message[9+31+offset] + 1); /* Length of UDH header */
739     
740                         dprintf("   UDH header available (length %i)\n",off);
741                 }
742                   
743                 DecodeSMSHeader(message, length, data->SMSMessage, 9, offset);
744                 DecodeTextSMS(message, length, data->SMSMessage, 9, offset, off);
745               
746                 break;
747     
748         default:
749
750                 for (i = 0; i < length-2; i ++)
751                         if (isprint(message[i]))
752                                 dprintf("[%02x%c]", message[i], message[i]);
753                         else
754                                 dprintf("[%02x ]", message[i]);
755                 dprintf("\n");
756                 dprintf("Message: Unknown message of type 14 : %d  length: %d\n", message[3], length);
757                 break;
758         }
759 #endif
760         return GE_NONE;
761 }
762
763 static GSM_Error P7110_GetSMS(GSM_Data *data, GSM_Statemachine *state)
764 {
765         unsigned char req[] = {FBUS_FRAME_HEADER, 0x07, 
766                                 0x08, // FolderID
767                                 0x00, 
768                                 0x01, // Location
769                                 0x01, 0x65, 0x01};
770       
771         dprintf("Getting SMS...\n");
772         req[4] = data->SMSMessage->MemoryType;
773         req[6] = data->SMSMessage->Location;
774         if (SM_SendMessage(state, 10, 0x14, req) != GE_NONE) return GE_NOTREADY;
775         return SM_Block(state, data, 0x14);
776 }
777
778
779 static GSM_Error P7110_GetSMSFolders(GSM_Data *data, GSM_Statemachine *state)
780 {
781         unsigned char req[] = {FBUS_FRAME_HEADER, 0x7A, 0x00, 0x00};
782       
783         dprintf("Getting SMS Folders...\n");
784         if (SM_SendMessage(state, 6, 0x14, req) != GE_NONE) return GE_NOTREADY;
785         return SM_Block(state, data, 0x14);
786 }
787
788 static GSM_Error P7110_GetSMSFolderStatus(GSM_Data *data, GSM_Statemachine *state)
789 {
790 #if 0
791         unsigned char req[] = {FBUS_FRAME_HEADER, 0x6B, 
792                                 0x08, // Folder ID
793                                 0x0F, 0x01};
794       
795         req[4] = data->OneSMSFolder->FolderID;
796         dprintf("Getting SMS Folder Status...\n");
797         if (SM_SendMessage(state, 7, 0x14, req) != GE_NONE) return GE_NOTREADY;
798         return SM_Block(state, data, 0x14);
799 #endif
800         return GE_NONE;
801 }
802
803 static GSM_Error P7110_IncomingSMS(int messagetype, unsigned char *message, int length, GSM_Data *data)
804 {
805         GSM_Error       e = GE_NONE;
806         int             digits, bytes;
807         
808         if (!data || !data->MessageCenter) return GE_INTERNALERROR;
809
810         switch (message[3]) {
811         case P7110_SUBSMS_SMSC_RCVD:
812                 /* FIXME: Implement all these in gsm-sms.c */
813                 data->MessageCenter->No = message[4];
814                 data->MessageCenter->Format = message[6];
815                 data->MessageCenter->Validity = message[8];  /* due to changes in format */
816                 
817                 digits = message[9];
818                 bytes = message[21] - 1;
819                 
820
821                 sprintf(data->MessageCenter->Name, "%s", message + 33);
822                 
823                 if (strlen(data->MessageCenter->Recipient) == 0) {
824                         sprintf(data->MessageCenter->Recipient, "(none)");
825                 }
826                 if (strlen(data->MessageCenter->Number) == 0) {
827                         sprintf(data->MessageCenter->Number, "(none)");
828                 }
829                 if(strlen(data->MessageCenter->Name) == 0) {
830                         sprintf(data->MessageCenter->Name, "(none)");
831                 }
832                 
833                 break;
834         case P7110_SUBSMS_SMS_SENT:
835         case P7110_SUBSMS_SEND_FAIL:
836         case P7110_SUBSMS_SMS_RCVD:
837         case P7110_SUBSMS_CELLBRD_OK:
838         case P7110_SUBSMS_CELLBRD_FAIL:
839         case P7110_SUBSMS_READ_CELLBRD:
840         case P7110_SUBSMS_SMSC_OK:
841         case P7110_SUBSMS_SMSC_FAIL:
842         case P7110_SUBSMS_SMSC_RCVFAIL:
843                 dprintf("Subtype 0x%02x of type 0x%02x (SMS handling) not implemented\n", message[3], P7110_MSG_SMS);
844                 e = GE_NOTIMPLEMENTED;
845                 break;
846         default:
847                 dprintf("Unknown subtype of type 0x%02x (SMS handling): 0x%02x\n", P7110_MSG_SMS, message[3]);
848                 e = GE_UNKNOWN;
849                 break;
850         }
851         return e;
852 }
853
854 static GSM_Error P7110_IncomingClock(int messagetype, unsigned char *message, int length, GSM_Data *data)
855 {
856         GSM_Error       e = GE_NONE;
857
858         if (!data || !data->DateTime) return GE_INTERNALERROR;  
859         switch (message[3]) {
860         case P7110_SUBCLO_DATE_RCVD:
861                 data->DateTime->Year = (((unsigned int)message[8]) << 8) + message[9];
862                 data->DateTime->Month = message[10];
863                 data->DateTime->Day = message[11];
864                 data->DateTime->Hour = message[12];
865                 data->DateTime->Minute = message[13];
866                 data->DateTime->Second = message[14];
867
868                 break;
869         case P7110_SUBCLO_ALARM_RCVD: 
870                 switch(message[8]) {
871                 case P7110_ALARM_ENABLED:
872                         data->DateTime->AlarmEnabled = 1;
873                         break;
874                 case P7110_ALARM_DISABLED:
875                         data->DateTime->AlarmEnabled = 0;
876                         break;
877                 default:
878                         data->DateTime->AlarmEnabled = -1;
879                         dprintf("Unknown value of alarm enable byte: 0x%02x\n", message[8]);
880                         e = GE_UNKNOWN;
881                         break;
882                 }
883                 
884                 data->DateTime->Hour = message[9];
885                 data->DateTime->Minute = message[10];
886                 
887                 break;
888         default:
889                 dprintf("Unknown subtype of type 0x%02x (clock handling): 0x%02x\n", P7110_MSG_CLOCK, message[3]);
890                 e = GE_UNKNOWN;
891                 break;
892         }
893         return e;
894 }
895
896 GSM_Error P7110_GetNoteAlarm(int alarmdiff, GSM_DateTime *time, GSM_DateTime *alarm)
897 {
898         time_t                          t_alarm;
899         struct tm                       tm_time;
900         struct tm                       *tm_alarm;
901         GSM_Error                       e = GE_NONE;
902         
903         if (!time || !alarm) return GE_INTERNALERROR;
904         
905         memset(&tm_time, 0, sizeof(tm_time));
906         tm_time.tm_year = time->Year - 1900;
907         tm_time.tm_mon = time->Month - 1;
908         tm_time.tm_mday = time->Day;
909         tm_time.tm_hour = time->Hour;
910         tm_time.tm_min = time->Minute;
911
912         tzset();
913         t_alarm = mktime(&tm_time);
914         t_alarm -= alarmdiff;
915         t_alarm += timezone;
916
917         tm_alarm = localtime(&t_alarm);
918
919         alarm->Year = tm_alarm->tm_year + 1900;
920         alarm->Month = tm_alarm->tm_mon + 1;
921         alarm->Day = tm_alarm->tm_mday;
922         alarm->Hour = tm_alarm->tm_hour;
923         alarm->Minute = tm_alarm->tm_min;
924         alarm->Second = tm_alarm->tm_sec;
925
926         return e;
927 }
928
929
930 GSM_Error P7110_GetNoteTimes(unsigned char *block, GSM_CalendarNote *c)
931 {
932         time_t          alarmdiff;
933         GSM_Error       e = GE_NONE;
934         
935         if (!c) return GE_INTERNALERROR;
936
937         c->Time.Hour = block[0];
938         c->Time.Minute = block[1];
939         c->Recurance = ((((unsigned int)block[4]) << 8) + block[5]) * 60;
940         alarmdiff = (((unsigned int)block[2]) << 8) + block[3];
941         
942         if (alarmdiff != 0xffff) {
943                 P7110_GetNoteAlarm(alarmdiff * 60, &(c->Time), &(c->Alarm));
944                 c->Alarm.AlarmEnabled = 1;
945         } else {
946                 c->Alarm.AlarmEnabled = 0;
947         }
948                 
949         return e;
950 }
951
952 static GSM_Error P7110_IncomingCalendar(int messagetype, unsigned char *message, int length, GSM_Data *data)
953 {
954         GSM_Error                       e = GE_NONE;
955         unsigned char                   *block;
956         int                             i, alarm, year;
957         
958         if (!data || !data->CalendarNote) return GE_INTERNALERROR;
959
960         year =  data->CalendarNote->Time.Year;
961         dprintf("Year: %i\n", data->CalendarNote->Time.Year);
962         switch (message[3]) {
963         case P7110_SUBCAL_NOTE_RCVD:
964                 block = message + 12;
965                         
966                 data->CalendarNote->Location = (((unsigned int)message[4]) << 8) + message[5];
967                 data->CalendarNote->Time.Year = (((unsigned int)message[8]) << 8) + message[9];
968                 data->CalendarNote->Time.Month = message[10];
969                 data->CalendarNote->Time.Day = message[11];
970                 data->CalendarNote->Time.Second = 0;
971                         
972                 dprintf("Year: %i\n", data->CalendarNote->Time.Year);
973                         
974                 switch (message[6]) {
975                 case P7110_NOTE_MEETING:
976                         data->CalendarNote->Type = GCN_MEETING;
977                         P7110_GetNoteTimes(block, data->CalendarNote);
978                         DecodeUnicode(data->CalendarNote->Text, (block + 8), block[6]);
979                         break;
980                 case P7110_NOTE_CALL:
981                         data->CalendarNote->Type = GCN_CALL;
982                         P7110_GetNoteTimes(block, data->CalendarNote);
983                         DecodeUnicode(data->CalendarNote->Text, (block + 8), block[6]);
984                         DecodeUnicode(data->CalendarNote->Phone, (block + 8 + block[6] * 2), block[7]);
985                         break;
986                 case P7110_NOTE_REMINDER:
987                         data->CalendarNote->Type = GCN_REMINDER;
988                         data->CalendarNote->Recurance = ((((unsigned int)block[0]) << 8) + block[1]) * 60;
989                         DecodeUnicode(data->CalendarNote->Text, (block + 4), block[2]);
990                         break;
991                 case P7110_NOTE_BIRTHDAY:
992                         
993                         for (i = 0; i < 10; i++) {
994                                 dprintf("(%i:0x%02x)", i, block[i]);
995                         }
996                         dprintf("\n");
997                         
998                         data->CalendarNote->Type = GCN_BIRTHDAY;
999                         data->CalendarNote->Time.Year = year;
1000                         data->CalendarNote->Time.Hour = 23;
1001                         data->CalendarNote->Time.Minute = 59;
1002                         data->CalendarNote->Time.Second = 58;
1003                         
1004                         alarm = ((unsigned int)block[2]) << 24;
1005                         alarm += ((unsigned int)block[3]) << 16;
1006                         alarm += ((unsigned int)block[4]) << 8;
1007                         alarm += block[5];
1008                         
1009                         dprintf("alarm: %i\n", alarm);
1010                         
1011                         if (alarm == 0xffff) {
1012                                 data->CalendarNote->Alarm.AlarmEnabled = 0;
1013                         } else {
1014                                 data->CalendarNote->Alarm.AlarmEnabled = 1;
1015                         }
1016                         
1017                         P7110_GetNoteAlarm(alarm, &(data->CalendarNote->Time), &(data->CalendarNote->Alarm));
1018                         
1019                         data->CalendarNote->Time.Hour = 0;
1020                         data->CalendarNote->Time.Minute = 0;
1021                         data->CalendarNote->Time.Second = 0;
1022                         data->CalendarNote->Time.Year = (((unsigned int)block[6]) << 8) + block[7];
1023                         
1024                         DecodeUnicode(data->CalendarNote->Text, (block + 10), block[9]);
1025                         
1026                         break;
1027                 default:
1028                         data->CalendarNote->Type = -1;
1029                         e = GE_UNKNOWN;
1030                         break;
1031                 }
1032                 
1033                 break;
1034         case P7110_SUBCAL_ADD_MEETING_RESP:
1035         case P7110_SUBCAL_ADD_CALL_RESP:
1036         case P7110_SUBCAL_ADD_BIRTHDAY_RESP:
1037         case P7110_SUBCAL_ADD_REMINDER_RESP:
1038         case P7110_SUBCAL_DEL_NOTE_RESP:
1039         case P7110_SUBCAL_FREEPOS_RCVD:
1040         case P7110_SUBCAL_INFO_RCVD:
1041                 dprintf("Subtype 0x%02x of type 0x%02x (calendar handling) not implemented\n", message[3], P7110_MSG_CALENDAR);
1042                 e = GE_NOTIMPLEMENTED;
1043                 break;
1044         default:
1045                 dprintf("Unknown subtype of type 0x%02x (calendar handling): 0x%02x\n", P7110_MSG_CALENDAR, message[3]);
1046                 e = GE_UNKNOWN;
1047                 break;
1048         }
1049         return e;
1050 }
1051
1052 static int GetMemoryType(GSM_MemoryType memory_type)
1053 {
1054         int result;
1055
1056         switch (memory_type) {
1057         case GMT_MT:
1058                 result = P7110_MEMORY_MT;
1059                 break;
1060         case GMT_ME:
1061                 result = P7110_MEMORY_ME;
1062                 break;
1063         case GMT_SM:
1064                 result = P7110_MEMORY_SM;
1065                 break;
1066         case GMT_FD:
1067                 result = P7110_MEMORY_FD;
1068                 break;
1069         case GMT_ON:
1070                 result = P7110_MEMORY_ON;
1071                 break;
1072         case GMT_EN:
1073                 result = P7110_MEMORY_EN;
1074                 break;
1075         case GMT_DC:
1076                 result = P7110_MEMORY_DC;
1077                 break;
1078         case GMT_RC:
1079                 result = P7110_MEMORY_RC;
1080                 break;
1081         case GMT_MC:
1082                 result = P7110_MEMORY_MC;
1083                 break;
1084         default:
1085                 result = P7110_MEMORY_XX;
1086                 break;
1087         }
1088         return (result);
1089 }
1090
1091 #if 0
1092
1093 static GSM_Error P7110_DialVoice(char *Number)
1094 {
1095
1096   /* Doesn't work (yet) */    /* 3 2 1 5 2 30 35 */
1097
1098         // unsigned char req0[100] = { 0x00, 0x01, 0x64, 0x01 };
1099
1100         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01, 0x01, 0x01, 0x01, 0x05, 0x00, 0x01, 0x03, 0x02, 0x91, 0x00, 0x031, 0x32, 0x00};
1101         // unsigned char req[100]={0x00, 0x01, 0x7c, 0x01, 0x31, 0x37, 0x30, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01};
1102         //  unsigned char req[100] = {FBUS_FRAME_HEADER, 0x01, 0x00, 0x20, 0x01, 0x46};
1103         // unsigned char req_end[] = {0x05, 0x01, 0x01, 0x05, 0x81, 0x01, 0x00, 0x00, 0x01};
1104         int len = 0/*, i*/;
1105
1106         //req[4]=strlen(Number);
1107
1108         //for(i=0; i < strlen(Number) ; i++)
1109         // req[5+i]=Number[i];
1110
1111         //memcpy(req+5+strlen(Number), req_end, 10);
1112
1113         //len=6+strlen(Number);
1114
1115         //len = 4;
1116
1117         
1118         //PGEN_CommandResponse(&link, req0, &len, 0x40, 0x40, 100);
1119         
1120         len=17;
1121
1122         if (PGEN_CommandResponse(&link, req, &len, 0x01, 0x01, 100)==GE_NONE) {
1123                 PGEN_DebugMessage(1, req, len);
1124 //              return GE_NONE;
1125
1126         }
1127 //      } else return GE_NOTIMPLEMENTED;
1128
1129  
1130         while(1){
1131                 link.Loop(NULL);
1132         }
1133
1134         return GE_NOTIMPLEMENTED;
1135 }
1136
1137 #endif
1138
1139 static GSM_Error GetCallerBitmap(GSM_Data *data, GSM_Statemachine *state)
1140 {
1141         unsigned char req[] = {FBUS_FRAME_HEADER, 0x07, 0x01, 0x01, 0x00, 0x01,
1142                                   0x00, 0x10 , /* memory type */
1143                                   0x00, 0x00,  /* location */
1144                                   0x00, 0x00};
1145
1146         req[11] = data->Bitmap->number + 1;
1147         dprintf("Getting caller(%d) logo...\n",data->Bitmap->number);
1148         if (SM_SendMessage(state, 14, 0x03, req)!=GE_NONE) return GE_NOTREADY;
1149         return SM_Block(state, data, 0x03);
1150 }
1151
1152 inline unsigned char PackBlock(u8 id, u8 size, u8 no, u8 *buf, u8 *block)
1153 {
1154         *(block++) = id;
1155         *(block++) = 0;
1156         *(block++) = 0;
1157         *(block++) = size + 6;
1158         *(block++) = no;
1159         memcpy(block, buf, size);
1160         block += size;
1161         *(block++) = 0;
1162         return (size + 6);
1163 }
1164
1165 static GSM_Error SetCallerBitmap(GSM_Data *data, GSM_Statemachine *state)
1166 {
1167         unsigned char req[500] = {FBUS_FRAME_HEADER, 0x0b, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0c,
1168                                   0x00, 0x10,  /* memory type */
1169                                   0x00, 0x00,  /* location */
1170                                   0x00, 0x00, 0x00};
1171         char string[500];
1172         int block, i;
1173         unsigned int count = 18;
1174
1175         if ((data->Bitmap->width!=state->Phone.Info.CallerLogoW) ||
1176             (data->Bitmap->height!=state->Phone.Info.CallerLogoH )) {
1177                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.CallerLogoH, state->Phone.Info.CallerLogoW, data->Bitmap->height, data->Bitmap->width); 
1178             return GE_INVALIDIMAGESIZE;
1179         }       
1180
1181         req[13] = data->Bitmap->number + 1;
1182         dprintf("Setting caller(%d) bitmap...\n",data->Bitmap->number);
1183         block = 1;
1184         /* Name */
1185         i = strlen(data->Bitmap->text);
1186         EncodeUnicode((string + 1), data->Bitmap->text, i);
1187         string[0] = i * 2;
1188         count += PackBlock(0x07, i * 2 + 1, block++, string, req + count);
1189         /* Ringtone */
1190         string[0] = data->Bitmap->ringtone;
1191         string[1] = 0;
1192         count += PackBlock(0x0c, 2, block++, string, req + count);
1193         /* Number */
1194         string[0] = data->Bitmap->number+1;
1195         string[1] = 0;
1196         count += PackBlock(0x1e, 2, block++, string, req + count);
1197         /* Logo on/off - assume on for now */
1198         string[0] = 1;
1199         string[1] = 0;
1200         count += PackBlock(0x1c, 2, block++, string, req + count);
1201         /* Logo */
1202         string[0] = data->Bitmap->width;
1203         string[1] = data->Bitmap->height;
1204         string[2] = 0;
1205         string[3] = 0;
1206         string[4] = 0x7e; /* Size */
1207         memcpy(string + 5, data->Bitmap->bitmap, data->Bitmap->size);
1208         count += PackBlock(0x1b, data->Bitmap->size + 5, block++, string, req + count);
1209         req[17] = block - 1;
1210
1211         if (SM_SendMessage(state, count, 0x03, req)!=GE_NONE) return GE_NOTREADY;
1212         return SM_Block(state, data, 0x03);
1213 }
1214
1215 static GSM_Error GetStartupBitmap(GSM_Data *data, GSM_Statemachine *state)
1216 {
1217         unsigned char req[] = {FBUS_FRAME_HEADER, 0xee, 0x15};
1218
1219         dprintf("Getting startup logo...\n");
1220         if (SM_SendMessage(state, 5, 0x7a, req)!=GE_NONE) return GE_NOTREADY;
1221         return SM_Block(state, data, 0x7a);
1222 }
1223
1224 static GSM_Error P7110_IncomingStartup(int messagetype, unsigned char *message, int length, GSM_Data *data)
1225 {
1226         switch (message[3]) {
1227         case 0xeb:
1228                 dprintf("Startup logo set ok\n");
1229                 return GE_NONE;
1230                 break;
1231         case 0xed:
1232                 if (data->Bitmap) {
1233                         /* I'm sure there are blocks here but never mind! */
1234                         data->Bitmap->type = GSM_StartupLogo;
1235                         data->Bitmap->height = message[13];
1236                         data->Bitmap->width = message[17];
1237                         data->Bitmap->size=((data->Bitmap->height/8)+(data->Bitmap->height%8>0))*data->Bitmap->width; /* Can't see this coded anywhere */
1238                         memcpy(data->Bitmap->bitmap, message+22, data->Bitmap->size);
1239                         dprintf("Startup logo got ok - height(%d) width(%d)\n", data->Bitmap->height, data->Bitmap->width);
1240                 }
1241                 return GE_NONE;
1242                 break;
1243         default:
1244                 dprintf("Unknown subtype of type 0x7a (%d)\n", message[3]);
1245                 return GE_UNKNOWN;
1246                 break;
1247         }
1248 }
1249
1250 static GSM_Error GetOperatorBitmap(GSM_Data *data, GSM_Statemachine *state)
1251 {
1252         unsigned char req[] = {FBUS_FRAME_HEADER, 0x70};
1253
1254         dprintf("Getting op logo...\n");
1255         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
1256         return SM_Block(state, data, 0x0a);
1257 }
1258
1259 static GSM_Error SetStartupBitmap(GSM_Data *data, GSM_Statemachine *state)
1260 {
1261         unsigned char req[1000] = {FBUS_FRAME_HEADER, 0xec, 0x15, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x02, 0x00,
1262                                    0x00,           /* Height */
1263                                    0xc0, 0x03, 0x00,
1264                                    0x00,           /* Width */
1265                                    0xc0, 0x04, 0x03, 0x00 };
1266         int count = 21;
1267
1268
1269         if ((data->Bitmap->width!=state->Phone.Info.StartupLogoW) ||
1270             (data->Bitmap->height!=state->Phone.Info.StartupLogoH )) {
1271                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.StartupLogoH, state->Phone.Info.StartupLogoW, data->Bitmap->height, data->Bitmap->width); 
1272             return GE_INVALIDIMAGESIZE;
1273         }
1274
1275         req[12] = data->Bitmap->height;
1276         req[16] = data->Bitmap->width;
1277         memcpy(req + count, data->Bitmap->bitmap, data->Bitmap->size);
1278         count += data->Bitmap->size;
1279         dprintf("Setting startup logo...\n");
1280
1281         if (SM_SendMessage(state, count, 0x7a, req) != GE_NONE) return GE_NOTREADY;
1282         return SM_Block(state, data, 0x7a);
1283 }
1284
1285 static GSM_Error SetOperatorBitmap(GSM_Data *data, GSM_Statemachine *state)
1286 {
1287         unsigned char req[500] = { FBUS_FRAME_HEADER, 0xa3, 0x01,
1288                                    0x00,              /* logo enabled */
1289                                    0x00, 0xf0, 0x00,  /* network code (000 00) */
1290                                    0x00 ,0x04,
1291                                    0x08,              /* length of rest */
1292                                    0x00, 0x00,        /* Bitmap width / height */
1293                                    0x00,
1294                                    0x00,              /* Bitmap size */
1295                                    0x00, 0x00
1296         };    
1297         int count = 18;
1298
1299         if ((data->Bitmap->width!=state->Phone.Info.OpLogoW) ||
1300             (data->Bitmap->height!=state->Phone.Info.OpLogoH )) {
1301                 dprintf("Invalid image size - expecting (%dx%d) got (%dx%d)\n",state->Phone.Info.OpLogoH, state->Phone.Info.OpLogoW, data->Bitmap->height, data->Bitmap->width); 
1302             return GE_INVALIDIMAGESIZE;
1303         }
1304
1305         if (strcmp(data->Bitmap->netcode,"000 00")) {  /* set logo */
1306                 req[5] = 0x01;      // Logo enabled
1307                 req[6] = ((data->Bitmap->netcode[1] & 0x0f) << 4) | (data->Bitmap->netcode[0] & 0x0f);
1308                 req[7] = 0xf0 | (data->Bitmap->netcode[2] & 0x0f);
1309                 req[8] = ((data->Bitmap->netcode[5] & 0x0f) << 4) | (data->Bitmap->netcode[4] & 0x0f);
1310                 req[11] = 8 + data->Bitmap->size;
1311                 req[12] = data->Bitmap->width;
1312                 req[13] = data->Bitmap->height;
1313                 req[15] = data->Bitmap->size;
1314                 memcpy(req + count, data->Bitmap->bitmap, data->Bitmap->size);
1315                 count += data->Bitmap->size;
1316         }
1317         dprintf("Setting op logo...\n");
1318         if (SM_SendMessage(state, count, 0x0a, req) != GE_NONE) return GE_NOTREADY;
1319         return SM_Block(state, data, 0x0a);
1320 }
1321
1322 static GSM_Error P7110_GetBitmap(GSM_Data *data, GSM_Statemachine *state)
1323 {
1324         switch(data->Bitmap->type) {
1325         case GSM_CallerLogo:
1326                 return GetCallerBitmap(data, state);
1327         case GSM_StartupLogo:
1328                 return GetStartupBitmap(data, state);
1329         case GSM_OperatorLogo:
1330                 return GetOperatorBitmap(data, state);
1331         default:
1332                 return GE_NOTIMPLEMENTED;
1333         }
1334 }
1335
1336 static GSM_Error P7110_SetBitmap(GSM_Data *data, GSM_Statemachine *state)
1337 {
1338         switch(data->Bitmap->type) {
1339         case GSM_CallerLogo:
1340                 return SetCallerBitmap(data, state);
1341         case GSM_StartupLogo:
1342                 return SetStartupBitmap(data, state);
1343         case GSM_OperatorLogo:
1344                 return SetOperatorBitmap(data, state);
1345         default:
1346                 return GE_NOTIMPLEMENTED;
1347         }
1348 }
1349
1350 static GSM_Error P7110_WritePhonebookLocation(GSM_Data *data, GSM_Statemachine *state)
1351 {
1352         unsigned char req[500] = {FBUS_FRAME_HEADER, 0x0b, 0x00, 0x01, 0x01, 0x00, 0x00, 0x0c,
1353                                   0x00, 0x00,  /* memory type */
1354                                   0x00, 0x00,  /* location */
1355                                   0x00, 0x00, 0x00};
1356         char string[500];
1357         int block, i, j, defaultn;
1358         unsigned int count = 18;
1359         GSM_PhonebookEntry *entry;
1360         
1361         if (data->PhonebookEntry) entry=data->PhonebookEntry;
1362         else return GE_TRYAGAIN;
1363
1364         req[11] = GetMemoryType(entry->MemoryType);
1365         req[12] = (entry->Location >> 8);
1366         req[13] = entry->Location & 0xff;
1367         block = 1;
1368         if (*(entry->Name)) {
1369                 /* Name */
1370                 i = strlen(entry->Name);
1371                 EncodeUnicode((string + 1), entry->Name, i);
1372                 string[0] = i * 2;
1373                 count += PackBlock(0x07, i * 2 + 1, block++, string, req + count);
1374                 /* Group */
1375                 string[0] = entry->Group + 1;
1376                 string[1] = 0;
1377                 count += PackBlock(0x1e, 2, block++, string, req + count);
1378                 /* Default Number */
1379                 defaultn = 999;
1380                 for (i = 0; i < entry->SubEntriesCount; i++)
1381                         if (entry->SubEntries[i].EntryType == GSM_Number)
1382                                 if (!strcmp(entry->Number, entry->SubEntries[i].data.Number))
1383                                         defaultn = i;
1384                 if (defaultn < i) {
1385                         string[0] = entry->SubEntries[defaultn].NumberType;
1386                         string[1] = 0;
1387                         string[2] = 0;
1388                         string[3] = 0;
1389                         i = strlen(entry->SubEntries[defaultn].data.Number);
1390                         EncodeUnicode((string + 5), entry->SubEntries[defaultn].data.Number, i);
1391                         string[4] = i * 2;
1392                         count += PackBlock(0x0b, i * 2 + 5, block++, string, req + count);
1393                 }
1394                 /* Rest of the numbers */
1395                 for (i = 0; i < entry->SubEntriesCount; i++)
1396                         if (entry->SubEntries[i].EntryType == GSM_Number)
1397                                 if (i != defaultn) {
1398                                         string[0] = entry->SubEntries[i].NumberType;
1399                                         string[1] = 0;
1400                                         string[2] = 0;
1401                                         string[3] = 0;
1402                                         j = strlen(entry->SubEntries[i].data.Number);
1403                                         EncodeUnicode((string + 5), entry->SubEntries[i].data.Number, j);
1404                                         string[4] = j + 2;
1405                                         count += PackBlock(0x0b, j * 2 + 5, block++, string, req + count);
1406                                 } 
1407                 req[17] = block - 1;
1408                 dprintf("Writing phonebook entry %s...\n",entry->Name);
1409         }
1410         if (SM_SendMessage(state, count, 0x03, req) != GE_NONE) return GE_NOTREADY;
1411         return SM_Block(state, data, 0x03);
1412 }
1413
1414 static GSM_Error P7110_ReadPhonebookLL(GSM_Data *data, GSM_Statemachine *state, int memtype, int location)
1415 {
1416         GSM_Error       error;
1417         unsigned char   req[2000] = {FBUS_FRAME_HEADER, 0x07, 0x01, 0x01, 0x00, 0x01,
1418                                         0x00, 0x00, /* memory type */ //02,05
1419                                         0x00, 0x00, /* location */
1420                                         0x00, 0x00};
1421
1422         dprintf("Reading phonebook location (%d)\n", location);
1423         
1424         req[9] = memtype;
1425         req[10] = location >> 8;
1426         req[11] = location & 0xff;
1427         
1428         if (SM_SendMessage(state, 14, P7110_MSG_PHONEBOOK, req) != GE_NONE) return GE_NOTREADY;
1429         error = SM_Block(state, data, P7110_MSG_PHONEBOOK);
1430         
1431         return error;
1432 }
1433
1434 static GSM_Error P7110_ReadPhonebook(GSM_Data *data, GSM_Statemachine *state)
1435 {
1436         int memtype, location;
1437         
1438         memtype = GetMemoryType(data->PhonebookEntry->MemoryType);
1439         location = data->PhonebookEntry->Location;
1440         
1441         return P7110_ReadPhonebookLL(data, state, memtype, location);
1442 }
1443
1444 static GSM_Error P7110_GetSpeedDial(GSM_Data *data, GSM_Statemachine *state)
1445 {
1446         int memtype, location;
1447         
1448         memtype = P7110_MEMORY_SPEEDDIALS;
1449         location = data->SpeedDial->Number;
1450         
1451         return P7110_ReadPhonebookLL(data, state, memtype, location);
1452 }
1453
1454 static GSM_Error P7110_GetSMSCenter(GSM_Data *data, GSM_Statemachine *state)
1455 {
1456         GSM_Error       error;
1457         unsigned char   req[2000] = {FBUS_FRAME_HEADER, P7110_SUBSMS_GET_SMSC, 0x64, 0x00};
1458         
1459         req[5] = data->MessageCenter->No;
1460         
1461         if (SM_SendMessage(state, 6, P7110_MSG_SMS, req) != GE_NONE) return GE_NOTREADY;
1462         error = SM_Block(state, data, P7110_MSG_SMS);
1463         
1464         return error;
1465 }
1466
1467 static GSM_Error P7110_GetClock(char req_type, GSM_Data *data, GSM_Statemachine *state)
1468 {
1469         GSM_Error       error;
1470         unsigned char   req[2000] = {FBUS_FRAME_HEADER, req_type};
1471         
1472         if (SM_SendMessage(state, 4, P7110_MSG_CLOCK, req) != GE_NONE) return GE_NOTREADY;
1473         error = SM_Block(state, data, P7110_MSG_CLOCK);
1474         
1475         return error;
1476 }
1477
1478 static GSM_Error P7110_GetCalendarNote(GSM_Data *data, GSM_Statemachine *state)
1479 {
1480         GSM_Error       error = GE_NOTREADY;
1481         unsigned char   req[2000] = {FBUS_FRAME_HEADER, P7110_SUBCAL_GET_NOTE, 0x00, 0x00};
1482         unsigned char   date[2000] = {FBUS_FRAME_HEADER, P7110_SUBCLO_GET_DATE};
1483         GSM_Data        tmpdata;
1484         GSM_DateTime    tmptime;
1485         
1486         tmpdata.DateTime = &tmptime;
1487         if (SM_SendMessage(state, 4, P7110_MSG_CLOCK, date) == GE_NONE) {
1488                 SM_Block(state, &tmpdata, P7110_MSG_CLOCK);
1489                 req[4] = data->CalendarNote->Location >> 8;
1490                 req[5] = data->CalendarNote->Location & 0xff;
1491                 data->CalendarNote->Time.Year = tmptime.Year;
1492                 
1493                 if(SM_SendMessage(state, 6, P7110_MSG_CALENDAR, req) == GE_NONE) {
1494                         error = SM_Block(state, data, P7110_MSG_CALENDAR);
1495                 }
1496         }       
1497         
1498         return error;
1499 }