This commit was generated by cvs2svn to compensate for changes in r158,
[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.3  2002/04/03 00:08:09  short
18   Found in "gnokii-working" directory, some November-patches version
19
20   Revision 1.3  2001/08/17 00:01:53  pkot
21   Fixed a typo in 6100.c (me)
22
23   Revision 1.2  2001/08/09 12:34:34  pkot
24   3330 and 6250 support - I have no idea if it does work (mygnokii)
25
26   Revision 1.1  2001/07/09 23:55:35  pkot
27   Initial support for 6100 series in the new structure (me)
28
29 */
30
31 #include <string.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34
35 #define __phones_nk6100_c
36 #include "misc.h"
37 #include "gsm-common.h"
38 #include "phones/generic.h"
39 #include "phones/nk6100.h"
40 #include "links/fbus.h"
41 #include "links/fbus-phonet.h"
42 #include "phones/nokia.h"
43
44 #ifdef WIN32
45 #define snprintf _snprintf
46 #endif
47
48 /* Some globals */
49
50 static unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
51
52 static GSM_IncomingFunctionType IncomingFunctions[] = {
53         { 0x64, IncomingPhoneInfo },
54         { 0xd2, IncomingModelInfo },
55         { 0x03, Incoming0x03 },
56         { 0x0a, Incoming0x0a },
57         { 0x17, Incoming0x17 },
58         { 0, NULL}
59 };
60
61 GSM_Phone phone_nokia_6100 = {
62         IncomingFunctions,
63         PGEN_IncomingDefault,
64         /* Mobile phone information */
65         {
66                 "6110|6130|6150|6190|5110|5130|5190|3210|3310|3330", /* Supported models */
67                 4,                     /* Max RF Level */
68                 0,                     /* Min RF Level */
69                 GRF_Arbitrary,         /* RF level units */
70                 4,                     /* Max Battery Level */
71                 0,                     /* Min Battery Level */
72                 GBU_Arbitrary,         /* Battery level units */
73                 GDT_DateTime,          /* Have date/time support */
74                 GDT_TimeOnly,          /* Alarm supports time only */
75                 1,                     /* Alarms available - FIXME */
76                 48, 84,                /* Startup logo size - 7110 is fixed at init*/
77                 14, 72,                /* Op logo size */
78                 14, 72                 /* Caller logo size */
79         },
80         Functions
81 };
82
83 static GSM_Error Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
84 {
85         switch (op) {
86         case GOP_Init:
87                 return Initialise(state);
88                 break;
89         case GOP_GetModel:
90                 return GetModelName(data, state);
91                 break;
92         case GOP_GetRevision:
93                 return GetRevision(data, state);
94                 break;
95         case GOP_GetImei:
96                 return GetIMEI(data, state);
97                 break;
98         case GOP_Identify:
99                 return Identify(data, state);
100                 break;
101         case GOP_GetBatteryLevel:
102                 return GetBatteryLevel(data, state);
103                 break;
104         case GOP_GetRFLevel:
105                 return GetRFLevel(data, state);
106                 break;
107         case GOP_GetMemoryStatus:
108                 return GetMemoryStatus(data, state);
109                 break;
110         default:
111                 return GE_NOTIMPLEMENTED;
112                 break;
113         }
114 }
115
116 static bool LinkOK = true;
117
118 /* Initialise is the only function allowed to 'use' state */
119 static GSM_Error Initialise(GSM_Statemachine *state)
120 {
121         GSM_Data data;
122         char model[10];
123         GSM_Error err;
124         int try = 0, connected = 0;
125
126         /* Copy in the phone info */
127         memcpy(&(state->Phone), &phone_nokia_6100, sizeof(GSM_Phone));
128
129         while (!connected) {
130                 switch (state->Link.ConnectionType) {
131                 case GCT_Serial:
132                         if (try > 1) return GE_NOTSUPPORTED;
133                         err = FBUS_Initialise(&(state->Link), state);
134                         break;
135                 case GCT_Infrared:
136                         if (try > 0) return GE_NOTSUPPORTED;
137                         err = PHONET_Initialise(&(state->Link), state);
138                         break;
139                 default:
140                         return GE_NOTSUPPORTED;
141                         break;
142                 }
143
144                 if (err != GE_NONE) {
145                         dprintf("Error in link initialisation\n");
146                         try++;
147                         continue;
148                 }
149
150                 SM_Initialise(state);
151
152                 /* Now test the link and get the model */
153                 GSM_DataClear(&data);
154                 data.Model = model;
155                 if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) try++;
156                 else connected = 1;
157         }
158         return GE_NONE;
159 }
160
161 static GSM_Error GetPhoneInfo(GSM_Data *data, GSM_Statemachine *state)
162 {
163         unsigned char req[] = { FBUS_FRAME_HEADER, 0x03, 0x00 };
164
165         dprintf("Getting phone info...\n");
166         if (SM_SendMessage(state, 5, 0xd1, req) != GE_NONE) return GE_NOTREADY;
167         return (SM_Block(state, data, 0xd2));
168 }
169
170 static GSM_Error GetModelName(GSM_Data *data, GSM_Statemachine *state)
171 {
172         dprintf("Getting model...\n");
173         return GetPhoneInfo(data, state);
174 }
175
176 static GSM_Error GetRevision(GSM_Data *data, GSM_Statemachine *state)
177 {
178         dprintf("Getting revision...\n");
179         return GetPhoneInfo(data, state);
180 }
181
182 static GSM_Error GetIMEI(GSM_Data *data, GSM_Statemachine *state)
183 {
184         unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
185   
186         dprintf("Getting imei...\n");
187         if (SM_SendMessage(state, 4, 0x1b, req)!=GE_NONE) return GE_NOTREADY;
188         return SM_Block(state, data, 0x1b);
189 }
190
191
192 static GSM_Error GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
193 {
194         unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
195
196         dprintf("Getting battery level...\n");
197         if (SM_SendMessage(state, 4, 0x17, req) != GE_NONE) return GE_NOTREADY;
198         return SM_Block(state, data, 0x17);
199 }
200
201
202 static GSM_Error Incoming0x17(int messagetype, unsigned char *message, int length, GSM_Data *data)
203 {
204         switch (message[3]) {
205         case 0x03:
206                 if (data->BatteryLevel) { 
207                         *(data->BatteryUnits) = GBU_Percentage;
208                         *(data->BatteryLevel) = message[5];
209                         dprintf("Battery level %f\n",*(data->BatteryLevel));
210                 }
211                 return GE_NONE;
212                 break;
213         default:
214                 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
215                 return GE_UNKNOWN;
216                 break;
217         }
218 }
219
220 static GSM_Error GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
221 {
222         unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
223
224         dprintf("Getting rf level...\n");
225         if (SM_SendMessage(state, 4, 0x0a, req) != GE_NONE) return GE_NOTREADY;
226         return SM_Block(state, data, 0x0a);
227 }
228
229 static GSM_Error Incoming0x0a(int messagetype, unsigned char *message, int length, GSM_Data *data)
230 {
231         switch (message[3]) {
232         case 0x82:
233                 if (data->RFLevel) { 
234                         *(data->RFUnits) = GRF_Percentage;
235                         *(data->RFLevel) = message[4];
236                         dprintf("RF level %f\n",*(data->RFLevel));
237                 }
238                 return GE_NONE;
239                 break;
240         default:
241                 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
242                 return GE_UNKNOWN;
243                 break;
244         }
245 }
246
247 static GSM_Error GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
248 {
249         unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
250       
251         dprintf("Getting memory status...\n");
252         req[5] = GetMemoryType(data->MemoryStatus->MemoryType);
253         if (SM_SendMessage(state, 6, 0x03, req) != GE_NONE) return GE_NOTREADY;
254         return SM_Block(state, data, 0x03);
255 }
256
257 static GSM_Error Incoming0x03(int messagetype, unsigned char *message, int length, GSM_Data *data)
258 {
259         switch (message[3]) {
260         case 0x04:
261                 if (data->MemoryStatus) {
262                         if (message[5] != 0xff) {
263                                 data->MemoryStatus->Used = (message[16] << 8) + message[17];
264                                 data->MemoryStatus->Free = ((message[14] << 8) + message[15]) - data->MemoryStatus->Used;
265                                 dprintf(_("Memory status - location = %d\n"), (message[8] << 8) + message[9]);
266                                 return GE_NONE;
267                         } else {
268                                 dprintf("Unknown error getting mem status\n");
269                                 return GE_NOTIMPLEMENTED;
270                                 
271                         }
272                 }
273                 return GE_NONE;
274                 break;
275         default:
276                 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
277                 return GE_UNKNOWN;
278                 break;
279         }
280 }
281
282 static GSM_Error Identify(GSM_Data *data, GSM_Statemachine *state)
283 {
284         unsigned char req[] = { FBUS_FRAME_HEADER, 0x10 };
285   
286         dprintf("Identifying...\n");
287         if (SM_SendMessage(state, 4, 0x64, req) != GE_NONE) return GE_NOTREADY;
288         SM_WaitFor(state, data, 0x64);
289         SM_Block(state, data, 0x64); /* waits for all requests */
290         SM_GetError(state, 0x64);
291         
292         /* Check that we are back at state Initialised */
293         if (SM_Loop(state, 0) != Initialised) return GE_UNKNOWN;
294         return GE_NONE;
295 }
296
297 static GSM_Error IncomingPhoneInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
298 {
299         if (data->Imei) { 
300 #if defined WIN32 || !defined HAVE_SNPRINTF
301                 sprintf(data->Imei, "%s", message + 4);
302 #else
303                 snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
304 #endif
305                 dprintf("Received imei %s\n", data->Imei);
306         }
307         if (data->Model) { 
308 #if defined WIN32 || !defined HAVE_SNPRINTF
309                 sprintf(data->Model, "%s", message + 22);
310 #else
311                 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
312 #endif
313                 dprintf("Received model %s\n", data->Model);
314         }
315         if (data->Revision) { 
316 #if defined WIN32 || !defined HAVE_SNPRINTF
317                 sprintf(data->Revision, "%s", message + 7);
318 #else
319                 snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
320 #endif
321                 dprintf("Received revision %s\n", data->Revision);
322         }
323
324         dprintf(_("Message: Mobile phone identification received:\n"));
325         dprintf(_("   IMEI: %s\n"), data->Imei);
326         dprintf(_("   Model: %s\n"), data->Model);
327         dprintf(_("   Production Code: %s\n"), message + 31);
328         dprintf(_("   HW: %s\n"), message + 39);
329         dprintf(_("   Firmware: %s\n"), message + 44);
330         
331         /* These bytes are probably the source of the "Accessory not connected"
332            messages on the phone when trying to emulate NCDS... I hope....
333            UPDATE: of course, now we have the authentication algorithm. */
334         dprintf(_("   Magic bytes: %02x %02x %02x %02x\n"), message[50], message[51], message[52], message[53]);
335         
336         MagicBytes[0] = message[50];
337         MagicBytes[1] = message[51];
338         MagicBytes[2] = message[52];
339         MagicBytes[3] = message[53];
340
341         return GE_NONE;
342 }
343
344 static GSM_Error IncomingModelInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
345 {
346 #if defined WIN32 || !defined HAVE_SNPRINTF
347         if (data->Model) sprintf(data->Model, "%s", message + 21);
348         if (data->Revision) sprintf(data->Revision, "SW%s", message + 5);
349 #else
350         dprintf("%p %p %p\n", data, data->Model, data->Revision);
351         if (data->Model) {
352                 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 21);
353                 data->Model[GSM_MAX_MODEL_LENGTH - 1] = 0;
354         }
355         if (data->Revision) {
356                 snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "SW%s", message + 5);
357                 data->Revision[GSM_MAX_REVISION_LENGTH - 1] = 0;
358         }
359 #endif
360         dprintf(_("Phone info:\n%s\n"), message + 4);
361
362         return GE_NONE;
363 }
364
365 static int GetMemoryType(GSM_MemoryType memory_type)
366 {
367         int result;
368
369         switch (memory_type) {
370         case GMT_MT:
371                 result = P6100_MEMORY_MT;
372                 break;
373         case GMT_ME:
374                 result = P6100_MEMORY_ME;
375                 break;
376         case GMT_SM:
377                 result = P6100_MEMORY_SM;
378                 break;
379         case GMT_FD:
380                 result = P6100_MEMORY_FD;
381                 break;
382         case GMT_ON:
383                 result = P6100_MEMORY_ON;
384                 break;
385         case GMT_EN:
386                 result = P6100_MEMORY_EN;
387                 break;
388         case GMT_DC:
389                 result = P6100_MEMORY_DC;
390                 break;
391         case GMT_RC:
392                 result = P6100_MEMORY_RC;
393                 break;
394         case GMT_MC:
395                 result = P6100_MEMORY_MC;
396                 break;
397         default:
398                 result = P6100_MEMORY_XX;
399                 break;
400         }
401         return (result);
402 }