7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 2000, 2001 Pavel Machek <pavel@ucw.cz>
11 Released under the terms of the GNU GPL, see file COPYING for more details.
13 Notice that this code was (partly) converted to "new" structure, but it
14 does not have code for bus separated. I think that separating it would
15 be waste of effort... --pavel
28 #include <sys/types.h>
30 #include <sys/ioctl.h>
37 #include "gsm-common.h"
38 #include "mbus-2110.h"
39 #include "phones/nokia.h"
48 #include "gsm-common.h"
49 #include "phones/generic.h"
50 #include "phones/nk2110.h"
53 #define ddprintf(x...)
54 #define eprintf(x...) fprintf(stderr, x)
57 static GSM_Error P2110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state);
59 /* Global variables used by code in gsm-api.c to expose the
60 functions supported by this model of phone. */
62 static char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
63 static char *Revision = NULL,
70 "2110|2140|6080", /* Models */ \
71 100, /* Max RF Level */ \
72 0, /* Min RF Level */ \
73 GRF_Percentage, /* RF level units */ \
74 100, /* Max Battery Level */ \
75 0, /* Min Battery Level */ \
76 GBU_Percentage, /* Battery level units */ \
77 GDT_None, /* No date/time support */ \
78 GDT_None, /* No alarm support */ \
79 0, /* Max alarms = 0 */ \
80 0, 0, /* Startup logo size */ \
81 0, 0, /* Op logo size */ \
82 0, 0 /* Caller logo size */ \
85 GSM_Information N2110_Information = INFO;
87 GSM_Phone phone_nokia_2110 = {
95 static volatile bool RequestTerminate;
96 static u8 TXPacketNumber = 0x01;
97 #define MAX_MODEL_LENGTH 16
98 static volatile unsigned char PacketData[10240];
103 static volatile int SMSpos = 0;
104 static volatile unsigned char SMSData[10240];
106 static long long LastChar = 0;
113 gettimeofday(&tv, NULL);
114 return (long long) tv.tv_sec * 1000000 + tv.tv_usec;
116 static void SigHandler(int status);
117 #define POLLIT do { SigHandler(0); } while (0)
126 Wait(long long from, int msec)
128 while (GetTime() < from + ((long long) msec)*1000) {
135 Wait2(long long from, int msec)
137 while (GetTime() < from + ((long long) msec)*1000) {
142 #define msleep(x) do { usleep(x*1000); } while (0)
143 #define msleep_poll(x) do { Wait(GetTime(), x); } while (0)
145 #define waitfor(condition, maxtime) \
147 long long limit = GetTime() + maxtime*1000; \
148 if (!maxtime) limit = 0x7fffffffffffffffULL; \
149 while ((!(condition)) && (limit > GetTime())) { \
153 if (!(limit > GetTime())) eprintf("???? TIMEOUT!"); \
156 /* Checksum calculation */
158 GetChecksum( u8 * packet, int len )
163 for( i = 0; i < len; i++ ) checksum ^= packet[i]; /* calculate checksum */
167 /* --------------- */
169 static int xread(unsigned char *d, int len)
173 res = device_read(d, len);
175 if (errno != EAGAIN) {
176 dprintf("I/O error : %m?!\n");
178 } else device_select(NULL);
182 dprintf("(%d)", len);
188 static int xwrite(unsigned char *d, int len)
192 res = device_write(d, len);
194 if (errno != EAGAIN) {
195 dprintf("I/O error : %m?!\n");
201 dprintf("<%d>", len);
207 /* --------------------------- */
210 SendFrame( u8 *buffer, u8 command, u8 length )
212 u8 pkt[10240], pkt2[10240];
215 pkt[current++] = 0x00; /* Construct the header. */
216 pkt[current++] = MYID;
217 pkt[current++] = length; /* Set data size */
218 pkt[current++] = command;
219 memcpy( pkt + current, buffer, length ); /* Copy in data. */
221 pkt[current++] = TXPacketNumber; /* Set packet number */
222 pkt[current++] = GetChecksum( pkt, current); /* Calculate and set checksum */
227 fprintf( stderr, _("PC : ") );
228 for( i = 0; i < current; i++ ) {
230 fprintf( stderr, "[%02X %c]", b, b > 0x20 ? b : '.' );
232 fprintf( stderr, "\n" );
238 /* I should put my messages at least 2msec apart... */
240 dprintf("writing...");
241 LastChar = GetTime();
242 if (xwrite(pkt, current) == -1)
243 return (GE_INTERNALERROR);
244 if (xread(pkt2, current) == -1)
245 return (GE_INTERNALERROR);
247 if (memcmp(pkt, pkt2, current)) {
248 eprintf("Bad echo?!");
256 SendCommand( u8 *buffer, u8 command, u8 length )
258 int time, retries = 10;
262 while ((time = device_read(pkt, 10240)) != -1) {
265 dprintf("Spurious? (%d)", time);
266 dprintf( _("Phone: ") );
267 for( j = 0; j < time; j++ ) {
269 dprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
278 SendFrame(buffer, command, length);
280 while ((GetTime() - now) < time*1000) {
286 time = 50; /* 5 seems to be enough */
289 eprintf("Command not okay after 10 retries!\n");
293 /* Applications should call Terminate to close the serial port. */
297 /* Request termination of thread */
298 RequestTerminate = true;
303 SMS(GSM_SMSMessage *message, int command)
305 u8 pkt[] = { 0x10, 0x02, 0, 0 };
308 memset((void *) &SMSData[0], 0, 255);
311 pkt[2] = 1; /* == LM_SMS_MEM_TYPE_DEFAULT or LM_SMS_MEM_TYPE_SIM or LM_SMS_MEM_TYPE_ME */
312 pkt[3] = message->Number;
314 SendCommand(pkt, LM_SMS_COMMAND, sizeof(pkt));
315 msleep_poll(300); /* We have to keep acknowledning phone's data */
316 waitfor(PacketOK, 1000);
318 eprintf("SMS: No reply came within second!\n");
320 if (PacketData[3] != LM_SMS_EVENT) {
321 eprintf("Something is very wrong with SMS\n");
322 return GE_BUSY; /* FIXME */
324 if ((SMSData[2]) && (SMSData[2] != message->Number)) {
325 eprintf("Wanted message @%d, got message at @%d!\n", message->Number, SMSData[2]);
333 DecodeIncomingSMS(GSM_SMSMessage *m)
339 /* Should be moved to gsm-sms.c */
341 ddprintf("Status: " );
342 switch (SMSData[3]) {
343 case 7: m->Type = SMS_Submit; /* m->Status = GSS_NOTSENTREAD; */ ddprintf("not sent\n"); break;
344 case 5: m->Type = SMS_Submit; /* m->Status = GSS_SENTREAD; */ ddprintf("sent\n"); break;
345 case 3: m->Type = SMS_Deliver; /* m->Status = GSS_NOTSENTREAD; */ ddprintf("not read\n"); break;
346 case 1: m->Type = SMS_Deliver; /* m->Status = GSS_SENTREAD; */ ddprintf("read\n"); break;
349 UnpackDateTime(SMSData+7, &m->Time);
351 m->Length = len = SMSData[14];
352 ddprintf("%d bytes: ", len );
353 for (i = 0; i<len; i++)
354 ddprintf("%c", SMSData[15+i]);
358 eprintf("Magic not allowed\n");
359 memset(m->MessageText, 0, 161);
360 strncpy(m->MessageText, (void *) &SMSData[15], len);
362 ddprintf("Text is %s\n", m->MessageText);
365 Originator address is at 15+i,
366 followed by message center addres (?)
369 char *s = (char *) &SMSData[15+i]; /* We discard volatile. Make compiler quiet. */
370 strcpy(m->RemoteNumber.number, s);
372 strcpy(m->MessageCenter.Number, s);
373 ddprintf("Sender = %s, MessageCenter = %s\n", m->Sender, m->MessageCenter.Name);
376 m->MessageCenter.No = 0;
377 strcpy(m->MessageCenter.Name, "(unknown)");
384 GetSMSMessage(GSM_SMSMessage *m)
387 return GE_INVALIDSMSLOCATION;
389 if (SMS(m, LM_SMS_READ_STORED_DATA) != GE_NONE)
390 return GE_BUSY; /* FIXME */
391 ddprintf("Have message?\n");
393 if (DecodeIncomingSMS(m) != GE_NONE)
396 if (SMSData[0] != LM_SMS_FORWARD_STORED_DATA) {
397 ddprintf("No sms there? (%x/%d)\n", SMSData[0], SMSpos);
398 return GE_EMPTYSMSLOCATION;
400 msleep_poll(1000); /* If phone lost our ack, it might retransmit data */
406 SendSMSMessage(GSM_SMSMessage *m)
409 return GE_INVALIDSMSLOCATION;
411 if (SMSData[0] != 0x0b) {
412 ddprintf("No sms there? (%x/%d)\n", SMSData[0], SMSpos);
413 return GE_EMPTYSMSLOCATION;
415 ddprintf("Status: " );
416 switch (SMSData[3]) {
417 case 7: m->Type = GST_MO; m->Status = GSS_NOTSENTREAD; ddprintf("not sent\n"); break;
418 case 5: m->Type = GST_MO; m->Status = GSS_SENTREAD; ddprintf("sent\n"); break;
419 case 3: m->Type = GST_MT; m->Status = GSS_NOTSENTREAD; ddprintf("not read\n"); break;
420 case 1: m->Type = GST_MT; m->Status = GSS_SENTREAD; ddprintf("read\n"); break;
426 static GSM_Error DeleteSMSMessage(GSM_SMSMessage *message)
428 ddprintf("deleting...");
429 return SMS(message, 3);
435 GetValue(u8 index, u8 type)
437 u8 pkt[] = {0x84, 2, 0}; /* Sending 4 at pkt[0] makes phone crash */
444 ddprintf("\nRequesting value(%d)", index);
445 SendCommand(pkt, 0xe5, 3);
447 waitfor(PacketOK, 0);
448 if ((PacketData[3] != 0xe6) ||
449 (PacketData[4] != index) ||
450 (PacketData[5] != type))
451 dprintf("Something is very wrong with GetValue\n");
453 ddprintf( "Value = %d\n", val );
458 GetRFLevel(GSM_RFUnits *units, float *level)
460 int val = GetValue(0x84, 2);
462 if (*units == GRF_Arbitrary) {
463 res = (100* (float) val) / 60.0; /* This should be / 99.0 for some models other than nokia-2110 */
474 *level = (100* (float) val) / 60.0; /* This should be / 99.0 for some models other than nokia-2110 */
475 *units = GRF_Percentage;
481 GetBatteryLevel(GSM_BatteryUnits *units, float *level)
483 int val = GetValue(0x85, 2);
491 if (*units == GBU_Arbitrary) {
493 /* *level = (100 * (float) val) / 90.0;*/ /* 5..first bar, 10..second bar, 90..third bar */
494 *level = *level * 33;
495 *units = GBU_Percentage;
501 static GSM_Error GetVersionInfo(void)
503 char *s = VersionInfo;
504 ddprintf("Getting version info...\n");
505 if (GetValue(0x11, 0x03) == -1)
508 strncpy( s, (void *) &PacketData[6], sizeof(VersionInfo) );
510 for( Revision = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
512 for( RevisionDate = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
514 for( Model = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
516 ddprintf("Revision %s, Date %s, Model %s\n", Revision, RevisionDate, Model );
520 /* Our "Not implemented" functions */
522 GetMemoryStatus(GSM_MemoryStatus *Status)
524 switch(Status->MemoryType) {
542 return (GE_NOTIMPLEMENTED);
548 SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
554 Display(u8 b, int shift, char *s, char *buf)
560 case 1: case 2: *buf++ = '!';
561 case 3: strcpy(buf, s); buf += strlen(s); *buf++ = ' ';
566 static GSM_Error (*OutputFn)(char *text, char *ctrl);
571 eprintf("[%x]", PacketData[3]);
572 switch(PacketData[3]) {
573 case 0x12: { /* Text from display */
574 char buf[10240], *s = buf, *t;
575 t = (char *)&PacketData[8];
576 #define COPY(x) strncpy(s, t, x); t+=x; s+=x; *s++ = '\n'
577 COPY(10); COPY(10); COPY(10); COPY(3); COPY(12); *s++ = 0;
579 (*OutputFn)(buf, NULL);
582 case 0x2f: { /* Display lights */
583 char buf[10240], *s = buf;
585 #define COPY(x, y, z) s = Display(PacketData[x], y, z, s)
587 COPY(4, 0, "d"); COPY(4, 2, "b"); COPY(4, 4, "a"); COPY(4, 6, "lights");
588 COPY(5, 0, "service"); COPY(5, 2, "scroll_up"); COPY(5, 4, "scroll_down"); COPY(5, 6, "ABC");
589 COPY(6, 0, "2.>"); COPY(6, 2, "1.>"); COPY(6, 4, "roam"); COPY(6, 6, "handset");
590 COPY(7, 0, "vmail"); COPY(7, 2, "envelope"); COPY(7, 4, "battbar"); COPY(7, 6, "3.>");
591 COPY(8, 0, "?1"); COPY(8, 2, "?2"); COPY(8, 4, "fieldbar"); COPY(8, 6, "ring");
594 (*OutputFn)(NULL, buf);
598 case LM_SMS_EVENT: /* SMS Data */
599 /* copy bytes 5+ to smsbuf */
600 ddprintf("SMSdata:");
603 for (i=5; i<PacketData[2]+4; i++) {
604 SMSData[SMSpos++] = PacketData[i];
605 ddprintf("%c", PacketData[i]);
609 return ((PacketData[4] & 0xf) != 0);
610 /* Make all but last fragment "secret" */
612 default: dprintf("Unknown response %dx\n", PacketData[3]);
617 /* Handler called when characters received from serial port.
618 * and process them. */
620 SigHandler(int status)
622 unsigned char buffer[256], ack[5], b;
624 static unsigned int Index = 0, Length = 5;
625 static unsigned char pkt[256];
628 res = device_read(buffer, 256);
629 if( res < 0 ) return;
630 for(i = 0; i < res ; i++) {
632 // dprintf("(%x)", b, Index);
633 if (!Index && b != MYID && b != 0xf8 && b != 0x00) /* MYID is code of computer */ {
634 /* something strange goes from phone. Just ignore it */
635 ddprintf("Get [%02X %c]\n", b, b >= 0x20 ? b : '.' );
641 if (b == 0x7f) Length = 5;
642 if (b == 0x7e) Length = 8;
644 if(Index >= Length) {
645 if((pkt[0] == MYID || pkt[0]==0xf8) && pkt[1] == 0x00) /* packet from phone */ {
647 for( j = 0; j < Length; j++ ) {
649 ddprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
652 /* ensure that we received valid packet */
653 if(pkt[Length - 1] != GetChecksum(pkt, Length-1)) {
654 eprintf( "***bad checksum***");
656 if((pkt[2] == 0x7F) || (pkt[2] == 0x7E)) /* acknowledge by phone */ {
657 if (pkt[2] == 0x7F) {
661 /* Increase TX packet number */
663 dprintf( "[registration ack]" );
668 /* Copy packet data */
670 memcpy((void *) PacketData,pkt,Length);
671 /* send acknowledge packet to phone */
673 ack[0] = 0x00; /* Construct the header. */
674 ack[1] = pkt[0]; /* Send back id */
675 ack[2] = 0x7F; /* Set special size value */
676 ack[3] = pkt[Length - 2]; /* Send back packet number */
677 ack[4] = GetChecksum( ack, 4); /* Set checksum */
678 ddprintf( _("PC : ") );
679 for( j = 0; j < 5; j++ ) {
681 ddprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
684 LastChar = GetTime();
685 if( xwrite( ack, 5 ) == -1 )
686 perror( _("Write error!\n") );
687 if( xread( ack, 5 ) == -1 )
688 perror( _("Read ack error!\n") );
690 /* Set validity flag */
696 eprintf("Got my own echo? That should not be possible!\n");
697 /* Look for new packet */
705 /* Called by initialisation code to open comm port in asynchronous mode. */
706 bool OpenSerial(void)
710 ddprintf(_("Setting MBUS communication with 2110...\n"));
712 result = device_open(PortDevice, true, false, false, GCT_Serial);
714 fprintf(stderr, "Failed to open %s ...\n", PortDevice);
718 ddprintf("%s opened...\n", PortDevice);
720 device_changespeed(9600);
721 device_setdtrrts(1, 1);
726 SetKey(int c, int up)
728 u8 reg[] = { 0x7a /* RPC_UI_KEY_PRESS or RPC_UI_KEY_RELEASE */, 0, 1, 0 /* key code */ };
731 dprintf("\n Pressing %d\n", c );
733 SendCommand( reg, 0xe5, 4 );
734 waitfor(PacketOK, 0);
738 #define XCTRL(a) (a&0x1f)
739 #define POWER XCTRL('o')
740 #define SEND XCTRL('t')
741 #define END XCTRL('s')
742 #define CLR XCTRL('h')
743 #define MENU XCTRL('d')
744 #define ALPHA XCTRL('a')
745 #define PLUS XCTRL('b')
746 #define MINUS XCTRL('e')
747 #define PREV XCTRL('p')
748 #define NEXT XCTRL('n')
749 #define SOFTA XCTRL('x')
750 #define SOFTB XCTRL('q')
754 static void PressKey(char c, int i)
757 #define X( a, b ) case a: SetKey(b, i); break;
759 case '1' ... '9': SetKey(c-'0',i); break;
776 X(STO, 19) /* These are not present on 2110, so I can't test this. Enable once tested. */
780 default: fprintf(stderr, "Unknown key %d\n", c);
787 PressString(char *s, int upcase)
790 static int lastupcase = 1;
792 if (lastchar == *s) {
793 fprintf(stderr, "***collision");
802 if (upcase != lastupcase) {
803 fprintf(stderr, "***size change");
813 * This is able to press keys at 62letters/36seconds, tested on message
814 * "Tohle je testovaci zprava schvalne za jak dlouho ji to napise"
815 * Well, it is possible to write that message in 17seconds...
821 #define X(a, b) case a: PressString(b, 0); break;
831 X('$', "1111111111");
832 /* X('$', "11111111111"); libra, not in ascii */
833 X('(', "111111111111");
834 X(')', "1111111111111");
835 X('/', "11111111111111");
836 X('%', "111111111111111");
837 X('@', "1111111111111111");
838 X('_', "11111111111111111");
839 X('=', "111111111111111111");
867 #define X(a, b) case a: PressString(b, 1); break;
895 case ' ': PressKey('#', 0); break;
896 case '+': PressKey(ALPHA, 0); PressKey('*', 0); PressKey('*', 0); PressKey(ALPHA, 0); break;
898 case '0' ... '9': PressKey(ALPHA, 0); PressKey(c, 0); PressKey(ALPHA, 0); break;
899 default: PressKey(c, 0);
904 HandleString(char *s)
910 fprintf(stderr,"***end of input");
911 PressKey(lastkey, 1);
918 u8 reg[] = { 1, 1, 0x0f, 1, 0x0f };
919 SendFrame( reg, 0xe9, 5 );
923 EnableDisplayOutput(GSM_Statemachine *sm)
925 /* LN_UC_SHARE, LN_UC_SHARE, LN_UC_RELEASE, LN_UC_RELEASE, LN_UC_KEEP */
926 u8 pkt[] = {3, 3, 0, 0, 1};
929 fprintf(stderr, "\nShould display output\n");
935 SendCommand(pkt, 0x19, 5);
936 fprintf(stderr, "\nGrabbing display");
937 waitfor(PacketOK, 0);
938 if ((PacketData[3] != 0xcd) ||
939 (PacketData[2] != 1) ||
940 (PacketData[4] != 1 /* LN_UC_REQUEST_OK */))
941 fprintf(stderr, "Something is very wrong with GrabDisplay\n");
942 fprintf(stderr, "Display grabbed okay (waiting)\n");
944 fprintf(stderr, "Okay\n");
948 static GSM_Error SMS_Reserve(GSM_Statemachine *sm)
950 u8 pkt[] = { 0x10, LM_SMS_RESERVE_PP, LN_SMS_NORMAL_RESERVE };
952 SendCommand(pkt, LM_SMS_COMMAND, sizeof(pkt));
954 waitfor(PacketOK, 100);
956 eprintf("No reply trying to reserve SMS-es\n");
957 if (PacketData[3] != LM_SMS_EVENT)
958 eprintf("Bad reply trying to reserve SMS-es\n");
959 if (SMSData[0] != LM_SMS_PP_RESERVE_COMPLETE)
960 eprintf("Not okay trying to reserve SMS-es (%d)\n", SMSData[0]);
964 static GSM_Error SMS_Slave(GSM_Statemachine *sm)
967 eprintf("Reserved okay\n");
971 memset((void *) &SMSData[0], 0, 255);
972 waitfor(PacketOK, 1000000);
973 if (PacketData[3] != LM_SMS_EVENT)
974 eprintf("Wrong packet came!\n");
975 switch (SMSData[0]) {
976 case LM_SMS_RECEIVED_PP_DATA:
977 eprintf("Data came!\n");
979 case LM_SMS_ALIVE_TEST:
980 eprintf("Am I alive?\n");
982 case LM_SMS_NEW_MESSAGE_INDICATION:
985 eprintf("New message indicated @%d\n", SMSData[2]);
987 memset(&m, 0, sizeof(m));
988 m.Number = SMSData[2];
989 m.MemoryType = GMT_ME;
990 if (GetSMSMessage(&m) != GE_NONE)
991 eprintf("Could not find promissed message?\n");
994 slave_process(&m, SMSData[2]);
999 eprintf("Unexpected packet came: %x\n", SMSData[0]);
1004 /* This is the main loop for the MB21 functions. When N2110_Initialise
1005 is called a thread is created to run this loop. This loop is
1006 exited when the application calls the N2110_Terminate function. */
1010 fprintf(stderr, "Initializing... ");
1011 /* Do initialisation stuff */
1012 LastChar = GetTime();
1013 if (OpenSerial() != true) {
1014 N2110_LinkOK = false;
1019 while(!N2110_LinkOK) {
1020 fprintf(stderr, "registration... ");
1024 fprintf(stderr, "okay\n");
1027 /* Initialise variables and state machine. */
1029 Initialise(char *port_device, char *initlength,
1030 GSM_ConnectionType connection,
1031 void (*rlp_callback)(RLP_F96Frame *frame))
1033 RequestTerminate = false;
1034 N2110_LinkOK = false;
1035 setvbuf(stdout, NULL, _IONBF, 0);
1036 setvbuf(stderr, NULL, _IONBF, 0);
1037 memset(VersionInfo, 0, sizeof(VersionInfo));
1038 strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
1039 switch (connection) {
1044 return GE_NOTSUPPORTED;
1051 /* Routine to get specifed phone book location. Designed to be called by
1052 application. Will block until location is retrieved or a timeout/error
1056 GetPhonebookLocation(GSM_PhonebookEntry *entry)
1058 u8 pkt[] = {0x1a, 0 /* 1 == phone */, 0};
1061 pkt[1] = 3 + (entry->MemoryType != GMT_ME);
1062 pkt[2] = entry->Location;
1065 SendCommand(pkt, LN_LOC_COMMAND, 3);
1066 waitfor(PacketOK, 0);
1067 if ((PacketData[3] != 0xc9) ||
1068 (PacketData[4] != 0x1a)) {
1069 fprintf(stderr, "Something is very wrong with GetPhonebookLocation\n");
1072 ddprintf("type= %x\n", PacketData[5]);
1073 ddprintf("location= %x\n", PacketData[6]);
1074 ddprintf("status= %x\n", PacketData[7]);
1075 for (i=8; PacketData[i]; i++) {
1076 ddprintf("%c", PacketData[i]);
1078 strcpy(entry->Name, (void *)&PacketData[8]);
1080 strcpy(entry->Number, (void *)&PacketData[i]);
1081 for (; PacketData[i]; i++) {
1082 ddprintf("%c", PacketData[i]);
1085 entry->Empty = false;
1091 /* Routine to write phonebook location in phone. Designed to be called by
1092 application code. Will block until location is written or timeout
1096 WritePhonebookLocation(GSM_PhonebookEntry *entry)
1098 u8 pkt[999] = {0x1b, 0 /* 1 == phone */, 0};
1100 pkt[1] = 3 + (entry->MemoryType != GMT_ME);
1101 pkt[2] = entry->Location;
1102 strcpy(&pkt[3], entry->Name);
1103 strcpy(&pkt[3+strlen(entry->Name)+1], entry->Number);
1106 SendCommand(pkt, LN_LOC_COMMAND, 3+strlen(entry->Number)+strlen(entry->Name)+2);
1107 waitfor(PacketOK, 0);
1109 if ((PacketData[3] != 0xc9) ||
1110 (PacketData[4] != 0x1b)) {
1111 fprintf(stderr, "Something is very wrong with WritePhonebookLocation\n");
1114 printf("type= %x\n", PacketData[5]);
1115 printf("location= %x\n", PacketData[6]);
1116 printf("status= %x\n", PacketData[7]);
1121 GetSMSStatus(GSM_SMSMemoryStatus *Status)
1129 GSM_Functions N2110_Functions = {
1132 GetPhonebookLocation,
1133 WritePhonebookLocation,
1153 PNOK_GetManufacturer,
1176 EnableDisplayOutput,
1188 static GSM_Error link_Loop(struct timeval *tm)
1194 GSM_Error P2110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
1196 GSM_Error err = GE_NONE;
1198 printf("Asked for %d\n", op);
1201 state->Link.Loop = link_Loop;
1205 case GOP_GetRevision:
1206 if (!Model) err = GetVersionInfo();
1208 if (data->Model) strncpy(data->Model, Model, 64);
1209 if (data->Revision) strncpy(data->Revision, Revision, 64);
1211 case GOP_GetBatteryLevel:
1212 err = GetBatteryLevel(data->BatteryUnits, data->BatteryLevel);
1214 case GOP_GetRFLevel:
1215 err = GetRFLevel(data->RFUnits, data->RFLevel);
1218 case GOP_GetMemoryStatus:
1219 err = N2110_GetMemoryStatus(data, state);
1222 case GOP_DisplayOutput:
1223 printf("DisplayOutput(%px)\n", data->OutputFn);
1224 OutputFn = data->OutputFn;
1226 err = EnableDisplayOutput(state);
1230 SMS_Slave(state); /* FIXME!!! */
1233 err = GetSMSMessage(data->SMSMessage);
1236 err = SMS(data->SMSMessage, 3);
1238 case GOP_ReadPhonebook:
1239 err = GetPhonebookLocation(data->PhonebookEntry);
1241 case GOP_WritePhonebook:
1242 err = WritePhonebookLocation(data->PhonebookEntry);
1245 err = SMS_Slave(state); /* Dirty hack, Fallthrough */
1248 err = GE_NOTIMPLEMENTED;