Update: orig2001_11_27_05_17 -> orig2001_12_04_22_45
[gnokii.git] / common / phones / nk6100.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) 2001 Pawe³ Kot <pkot@linuxnews.pl>
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 6100 series. 
15   See README for more details on supported mobile phones.
16
17 */
18
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22
23 #define __phones_nk6100_c
24 #include "misc.h"
25 #include "gsm-common.h"
26 #include "phones/generic.h"
27 #include "phones/nk6100.h"
28 #include "links/fbus.h"
29 #include "links/fbus-phonet.h"
30 #include "phones/nokia.h"
31
32 #ifdef WIN32
33 #define snprintf _snprintf
34 #endif
35
36 /* Some globals */
37
38 static const SMSMessage_Layout nk6100_deliver = {
39         true,
40         0, 11, 0, 0, 6, 0, 0, -1, 23, 22, 0, 20,
41         8, true, 24, true, 36, -1,
42         5, 4,
43         43, true
44 };
45
46 static const SMSMessage_Layout nk6100_submit = {
47         true,
48         -1, 20, 20, 20, 6, 21, 22, -1, 24, 23, 20, 20,
49         8, true, 25, true, 37, -1,
50         -1, -1,
51         44, true
52 };
53
54 static const SMSMessage_Layout nk6100_delivery_report = {
55         true,
56         0, 0, 0, 0, 6, 0, 0, 0, 22, 21, -1, 20,
57         8, true, 24, true, 35, 42,
58         5, 4,
59         22, true
60 };
61
62 static const SMSMessage_Layout nk6100_picture = {
63         false,
64         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65         0, true, 0, true, 0, 0,
66         0, 0,
67         0, true
68 };
69
70 static SMSMessage_PhoneLayout nk6100_layout;
71
72 static unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
73
74 static GSM_IncomingFunctionType IncomingFunctions[] = {
75         { 0x64, IncomingPhoneInfo },
76         { 0xd2, IncomingModelInfo },
77         { 0x14, IncomingSMS },
78         { 0x03, Incoming0x03 },
79         { 0x0a, Incoming0x0a },
80         { 0x17, Incoming0x17 },
81         { 0, NULL}
82 };
83
84 GSM_Phone phone_nokia_6100 = {
85         IncomingFunctions,
86         PGEN_IncomingDefault,
87         /* Mobile phone information */
88         {
89                 "6110|6130|6150|6190|5110|5130|5190|3210|3310|3330", /* Supported models */
90                 4,                     /* Max RF Level */
91                 0,                     /* Min RF Level */
92                 GRF_Arbitrary,         /* RF level units */
93                 4,                     /* Max Battery Level */
94                 0,                     /* Min Battery Level */
95                 GBU_Arbitrary,         /* Battery level units */
96                 GDT_DateTime,          /* Have date/time support */
97                 GDT_TimeOnly,          /* Alarm supports time only */
98                 1,                     /* Alarms available - FIXME */
99                 48, 84,                /* Startup logo size - 7110 is fixed at init*/
100                 14, 72,                /* Op logo size */
101                 14, 72                 /* Caller logo size */
102         },
103         Functions
104 };
105
106 static GSM_Error Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
107 {
108         switch (op) {
109         case GOP_Init:
110                 return Initialise(state);
111         case GOP_GetModel:
112                 return GetModelName(data, state);
113         case GOP_GetRevision:
114                 return GetRevision(data, state);
115         case GOP_GetImei:
116                 return GetIMEI(data, state);
117         case GOP_Identify:
118                 return Identify(data, state);
119         case GOP_GetBatteryLevel:
120                 return GetBatteryLevel(data, state);
121         case GOP_GetRFLevel:
122                 return GetRFLevel(data, state);
123         case GOP_GetMemoryStatus:
124                 return GetMemoryStatus(data, state);
125         case GOP_GetSMS:
126                 return GetSMSMessage(data, state);
127         default:
128                 return GE_NOTIMPLEMENTED;
129         }
130 }
131
132 /* static bool LinkOK = true; */
133
134 /* Initialise is the only function allowed to 'use' state */
135 static GSM_Error Initialise(GSM_Statemachine *state)
136 {
137         GSM_Data data;
138         char model[10];
139         GSM_Error err;
140
141         /* Copy in the phone info */
142         memcpy(&(state->Phone), &phone_nokia_6100, sizeof(GSM_Phone));
143
144         /* SMS Layout */
145         nk6100_layout.Type = 7;
146         nk6100_layout.Deliver = nk6100_deliver;
147         nk6100_layout.Submit = nk6100_submit;
148         nk6100_layout.DeliveryReport = nk6100_delivery_report;
149         nk6100_layout.Picture = nk6100_picture;
150         layout = nk6100_layout;
151
152         switch (state->Link.ConnectionType) {
153         case GCT_Serial:
154                 err = FBUS_Initialise(&(state->Link), state, 0);
155                 break;
156         case GCT_Infrared:
157                 err = PHONET_Initialise(&(state->Link), state);
158                 break;
159         default:
160                 return GE_NOTSUPPORTED;
161         }
162
163         if (err != GE_NONE) {
164                 dprintf("Error in link initialisation\n");
165                 return GE_NOTSUPPORTED;
166         }
167         
168         SM_Initialise(state);
169
170         /* Now test the link and get the model */
171         GSM_DataClear(&data);
172         data.Model = model;
173         if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) return GE_NOTSUPPORTED;
174         return GE_NONE;
175 }
176
177 static GSM_Error GetPhoneInfo(GSM_Data *data, GSM_Statemachine *state)
178 {
179         unsigned char req[] = { FBUS_FRAME_HEADER, 0x03, 0x00 };
180
181         dprintf("Getting phone info...\n");
182         if (SM_SendMessage(state, 5, 0xd1, req) != GE_NONE) return GE_NOTREADY;
183         return (SM_Block(state, data, 0xd2));
184 }
185
186 static GSM_Error GetModelName(GSM_Data *data, GSM_Statemachine *state)
187 {
188         dprintf("Getting model...\n");
189         return GetPhoneInfo(data, state);
190 }
191
192 static GSM_Error GetRevision(GSM_Data *data, GSM_Statemachine *state)
193 {
194         dprintf("Getting revision...\n");
195         return GetPhoneInfo(data, state);
196 }
197
198 static GSM_Error GetIMEI(GSM_Data *data, GSM_Statemachine *state)
199 {
200         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
201   
202         dprintf("Getting imei...\n");
203         if (SM_SendMessage(state, 4, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
204         return SM_Block(state, data, 0x1b);
205 }
206
207
208 static GSM_Error GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
209 {
210         unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
211
212         dprintf("Getting battery level...\n");
213         if (SM_SendMessage(state, 4, 0x17, req) != GE_NONE) return GE_NOTREADY;
214         return SM_Block(state, data, 0x17);
215 }
216
217
218 static GSM_Error Incoming0x17(int messagetype, unsigned char *message, int length, GSM_Data *data)
219 {
220         switch (message[3]) {
221         case 0x03:
222                 if (data->BatteryLevel) { 
223                         *(data->BatteryUnits) = GBU_Percentage;
224                         *(data->BatteryLevel) = message[5];
225                         dprintf("Battery level %f\n",*(data->BatteryLevel));
226                 }
227                 return GE_NONE;
228                 break;
229         default:
230                 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
231                 return GE_UNKNOWN;
232                 break;
233         }
234 }
235
236 static GSM_Error GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
237 {
238         unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
239
240         dprintf("Getting rf level...\n");
241         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
242         return SM_Block(state, data, 0x0a);
243 }
244
245 static GSM_Error Incoming0x0a(int messagetype, unsigned char *message, int length, GSM_Data *data)
246 {
247         switch (message[3]) {
248         case 0x82:
249                 if (data->RFLevel) { 
250                         *(data->RFUnits) = GRF_Percentage;
251                         *(data->RFLevel) = message[4];
252                         dprintf("RF level %f\n",*(data->RFLevel));
253                 }
254                 return GE_NONE;
255                 break;
256         default:
257                 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
258                 return GE_UNKNOWN;
259                 break;
260         }
261 }
262
263 static GSM_Error GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
264 {
265         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
266       
267         dprintf("Getting memory status...\n");
268         req[5] = GetMemoryType(data->MemoryStatus->MemoryType);
269         if (SM_SendMessage(state, 6, 0x03, req) != GE_NONE) return GE_NOTREADY;
270         return SM_Block(state, data, 0x03);
271 }
272
273 static GSM_Error Incoming0x03(int messagetype, unsigned char *message, int length, GSM_Data *data)
274 {
275         switch (message[3]) {
276         case 0x04:
277                 if (data->MemoryStatus) {
278                         if (message[5] != 0xff) {
279                                 data->MemoryStatus->Used = (message[16] << 8) + message[17];
280                                 data->MemoryStatus->Free = ((message[14] << 8) + message[15]) - data->MemoryStatus->Used;
281                                 dprintf("Memory status - location = %d\n", (message[8] << 8) + message[9]);
282                                 return GE_NONE;
283                         } else {
284                                 dprintf("Unknown error getting mem status\n");
285                                 return GE_NOTIMPLEMENTED;
286                                 
287                         }
288                 }
289                 return GE_NONE;
290                 break;
291         default:
292                 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
293                 return GE_UNKNOWN;
294                 break;
295         }
296 }
297
298 static GSM_Error Identify(GSM_Data *data, GSM_Statemachine *state)
299 {
300         unsigned char req[] = { FBUS_FRAME_HEADER, 0x10 };
301
302         dprintf("Identifying...\n");
303         PNOK_GetManufacturer(data->Manufacturer);
304         if (SM_SendMessage(state, 4, 0x64, req) != GE_NONE) return GE_NOTREADY;
305         SM_WaitFor(state, data, 0x64);
306         SM_Block(state, data, 0x64); /* waits for all requests */
307         SM_GetError(state, 0x64);
308         
309         /* Check that we are back at state Initialised */
310         if (SM_Loop(state, 0) != Initialised) return GE_UNKNOWN;
311         return GE_NONE;
312 }
313
314 static GSM_Error IncomingPhoneInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
315 {
316         if (data->Imei) { 
317 #if defined WIN32 || !defined HAVE_SNPRINTF
318                 sprintf(data->Imei, "%s", message + 4);
319 #else
320                 snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
321 #endif
322                 dprintf("Received imei %s\n", data->Imei);
323         }
324         if (data->Model) { 
325 #if defined WIN32 || !defined HAVE_SNPRINTF
326                 sprintf(data->Model, "%s", message + 22);
327 #else
328                 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
329 #endif
330                 dprintf("Received model %s\n", data->Model);
331         }
332         if (data->Revision) { 
333 #if defined WIN32 || !defined HAVE_SNPRINTF
334                 sprintf(data->Revision, "%s", message + 7);
335 #else
336                 snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
337 #endif
338                 dprintf("Received revision %s\n", data->Revision);
339         }
340
341         dprintf("Message: Mobile phone identification received:\n");
342         dprintf("\tIMEI: %s\n", data->Imei);
343         dprintf("\tModel: %s\n", data->Model);
344         dprintf("\tProduction Code: %s\n", message + 31);
345         dprintf("\tHW: %s\n", message + 39);
346         dprintf("\tFirmware: %s\n", message + 44);
347         
348         /* These bytes are probably the source of the "Accessory not connected"
349            messages on the phone when trying to emulate NCDS... I hope....
350            UPDATE: of course, now we have the authentication algorithm. */
351         dprintf("\tMagic bytes: %02x %02x %02x %02x\n", message[50], message[51], message[52], message[53]);
352         
353         MagicBytes[0] = message[50];
354         MagicBytes[1] = message[51];
355         MagicBytes[2] = message[52];
356         MagicBytes[3] = message[53];
357
358         return GE_NONE;
359 }
360
361 static GSM_Error IncomingModelInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
362 {
363 #if defined WIN32 || !defined HAVE_SNPRINTF
364         if (data->Model) sprintf(data->Model, "%s", message + 21);
365         if (data->Revision) sprintf(data->Revision, "SW%s", message + 5);
366 #else
367         dprintf("%p %p %p\n", data, data->Model, data->Revision);
368         if (data->Model) {
369                 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 21);
370                 data->Model[GSM_MAX_MODEL_LENGTH - 1] = 0;
371         }
372         if (data->Revision) {
373                 snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "SW%s", message + 5);
374                 data->Revision[GSM_MAX_REVISION_LENGTH - 1] = 0;
375         }
376 #endif
377         dprintf("Phone info:\n%s\n", message + 4);
378
379         return GE_NONE;
380 }
381
382 static int GetMemoryType(GSM_MemoryType memory_type)
383 {
384         int result;
385
386         switch (memory_type) {
387         case GMT_MT:
388                 result = P6100_MEMORY_MT;
389                 break;
390         case GMT_ME:
391                 result = P6100_MEMORY_ME;
392                 break;
393         case GMT_SM:
394                 result = P6100_MEMORY_SM;
395                 break;
396         case GMT_FD:
397                 result = P6100_MEMORY_FD;
398                 break;
399         case GMT_ON:
400                 result = P6100_MEMORY_ON;
401                 break;
402         case GMT_EN:
403                 result = P6100_MEMORY_EN;
404                 break;
405         case GMT_DC:
406                 result = P6100_MEMORY_DC;
407                 break;
408         case GMT_RC:
409                 result = P6100_MEMORY_RC;
410                 break;
411         case GMT_MC:
412                 result = P6100_MEMORY_MC;
413                 break;
414         default:
415                 result = P6100_MEMORY_XX;
416                 break;
417         }
418         return (result);
419 }
420
421 static GSM_Error GetSMSMessage(GSM_Data *data, GSM_Statemachine *state)
422 {
423         unsigned char req[] = { FBUS_FRAME_HEADER, 0x07, 0x02 /* Unknown */, 0x00 /* Location */, 0x01, 0x64};
424
425         req[5] = data->SMSMessage->Number;
426
427         if (SM_SendMessage(state, 8, 0x02, req) != GE_NONE) return GE_NOTREADY;
428         return SM_Block(state, data, 0x14);
429 }
430
431 static GSM_Error IncomingSMS(int messagetype, unsigned char *message, int length, GSM_Data *data)
432 {
433         int i;
434
435         switch (message[3]) {
436         /* save sms succeeded */
437         case 0x05:
438                 dprintf("Message stored at %d\n", message[5]);
439                 break;
440         /* save sms failed */
441         case 0x06:
442                 dprintf("SMS saving failed:\n");
443                 switch (message[4]) {
444                 case 0x02:
445                         dprintf("\tAll locations busy.\n");
446                         return GE_MEMORYFULL;
447                 case 0x03:
448                         dprintf("\tInvalid location!\n");
449                         return GE_INVALIDSMSLOCATION;
450                 default:
451                         dprintf("\tUnknown reason.\n");
452                         return GE_UNKNOWN;
453                 }
454         /* read sms */
455         case 0x08:
456                 for (i = 0; i < length; i ++)
457                         if (isprint(message[i]))
458                                 dprintf("[%02x%c]", message[i], message[i]);
459                         else
460                                 dprintf("[%02x ]", message[i]);
461                 dprintf("\n");
462
463                 memset(data->SMSMessage, 0, sizeof(GSM_SMSMessage));
464
465                 /* Short Message status */
466                 DecodePDUSMS(message, data->SMSMessage, length);
467
468                 break;
469         /* read sms failed */
470         case 0x09:
471                 dprintf("SMS reading failed:\n");
472                 switch (message[4]) {
473                 case 0x02:
474                         dprintf("\tInvalid location!\n");
475                         return GE_INVALIDSMSLOCATION;
476                 case 0x07:
477                         dprintf("\tEmpty SMS location.\n");
478                         return GE_EMPTYSMSLOCATION;
479                 default:
480                         dprintf("\tUnknown reason.\n");
481                         return GE_UNKNOWN;
482                 }
483         /* delete sms succeeded */
484         case 0x0b:
485                 dprintf("Message: SMS deleted successfully.\n");
486                 break;
487         /* sms status succeded */
488         case 0x37:
489                 dprintf("Message: SMS Status Received\n");
490                 dprintf("\tThe number of messages: %d\n", message[10]);
491                 dprintf("\tUnread messages: %d\n", message[11]);
492                 data->SMSStatus->Unread = message[11];
493                 data->SMSStatus->Number = message[10];
494                 break;
495         /* sms status failed */
496         case 0x38:
497                 dprintf("Message: SMS Status error, probably not authorized by PIN\n");
498                 return GE_INTERNALERROR;
499         /* unknown */
500         default:
501                 dprintf("Unknown message.\n");
502                 return GE_UNKNOWN;
503         }
504         return GE_NONE;
505 }