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