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.8.1 2001/11/27 23:06:09 short
19 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
21 Revision 1.1.1.1.2.1 2001/11/27 22:48:37 short
22 Update: orig2001_11_27_05_17 -> orig2001_11_27_22_58
24 Revision 1.1.1.2 2001/11/27 22:01:20 short
25 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Tue Nov 27 22:58 CET 2001
27 Revision 1.7 2001/11/27 12:19:01 pkot
28 Cleanup, indentation, ANSI complaint preprocesor symbols (Jan Kratochvil, me)
30 Revision 1.6 2001/11/20 16:22:22 pkot
31 First attempt to read Picture Messages. They should appear when you enable DEBUG. Nokia seems to break own standards. :/ (Markus Plail)
33 Revision 1.5 2001/11/19 13:03:18 pkot
36 Revision 1.4 2001/11/17 16:42:47 pkot
39 Revision 1.3 2001/11/09 14:25:04 pkot
42 Revision 1.2 2001/11/09 13:47:58 pkot
43 Removed pthreads from 3110 support. It may break it.
45 Revision 1.1 2001/11/08 16:39:09 pkot
46 3810/3110 support for the new structure (Tamas Bondar)
55 #define __phones_nk3110_c
57 #include "gsm-common.h"
58 #include "phones/generic.h"
59 #include "phones/nk3110.h"
60 #include "links/fbus-3110.h"
61 #include "phones/nokia.h"
66 # define snprintf _snprintf
67 # define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
72 static GSM_IncomingFunctionType IncomingFunctions[] = {
73 { 0x0a, P3110_IncomingNothing },
74 { 0x0b, P3110_IncomingCall },
75 { 0x0c, P3110_IncomingNothing },
76 { 0x0d, P3110_IncomingCallAnswered },
77 { 0x0e, P3110_IncomingCallEstablished },
78 { 0x0f, P3110_IncomingNothing },
79 { 0x10, P3110_IncomingEndOfOutgoingCall },
80 { 0x11, P3110_IncomingEndOfIncomingCall },
81 { 0x12, P3110_IncomingEndOfOutgoingCall2 },
82 { 0x13, P3110_IncomingRestart },
83 { 0x15, P3110_IncomingInitFrame_0x15 },
84 { 0x16, P3110_IncomingInitFrame_0x16 },
85 { 0x17, P3110_IncomingInitFrame_0x17 },
86 { 0x20, P3110_IncomingNothing },
87 /*{ 0x21, P3110_IncomingDTMFSucess },*/
88 /*{ 0x22, P3110_IncomingDTMFFailure },*/
89 { 0x23, P3110_IncomingNothing },
90 { 0x24, P3110_IncomingNothing },
91 { 0x25, P3110_IncomingNothing },
92 { 0x26, P3110_IncomingNothing },
93 { 0x27, P3110_IncomingSMSUserData },
94 { 0x28, P3110_IncomingSMSSend },
95 { 0x29, P3110_IncomingSMSSendError },
97 { 0x2c, P3110_IncomingSMSHeader },
98 { 0x2d, P3110_IncomingSMSError },
99 { 0x2e, P3110_IncomingSMSDelete },
100 { 0x2f, P3110_IncomingSMSDeleteError },
102 { 0x32, P3110_IncomingSMSDelivered },
103 { 0x3f, P3110_IncomingNothing },
104 { 0x40, P3110_IncomingNoSMSInfo },
105 { 0x41, P3110_IncomingSMSInfo },
106 { 0x48, P3110_IncomingPINEntered },
107 { 0x4a, P3110_IncomingNothing },
108 { 0x4b, P3110_IncomingStatusInfo },
109 { 0x4c, P3110_IncomingNothing },
110 { 0x4d, P3110_IncomingPhoneInfo },
114 GSM_Phone phone_nokia_3110 = {
116 PGEN_IncomingDefault,
117 /* Mobile phone information */
119 "3110|3810|8110|8110i", /* Models */
120 4, /* Max RF Level */
121 0, /* Min RF Level */
122 GRF_Arbitrary, /* RF level units */
123 4, /* Max Battery Level */
124 0, /* Min Battery Level */
125 GBU_Arbitrary, /* Battery level units */
126 GDT_None, /* No date/time support */
127 GDT_None, /* No alarm support */
128 0, /* Max alarms = 0 */
129 0, 0, /* Startup logo size */
130 0, 0, /* Op logo size */
131 0, 0 /* Caller logo size */
136 static GSM_Error Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
140 return P3110_Initialise(state);
142 case GOP_GetRevision:
144 return P3110_GetPhoneInfo(data, state);
146 return P3110_Identify(data, state);
147 case GOP_GetBatteryLevel:
149 return P3110_GetStatusInfo(data, state);
150 case GOP_GetMemoryStatus:
151 return P3110_GetMemoryStatus(data, state);
152 case GOP_ReadPhonebook:
153 case GOP_WritePhonebook:
154 case GOP_GetPowersource:
156 case GOP_GetSMSStatus:
157 case GOP_GetIncomingCallNr:
158 case GOP_GetNetworkInfo:
159 return GE_NOTIMPLEMENTED;
161 return P3110_GetSMSMessage(data, state);
163 return P3110_DeleteSMSMessage(data, state);
165 return P3110_SendSMSMessage(data, state);
166 case GOP_GetSMSCenter:
167 return P3110_GetSMSInfo(data, state);
168 case GOP_GetSpeedDial:
169 case GOP_GetDateTime:
171 return GE_NOTIMPLEMENTED;
175 static bool LinkOK = false;
176 static bool SimAvailable = false;
178 /* These are related to keepalive functionality */
179 static bool RequestTerminate;
180 static bool DisableKeepAlive;
181 static int KeepAliveTimer;
183 /* Initialise is the only function allowed to 'use' state */
184 static GSM_Error P3110_Initialise(GSM_Statemachine *state)
187 u8 init_sequence[20] = {0x02, 0x01, 0x07, 0xa2, 0x88, 0x81, 0x21, 0x55, 0x63, 0xa8, 0x00, 0x00, 0x07, 0xa3, 0xb8, 0x81, 0x20, 0x15, 0x63, 0x80};
189 /* Copy in the phone info */
190 memcpy(&(state->Phone), &phone_nokia_3110, sizeof(GSM_Phone));
192 /* Only serial connection is supported */
193 if (state->Link.ConnectionType != GCT_Serial) return GE_NOTSUPPORTED;
195 /* Initialise FBUS link */
196 if (FB3110_Initialise(&(state->Link), state) != GE_NONE) {
197 dprintf("Error in link initialisation\n");
201 /* Initialise state machine */
202 SM_Initialise(state);
204 /* 0x15 messages are sent by the PC during the initialisation phase.
205 Anyway, the contents of the message are not understood so we
206 simply send the same sequence observed between the W95 PC and
207 the phone. The init sequence may still be a bit flaky and is not
209 if (SM_SendMessage(state, 20, 0x15, init_sequence) != GE_NONE) return GE_NOTREADY;
211 /* Wait for response to 0x15 sequence */
212 GSM_DataClear(&data);
213 if (SM_Block(state, &data, 0x16) != GE_NONE) return GE_NOTREADY;
215 /* Most probably link is OK now */
218 /* Start sending keepalive messages in separate thread */
219 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
220 RequestTerminate = false;
221 DisableKeepAlive = false;
226 static GSM_Error P3110_GetSMSInfo(GSM_Data *data, GSM_Statemachine *state)
228 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
229 if (SM_SendMessage(state, 0, 0x3f, NULL) != GE_NONE) return GE_NOTREADY;
230 return SM_Block(state, data, 0x41);
233 static GSM_Error P3110_GetPhoneInfo(GSM_Data *data, GSM_Statemachine *state)
235 dprintf("Getting phone info...\n");
236 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
237 if (SM_SendMessage(state, 0, 0x4c, NULL) != GE_NONE) return GE_NOTREADY;
238 return SM_Block(state, data, 0x4d);
241 static GSM_Error P3110_GetStatusInfo(GSM_Data *data, GSM_Statemachine *state)
243 dprintf("Getting phone status...\n");
244 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
245 if (SM_SendMessage(state, 0, 0x4a, NULL) != GE_NONE) return GE_NOTREADY;
246 return SM_Block(state, data, 0x4b);
249 static GSM_Error P3110_GetMemoryStatus(GSM_Data *data, GSM_Statemachine *state)
251 dprintf("Getting memory status...\n");
253 /* Check if this type of memory is available */
254 switch (data->MemoryStatus->MemoryType) {
256 if (!SimAvailable) return GE_NOTREADY;
257 return P3110_GetSMSInfo(data, state);
259 if (P3110_MEMORY_SIZE_ME == 0) return GE_NOTREADY;
260 return P3110_GetSMSInfo(data, state);
268 static GSM_Error P3110_Identify(GSM_Data *data, GSM_Statemachine *state)
270 dprintf("Identifying...\n");
271 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
272 if (SM_SendMessage(state, 0, 0x4c, NULL) != GE_NONE) return GE_NOTREADY;
273 SM_Block(state, data, 0x4d);
275 /* Check that we are back at state Initialised */
276 if (SM_Loop(state, 0) != Initialised) return GE_UNKNOWN;
281 static GSM_Error P3110_GetSMSMessage(GSM_Data *data, GSM_Statemachine *state)
283 int total_length, timeout, c;
284 u8 response = 0, request[2];
285 GSM_Error error = GE_INTERNALERROR;
287 dprintf("Getting SMS message...\n");
289 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
291 switch(data->SMSMessage->MemoryType) {
293 data->SMSMessage->MemoryType = 1; /* 3 in 8110, 1 is GMT_CB */
296 data->SMSMessage->MemoryType = 2;
299 return (GE_INVALIDMEMORYTYPE);
302 /* Set memory type and location in the request */
303 request[0] = data->SMSMessage->MemoryType;
304 request[1] = data->SMSMessage->Number;
306 /* 0x25 messages requests the contents of an SMS message
307 from the phone. The first byte has only ever been
308 observed to be 0x02 - could be selecting internal versus
309 external memory. Specifying memory 0x00 may request the
310 first location? Phone replies with 0x2c and 0x27 messages
311 for valid locations, 0x2d for empty ones. */
312 if (SM_SendMessage(state, 2, 0x25, request) != GE_NONE) return GE_NOTREADY;
314 SM_WaitFor(state, data, 0x2d);
315 SM_WaitFor(state, data, 0x2c);
317 timeout = 30; /* ~3secs timeout */
322 } while ((timeout > 0) && state->NumReceived == 0);
325 if (state->NumReceived == 0) return GE_TIMEOUT;
327 /* find response in state machine */
328 for (c = 0; c < state->NumWaitingFor; c++) {
329 if (state->ResponseError[c] != GE_BUSY) {
330 response = state->WaitingFor[c];
331 error = state->ResponseError[c];
335 /* reset state machine */
338 /* process response */
341 if (error != GE_NONE) return error;
343 /* Save total length of message */
344 total_length = data->SMSMessage->Length;
346 /* Block for subsequent content frames... */
348 SM_Block(state, data, 0x27);
349 } while (data->SMSMessage->Length < total_length);
351 /* Terminate message text */
352 data->SMSMessage->MessageText[data->SMSMessage->Length] = 0;
357 return GE_INTERNALERROR;
362 static GSM_Error P3110_DeleteSMSMessage(GSM_Data *data, GSM_Statemachine *state)
365 u8 response = 0, request[2];
366 GSM_Error error = GE_INTERNALERROR;
368 dprintf("Deleting SMS message...\n");
370 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
372 switch(data->SMSMessage->MemoryType) {
374 data->SMSMessage->MemoryType = 1; /* 3 in 8110, 1 is GMT_CB */
377 data->SMSMessage->MemoryType = 2;
380 return (GE_INVALIDMEMORYTYPE);
383 /* Set memory type and location in the request */
384 request[0] = data->SMSMessage->MemoryType;
385 request[1] = data->SMSMessage->Number;
387 /* 0x26 message deletes an SMS message from the phone.
388 The first byte has only ever been observed to be 0x02
389 but is assumed to be selecting internal versus
390 external memory. Phone replies with 0x2e for valid locations,
391 0x2f for invalid ones. If a location is empty but otherwise
392 valid 0x2e is still returned. */
393 if (SM_SendMessage(state, 2, 0x26, request) != GE_NONE) return GE_NOTREADY;
395 SM_WaitFor(state, data, 0x2e);
396 SM_WaitFor(state, data, 0x2f);
398 timeout = 30; /* ~3secs timeout */
403 } while ((timeout > 0) && state->NumReceived == 0);
406 if (state->NumReceived == 0) return GE_TIMEOUT;
408 /* find response in state machine */
409 for (c = 0; c < state->NumWaitingFor; c++) {
410 if (state->ResponseError[c] != GE_BUSY) {
411 response = state->WaitingFor[c];
412 error = state->ResponseError[c];
416 /* reset state machine */
419 /* process response */
425 return GE_INTERNALERROR;
430 static GSM_Error P3110_SendSMSMessage(GSM_Data *data, GSM_Statemachine *state)
432 int timeout, c, retry_count, block_count, block_length;
433 u8 userdata[GSM_MAX_SMS_LENGTH];
434 int userdata_length, userdata_offset, userdata_remaining;
435 u8 response, request[GSM_MAX_SMS_LENGTH];
437 SMS_MessageCenter smsc;
440 /* Get default SMSC from phone if not set in SMS */
441 if (!data->SMSMessage->MessageCenter.Number[0]) {
442 data->MessageCenter = &smsc;
443 error = P3110_GetSMSInfo(data, state);
444 if (error != GE_NONE) return error;
445 data->SMSMessage->MessageCenter = smsc;
448 dprintf("Sending SMS to %s via message center %s\n", data->SMSMessage->RemoteNumber.number, data->SMSMessage->MessageCenter.Number);
452 if (data->SMSMessage->UDH[0].Type) {
453 userdata_offset = 1 + data->SMSMessage->udhlen;
454 memcpy(userdata, data->SMSMessage->MessageText, userdata_offset);
463 if (data->SMSMessage->EightBit) {
464 memcpy(userdata + userdata_offset, data->SMSMessage->MessageText, data->SMSMessage->Length);
465 userdata_length = data->SMSMessage->Length + userdata_offset;
466 max_userdata_length = GSM_MAX_SMS_8_BIT_LENGTH;
467 dcs = DCS_DATA | DCS_CLASS1;
469 userdata_length = strlen(data->SMSMessage->MessageText);
470 memcpy(userdata + userdata_offset, data->SMSMessage->MessageText, userdata_length);
471 userdata_length += userdata_offset;
472 max_userdata_length = GSM_MAX_SMS_LENGTH;
479 request[1] = PID_DEFAULT;
481 request[3] = GSMV_Max_Time;
488 request[10] = userdata_length;
489 request[11] = smsc_length;
490 memcpy(request+12, data->SMSMessage->MessageCenter.Number, smsc_length);
491 request[12+smsc_length] = dest_length;
492 memcpy(request+13+smsc_length, data->SMSMessage->Destination, dest_length);
495 error = EncodePDUSMS(data->SMSMessage, request);
496 if (error) return error;
498 /* We have a loop here as if the response from the phone is
499 0x65 0x26 the rule appears to be just to try sending the
500 message again. We do this a maximum of FB38_SMS_SEND_RETRY_COUNT
501 times before giving up. This value is empirical only! */
502 retry_count = P3110_SMS_SEND_RETRY_COUNT;
504 while (retry_count > 0) {
506 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
508 dprintf("Transferring FBUS SMS header [");
509 for (i = 0; i < data->SMSMessage->Length; i++) dprintf(" %02hhX", request[i]);
512 if (SM_SendMessage(state, data->SMSMessage->Length, 0x23, request) != GE_NONE) return GE_NOTREADY;
514 error = SM_Block(state, data, 0x23);
515 if (error != GE_NONE) return error;
517 /* Now send as many blocks of maximum 55 characters as required
518 to send complete message. */
521 userdata_remaining = userdata_length;
523 while (userdata_remaining > 0) {
524 block_length = userdata_remaining;
526 /* Limit block length */
527 if (block_length > 55) block_length = 55;
530 request[0] = block_count;
531 memcpy(request+1, userdata + userdata_offset, block_length);
534 if (SM_SendMessage(state, block_length+1, 0x27, request) != GE_NONE) return GE_NOTREADY;
535 error = SM_Block(state, data, 0x27);
536 if (error != GE_NONE) return error;
538 /* update remaining and offset values for next block */
539 userdata_remaining -= block_length;
540 userdata_offset += block_length;
544 /* Now wait for response from network which will see
545 CurrentSMSMessageError change from busy. */
546 SM_WaitFor(state, data, 0x28);
547 SM_WaitFor(state, data, 0x29);
549 timeout = 1200; /* 120secs timeout */
554 } while ((timeout > 0) && state->NumReceived == 0);
557 if (state->NumReceived == 0) return GE_TIMEOUT;
559 /* find response in state machine */
560 for (c = 0; c < state->NumWaitingFor; c++) {
561 if (state->ResponseError[c] != GE_BUSY) {
562 response = state->WaitingFor[c];
563 error = state->ResponseError[c];
567 /* reset state machine */
570 /* process response */
575 /* Got a retry response so try again! */
576 dprintf("SMS send attempt failed, trying again...\n");
578 /* After an empirically determined pause... */
579 usleep(500000); /* 0.5 seconds. */
582 return GE_INTERNALERROR;
585 /* Retries must have failed. */
586 return GE_SMSSENDFAILED;
590 static GSM_Error P3110_IncomingNothing(int messagetype, unsigned char *message, int length, GSM_Data *data)
595 /* 0x0b messages are sent by phone when an incoming call occurs,
596 this message must be acknowledged. */
597 static GSM_Error P3110_IncomingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
602 /* Get info out of message. At present, first three bytes are
603 unknown (though third seems to correspond to length of
604 number). Remaining bytes are the phone number, ASCII
606 for (count = 0; count < message[4]; count ++) {
607 buffer[count] = message[5 + count];
609 buffer[count] = 0x00;
611 /* Now display incoming call message. */
612 dprintf("Incoming call - Type: %s. %02x, Number %s.\n",
613 (message[2] == 0x05 ? "Voice":"Data?"), message[3], buffer);
618 static GSM_Error P3110_IncomingCallAnswered(int messagetype, unsigned char *message, int length, GSM_Data *data)
620 dprintf("Incoming call answered from phone.\n");
625 /* Fairly self explanatory these two, though the outgoing
626 call message has three (unexplained) data bytes. */
627 static GSM_Error P3110_IncomingCallEstablished(int messagetype, unsigned char *message, int length, GSM_Data *data)
629 dprintf("%s call established - status bytes %02x %02x.\n",
630 (message[2] == 0x05 ? "voice":"data(?)"), message[3], message[4]);
635 /* 0x10 messages are sent by the phone when an outgoing
637 static GSM_Error P3110_IncomingEndOfOutgoingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
639 dprintf("Call terminated from phone (0x10 message).\n");
640 /* FIXME: Tell datapump code that the call has terminated. */
648 /* 0x11 messages are sent by the phone when an incoming call
649 terminates. There is some other data in the message,
650 purpose as yet undertermined. */
651 static GSM_Error P3110_IncomingEndOfIncomingCall(int messagetype, unsigned char *message, int length, GSM_Data *data)
653 dprintf("Call terminated from opposite end of line (or from network).\n");
655 /* FIXME: Tell datapump code that the call has terminated. */
663 /* 0x12 messages are sent after the 0x10 message at the
664 end of an outgoing call. Significance of two messages
665 versus the one at the end of an incoming call is as
666 yet undertermined. */
667 static GSM_Error P3110_IncomingEndOfOutgoingCall2(int messagetype, unsigned char *message, int length, GSM_Data *data)
669 dprintf("Call terminated from phone (0x12 message).\n");
671 /* FIXME: Tell datapump code that the call has terminated. */
680 /* 0x13 messages are sent after the phone restarts.
683 static GSM_Error P3110_IncomingRestart(int messagetype, unsigned char *message, int length, GSM_Data *data)
685 /* FIXME: send 0x15 message somehow */
690 /* 0x15 messages are sent by the phone in response to the
691 init sequence sent so we don't acknowledge them! */
693 static GSM_Error P3110_IncomingInitFrame_0x15(int messagetype, unsigned char *message, int length, GSM_Data *data)
699 /* 0x16 messages are sent by the phone during initialisation, to response
701 Sequence bytes have been observed to change with differing software
702 versions: V06.61 (19/08/97) sends 0x10 0x02, V07.02 (17/03/98) sends
703 0x30 0x02. The actual data byte is 0x02 when SIM memory is available,
704 and 0x01 when not (e.g. when SIM card isn't inserted to phone or when
705 it is waiting for PIN) */
707 static GSM_Error P3110_IncomingInitFrame_0x16(int messagetype, unsigned char *message, int length, GSM_Data *data)
709 SimAvailable = (message[2] == 0x02);
710 dprintf("SIM available: %s.\n", (SimAvailable ? "Yes" : "No"));
715 static GSM_Error P3110_IncomingInitFrame_0x17(int messagetype, unsigned char *message, int length, GSM_Data *data)
717 dprintf("0x17 Registration Response: Failure!\n");
722 /* 0x27 messages are a little unusual when sent by the phone in that
723 they can either be an acknowledgement of an 0x27 message we sent
724 to the phone with message text in it or they could
725 contain message text for a message we requested. */
727 static GSM_Error P3110_IncomingSMSUserData(int messagetype, unsigned char *message, int length, GSM_Data *data)
731 /* First see if it was an acknowledgement to one of our messages,
732 if so then nothing to do */
733 if (length == 0x02) return GE_NONE;
735 /* Copy into current SMS message as long as it's non-NULL */
736 if (!data->SMSMessage) return GE_INTERNALERROR;
738 /* If this is the first block, reset accumulated message length. */
739 if (message[2] == 1) data->SMSMessage->Length = 0;
741 /* Copy message text */
742 for (count = 0; count < length-3 && data->SMSMessage->Length < GSM_MAX_SMS_LENGTH; count++, data->SMSMessage->Length++)
743 data->SMSMessage->MessageText[data->SMSMessage->Length] = message[count + 3];
749 /* 0x28 messages are sent by the phone to acknowledge succesfull
750 sending of an SMS message. The byte returned is a receipt
751 number of some form, not sure if it's from the network, sending
752 sending of an SMS message. The byte returned is the TP-MR
753 (TP-Message-Reference) from sending phone (Also sent to network).
754 TP-MR is send from phone within 0x32 message. TP-MR is increased
755 by phone after each sent SMS */
757 static GSM_Error P3110_IncomingSMSSend(int messagetype, unsigned char *message, int length, GSM_Data *data)
759 dprintf("SMS send OK (0x%02hhx)\n", message[2]);
760 data->SMSMessage->Number = (int) message[2];
765 /* 0x29 messages are sent by the phone to indicate an error in
766 sending an SMS message. Observed values are 0x65 0x15 when
767 the phone originated SMS was disabled by the network for
768 the particular phone. 0x65 0x26 was observed too, whereupon
769 the message was retried. */
771 static GSM_Error P3110_IncomingSMSSendError(int messagetype, unsigned char *message, int length, GSM_Data *data)
773 dprintf("SMS send failed (0x%02hhx 0x%02hhx)\n", message[2], message[3]);
774 return GE_SMSSENDFAILED;
778 /* 0x2c messages are generated by the phone when we request an SMS
779 message with an 0x25 message. Appears to have the same fields
780 as the 0x30 notification but with one extra. Immediately after
781 the 0x2c nessage, the phone sends 0x27 message(s) */
783 static GSM_Error P3110_IncomingSMSHeader(int messagetype, unsigned char *message, int length, GSM_Data *data)
785 /* u8 sender_length, smsc_length, l; */
787 if (!data->SMSMessage) return GE_INTERNALERROR;
789 /* Extract data from message into SMSMessage */
791 DecodePDUSMS(message, data->SMSMessage, length);
793 /* All these moved to gsm-sms.c
797 data->SMSMessage->MemoryType = GMT_ME;
800 data->SMSMessage->MemoryType = GMT_SM;
803 data->SMSMessage->MemoryType = GMT_XX;
807 Set location in memory
808 data->SMSMessage->Location = message[3];
809 data->SMSMessage->MessageNumber = message[3];
811 3810 series has limited support for different SMS "mailboxes"
812 to the extent that the only know differentiation is between
813 received messages 0x01, 0x04 and written messages 0x07 0x01.
814 No flag has been found (yet) that indicates whether the
815 message has been sent or not.
817 Default to unknown message type
818 data->SMSMessage->Type = GST_UN;
820 Consider received messages "Inbox" (Mobile Terminated)
821 if (message[4] == 0x01 && message[5] == 0x04)
822 data->SMSMessage->Type = GST_MT;
824 Consider written messages "Outbox" (Mobile Originated)
825 if (message[4] == 0x07 && message[5] == 0x01)
826 data->SMSMessage->Type = GST_MO;
828 We don't know about read/unread or sent/unsent status.
829 so assume has been sent or read
830 data->SMSMessage->Status = GSS_SENTREAD;
832 Based on experiences with a 3110 it seems, that
833 0x03 means a received unread message,
834 0x07 means a stored unsent message
835 if (message[4] == 0x03 || message[4] == 0x07)
836 data->SMSMessage->Status = GSS_NOTSENTREAD;
838 data->SMSMessage->Status = GSS_SENTREAD;
841 if (message[5] & FO_UDHI)
842 data->SMSMessage->UDHType = GSM_RingtoneUDH; FIXME
844 data->SMSMessage->UDHType = GSM_NoUDH;
846 Check Data Coding Scheme and set text/binary flag
847 if (message[7] == 0xf5)
848 data->SMSMessage->EightBit = true;
850 data->SMSMessage->EightBit = false;
852 Extract date and time information which is packed in to
853 nibbles of each byte in reverse order. Thus day 28 would be
855 P3110_DecodeTime(message+8, &(data->SMSMessage->Time));
858 data->SMSMessage->Length = message[15];
860 Now get sender and message center length
861 smsc_length = message[16];
862 sender_length = message[17 + smsc_length];
865 l = smsc_length < GSM_MAX_SMS_CENTER_LENGTH ? smsc_length : GSM_MAX_SMS_CENTER_LENGTH;
866 strncpy(data->SMSMessage->MessageCenter.Number, message + 17, l);
867 data->SMSMessage->MessageCenter.Number[l] = 0;
870 l = sender_length < GSM_MAX_SENDER_LENGTH ? sender_length : GSM_MAX_SENDER_LENGTH;
871 strncpy(data->SMSMessage->Sender, message + 18 + smsc_length, l);
872 data->SMSMessage->Sender[l] = 0;
875 dprintf("PID:%02x DCS:%02x Timezone:%02x Stat1:%02x Stat2:%02x\n",
876 message[6], message[7], message[14], message[4], message[5]);
878 dprintf("Message Read:\n");
879 dprintf(" Location: %d. Type: %d Status: %d\n", data->SMSMessage->Number, data->SMSMessage->Type, data->SMSMessage->Status);
880 dprintf(" Sender: %s\n", data->SMSMessage->RemoteNumber.number);
881 dprintf(" Message Center: %s\n", data->SMSMessage->MessageCenter.Number);
882 dprintf(" Time: %02d.%02d.%02d %02d:%02d:%02d\n",
883 data->SMSMessage->Time.Day, data->SMSMessage->Time.Month, data->SMSMessage->Time.Year, data->SMSMessage->Time.Hour, data->SMSMessage->Time.Minute, data->SMSMessage->Time.Second);
889 /* 0x2d messages are generated when an SMS message is requested
890 that does not exist or is empty. */
892 static GSM_Error P3110_IncomingSMSError(int messagetype, unsigned char *message, int length, GSM_Data *data)
894 if (message[2] == 0x74)
895 return GE_INVALIDSMSLOCATION;
897 return GE_EMPTYSMSLOCATION;
901 /* 0x2e messages are generated when an SMS message is deleted
904 static GSM_Error P3110_IncomingSMSDelete(int messagetype, unsigned char *message, int length, GSM_Data *data)
910 /* 0x2f messages are generated when an SMS message is deleted
911 that does not exist. Unlike responses to a getsms message
912 no error is returned when the entry is already empty */
914 static GSM_Error P3110_IncomingSMSDeleteError(int messagetype, unsigned char *message, int length, GSM_Data *data)
916 /* Note 0x74 is the only value that has been seen! */
917 if (message[2] == 0x74)
918 return GE_INVALIDSMSLOCATION;
920 return GE_EMPTYSMSLOCATION;
924 /* 0x32 messages are generated when delivery notification arrives
925 to phone from network */
927 static GSM_Error P3110_IncomingSMSDelivered(int messagetype, unsigned char *message, int length, GSM_Data *data)
929 static GSM_SMSMessage sms;
930 /* u8 dest_length, smsc_length, l;*/
933 data->SMSMessage = &sms;
935 if (!data->SMSMessage) return GE_INTERNALERROR;
941 DecodePDUSMS(message, data->SMSMessage, length);
943 /* All these are moved fo gsm-sms.c
944 P3110_DecodeTime(message+3, &(data->SMSMessage->Time));
945 P3110_DecodeTime(message+10, &(data->SMSMessage->SMSCTime));
949 data->SMSMessage->MessageNumber = (int) message[18];
951 Get sender and message center length
952 dest_length = message[19];
953 smsc_length = message[20 + dest_length];
955 Copy destination number
956 l = dest_length < GSM_MAX_DESTINATION_LENGTH ? dest_length : GSM_MAX_DESTINATION_LENGTH;
957 strncpy(data->SMSMessage->Destination, message + 20, l);
958 data->SMSMessage->Destination[l] = 0;
961 l = smsc_length < GSM_MAX_SMS_CENTER_LENGTH ? smsc_length : GSM_MAX_SMS_CENTER_LENGTH;
962 strncpy(data->SMSMessage->MessageCenter.Number, message + 21 + dest_length, l);
963 data->SMSMessage->MessageCenter.Number[l] = 0;
966 dprintf("Message [0x%02x] Delivered!\n", data->SMSMessage->Number);
967 dprintf(" Destination: %s\n", data->SMSMessage->RemoteNumber.number);
968 dprintf(" Message Center: %s\n", data->SMSMessage->MessageCenter.Number);
969 dprintf(" Unknowns: 0x%02x 0x%02x 0x%02x\n", U0, U1, U2);
970 dprintf(" Discharge Time: %02d.%02d.%02d %02d:%02d:%02d\n",
971 data->SMSMessage->Time.Day, data->SMSMessage->Time.Month, data->SMSMessage->Time.Year, data->SMSMessage->Time.Hour, data->SMSMessage->Time.Minute, data->SMSMessage->Time.Second);
972 dprintf(" SMSC Time Stamp: %02d.%02d.%02d %02d:%02d:%02d\n",
973 data->SMSMessage->SMSCTime.Day, data->SMSMessage->SMSCTime.Month, data->SMSMessage->SMSCTime.Year, data->SMSMessage->SMSCTime.Hour, data->SMSMessage->SMSCTime.Minute, data->SMSMessage->SMSCTime.Second);
979 /* 0x40 Messages are sent to response to an 0x3f request.
980 e.g. when phone is waiting for PIN */
982 static GSM_Error P3110_IncomingNoSMSInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
984 dprintf("SMS Message Center Data not reachable.\n");
989 /* Handle 0x41 message which is sent by phone in response to an
990 0x3f request. Contains data about the Message Center in use */
992 static GSM_Error P3110_IncomingSMSInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
994 u8 center_number_length;
995 u8 option_number_length;
998 if (!data) return GE_INTERNALERROR;
1000 /* We don't know what this option number is, just handle it */
1001 option_number_length = message[12];
1003 /* Get message center length */
1004 center_number_length = message[13 + option_number_length];
1006 dprintf("SMS Message Center Data:\n");
1007 dprintf(" Selected memory: 0x%02x\n", message[2]);
1008 dprintf(" Messages in Phone: 0x%02x Unread: 0x%02x\n", message[3], message[4]);
1009 dprintf(" Messages in SIM: 0x%02x Unread: 0x%02x\n", message[5], message[6]);
1010 dprintf(" Reply via own centre: 0x%02x (%s)\n", message[10], (message[10] == 0x02 ? "Yes" : "No"));
1011 dprintf(" Delivery reports: 0x%02x (%s)\n", message[11], (message[11] == 0x02 ? "Yes" : "No"));
1012 dprintf(" Messages sent as: 0x%02x\n", message[7]);
1013 dprintf(" Message validity: 0x%02x\n", message[9]);
1014 dprintf(" Unknown: 0x%02x\n", message[8]);
1016 dprintf(" UnknownNumber: ");
1017 for (count = 0; count < option_number_length; count ++)
1018 dprintf("%c", message[13 + count]);
1021 dprintf(" Message center number: ");
1022 for (count = 0; count < center_number_length; count ++) {
1023 dprintf("%c", message[14 + option_number_length + count]);
1027 /* Get message center related info if upper layer wants to know */
1028 if (data->MessageCenter) {
1029 data->MessageCenter->Format = message[7];
1030 data->MessageCenter->Validity = message[9];
1032 if (center_number_length == 0) {
1033 data->MessageCenter->Number[0] = 0x00; /* Null terminate */
1035 memcpy(data->MessageCenter->Number,
1036 message + 14 + option_number_length,
1037 center_number_length);
1038 data->MessageCenter->Number[center_number_length] = '\0';
1041 /* 3810 series doesn't support Name or multiple center numbers
1042 so put in null data for them . */
1043 data->MessageCenter->Name[0] = 0x00;
1044 data->MessageCenter->No = 0;
1047 /* Get SMS related info if upper layer wants to know */
1048 if (data->SMSStatus) {
1049 data->SMSStatus->Unread = message[4] + message[6];
1050 data->SMSStatus->Number = message[3] + message[5];
1053 /* Get memory info if upper layer wants to know */
1054 if (data->MemoryStatus) {
1055 switch (data->MemoryStatus->MemoryType) {
1057 data->MemoryStatus->Used = message[5];
1058 data->MemoryStatus->Free = P3110_MEMORY_SIZE_SM - message[5];
1061 data->MemoryStatus->Used = message[3];
1062 data->MemoryStatus->Free = P3110_MEMORY_SIZE_ME - message[3];
1073 /* 0x48 is sent during power-on of the phone, after the 0x13
1074 message is received and the PIN (if any) has been entered
1077 static GSM_Error P3110_IncomingPINEntered(int messagetype, unsigned char *message, int length, GSM_Data *data)
1079 SimAvailable = true;
1080 dprintf("PIN [possibly] entered.\n");
1085 /* 0x4b messages are sent by phone in response (it seems) to the keep
1086 alive packet. We must acknowledge these it seems by sending a
1087 response with the "sequence number" byte loaded appropriately. */
1089 static GSM_Error P3110_IncomingStatusInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
1091 /* Strings for the status byte received from phone. */
1092 char *StatusStr[] = {
1100 /* There are three data bytes in the status message, two have been
1101 attributed to signal level, the third is presently unknown.
1102 Unknown byte has been observed to be 0x01 when connected to normal
1103 network, 0x04 when no network available. Steps through 0x02, 0x03
1104 when incoming or outgoing calls occur...*/
1105 /*FB38_LinkOK = true;*/
1107 /* Note: GetRFLevel function in fbus-3810.c does conversion
1108 into required units. */
1109 if (data->RFLevel) {
1110 *(data->RFUnits) = GRF_Arbitrary;
1111 *(data->RFLevel) = message[3];
1114 /* Note: GetBatteryLevel function in fbus-3810.c does conversion
1115 into required units. */
1116 if (data->BatteryLevel) {
1117 *(data->BatteryUnits) = GBU_Arbitrary;
1118 *(data->BatteryLevel) = message[4];
1121 /* Only output connection status byte now as the RF and Battery
1122 levels are displayed by the main gnokii code. */
1123 dprintf("Status: %s, Battery level: %d, RF level: %d.\n",
1124 StatusStr[message[2]], message[4], message[3]);
1128 /* 0x4d Message provides IMEI, Revision and Model information. */
1130 static GSM_Error P3110_IncomingPhoneInfo(int messagetype, unsigned char *message, int length, GSM_Data *data)
1132 size_t imei_length, rev_length, model_length;
1134 imei_length = strlen(message + 2);
1135 rev_length = strlen(message + 3 + imei_length);
1136 model_length = strlen(message + 4 + imei_length + rev_length);
1139 strcpy(data->Imei, message + 2);
1142 strcpy(data->Revision, message + 3 + imei_length);
1145 strcpy(data->Model, message + 4 + imei_length + rev_length);
1147 dprintf("Mobile Phone Identification:\n");
1148 dprintf(" IMEI: %s\n", message + 2);
1149 dprintf(" Model: %s\n", message + 4 + imei_length + rev_length);
1150 dprintf(" Revision: %s\n", message + 3 + imei_length);
1159 void P3110_KeepAliveLoop(GSM_Statemachine *state)
1162 GSM_DataClear(&data);
1164 while (!RequestTerminate) {
1166 if (KeepAliveTimer == 0) {
1167 KeepAliveTimer = P3110_KEEPALIVE_TIMEOUT;
1168 /* Dont send keepalive packets when statemachine
1169 is doing other transactions. */
1170 if (state->CurrentState == Initialised) {
1171 dprintf("Sending keepalive message.\n");
1172 P3110_GetStatusInfo(&data, state);
1177 usleep(100000); /* Avoid becoming a "busy" loop. */
1181 void P3110_DecodeTime(unsigned char *b, GSM_DateTime *dt)
1183 dt->Year = P3110_bcd2int(b[0]);
1184 dt->Month = P3110_bcd2int(b[1]);
1185 dt->Day = P3110_bcd2int(b[2]);
1186 dt->Hour = P3110_bcd2int(b[3]);
1187 dt->Minute = P3110_bcd2int(b[4]);
1188 dt->Second = P3110_bcd2int(b[5]);
1189 dt->Timezone = P3110_bcd2int(b[6]);
1193 int P3110_bcd2int(u8 x)
1195 return (int)(10 * ((x & 0x0f)) + (x >> 4));