7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 2000 Hugh Blemings & Pavel Janík ml.
10 Copyright (C) 2001 Pawe³ Kot <pkot@linuxnews.pl>
12 Released under the terms of the GNU GPL, see file COPYING for more details.
14 This file provides functions specific to the 6100 series.
15 See README for more details on supported mobile phones.
23 #define __phones_nk6100_c
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"
33 #define snprintf _snprintf
38 static const SMSMessage_Layout nk6100_deliver = {
40 0, 11, 0, 0, 6, 0, 0, -1, 23, 22, 0, 20,
41 8, true, 24, true, 36, -1,
46 static const SMSMessage_Layout nk6100_submit = {
48 -1, 20, 20, 20, 6, 21, 22, -1, 24, 23, 20, 20,
49 8, true, 25, true, 37, -1,
54 static const SMSMessage_Layout nk6100_delivery_report = {
56 0, 0, 0, 0, 6, 0, 0, 0, 22, 21, -1, 20,
57 8, true, 24, true, 35, 42,
62 static const SMSMessage_Layout nk6100_picture = {
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, true, 0, true, 0, 0,
70 static SMSMessage_PhoneLayout nk6100_layout;
72 static unsigned char MagicBytes[4] = { 0x00, 0x00, 0x00, 0x00 };
74 static GSM_IncomingFunctionType IncomingFunctions[] = {
75 { 0x64, IncomingPhoneInfo },
76 { 0xd2, IncomingModelInfo },
77 { 0x14, IncomingSMS },
78 { 0x03, Incoming0x03 },
79 { 0x0a, Incoming0x0a },
80 { 0x17, Incoming0x17 },
84 GSM_Phone phone_nokia_6100 = {
87 /* Mobile phone information */
89 "6110|6130|6150|6190|5110|5130|5190|3210|3310|3330", /* Supported models */
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 */
106 static GSM_Error Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
110 return Initialise(state);
112 return GetModelName(data, state);
113 case GOP_GetRevision:
114 return GetRevision(data, state);
116 return GetIMEI(data, state);
118 return Identify(data, state);
119 case GOP_GetBatteryLevel:
120 return GetBatteryLevel(data, state);
122 return GetRFLevel(data, state);
123 case GOP_GetMemoryStatus:
124 return GetMemoryStatus(data, state);
126 return GetSMSMessage(data, state);
128 return GE_NOTIMPLEMENTED;
132 /* static bool LinkOK = true; */
134 /* Initialise is the only function allowed to 'use' state */
135 static GSM_Error Initialise(GSM_Statemachine *state)
141 /* Copy in the phone info */
142 memcpy(&(state->Phone), &phone_nokia_6100, sizeof(GSM_Phone));
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;
152 switch (state->Link.ConnectionType) {
154 err = FBUS_Initialise(&(state->Link), state, 0);
157 err = PHONET_Initialise(&(state->Link), state);
160 return GE_NOTSUPPORTED;
163 if (err != GE_NONE) {
164 dprintf("Error in link initialisation\n");
165 return GE_NOTSUPPORTED;
168 SM_Initialise(state);
170 /* Now test the link and get the model */
171 GSM_DataClear(&data);
173 if (state->Phone.Functions(GOP_GetModel, &data, state) != GE_NONE) return GE_NOTSUPPORTED;
177 static GSM_Error GetPhoneInfo(GSM_Data *data, GSM_Statemachine *state)
179 unsigned char req[] = { FBUS_FRAME_HEADER, 0x03, 0x00 };
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));
186 static GSM_Error GetModelName(GSM_Data *data, GSM_Statemachine *state)
188 dprintf("Getting model...\n");
189 return GetPhoneInfo(data, state);
192 static GSM_Error GetRevision(GSM_Data *data, GSM_Statemachine *state)
194 dprintf("Getting revision...\n");
195 return GetPhoneInfo(data, state);
198 static GSM_Error GetIMEI(GSM_Data *data, GSM_Statemachine *state)
200 unsigned char req[] = {FBUS_FRAME_HEADER, 0x01};
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);
208 static GSM_Error GetBatteryLevel(GSM_Data *data, GSM_Statemachine *state)
210 unsigned char req[] = {FBUS_FRAME_HEADER, 0x02};
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);
218 static GSM_Error Incoming0x17(int messagetype, unsigned char *message, int length, GSM_Data *data)
220 switch (message[3]) {
222 if (data->BatteryLevel) {
223 *(data->BatteryUnits) = GBU_Percentage;
224 *(data->BatteryLevel) = message[5];
225 dprintf("Battery level %f\n",*(data->BatteryLevel));
230 dprintf("Unknown subtype of type 0x17 (%d)\n", message[3]);
236 static GSM_Error GetRFLevel(GSM_Data *data, GSM_Statemachine *state)
238 unsigned char req[] = {FBUS_FRAME_HEADER, 0x81};
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);
245 static GSM_Error Incoming0x0a(int messagetype, unsigned char *message, int length, GSM_Data *data)
247 switch (message[3]) {
250 *(data->RFUnits) = GRF_Percentage;
251 *(data->RFLevel) = message[4];
252 dprintf("RF level %f\n",*(data->RFLevel));
257 dprintf("Unknown subtype of type 0x0a (%d)\n", message[3]);
263 static GSM_Error GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
265 unsigned char req[] = {FBUS_FRAME_HEADER, 0x03, 0x00, 0x00};
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);
273 static GSM_Error Incoming0x03(int messagetype, unsigned char *message, int length, GSM_Data *data)
275 switch (message[3]) {
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]);
284 dprintf("Unknown error getting mem status\n");
285 return GE_NOTIMPLEMENTED;
292 dprintf("Unknown subtype of type 0x03 (%d)\n", message[3]);
298 static GSM_Error Identify(GSM_Data *data, GSM_Statemachine *state)
300 unsigned char req[] = { FBUS_FRAME_HEADER, 0x10 };
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);
309 /* Check that we are back at state Initialised */
310 if (SM_Loop(state, 0) != Initialised) return GE_UNKNOWN;
314 static GSM_Error IncomingPhoneInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
317 #if defined WIN32 || !defined HAVE_SNPRINTF
318 sprintf(data->Imei, "%s", message + 4);
320 snprintf(data->Imei, GSM_MAX_IMEI_LENGTH, "%s", message + 4);
322 dprintf("Received imei %s\n", data->Imei);
325 #if defined WIN32 || !defined HAVE_SNPRINTF
326 sprintf(data->Model, "%s", message + 22);
328 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 22);
330 dprintf("Received model %s\n", data->Model);
332 if (data->Revision) {
333 #if defined WIN32 || !defined HAVE_SNPRINTF
334 sprintf(data->Revision, "%s", message + 7);
336 snprintf(data->Revision, GSM_MAX_REVISION_LENGTH, "%s", message + 7);
338 dprintf("Received revision %s\n", data->Revision);
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);
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]);
353 MagicBytes[0] = message[50];
354 MagicBytes[1] = message[51];
355 MagicBytes[2] = message[52];
356 MagicBytes[3] = message[53];
361 static GSM_Error IncomingModelInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
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);
367 dprintf("%p %p %p\n", data, data->Model, data->Revision);
369 snprintf(data->Model, GSM_MAX_MODEL_LENGTH, "%s", message + 21);
370 data->Model[GSM_MAX_MODEL_LENGTH - 1] = 0;
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;
377 dprintf("Phone info:\n%s\n", message + 4);
382 static int GetMemoryType(GSM_MemoryType memory_type)
386 switch (memory_type) {
388 result = P6100_MEMORY_MT;
391 result = P6100_MEMORY_ME;
394 result = P6100_MEMORY_SM;
397 result = P6100_MEMORY_FD;
400 result = P6100_MEMORY_ON;
403 result = P6100_MEMORY_EN;
406 result = P6100_MEMORY_DC;
409 result = P6100_MEMORY_RC;
412 result = P6100_MEMORY_MC;
415 result = P6100_MEMORY_XX;
421 static GSM_Error GetSMSMessage(GSM_Data *data, GSM_Statemachine *state)
423 unsigned char req[] = { FBUS_FRAME_HEADER, 0x07, 0x02 /* Unknown */, 0x00 /* Location */, 0x01, 0x64};
425 req[5] = data->SMSMessage->Number;
427 if (SM_SendMessage(state, 8, 0x02, req) != GE_NONE) return GE_NOTREADY;
428 return SM_Block(state, data, 0x14);
431 static GSM_Error IncomingSMS(int messagetype, unsigned char *message, int length, GSM_Data *data)
435 switch (message[3]) {
436 /* save sms succeeded */
438 dprintf("Message stored at %d\n", message[5]);
440 /* save sms failed */
442 dprintf("SMS saving failed:\n");
443 switch (message[4]) {
445 dprintf("\tAll locations busy.\n");
446 return GE_MEMORYFULL;
448 dprintf("\tInvalid location!\n");
449 return GE_INVALIDSMSLOCATION;
451 dprintf("\tUnknown reason.\n");
456 for (i = 0; i < length; i ++)
457 if (isprint(message[i]))
458 dprintf("[%02x%c]", message[i], message[i]);
460 dprintf("[%02x ]", message[i]);
463 memset(data->SMSMessage, 0, sizeof(GSM_SMSMessage));
465 /* Short Message status */
466 DecodePDUSMS(message, data->SMSMessage, length);
469 /* read sms failed */
471 dprintf("SMS reading failed:\n");
472 switch (message[4]) {
474 dprintf("\tInvalid location!\n");
475 return GE_INVALIDSMSLOCATION;
477 dprintf("\tEmpty SMS location.\n");
478 return GE_EMPTYSMSLOCATION;
480 dprintf("\tUnknown reason.\n");
483 /* delete sms succeeded */
485 dprintf("Message: SMS deleted successfully.\n");
487 /* sms status succeded */
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];
495 /* sms status failed */
497 dprintf("Message: SMS Status error, probably not authorized by PIN\n");
498 return GE_INTERNALERROR;
501 dprintf("Unknown message.\n");