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 3110 series.
15 See README for more details on supported mobile phones.
18 Revision 1.1.1.1.12.1 2001/11/27 23:34:48 short
19 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
21 Revision 1.1.1.1.8.1 2001/11/27 23:06:09 short
22 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
24 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
25 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
27 Revision 1.1.1.2 2001/11/27 22:01:20 short
28 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
30 Revision 1.7 2001/11/27 12:19:01 pkot
31 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
33 Revision 1.6 2001/11/20 16:22:22 pkot
34 First attempt to read Picture Messages. They should appear when you enable DEBUG. Nokia seems to break own standards. :/ (Markus Plail)
36 Revision 1.5 2001/11/19 13:03:18 pkot
39 Revision 1.4 2001/11/17 16:42:47 pkot
42 Revision 1.3 2001/11/09 14:25:04 pkot
45 Revision 1.2 2001/11/09 13:47:58 pkot
46 Removed pthreads from 3110 support. It may break it.
48 Revision 1.1 2001/11/08 16:39:09 pkot
49 3810/3110 support for the new structure (Tamas Bondar)
58 #define __phones_nk3110_c
60 #include "gsm-common.h"
61 #include "phones/generic.h"
62 #include "phones/nk3110.h"
63 #include "links/fbus-3110.h"
64 #include "phones/nokia.h"
69 # define snprintf _snprintf
70 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
75 static GSM_IncomingFunctionType IncomingFunctions[] = {
76 { 0x0a, P3110_IncomingNothing },
77 { 0x0b, P3110_IncomingCall },
78 { 0x0c, P3110_IncomingNothing },
79 { 0x0d, P3110_IncomingCallAnswered },
80 { 0x0e, P3110_IncomingCallEstablished },
81 { 0x0f, P3110_IncomingNothing },
82 { 0x10, P3110_IncomingEndOfOutgoingCall },
83 { 0x11, P3110_IncomingEndOfIncomingCall },
84 { 0x12, P3110_IncomingEndOfOutgoingCall2 },
85 { 0x13, P3110_IncomingRestart },
86 { 0x15, P3110_IncomingInitFrame_0x15 },
87 { 0x16, P3110_IncomingInitFrame_0x16 },
88 { 0x17, P3110_IncomingInitFrame_0x17 },
89 { 0x20, P3110_IncomingNothing },
90 /*{ 0x21, P3110_IncomingDTMFSucess },*/
91 /*{ 0x22, P3110_IncomingDTMFFailure },*/
92 { 0x23, P3110_IncomingNothing },
93 { 0x24, P3110_IncomingNothing },
94 { 0x25, P3110_IncomingNothing },
95 { 0x26, P3110_IncomingNothing },
96 { 0x27, P3110_IncomingSMSUserData },
97 { 0x28, P3110_IncomingSMSSend },
98 { 0x29, P3110_IncomingSMSSendError },
100 { 0x2c, P3110_IncomingSMSHeader },
101 { 0x2d, P3110_IncomingSMSError },
102 { 0x2e, P3110_IncomingSMSDelete },
103 { 0x2f, P3110_IncomingSMSDeleteError },
105 { 0x32, P3110_IncomingSMSDelivered },
106 { 0x3f, P3110_IncomingNothing },
107 { 0x40, P3110_IncomingNoSMSInfo },
108 { 0x41, P3110_IncomingSMSInfo },
109 { 0x48, P3110_IncomingPINEntered },
110 { 0x4a, P3110_IncomingNothing },
111 { 0x4b, P3110_IncomingStatusInfo },
112 { 0x4c, P3110_IncomingNothing },
113 { 0x4d, P3110_IncomingPhoneInfo },
117 GSM_Phone phone_nokia_3110 = {
119 PGEN_IncomingDefault,
120 /* Mobile phone information */
122 "3110|3810|8110|8110i", /* Models */
123 4, /* Max RF Level */
124 0, /* Min RF Level */
125 GRF_Arbitrary, /* RF level units */
126 4, /* Max Battery Level */
127 0, /* Min Battery Level */
128 GBU_Arbitrary, /* Battery level units */
129 GDT_None, /* No date/time support */
130 GDT_None, /* No alarm support */
131 0, /* Max alarms = 0 */
132 0, 0, /* Startup logo size */
133 0, 0, /* Op logo size */
134 0, 0 /* Caller logo size */
139 static GSM_Error Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
143 return P3110_Initialise(state);
145 case GOP_GetRevision:
147 return P3110_GetPhoneInfo(data, state);
149 return P3110_Identify(data, state);
150 case GOP_GetBatteryLevel:
152 return P3110_GetStatusInfo(data, state);
153 case GOP_GetMemoryStatus:
154 return P3110_GetMemoryStatus(data, state);
155 case GOP_ReadPhonebook:
156 case GOP_WritePhonebook:
157 case GOP_GetPowersource:
159 case GOP_GetSMSStatus:
160 case GOP_GetIncomingCallNr:
161 case GOP_GetNetworkInfo:
162 return GE_NOTIMPLEMENTED;
164 return P3110_GetSMSMessage(data, state);
166 return P3110_DeleteSMSMessage(data, state);
168 return P3110_SendSMSMessage(data, state);
169 case GOP_GetSMSCenter:
170 return P3110_GetSMSInfo(data, state);
171 case GOP_GetSpeedDial:
172 case GOP_GetDateTime:
174 return GE_NOTIMPLEMENTED;
178 static bool LinkOK = false;
179 static bool SimAvailable = false;
181 /* These are related to keepalive functionality */
182 static bool RequestTerminate;
183 static bool DisableKeepAlive;
184 static int KeepAliveTimer;
186 /* Initialise is the only function allowed to 'use' state */
187 static GSM_Error P3110_Initialise(GSM_Statemachine *state)
190 u8 init_sequence[20] = {0x02, 0x01, 0x07, 0xa2, 0x88, 0x81, 0x21, 0x55, 0x63, 0xa8, 0x00, 0x00, 0x07, 0xa3, 0xb8, 0x81, 0x20, 0x15, 0x63, 0x80};
192 /* Copy in the phone info */
193 memcpy(&(state->Phone), &phone_nokia_3110, sizeof(GSM_Phone));
195 /* Only serial connection is supported */
196 if (state->Link.ConnectionType != GCT_Serial) return GE_NOTSUPPORTED;
198 /* Initialise FBUS link */
199 if (FB3110_Initialise(&(state->Link), state) != GE_NONE) {
200 dprintf("Error in link initialisation\n");
204 /* Initialise state machine */
205 SM_Initialise(state);
207 /* 0x15 messages are sent by the PC during the initialisation phase.
208 Anyway, the contents of the message are not understood so we
209 simply send the same sequence observed between the W95 PC and
210 the phone. The init sequence may still be a bit flaky and is not
212 if (SM_SendMessage(state, 20, 0x15, init_sequence) != GE_NONE) return GE_NOTREADY;
214 /* Wait for response to 0x15 sequence */
215 GSM_DataClear(&data);
216 if (SM_Block(state, &data, 0x16) != GE_NONE) return GE_NOTREADY;
218 /* Most probably link is OK now */
221 /* Start sending keepalive messages in separate thread */
222 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
223 RequestTerminate = false;
224 DisableKeepAlive = false;
229 static GSM_Error P3110_GetSMSInfo(GSM_Data *data, GSM_Statemachine *state)
231 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
232 if (SM_SendMessage(state, 0, 0x3f, NULL) != GE_NONE) return GE_NOTREADY;
233 return SM_Block(state, data, 0x41);
236 static GSM_Error P3110_GetPhoneInfo(GSM_Data *data, GSM_Statemachine *state)
238 dprintf("Getting phone info...\n");
239 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
240 if (SM_SendMessage(state, 0, 0x4c, NULL) != GE_NONE) return GE_NOTREADY;
241 return SM_Block(state, data, 0x4d);
244 static GSM_Error P3110_GetStatusInfo(GSM_Data *data, GSM_Statemachine *state)
246 dprintf("Getting phone status...\n");
247 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
248 if (SM_SendMessage(state, 0, 0x4a, NULL) != GE_NONE) return GE_NOTREADY;
249 return SM_Block(state, data, 0x4b);
252 static GSM_Error P3110_GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
254 dprintf("Getting memory status...\n");
256 /* Check if this type of memory is available */
257 switch (data->MemoryStatus->MemoryType) {
259 if (!SimAvailable) return GE_NOTREADY;
260 return P3110_GetSMSInfo(data, state);
262 if (P3110_MEMORY_SIZE_ME == 0) return GE_NOTREADY;
263 return P3110_GetSMSInfo(data, state);
271 static GSM_Error P3110_Identify(GSM_Data *data, GSM_Statemachine *state)
273 dprintf("Identifying...\n");
274 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
275 if (SM_SendMessage(state, 0, 0x4c, NULL) != GE_NONE) return GE_NOTREADY;
276 SM_Block(state, data, 0x4d);
278 /* Check that we are back at state Initialised */
279 if (SM_Loop(state, 0) != Initialised) return GE_UNKNOWN;
284 static GSM_Error P3110_GetSMSMessage(GSM_Data *data, GSM_Statemachine *state)
286 int total_length, timeout, c;
287 u8 response = 0, request[2];
288 GSM_Error error = GE_INTERNALERROR;
290 dprintf("Getting SMS message...\n");
292 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
294 switch(data->SMSMessage->MemoryType) {
296 data->SMSMessage->MemoryType = 1; /* 3 in 8110, 1 is GMT_CB */
299 data->SMSMessage->MemoryType = 2;
302 return (GE_INVALIDMEMORYTYPE);
305 /* Set memory type and location in the request */
306 request[0] = data->SMSMessage->MemoryType;
307 request[1] = data->SMSMessage->Number;
309 /* 0x25 messages requests the contents of an SMS message
310 from the phone. The first byte has only ever been
311 observed to be 0x02 - could be selecting internal versus
312 external memory. Specifying memory 0x00 may request the
313 first location? Phone replies with 0x2c and 0x27 messages
314 for valid locations, 0x2d for empty ones. */
315 if (SM_SendMessage(state, 2, 0x25, request) != GE_NONE) return GE_NOTREADY;
317 SM_WaitFor(state, data, 0x2d);
318 SM_WaitFor(state, data, 0x2c);
320 timeout = 30; /* ~3secs timeout */
325 } while ((timeout > 0) && state->NumReceived == 0);
328 if (state->NumReceived == 0) return GE_TIMEOUT;
330 /* find response in state machine */
331 for (c = 0; c < state->NumWaitingFor; c++) {
332 if (state->ResponseError[c] != GE_BUSY) {
333 response = state->WaitingFor[c];
334 error = state->ResponseError[c];
338 /* reset state machine */
341 /* process response */
344 if (error != GE_NONE) return error;
346 /* Save total length of message */
347 total_length = data->SMSMessage->Length;
349 /* Block for subsequent content frames... */
351 SM_Block(state, data, 0x27);
352 } while (data->SMSMessage->Length < total_length);
354 /* Terminate message text */
355 data->SMSMessage->MessageText[data->SMSMessage->Length] = 0;
360 return GE_INTERNALERROR;
365 static GSM_Error P3110_DeleteSMSMessage(GSM_Data *data, GSM_Statemachine *state)
368 u8 response = 0, request[2];
369 GSM_Error error = GE_INTERNALERROR;
371 dprintf("Deleting SMS message...\n");
373 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
375 switch(data->SMSMessage->MemoryType) {
377 data->SMSMessage->MemoryType = 1; /* 3 in 8110, 1 is GMT_CB */
380 data->SMSMessage->MemoryType = 2;
383 return (GE_INVALIDMEMORYTYPE);
386 /* Set memory type and location in the request */
387 request[0] = data->SMSMessage->MemoryType;
388 request[1] = data->SMSMessage->Number;
390 /* 0x26 message deletes an SMS message from the phone.
391 The first byte has only ever been observed to be 0x02
392 but is assumed to be selecting internal versus
393 external memory. Phone replies with 0x2e for valid locations,
394 0x2f for invalid ones. If a location is empty but otherwise
395 valid 0x2e is still returned. */
396 if (SM_SendMessage(state, 2, 0x26, request) != GE_NONE) return GE_NOTREADY;
398 SM_WaitFor(state, data, 0x2e);
399 SM_WaitFor(state, data, 0x2f);
401 timeout = 30; /* ~3secs timeout */
406 } while ((timeout > 0) && state->NumReceived == 0);
409 if (state->NumReceived == 0) return GE_TIMEOUT;
411 /* find response in state machine */
412 for (c = 0; c < state->NumWaitingFor; c++) {
413 if (state->ResponseError[c] != GE_BUSY) {
414 response = state->WaitingFor[c];
415 error = state->ResponseError[c];
419 /* reset state machine */
422 /* process response */
428 return GE_INTERNALERROR;
433 static GSM_Error P3110_SendSMSMessage(GSM_Data *data, GSM_Statemachine *state)
435 int timeout, c, retry_count, block_count, block_length;
436 u8 userdata[GSM_MAX_SMS_LENGTH];
437 int userdata_length, userdata_offset, userdata_remaining;
438 u8 response, request[GSM_MAX_SMS_LENGTH];
440 SMS_MessageCenter smsc;
443 /* Get default SMSC from phone if not set in SMS */
444 if (!data->SMSMessage->MessageCenter.Number[0]) {
445 data->MessageCenter = &smsc;
446 error = P3110_GetSMSInfo(data, state);
447 if (error != GE_NONE) return error;
448 data->SMSMessage->MessageCenter = smsc;
451 dprintf("Sending SMS to %s via message center %s\n", data->SMSMessage->RemoteNumber.number, data->SMSMessage->MessageCenter.Number);
455 if (data->SMSMessage->UDH[0].Type) {
456 userdata_offset = 1 + data->SMSMessage->udhlen;
457 memcpy(userdata, data->SMSMessage->MessageText, userdata_offset);
466 if (data->SMSMessage->EightBit) {
467 memcpy(userdata + userdata_offset, data->SMSMessage->MessageText, data->SMSMessage->Length);
468 userdata_length = data->SMSMessage->Length + userdata_offset;
469 max_userdata_length = GSM_MAX_SMS_8_BIT_LENGTH;
470 dcs = DCS_DATA | DCS_CLASS1;
472 userdata_length = strlen(data->SMSMessage->MessageText);
473 memcpy(userdata + userdata_offset, data->SMSMessage->MessageText, userdata_length);
474 userdata_length += userdata_offset;
475 max_userdata_length = GSM_MAX_SMS_LENGTH;
482 request[1] = PID_DEFAULT;
484 request[3] = GSMV_Max_Time;
491 request[10] = userdata_length;
492 request[11] = smsc_length;
493 memcpy(request+12, data->SMSMessage->MessageCenter.Number, smsc_length);
494 request[12+smsc_length] = dest_length;
495 memcpy(request+13+smsc_length, data->SMSMessage->Destination, dest_length);
498 error = EncodePDUSMS(data->SMSMessage, request);
499 if (error) return error;
501 /* We have a loop here as if the response from the phone is
502 0x65 0x26 the rule appears to be just to try sending the
503 message again. We do this a maximum of FB38_SMS_SEND_RETRY_COUNT
504 times before giving up. This value is empirical only! */
505 retry_count = P3110_SMS_SEND_RETRY_COUNT;
507 while (retry_count > 0) {
509 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
511 dprintf("Transferring FBUS SMS header [");
512 for (i = 0; i < data->SMSMessage->Length; i++) dprintf(" %02hhX", request[i]);
515 if (SM_SendMessage(state, data->SMSMessage->Length, 0x23, request) != GE_NONE) return GE_NOTREADY;
517 error = SM_Block(state, data, 0x23);
518 if (error != GE_NONE) return error;
520 /* Now send as many blocks of maximum 55 characters as required
521 to send complete message. */
524 userdata_remaining = userdata_length;
526 while (userdata_remaining > 0) {
527 block_length = userdata_remaining;
529 /* Limit block length */
530 if (block_length > 55) block_length = 55;
533 request[0] = block_count;
534 memcpy(request+1, userdata + userdata_offset, block_length);
537 if (SM_SendMessage(state, block_length+1, 0x27, request) != GE_NONE) return GE_NOTREADY;
538 error = SM_Block(state, data, 0x27);
539 if (error != GE_NONE) return error;
541 /* update remaining and offset values for next block */
542 userdata_remaining -= block_length;
543 userdata_offset += block_length;
547 /* Now wait for response from network which will see
548 CurrentSMSMessageError change from busy. */
549 SM_WaitFor(state, data, 0x28);
550 SM_WaitFor(state, data, 0x29);
552 timeout = 1200; /* 120secs timeout */
557 } while ((timeout > 0) && state->NumReceived == 0);
560 if (state->NumReceived == 0) return GE_TIMEOUT;
562 /* find response in state machine */
563 for (c = 0; c < state->NumWaitingFor; c++) {
564 if (state->ResponseError[c] != GE_BUSY) {
565 response = state->WaitingFor[c];
566 error = state->ResponseError[c];
570 /* reset state machine */
573 /* process response */
578 /* Got a retry response so try again! */
579 dprintf("SMS send attempt failed, trying again...\n");
581 /* After an empirically determined pause... */
582 usleep(500000); /* 0.5 seconds. */
585 return GE_INTERNALERROR;
588 /* Retries must have failed. */
589 return GE_SMSSENDFAILED;
593 static GSM_Error P3110_IncomingNothing(int messagetype, unsigned char *message, int length, GSM_Data *data)
598 /* 0x0b messages are sent by phone when an incoming call occurs,
599 this message must be acknowledged. */
600 static GSM_Error P3110_IncomingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
605 /* Get info out of message. At present, first three bytes are
606 unknown (though third seems to correspond to length of
607 number). Remaining bytes are the phone number, ASCII
609 for (count = 0; count < message[4]; count ++) {
610 buffer[count] = message[5 + count];
612 buffer[count] = 0x00;
614 /* Now display incoming call message. */
615 dprintf("Incoming call - Type: %s. %02x, Number %s.\n",
616 (message[2] == 0x05 ? "Voice":"Data?"), message[3], buffer);
621 static GSM_Error P3110_IncomingCallAnswered(int messagetype, unsigned char *message, int length, GSM_Data *data)
623 dprintf("Incoming call answered from phone.\n");
628 /* Fairly self explanatory these two, though the outgoing
629 call message has three (unexplained) data bytes. */
630 static GSM_Error P3110_IncomingCallEstablished(int messagetype, unsigned char *message, int length, GSM_Data *data)
632 dprintf("%s call established - status bytes %02x %02x.\n",
633 (message[2] == 0x05 ? "voice":"data(?)"), message[3], message[4]);
638 /* 0x10 messages are sent by the phone when an outgoing
640 static GSM_Error P3110_IncomingEndOfOutgoingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
642 dprintf("Call terminated from phone (0x10 message).\n");
643 /* FIXME: Tell datapump code that the call has terminated. */
651 /* 0x11 messages are sent by the phone when an incoming call
652 terminates. There is some other data in the message,
653 purpose as yet undertermined. */
654 static GSM_Error P3110_IncomingEndOfIncomingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
656 dprintf("Call terminated from opposite end of line (or from network).\n");
658 /* FIXME: Tell datapump code that the call has terminated. */
666 /* 0x12 messages are sent after the 0x10 message at the
667 end of an outgoing call. Significance of two messages
668 versus the one at the end of an incoming call is as
669 yet undertermined. */
670 static GSM_Error P3110_IncomingEndOfOutgoingCall2(int messagetype, unsigned char *message, int length, GSM_Data *data)
672 dprintf("Call terminated from phone (0x12 message).\n");
674 /* FIXME: Tell datapump code that the call has terminated. */
683 /* 0x13 messages are sent after the phone restarts.
686 static GSM_Error P3110_IncomingRestart(int messagetype, unsigned char *message, int length, GSM_Data *data)
688 /* FIXME: send 0x15 message somehow */
693 /* 0x15 messages are sent by the phone in response to the
694 init sequence sent so we don't acknowledge them! */
696 static GSM_Error P3110_IncomingInitFrame_0x15(int messagetype, unsigned char *message, int length, GSM_Data *data)
702 /* 0x16 messages are sent by the phone during initialisation, to response
704 Sequence bytes have been observed to change with differing software
705 versions: V06.61 (19/08/97) sends 0x10 0x02, V07.02 (17/03/98) sends
706 0x30 0x02. The actual data byte is 0x02 when SIM memory is available,
707 and 0x01 when not (e.g. when SIM card isn't inserted to phone or when
708 it is waiting for PIN) */
710 static GSM_Error P3110_IncomingInitFrame_0x16(int messagetype, unsigned char *message, int length, GSM_Data *data)
712 SimAvailable = (message[2] == 0x02);
713 dprintf("SIM available: %s.\n", (SimAvailable ? "Yes" : "No"));
718 static GSM_Error P3110_IncomingInitFrame_0x17(int messagetype, unsigned char *message, int length, GSM_Data *data)
720 dprintf("0x17 Registration Response: Failure!\n");
725 /* 0x27 messages are a little unusual when sent by the phone in that
726 they can either be an acknowledgement of an 0x27 message we sent
727 to the phone with message text in it or they could
728 contain message text for a message we requested. */
730 static GSM_Error P3110_IncomingSMSUserData(int messagetype, unsigned char *message, int length, GSM_Data *data)
734 /* First see if it was an acknowledgement to one of our messages,
735 if so then nothing to do */
736 if (length == 0x02) return GE_NONE;
738 /* Copy into current SMS message as long as it's non-NULL */
739 if (!data->SMSMessage) return GE_INTERNALERROR;
741 /* If this is the first block, reset accumulated message length. */
742 if (message[2] == 1) data->SMSMessage->Length = 0;
744 /* Copy message text */
745 for (count = 0; count < length-3 && data->SMSMessage->Length < GSM_MAX_SMS_LENGTH; count++, data->SMSMessage->Length++)
746 data->SMSMessage->MessageText[data->SMSMessage->Length] = message[count + 3];
752 /* 0x28 messages are sent by the phone to acknowledge succesfull
753 sending of an SMS message. The byte returned is a receipt
754 number of some form, not sure if it's from the network, sending
755 sending of an SMS message. The byte returned is the TP-MR
756 (TP-Message-Reference) from sending phone (Also sent to network).
757 TP-MR is send from phone within 0x32 message. TP-MR is increased
758 by phone after each sent SMS */
760 static GSM_Error P3110_IncomingSMSSend(int messagetype, unsigned char *message, int length, GSM_Data *data)
762 dprintf("SMS send OK (0x%02hhx)\n", message[2]);
763 data->SMSMessage->Number = (int) message[2];
768 /* 0x29 messages are sent by the phone to indicate an error in
769 sending an SMS message. Observed values are 0x65 0x15 when
770 the phone originated SMS was disabled by the network for
771 the particular phone. 0x65 0x26 was observed too, whereupon
772 the message was retried. */
774 static GSM_Error P3110_IncomingSMSSendError(int messagetype, unsigned char *message, int length, GSM_Data *data)
776 dprintf("SMS send failed (0x%02hhx 0x%02hhx)\n", message[2], message[3]);
777 return GE_SMSSENDFAILED;
781 /* 0x2c messages are generated by the phone when we request an SMS
782 message with an 0x25 message. Appears to have the same fields
783 as the 0x30 notification but with one extra. Immediately after
784 the 0x2c nessage, the phone sends 0x27 message(s) */
786 static GSM_Error P3110_IncomingSMSHeader(int messagetype, unsigned char *message, int length, GSM_Data *data)
788 /* u8 sender_length, smsc_length, l; */
790 if (!data->SMSMessage) return GE_INTERNALERROR;
792 /* Extract data from message into SMSMessage */
794 DecodePDUSMS(message, data->SMSMessage, length);
796 /* All these moved to gsm-sms.c
800 data->SMSMessage->MemoryType = GMT_ME;
803 data->SMSMessage->MemoryType = GMT_SM;
806 data->SMSMessage->MemoryType = GMT_XX;
810 Set location in memory
811 data->SMSMessage->Location = message[3];
812 data->SMSMessage->MessageNumber = message[3];
814 3810 series has limited support for different SMS "mailboxes"
815 to the extent that the only know differentiation is between
816 received messages 0x01, 0x04 and written messages 0x07 0x01.
817 No flag has been found (yet) that indicates whether the
818 message has been sent or not.
820 Default to unknown message type
821 data->SMSMessage->Type = GST_UN;
823 Consider received messages "Inbox" (Mobile Terminated)
824 if (message[4] == 0x01 && message[5] == 0x04)
825 data->SMSMessage->Type = GST_MT;
827 Consider written messages "Outbox" (Mobile Originated)
828 if (message[4] == 0x07 && message[5] == 0x01)
829 data->SMSMessage->Type = GST_MO;
831 We don't know about read/unread or sent/unsent status.
832 so assume has been sent or read
833 data->SMSMessage->Status = GSS_SENTREAD;
835 Based on experiences with a 3110 it seems, that
836 0x03 means a received unread message,
837 0x07 means a stored unsent message
838 if (message[4] == 0x03 || message[4] == 0x07)
839 data->SMSMessage->Status = GSS_NOTSENTREAD;
841 data->SMSMessage->Status = GSS_SENTREAD;
844 if (message[5] & FO_UDHI)
845 data->SMSMessage->UDHType = GSM_RingtoneUDH; FIXME
847 data->SMSMessage->UDHType = GSM_NoUDH;
849 Check Data Coding Scheme and set text/binary flag
850 if (message[7] == 0xf5)
851 data->SMSMessage->EightBit = true;
853 data->SMSMessage->EightBit = false;
855 Extract date and time information which is packed in to
856 nibbles of each byte in reverse order. Thus day 28 would be
858 P3110_DecodeTime(message+8, &(data->SMSMessage->Time));
861 data->SMSMessage->Length = message[15];
863 Now get sender and message center length
864 smsc_length = message[16];
865 sender_length = message[17 + smsc_length];
868 l = smsc_length < GSM_MAX_SMS_CENTER_LENGTH ? smsc_length : GSM_MAX_SMS_CENTER_LENGTH;
869 strncpy(data->SMSMessage->MessageCenter.Number, message + 17, l);
870 data->SMSMessage->MessageCenter.Number[l] = 0;
873 l = sender_length < GSM_MAX_SENDER_LENGTH ? sender_length : GSM_MAX_SENDER_LENGTH;
874 strncpy(data->SMSMessage->Sender, message + 18 + smsc_length, l);
875 data->SMSMessage->Sender[l] = 0;
878 dprintf("PID:%02x DCS:%02x Timezone:%02x Stat1:%02x Stat2:%02x\n",
879 message[6], message[7], message[14], message[4], message[5]);
881 dprintf("Message Read:\n");
882 dprintf(" Location: %d. Type: %d Status: %d\n", data->SMSMessage->Number, data->SMSMessage->Type, data->SMSMessage->Status);
883 dprintf(" Sender: %s\n", data->SMSMessage->RemoteNumber.number);
884 dprintf(" Message Center: %s\n", data->SMSMessage->MessageCenter.Number);
885 dprintf(" Time: %02d.%02d.%02d %02d:%02d:%02d\n",
886 data->SMSMessage->Time.Day, data->SMSMessage->Time.Month, data->SMSMessage->Time.Year, data->SMSMessage->Time.Hour, data->SMSMessage->Time.Minute, data->SMSMessage->Time.Second);
892 /* 0x2d messages are generated when an SMS message is requested
893 that does not exist or is empty. */
895 static GSM_Error P3110_IncomingSMSError(int messagetype, unsigned char *message, int length, GSM_Data *data)
897 if (message[2] == 0x74)
898 return GE_INVALIDSMSLOCATION;
900 return GE_EMPTYSMSLOCATION;
904 /* 0x2e messages are generated when an SMS message is deleted
907 static GSM_Error P3110_IncomingSMSDelete(int messagetype, unsigned char *message, int length, GSM_Data *data)
913 /* 0x2f messages are generated when an SMS message is deleted
914 that does not exist. Unlike responses to a getsms message
915 no error is returned when the entry is already empty */
917 static GSM_Error P3110_IncomingSMSDeleteError(int messagetype, unsigned char *message, int length, GSM_Data *data)
919 /* Note 0x74 is the only value that has been seen! */
920 if (message[2] == 0x74)
921 return GE_INVALIDSMSLOCATION;
923 return GE_EMPTYSMSLOCATION;
927 /* 0x32 messages are generated when delivery notification arrives
928 to phone from network */
930 static GSM_Error P3110_IncomingSMSDelivered(int messagetype, unsigned char *message, int length, GSM_Data *data)
932 static GSM_SMSMessage sms;
933 /* u8 dest_length, smsc_length, l;*/
936 data->SMSMessage = &sms;
938 if (!data->SMSMessage) return GE_INTERNALERROR;
944 DecodePDUSMS(message, data->SMSMessage, length);
946 /* All these are moved fo gsm-sms.c
947 P3110_DecodeTime(message+3, &(data->SMSMessage->Time));
948 P3110_DecodeTime(message+10, &(data->SMSMessage->SMSCTime));
952 data->SMSMessage->MessageNumber = (int) message[18];
954 Get sender and message center length
955 dest_length = message[19];
956 smsc_length = message[20 + dest_length];
958 Copy destination number
959 l = dest_length < GSM_MAX_DESTINATION_LENGTH ? dest_length : GSM_MAX_DESTINATION_LENGTH;
960 strncpy(data->SMSMessage->Destination, message + 20, l);
961 data->SMSMessage->Destination[l] = 0;
964 l = smsc_length < GSM_MAX_SMS_CENTER_LENGTH ? smsc_length : GSM_MAX_SMS_CENTER_LENGTH;
965 strncpy(data->SMSMessage->MessageCenter.Number, message + 21 + dest_length, l);
966 data->SMSMessage->MessageCenter.Number[l] = 0;
969 dprintf("Message [0x%02x] Delivered!\n", data->SMSMessage->Number);
970 dprintf(" Destination: %s\n", data->SMSMessage->RemoteNumber.number);
971 dprintf(" Message Center: %s\n", data->SMSMessage->MessageCenter.Number);
972 dprintf(" Unknowns: 0x%02x 0x%02x 0x%02x\n", U0, U1, U2);
973 dprintf(" Discharge Time: %02d.%02d.%02d %02d:%02d:%02d\n",
974 data->SMSMessage->Time.Day, data->SMSMessage->Time.Month, data->SMSMessage->Time.Year, data->SMSMessage->Time.Hour, data->SMSMessage->Time.Minute, data->SMSMessage->Time.Second);
975 dprintf(" SMSC Time Stamp: %02d.%02d.%02d %02d:%02d:%02d\n",
976 data->SMSMessage->SMSCTime.Day, data->SMSMessage->SMSCTime.Month, data->SMSMessage->SMSCTime.Year, data->SMSMessage->SMSCTime.Hour, data->SMSMessage->SMSCTime.Minute, data->SMSMessage->SMSCTime.Second);
982 /* 0x40 Messages are sent to response to an 0x3f request.
983 e.g. when phone is waiting for PIN */
985 static GSM_Error P3110_IncomingNoSMSInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
987 dprintf("SMS Message Center Data not reachable.\n");
992 /* Handle 0x41 message which is sent by phone in response to an
993 0x3f request. Contains data about the Message Center in use */
995 static GSM_Error P3110_IncomingSMSInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
997 u8 center_number_length;
998 u8 option_number_length;
1001 if (!data) return GE_INTERNALERROR;
1003 /* We don't know what this option number is, just handle it */
1004 option_number_length = message[12];
1006 /* Get message center length */
1007 center_number_length = message[13 + option_number_length];
1009 dprintf("SMS Message Center Data:\n");
1010 dprintf(" Selected memory: 0x%02x\n", message[2]);
1011 dprintf(" Messages in Phone: 0x%02x Unread: 0x%02x\n", message[3], message[4]);
1012 dprintf(" Messages in SIM: 0x%02x Unread: 0x%02x\n", message[5], message[6]);
1013 dprintf(" Reply via own centre: 0x%02x (%s)\n", message[10], (message[10] == 0x02 ? "Yes" : "No"));
1014 dprintf(" Delivery reports: 0x%02x (%s)\n", message[11], (message[11] == 0x02 ? "Yes" : "No"));
1015 dprintf(" Messages sent as: 0x%02x\n", message[7]);
1016 dprintf(" Message validity: 0x%02x\n", message[9]);
1017 dprintf(" Unknown: 0x%02x\n", message[8]);
1019 dprintf(" UnknownNumber: ");
1020 for (count = 0; count < option_number_length; count ++)
1021 dprintf("%c", message[13 + count]);
1024 dprintf(" Message center number: ");
1025 for (count = 0; count < center_number_length; count ++) {
1026 dprintf("%c", message[14 + option_number_length + count]);
1030 /* Get message center related info if upper layer wants to know */
1031 if (data->MessageCenter) {
1032 data->MessageCenter->Format = message[7];
1033 data->MessageCenter->Validity = message[9];
1035 if (center_number_length == 0) {
1036 data->MessageCenter->Number[0] = 0x00; /* Null terminate */
1038 memcpy(data->MessageCenter->Number,
1039 message + 14 + option_number_length,
1040 center_number_length);
1041 data->MessageCenter->Number[center_number_length] = '\0';
1044 /* 3810 series doesn't support Name or multiple center numbers
1045 so put in null data for them . */
1046 data->MessageCenter->Name[0] = 0x00;
1047 data->MessageCenter->No = 0;
1050 /* Get SMS related info if upper layer wants to know */
1051 if (data->SMSStatus) {
1052 data->SMSStatus->Unread = message[4] + message[6];
1053 data->SMSStatus->Number = message[3] + message[5];
1056 /* Get memory info if upper layer wants to know */
1057 if (data->MemoryStatus) {
1058 switch (data->MemoryStatus->MemoryType) {
1060 data->MemoryStatus->Used = message[5];
1061 data->MemoryStatus->Free = P3110_MEMORY_SIZE_SM - message[5];
1064 data->MemoryStatus->Used = message[3];
1065 data->MemoryStatus->Free = P3110_MEMORY_SIZE_ME - message[3];
1076 /* 0x48 is sent during power-on of the phone, after the 0x13
1077 message is received and the PIN (if any) has been entered
1080 static GSM_Error P3110_IncomingPINEntered(int messagetype, unsigned char *message, int length, GSM_Data *data)
1082 SimAvailable = true;
1083 dprintf("PIN [possibly] entered.\n");
1088 /* 0x4b messages are sent by phone in response (it seems) to the keep
1089 alive packet. We must acknowledge these it seems by sending a
1090 response with the "sequence number" byte loaded appropriately. */
1092 static GSM_Error P3110_IncomingStatusInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
1094 /* Strings for the status byte received from phone. */
1095 char *StatusStr[] = {
1103 /* There are three data bytes in the status message, two have been
1104 attributed to signal level, the third is presently unknown.
1105 Unknown byte has been observed to be 0x01 when connected to normal
1106 network, 0x04 when no network available. Steps through 0x02, 0x03
1107 when incoming or outgoing calls occur...*/
1108 /*FB38_LinkOK = true;*/
1110 /* Note: GetRFLevel function in fbus-3810.c does conversion
1111 into required units. */
1112 if (data->RFLevel) {
1113 *(data->RFUnits) = GRF_Arbitrary;
1114 *(data->RFLevel) = message[3];
1117 /* Note: GetBatteryLevel function in fbus-3810.c does conversion
1118 into required units. */
1119 if (data->BatteryLevel) {
1120 *(data->BatteryUnits) = GBU_Arbitrary;
1121 *(data->BatteryLevel) = message[4];
1124 /* Only output connection status byte now as the RF and Battery
1125 levels are displayed by the main gnokii code. */
1126 dprintf("Status: %s, Battery level: %d, RF level: %d.\n",
1127 StatusStr[message[2]], message[4], message[3]);
1131 /* 0x4d Message provides IMEI, Revision and Model information. */
1133 static GSM_Error P3110_IncomingPhoneInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
1135 size_t imei_length, rev_length, model_length;
1137 imei_length = strlen(message + 2);
1138 rev_length = strlen(message + 3 + imei_length);
1139 model_length = strlen(message + 4 + imei_length + rev_length);
1142 strcpy(data->Imei, message + 2);
1145 strcpy(data->Revision, message + 3 + imei_length);
1148 strcpy(data->Model, message + 4 + imei_length + rev_length);
1150 dprintf("Mobile Phone Identification:\n");
1151 dprintf(" IMEI: %s\n", message + 2);
1152 dprintf(" Model: %s\n", message + 4 + imei_length + rev_length);
1153 dprintf(" Revision: %s\n", message + 3 + imei_length);
1162 void P3110_KeepAliveLoop(GSM_Statemachine *state)
1165 GSM_DataClear(&data);
1167 while (!RequestTerminate) {
1169 if (KeepAliveTimer == 0) {
1170 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
1171 /* Dont send keepalive packets when statemachine
1172 is doing other transactions. */
1173 if (state->CurrentState == Initialised) {
1174 dprintf("Sending keepalive message.\n");
1175 P3110_GetStatusInfo(&data, state);
1180 usleep(100000); /* Avoid becoming a "busy" loop. */
1184 void P3110_DecodeTime(unsigned char *b, GSM_DateTime *dt)
1186 dt->Year = P3110_bcd2int(b[0]);
1187 dt->Month = P3110_bcd2int(b[1]);
1188 dt->Day = P3110_bcd2int(b[2]);
1189 dt->Hour = P3110_bcd2int(b[3]);
1190 dt->Minute = P3110_bcd2int(b[4]);
1191 dt->Second = P3110_bcd2int(b[5]);
1192 dt->Timezone = P3110_bcd2int(b[6]);
1196 int P3110_bcd2int(u8 x)
1198 return (int)(10 * ((x & 0x0f)) + (x >> 4));