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