bee7093815630927c5d64857b079b9b34619ccae
[gnokii.git] / common / phones / nk2110.c
1 /* -*- linux-c -*-
2
3   $Id$
4
5   G N O K I I
6
7   A Linux/Unix toolset and driver for Nokia mobile phones.
8
9   Copyright (C) 2000, 2001 Pavel Machek <pavel@ucw.cz>
10
11   Released under the terms of the GNU GPL, see file COPYING for more details.
12
13   $Log$
14   Revision 1.1.1.1  2001/11/25 21:59:11  short
15   :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
16
17   Revision 1.16  2001/11/23 22:07:44  machek
18   Fix SMS receiving to work, again. Unfortunately, it is not possible to
19   reuse much of gsm-sms.c...
20
21   Revision 1.15  2001/11/15 12:10:57  pkot
22   Removed a warning from 2110 compilation
23
24   Revision 1.14  2001/11/09 13:49:12  pkot
25   Pavel! You haven't implemented slave_process() function!
26
27   Revision 1.13  2001/11/09 13:17:11  pkot
28   Update 2110 to a new libsms api
29
30   Revision 1.12  2001/10/21 22:23:56  machek
31   Use symbolic constants instead of numbers
32
33   At least detect when we get other message than we asked for
34
35   Provide option to passively wait for sms-es
36
37   Revision 1.11  2001/08/20 23:27:37  pkot
38   Add hardware shakehand to the link layer (Manfred Jonsson)
39
40   Revision 1.10  2001/07/17 22:46:27  pkot
41   Removed warning when compiling with --enable-debug (Pawel Kot)
42
43   Revision 1.9  2001/06/17 16:42:59  machek
44   Created another level of error message (ddprintf), fixed code not to
45   exit on error condition. Now it is actualy usable on my Philips Velo.
46
47   Revision 1.8  2001/06/16 10:00:41  machek
48   Implement timeouts on waiting for SMS.
49
50   Revision 1.7  2001/06/10 23:49:49  pkot
51   Small fixes to hide compilation warnings and allow gnokii.c to compile
52
53   Revision 1.6  2001/06/10 11:28:00  machek
54   Convert GetSMS/DeleteSMS to new structure.
55
56   Revision 1.5  2001/06/06 09:05:56  machek
57   Convert Grab/Release display to new structure.
58
59   Revision 1.4  2001/05/09 20:18:46  machek
60   Cleaned up code a bit. Made it use device_() interface. Reworked delay
61   system; now it is 4 times faster. 5 times faster if you hold * key on
62   phone (?!).
63
64   Revision 1.3  2001/05/07 14:13:03  machek
65   nokia-2110 module converted to suit new API better. --identify now works.
66
67   Revision 1.2  2001/04/27 16:00:01  machek
68   Better error messages.
69
70   Revision 1.1  2001/04/25 12:54:47  machek
71   Partly converted nokia 2110 to "new" form, and moved it to phone
72   directory.
73
74
75   Notice that this code was (partly) converted to "new" structure, but it 
76   does not have code for bus separated. I think that separating it would
77   be waste of effort...                                         --pavel
78
79 */
80
81 #ifndef WIN32
82
83 #include <termios.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <unistd.h>
87 #include <fcntl.h>
88 #include <ctype.h>
89 #include <signal.h>
90 #include <sys/types.h>
91 #include <sys/time.h>
92 #include <sys/ioctl.h>
93 #include <string.h>
94 #include <pthread.h>
95 #include <errno.h>
96
97 #undef DEBUG
98 #include "misc.h"
99 #include "gsm-common.h"
100 #include "mbus-2110.h"
101 #include "phones/nokia.h"
102 #include "device.h"
103 #include "gsm-sms.h"
104
105 #include <string.h>
106 #include <stdlib.h>
107 #include <ctype.h>
108
109 #include "misc.h"
110 #include "gsm-common.h"
111 #include "phones/generic.h"
112 #include "phones/nk2110.h"
113
114 #define MYID 0x78
115 #define ddprintf(x...)
116 #define eprintf(x...) fprintf(stderr, x)
117 #undef DEBUG
118
119 static GSM_Error P2110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state);
120
121 /* Global variables used by code in gsm-api.c to expose the
122    functions supported by this model of phone.  */
123 bool N2110_LinkOK;
124 static char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH];
125 static char *Revision = NULL,
126         *RevisionDate = NULL,
127         *Model = NULL,
128         VersionInfo[64];
129
130 #define INFO \
131 { \
132         "2110|2140|6080",               /* Models */ \
133         100,                            /* Max RF Level */ \
134         0,                              /* Min RF Level */ \
135         GRF_Percentage,                 /* RF level units */ \
136         100,                            /* Max Battery Level */ \
137         0,                              /* Min Battery Level */ \
138         GBU_Percentage,                 /* Battery level units */ \
139         GDT_None,                       /* No date/time support */ \
140         GDT_None,                       /* No alarm support */ \
141         0,                              /* Max alarms = 0 */ \
142         0, 0,                           /* Startup logo size */ \
143         0, 0,                           /* Op logo size */ \
144         0, 0                            /* Caller logo size */ \
145 }
146
147 GSM_Information N2110_Information = INFO;
148
149 GSM_Phone phone_nokia_2110 = {
150         NULL,
151         NULL,
152         INFO,
153         P2110_Functions
154 };
155
156 /* Local variables */
157 static volatile bool RequestTerminate;
158 static u8 TXPacketNumber = 0x01;
159 #define MAX_MODEL_LENGTH 16
160 static volatile unsigned char PacketData[10240];
161 static volatile bool
162         ACKOK    = false,
163         PacketOK = false;
164
165 static volatile int SMSpos = 0;
166 static volatile unsigned char SMSData[10240];
167
168 static long long LastChar = 0;
169
170 static long long
171 GetTime(void)
172 {
173         struct timeval tv;
174
175         gettimeofday(&tv, NULL);
176         return (long long) tv.tv_sec * 1000000 + tv.tv_usec;
177 }
178 static void SigHandler(int status);
179 #define POLLIT do { SigHandler(0); } while (0)
180
181 static void
182 yield(void)
183 {
184         usleep(5000);
185 }
186
187 static void
188 Wait(long long from, int msec)
189 {
190         while (GetTime() < from + ((long long) msec)*1000) {
191                 yield();
192                 POLLIT;
193         }
194 }
195
196 static void
197 Wait2(long long from, int msec)
198 {
199         while (GetTime() < from + ((long long) msec)*1000) {
200                 yield();
201         }
202 }
203
204 #define msleep(x) do { usleep(x*1000); } while (0)
205 #define msleep_poll(x) do { Wait(GetTime(), x); } while (0)
206
207 #define waitfor(condition, maxtime) \
208 do { \
209         long long limit = GetTime() + maxtime*1000; \
210         if (!maxtime) limit = 0x7fffffffffffffffULL; \
211         while ((!(condition)) && (limit > GetTime())) { \
212                 yield(); \
213                 POLLIT; \
214         } \
215         if (!(limit > GetTime())) eprintf("???? TIMEOUT!"); \
216 } while(0)
217
218 /* Checksum calculation */
219 static u8
220 GetChecksum( u8 * packet, int len )
221 {
222         u8 checksum = 0;
223         unsigned int i;
224
225         for( i = 0; i < len; i++ ) checksum ^= packet[i]; /* calculate checksum */
226         return checksum;
227 }
228
229 /* --------------- */
230
231 static int xread(unsigned char *d, int len)
232 {
233         int res;
234         while (len) {
235                 res = device_read(d, len);
236                 if (res == -1) {
237                         if (errno != EAGAIN) {
238                                 dprintf("I/O error : %m?!\n");
239                                 return -1;
240                         } else device_select(NULL);
241                 } else {
242                         d += res;
243                         len -= res;
244                         dprintf("(%d)", len);
245                 }
246         }
247         return 0;
248 }
249
250 static int xwrite(unsigned char *d, int len)
251 {
252         int res;
253         while (len) {
254                 res = device_write(d, len);
255                 if (res == -1) {
256                         if (errno != EAGAIN) {
257                                 dprintf("I/O error : %m?!\n");
258                                 return -1;
259                         }
260                 } else {
261                         d += res;
262                         len -= res;
263                         dprintf("<%d>", len);
264                 }
265         }
266         return 0;
267 }
268
269 /* --------------------------- */
270
271 static GSM_Error
272 SendFrame( u8 *buffer, u8 command, u8 length )
273 {
274         u8  pkt[10240], pkt2[10240];
275         int current = 0;
276
277         pkt[current++] = 0x00;               /* Construct the header.      */
278         pkt[current++] = MYID;
279         pkt[current++] = length;             /* Set data size              */
280         pkt[current++] = command;
281         memcpy( pkt + current, buffer, length ); /* Copy in data.          */
282         current += length;
283         pkt[current++] = TXPacketNumber;         /* Set packet number      */
284         pkt[current++] = GetChecksum( pkt, current); /* Calculate and set checksum */
285 #ifdef DEBUG
286         {
287                 int i;
288                 u8  b;
289                 fprintf( stderr, _("PC   : ") );
290                 for( i = 0; i < current; i++ ) {
291                         b = pkt[i];
292                         fprintf( stderr, "[%02X %c]", b, b > 0x20 ? b : '.' );
293                 }
294                 fprintf( stderr, "\n" );
295         }
296 #endif /* DEBUG */
297         /* Send it out... */
298         ddprintf("(");
299         Wait2(LastChar, 3);
300         /* I should put my messages at least 2msec apart... */
301         ddprintf(")");
302         dprintf("writing...");
303         LastChar = GetTime();
304         if (xwrite(pkt, current) == -1)
305                 return (GE_INTERNALERROR);
306         if (xread(pkt2, current) == -1)
307                 return (GE_INTERNALERROR);
308         dprintf("echook");
309         if (memcmp(pkt, pkt2, current)) {
310                 eprintf("Bad echo?!");
311                 msleep(1000);
312                 return (GE_TIMEOUT);
313         }
314         return (GE_NONE);
315 }
316
317 static GSM_Error
318 SendCommand( u8 *buffer, u8 command, u8 length )
319 {
320         int time, retries = 10;
321         char pkt[10240];
322
323 //      msleep(2);
324         while ((time = device_read(pkt, 10240)) != -1) {
325                 int j;
326                 char b;
327                 dprintf("Spurious? (%d)", time);
328                                         dprintf( _("Phone: ") );
329                                         for( j = 0; j < time; j++ ) {
330                                                 b = pkt[j];
331                                                 dprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
332                                         }
333                 msleep(2);
334         }
335
336         ACKOK = false;
337         time = 30;
338         while (retries--) {
339                 long long now;
340                 SendFrame(buffer, command, length);
341                 now = GetTime();
342                 while ((GetTime() - now) < time*1000) {
343                         if (ACKOK)
344                                 return GE_NONE;
345                         yield();
346                         POLLIT;
347                 }
348                 time = 50;              /* 5 seems to be enough */
349                 dprintf("[resend]");
350         }
351         eprintf("Command not okay after 10 retries!\n");
352         return GE_BUSY;
353 }
354
355 /* Applications should call Terminate to close the serial port. */
356 static void
357 Terminate(void)
358 {
359         /* Request termination of thread */
360         RequestTerminate = true;
361         device_close();
362 }
363
364 static GSM_Error
365 SMS(GSM_SMSMessage *message, int command)
366 {
367         u8 pkt[] = { 0x10, 0x02, 0, 0 };
368
369         SMSpos = 0;
370         memset((void *) &SMSData[0], 0, 255);
371         PacketOK = false;
372         pkt[1] = command;
373         pkt[2] = 1; /* == LM_SMS_MEM_TYPE_DEFAULT or LM_SMS_MEM_TYPE_SIM or LM_SMS_MEM_TYPE_ME */
374         pkt[3] = message->Number;
375
376         SendCommand(pkt, LM_SMS_COMMAND, sizeof(pkt));
377         msleep_poll(300);       /* We have to keep acknowledning phone's data */
378         waitfor(PacketOK, 1000);
379         if (!PacketOK) {
380                 eprintf("SMS: No reply came within second!\n");
381         }
382         if (PacketData[3] != LM_SMS_EVENT) {
383                 eprintf("Something is very wrong with SMS\n");
384                 return GE_BUSY; /* FIXME */
385         }
386         if ((SMSData[2]) && (SMSData[2] != message->Number)) {
387                 eprintf("Wanted message @%d, got message at @%d!\n", message->Number, SMSData[2]);
388                 return GE_BUSY;
389         }
390         return (GE_NONE);
391 }
392
393
394 static GSM_Error
395 DecodeIncomingSMS(GSM_SMSMessage *m)
396 {
397         GSM_Error error;
398         int len, i;
399
400         error = GE_NONE;
401 /*      Should be moved to gsm-sms.c */
402
403         ddprintf("Status: " );
404         switch (SMSData[3]) {
405         case 7: m->Type = SMS_Submit;  /* m->Status = GSS_NOTSENTREAD; */ ddprintf("not sent\n"); break;
406         case 5: m->Type = SMS_Submit;  /* m->Status = GSS_SENTREAD;    */ ddprintf("sent\n"); break;
407         case 3: m->Type = SMS_Deliver; /* m->Status = GSS_NOTSENTREAD; */ ddprintf("not read\n"); break;
408         case 1: m->Type = SMS_Deliver; /* m->Status = GSS_SENTREAD;    */ ddprintf("read\n"); break;
409         }
410
411         UnpackDateTime(SMSData+7, &m->Time);
412
413         m->Length = len = SMSData[14];
414         ddprintf("%d bytes: ", len );
415         for (i = 0; i<len; i++)
416                 ddprintf("%c", SMSData[15+i]);
417         ddprintf("\n");
418
419         if (len>160)
420                 eprintf("Magic not allowed\n");
421         memset(m->MessageText, 0, 161);
422         strncpy(m->MessageText, (void *) &SMSData[15], len);
423
424         ddprintf("Text is %s\n", m->MessageText);
425
426         /* 
427         Originator address is at 15+i,
428            followed by message center addres (?)
429         */
430         {
431                 char *s = (char *) &SMSData[15+i];      /* We discard volatile. Make compiler quiet. */
432                 strcpy(m->RemoteNumber.number, s);
433                 s+=strlen(s)+1;
434                 strcpy(m->MessageCenter.Number, s);
435                 ddprintf("Sender = %s, MessageCenter = %s\n", m->Sender, m->MessageCenter.Name);
436         }
437
438         m->MessageCenter.No = 0;
439         strcpy(m->MessageCenter.Name, "(unknown)");
440         m->UDH_No = 0;
441
442         return error;
443 }
444
445 static GSM_Error
446 GetSMSMessage(GSM_SMSMessage *m)
447 {
448         if (m->Number > 10)
449                 return GE_INVALIDSMSLOCATION;
450
451         if (SMS(m, LM_SMS_READ_STORED_DATA) != GE_NONE)
452                 return GE_BUSY; /* FIXME */
453         ddprintf("Have message?\n");
454         
455         if (DecodeIncomingSMS(m) != GE_NONE)
456                 return GE_BUSY;
457
458         if (SMSData[0] != LM_SMS_FORWARD_STORED_DATA) {
459                 ddprintf("No sms there? (%x/%d)\n", SMSData[0], SMSpos);
460                 return GE_EMPTYSMSLOCATION;
461         }
462         msleep_poll(1000);              /* If phone lost our ack, it might retransmit data */
463         return (GE_NONE);
464 }
465
466 #if 0
467 static GSM_Error
468 SendSMSMessage(GSM_SMSMessage *m)
469 {
470         if (m->Number > 10)
471                 return GE_INVALIDSMSLOCATION;
472
473         if (SMSData[0] != 0x0b) {
474                 ddprintf("No sms there? (%x/%d)\n", SMSData[0], SMSpos);
475                 return GE_EMPTYSMSLOCATION;
476         }
477         ddprintf("Status: " );
478         switch (SMSData[3]) {
479         case 7: m->Type = GST_MO; m->Status = GSS_NOTSENTREAD; ddprintf("not sent\n"); break;
480         case 5: m->Type = GST_MO; m->Status = GSS_SENTREAD; ddprintf("sent\n"); break;
481         case 3: m->Type = GST_MT; m->Status = GSS_NOTSENTREAD; ddprintf("not read\n"); break;
482         case 1: m->Type = GST_MT; m->Status = GSS_SENTREAD; ddprintf("read\n"); break;
483         }
484         return (GE_NONE);
485 }
486 #endif
487
488 static GSM_Error        DeleteSMSMessage(GSM_SMSMessage *message)
489 {
490         ddprintf("deleting...");
491         return SMS(message, 3);
492 }
493
494 /* GetRFLevel */
495
496 static int
497 GetValue(u8 index, u8 type)
498 {
499         u8  pkt[] = {0x84, 2, 0};       /* Sending 4 at pkt[0] makes phone crash */
500         int val;
501         pkt[0] = index;
502         pkt[1] = type;
503
504         PacketOK = false;
505
506         ddprintf("\nRequesting value(%d)", index);
507         SendCommand(pkt, 0xe5, 3);
508
509         waitfor(PacketOK, 0);
510         if ((PacketData[3] != 0xe6) ||
511             (PacketData[4] != index) || 
512             (PacketData[5] != type))
513                 dprintf("Something is very wrong with GetValue\n");
514         val = PacketData[7];
515         ddprintf( "Value = %d\n", val );
516         return (val);
517 }
518
519 static GSM_Error
520 GetRFLevel(GSM_RFUnits *units, float *level)
521 {
522         int val = GetValue(0x84, 2);
523         float res;
524         if (*units == GRF_Arbitrary) {
525                 res = (100* (float) val) / 60.0;        /* This should be / 99.0 for some models other than nokia-2110 */
526                 *level = 0;
527                 if (res > 10)
528                         *level = 1;
529                 if (res > 30)
530                         *level = 2;
531                 if (res > 50)
532                         *level = 3;
533                 if (res > 70)
534                         *level = 4;
535         } else {
536                 *level = (100* (float) val) / 60.0;     /* This should be / 99.0 for some models other than nokia-2110 */
537                 *units = GRF_Percentage;
538         }
539         return (GE_NONE);
540 }
541
542 static GSM_Error
543 GetBatteryLevel(GSM_BatteryUnits *units, float *level)
544 {
545         int val = GetValue(0x85, 2);
546         *level = 0;
547         if (val >= 5)
548                 *level = 1;
549         if (val >= 10)
550                 *level = 2;
551         if (val >= 90)
552                 *level = 3;
553         if (*units == GBU_Arbitrary) {
554         } else {
555 /*              *level = (100 * (float) val) / 90.0;*/  /* 5..first bar, 10..second bar, 90..third bar */
556                 *level = *level * 33;
557                 *units = GBU_Percentage;
558         }
559
560         return (GE_NONE);
561 }
562
563 static GSM_Error GetVersionInfo(void)
564 {
565         char *s = VersionInfo;
566         ddprintf("Getting version info...\n");
567         if (GetValue(0x11, 0x03) == -1)
568                 return GE_TIMEOUT;
569
570         strncpy( s, (void *) &PacketData[6], sizeof(VersionInfo) );
571
572         for( Revision     = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
573         *s++ = 0;
574         for( RevisionDate = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
575         *s++ = 0;
576         for( Model        = s; *s != 0x0A; s++ ) if( !*s ) return (GE_NONE);
577         *s++ = 0;
578         ddprintf("Revision %s, Date %s, Model %s\n", Revision, RevisionDate, Model );
579         return (GE_NONE);
580 }
581
582 /* Our "Not implemented" functions */
583 static GSM_Error
584 GetMemoryStatus(GSM_MemoryStatus *Status)
585 {
586         switch(Status->MemoryType) {
587         case GMT_ME:
588                 Status->Used = 0;
589                 Status->Free = 150;
590                 break;
591         case GMT_LD:
592                 Status->Used = 5;
593                 Status->Free = 0;
594                 break;
595         case GMT_ON:
596                 Status->Used = 1;
597                 Status->Free = 0;
598                 break;
599         case GMT_SM:
600                 Status->Used = 0;
601                 Status->Free = 150;
602                 break;
603         default:
604                 return (GE_NOTIMPLEMENTED);
605         }
606         return (GE_NONE);
607 }
608
609 static bool
610 SendRLPFrame(RLP_F96Frame *frame, bool out_dtx)
611 {
612         return (false);
613 }
614
615 static char *
616 Display(u8 b, int shift, char *s, char *buf)
617 {
618         b >>= shift;
619         b &= 0x03;
620         switch (b) {
621         case 0: break;
622         case 1: case 2: *buf++ = '!';
623         case 3: strcpy(buf, s); buf += strlen(s); *buf++ = ' ';
624         }
625         return buf;
626 }
627
628 static GSM_Error (*OutputFn)(char *text, char *ctrl);
629
630 static int
631 HandlePacket(void)
632 {
633         eprintf("[%x]", PacketData[3]);
634         switch(PacketData[3]) {
635         case 0x12: {                    /* Text from display */
636                 char buf[10240], *s = buf, *t;
637                 t = (char *)&PacketData[8];
638 #define COPY(x) strncpy(s, t, x); t+=x; s+=x; *s++ = '\n'
639                 COPY(10); COPY(10); COPY(10); COPY(3); COPY(12); *s++ = 0;
640                 if (OutputFn)
641                         (*OutputFn)(buf, NULL);
642                 return 1;
643         }
644         case 0x2f: {                    /* Display lights */
645                 char buf[10240], *s = buf;
646 #undef COPY
647 #define COPY(x, y, z) s = Display(PacketData[x], y, z, s)
648                 /* Valid for 2110 */
649                 COPY(4, 0, "d"); COPY(4, 2, "b"); COPY(4, 4, "a"); COPY(4, 6, "lights");
650                 COPY(5, 0, "service"); COPY(5, 2, "scroll_up"); COPY(5, 4, "scroll_down"); COPY(5, 6, "ABC");
651                 COPY(6, 0, "2.>"); COPY(6, 2, "1.>"); COPY(6, 4, "roam"); COPY(6, 6, "handset");
652                 COPY(7, 0, "vmail"); COPY(7, 2, "envelope"); COPY(7, 4, "battbar"); COPY(7, 6, "3.>");
653                 COPY(8, 0, "?1"); COPY(8, 2, "?2"); COPY(8, 4, "fieldbar"); COPY(8, 6, "ring");
654                 *s++ = 0;
655                 if (OutputFn)
656                         (*OutputFn)(NULL, buf);
657                 return 1;
658 #undef COPY
659         }
660         case LM_SMS_EVENT:              /* SMS Data */
661                 /* copy bytes 5+ to smsbuf */
662                 ddprintf("SMSdata:");
663                 {
664                         int i;
665                         for (i=5; i<PacketData[2]+4; i++) {
666                                 SMSData[SMSpos++] = PacketData[i];
667                                 ddprintf("%c", PacketData[i]);
668                         }
669                         fflush(stdout);
670                 }
671                 return ((PacketData[4] & 0xf) != 0);
672                 /* Make all but last fragment "secret" */
673
674         default: dprintf("Unknown response %dx\n", PacketData[3]); 
675                  return 0;
676         }       
677 }
678
679 /* Handler called when characters received from serial port. 
680  * and process them. */
681 static void
682 SigHandler(int status)
683 {
684         unsigned char        buffer[256], ack[5], b;
685         int                  i, res;
686         static unsigned int  Index = 0, Length = 5;
687         static unsigned char pkt[256];
688         int                  j;
689
690         res = device_read(buffer, 256);
691         if( res < 0 ) return;
692         for(i = 0; i < res ; i++) {
693                 b = buffer[i];
694 //       dprintf("(%x)", b, Index);
695                 if (!Index && b != MYID && b != 0xf8 && b != 0x00) /* MYID is code of computer */ {
696                         /* something strange goes from phone. Just ignore it */
697                         ddprintf( "Get [%02X %c]\n", b, b >= 0x20 ? b : '.' );
698                         continue;
699                 } else {
700                         pkt[Index++] = b;
701                         if(Index == 3) {
702                                 Length = b + 6;
703                                 if (b == 0x7f) Length = 5;
704                                 if (b == 0x7e) Length = 8;
705                         }
706                         if(Index >= Length) {
707                                 if((pkt[0] == MYID || pkt[0]==0xf8) && pkt[1] == 0x00) /* packet from phone */ {
708                                         ddprintf( _("Phone: ") );
709                                         for( j = 0; j < Length; j++ ) {
710                                                 b = pkt[j];
711                                                 ddprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
712                                         }
713                                         ddprintf( "\n" );
714                                         /* ensure that we received valid packet */
715                                         if(pkt[Length - 1] != GetChecksum(pkt, Length-1)) {
716                                                 eprintf( "***bad checksum***");
717                                         } else {
718                                                 if((pkt[2] == 0x7F) || (pkt[2] == 0x7E)) /* acknowledge by phone */ {
719                                                         if (pkt[2] == 0x7F) {
720                                                                 dprintf( "[ack]" );
721                                                                 /* Set ACKOK flag */
722                                                                 ACKOK    = true;
723                                                                 /* Increase TX packet number */
724                                                         } else {
725                                                                 dprintf( "[registration ack]" );
726                                                                 N2110_LinkOK = true;
727                                                         }
728                                                         TXPacketNumber++;
729                                                 } else {
730                                                         /* Copy packet data  */
731                                                         dprintf( "[data]" );
732                                                         memcpy((void *) PacketData,pkt,Length);
733                                                         /* send acknowledge packet to phone */
734                                                         msleep(10);
735                                                         ack[0] = 0x00;                     /* Construct the header.   */
736                                                         ack[1] = pkt[0];                   /* Send back id            */
737                                                         ack[2] = 0x7F;                     /* Set special size value  */
738                                                         ack[3] = pkt[Length - 2];          /* Send back packet number */
739                                                         ack[4] = GetChecksum( ack, 4); /* Set checksum            */
740                                                         ddprintf( _("PC   : ") );
741                                                         for( j = 0; j < 5; j++ ) {
742                                                                 b = ack[j];
743                                                                 ddprintf( "[%02X %c]", b, b >= 0x20 ? b : '.' );
744                                                         }
745                                                         ddprintf( "\n" );
746                                                         LastChar = GetTime();
747                                                         if( xwrite( ack, 5 ) == -1 )
748                                                                 perror( _("Write error!\n") );
749                                                         if( xread( ack, 5 ) == -1 )
750                                                                 perror( _("Read ack error!\n") );
751
752                                                         /* Set validity flag */
753                                                         if (!HandlePacket())
754                                                                 PacketOK = true;
755                                                 }
756                                         }
757                                 } else
758                                         eprintf("Got my own echo? That should not be possible!\n");
759                                 /* Look for new packet */
760                                 Index  = 0;
761                                 Length = 5;
762                         }
763                 }
764         }
765 }
766
767 /* Called by initialisation code to open comm port in asynchronous mode. */
768 bool OpenSerial(void)
769 {
770         int result;
771
772         ddprintf(_("Setting MBUS communication with 2110...\n"));
773
774         result = device_open(PortDevice, true, false, false, GCT_Serial);
775         if (!result) { 
776                 fprintf(stderr, "Failed to open %s ...\n", PortDevice);
777                 return (false);
778         }
779
780         ddprintf("%s opened...\n", PortDevice);
781
782         device_changespeed(9600);
783         device_setdtrrts(1, 1);
784         return (true);
785 }
786
787 static GSM_Error
788 SetKey(int c, int up)
789 {
790         u8 reg[] = { 0x7a /* RPC_UI_KEY_PRESS or RPC_UI_KEY_RELEASE */, 0, 1, 0 /* key code */ };
791         reg[0] += up;
792         reg[3] = c;
793         dprintf("\n Pressing %d\n", c );
794         PacketOK = false;
795         SendCommand( reg, 0xe5, 4 );
796         waitfor(PacketOK, 0);
797         return GE_NONE;
798 }
799
800 #define XCTRL(a) (a&0x1f)
801 #define POWER XCTRL('o')
802 #define SEND XCTRL('t')
803 #define END XCTRL('s')
804 #define CLR XCTRL('h')
805 #define MENU XCTRL('d')
806 #define ALPHA XCTRL('a')
807 #define PLUS XCTRL('b')
808 #define MINUS XCTRL('e')
809 #define PREV XCTRL('p')
810 #define NEXT XCTRL('n')
811 #define SOFTA XCTRL('x')
812 #define SOFTB XCTRL('q')
813
814 static char lastkey;
815
816 static void PressKey(char c, int i)
817 {
818         lastkey = c;
819 #define X( a, b ) case a: SetKey(b, i); break;
820         switch (c) {
821         case '1' ... '9': SetKey(c-'0',i); break;
822         X('0', 10)
823         X('#', 11)
824         X('*', 12)
825         X(POWER, 13)
826         X(SEND, 14)
827         X(END, 15)
828         X(PLUS, 16)
829         X(MINUS, 17)
830         X(CLR, 18)
831         X(MENU, 21)
832         X(ALPHA, 22)
833         X(PREV, 23)
834         X(NEXT, 24)
835         X(SOFTA, 25)
836         X(SOFTB, 26)
837 #if 0
838         X(STO, 19)      /* These are not present on 2110, so I can't test this. Enable once tested. */
839         X(RCL, 20)
840         X(MUTE, 28)
841 #endif
842         default: fprintf(stderr, "Unknown key %d\n", c);
843         }
844 #undef X
845 }
846
847
848 static void
849 PressString(char *s, int upcase)
850 {
851         static int lastchar;
852         static int lastupcase = 1;
853
854         if (lastchar == *s) {
855                 fprintf(stderr, "***collision");
856                 PressKey(ALPHA, 0);
857                 PressKey(ALPHA, 0);
858                 lastupcase = 1;
859         }
860
861         while (*s) {
862                 lastchar = *s;
863                 PressKey(*s, 0);
864                 if (upcase != lastupcase) {
865                         fprintf(stderr, "***size change");
866                         msleep_poll(1500);
867                         PressKey(*s, 1);
868                         lastupcase = upcase;
869                 }
870                 s++;
871         }
872 }
873
874 /*
875  * This is able to press keys at 62letters/36seconds, tested on message
876  * "Tohle je testovaci zprava schvalne za jak dlouho ji to napise"
877  * Well, it is possible to write that message in 17seconds...
878  */
879 static void
880 HandleKey(char c)
881 {
882         switch(c) {
883 #define X(a, b) case a: PressString(b, 0); break;
884         X('-', "1");
885         X('?', "11");
886         X('!', "111");
887         X(',', "1111");
888         X('.', "11111");
889         X(':', "111111");
890         X('"', "1111111");
891         X('\'', "11111111");
892         X('&', "111111111");
893         X('$', "1111111111");
894 /*      X('$', "11111111111"); libra, not in ascii */
895         X('(', "111111111111");
896         X(')', "1111111111111");
897         X('/', "11111111111111");
898         X('%', "111111111111111");
899         X('@', "1111111111111111");
900         X('_', "11111111111111111");
901         X('=', "111111111111111111");
902         X('a', "2");
903         X('b', "22");
904         X('c', "222");
905         X('d', "3");
906         X('e', "33");
907         X('f', "333");
908         X('g', "4");
909         X('h', "44");
910         X('i', "444");
911         X('j', "5");
912         X('k', "55");
913         X('l', "555");
914         X('m', "6");
915         X('n', "66");
916         X('o', "666");
917         X('p', "7");
918         X('q', "77");
919         X('r', "777");
920         X('s', "7777");
921         X('t', "8");
922         X('u', "88");
923         X('v', "888");
924         X('w', "9");
925         X('x', "99");
926         X('y', "999");
927         X('z', "9999");
928 #undef X
929 #define X(a, b) case a: PressString(b, 1); break;
930         X('A', "2");
931         X('B', "22");
932         X('C', "222");
933         X('D', "3");
934         X('E', "33");
935         X('F', "333");
936         X('G', "4");
937         X('H', "44");
938         X('I', "444");
939         X('J', "5");
940         X('K', "55");
941         X('L', "555");
942         X('M', "6");
943         X('N', "66");
944         X('O', "666");
945         X('P', "7");
946         X('Q', "77");
947         X('R', "777");
948         X('S', "7777");
949         X('T', "8");
950         X('U', "88");
951         X('V', "888");
952         X('W', "9");
953         X('X', "99");
954         X('Y', "999");
955         X('Z', "9999");
956 #undef X
957         case ' ': PressKey('#', 0); break;
958         case '+': PressKey(ALPHA, 0); PressKey('*', 0); PressKey('*', 0);  PressKey(ALPHA, 0); break;
959         case '*': case '#':
960         case '0' ... '9': PressKey(ALPHA, 0); PressKey(c, 0); PressKey(ALPHA, 0); break;
961         default: PressKey(c, 0);
962         }
963 }
964
965 static GSM_Error
966 HandleString(char *s)
967 {
968         while (*s) {
969                 HandleKey(*s);
970                 s++;
971         }
972         fprintf(stderr,"***end of input");
973         PressKey(lastkey, 1);
974         return GE_NONE;
975 }
976
977 static void
978 Register(void)
979 {
980         u8 reg[] = { 1, 1, 0x0f, 1, 0x0f };
981         SendFrame( reg, 0xe9, 5 );
982 }
983
984 static GSM_Error
985 EnableDisplayOutput(GSM_Statemachine *sm)
986 {
987         /* LN_UC_SHARE, LN_UC_SHARE, LN_UC_RELEASE, LN_UC_RELEASE, LN_UC_KEEP */
988         u8  pkt[] = {3, 3, 0, 0, 1};
989
990         msleep_poll(500);
991         fprintf(stderr, "\nShould display output\n");
992         if (!OutputFn) {
993                 pkt[0] = 0;
994                 pkt[1] = 0;
995         }
996         PacketOK = false;
997         SendCommand(pkt, 0x19, 5);
998         fprintf(stderr, "\nGrabbing display");
999         waitfor(PacketOK, 0);
1000         if ((PacketData[3] != 0xcd) ||
1001             (PacketData[2] != 1) || 
1002             (PacketData[4] != 1 /* LN_UC_REQUEST_OK */))
1003                 fprintf(stderr, "Something is very wrong with GrabDisplay\n");
1004         fprintf(stderr, "Display grabbed okay (waiting)\n");
1005         msleep_poll(500);
1006         fprintf(stderr, "Okay\n");
1007         return GE_NONE;
1008 }
1009
1010 static GSM_Error SMS_Reserve(GSM_Statemachine *sm)
1011 {
1012         u8 pkt[] = { 0x10, LM_SMS_RESERVE_PP, LN_SMS_NORMAL_RESERVE };
1013         PacketOK = false;
1014         SendCommand(pkt, LM_SMS_COMMAND, sizeof(pkt));
1015         PacketOK = 0;
1016         waitfor(PacketOK, 100);
1017         if (!PacketOK)
1018                 eprintf("No reply trying to reserve SMS-es\n");
1019         if (PacketData[3] != LM_SMS_EVENT)
1020                 eprintf("Bad reply trying to reserve SMS-es\n");
1021         if (SMSData[0] != LM_SMS_PP_RESERVE_COMPLETE)
1022                 eprintf("Not okay trying to reserve SMS-es (%d)\n", SMSData[0]);
1023         return GE_NONE;
1024 }
1025
1026 static GSM_Error SMS_Slave(GSM_Statemachine *sm)
1027 {
1028         SMS_Reserve(sm);
1029         eprintf("Reserved okay\n");
1030         while (1) {
1031                 PacketOK = 0;
1032                 SMSpos = 0;
1033                 memset((void *) &SMSData[0], 0, 255);
1034                 waitfor(PacketOK, 1000000);
1035                 if (PacketData[3] != LM_SMS_EVENT)
1036                         eprintf("Wrong packet came!\n");
1037                 switch (SMSData[0]) {
1038                 case LM_SMS_RECEIVED_PP_DATA:
1039                         eprintf("Data came!\n");
1040                         break;
1041                 case LM_SMS_ALIVE_TEST:
1042                         eprintf("Am I alive?\n");
1043                         break;
1044                 case LM_SMS_NEW_MESSAGE_INDICATION:
1045                         {
1046                                 GSM_SMSMessage m;
1047                                 eprintf("New message indicated @%d\n", SMSData[2]);
1048                                 msleep_poll(200);
1049                                 memset(&m, 0, sizeof(m));
1050                                 m.Number = SMSData[2];
1051                                 m.MemoryType = GMT_ME;
1052                                 if (GetSMSMessage(&m) != GE_NONE)
1053                                         eprintf("Could not find promissed message?\n");
1054 #if 0
1055                                 else
1056                                         slave_process(&m, SMSData[2]);
1057 #endif
1058                         }
1059                         break;
1060                 default:
1061                         eprintf("Unexpected packet came: %x\n", SMSData[0]);
1062                 }
1063         }
1064 }
1065
1066 /* This is the main loop for the MB21 functions.  When N2110_Initialise
1067            is called a thread is created to run this loop.  This loop is
1068            exited when the application calls the N2110_Terminate function. */
1069 static void
1070 RegisterMe(void)
1071 {
1072         fprintf(stderr, "Initializing... ");
1073         /* Do initialisation stuff */
1074         LastChar = GetTime();
1075         if (OpenSerial() != true) {
1076                 N2110_LinkOK = false;
1077                 return;
1078         }
1079
1080         msleep(100);
1081         while(!N2110_LinkOK) {
1082                 fprintf(stderr, "registration... ");
1083                 Register();
1084                 msleep_poll(100);
1085         }
1086         fprintf(stderr, "okay\n");
1087 }
1088
1089 /* Initialise variables and state machine. */
1090 static GSM_Error   
1091 Initialise(char *port_device, char *initlength, 
1092            GSM_ConnectionType connection,
1093            void (*rlp_callback)(RLP_F96Frame *frame))
1094 {
1095         RequestTerminate = false;
1096         N2110_LinkOK     = false;
1097         setvbuf(stdout, NULL, _IONBF, 0);
1098         setvbuf(stderr, NULL, _IONBF, 0);
1099         memset(VersionInfo, 0, sizeof(VersionInfo));
1100         strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
1101         switch (connection) {
1102         case GCT_Serial:
1103                 RegisterMe();
1104                 break;
1105         default:
1106                 return GE_NOTSUPPORTED;
1107                 break;
1108         }
1109
1110         return (GE_NONE);
1111 }
1112
1113 /* Routine to get specifed phone book location.  Designed to be called by
1114    application.  Will block until location is retrieved or a timeout/error
1115    occurs. */
1116
1117 static GSM_Error
1118 GetPhonebookLocation(GSM_PhonebookEntry *entry)
1119 {
1120         u8  pkt[] = {0x1a, 0 /* 1 == phone */, 0};
1121         int i;
1122
1123         pkt[1] = 3 + (entry->MemoryType != GMT_ME);
1124         pkt[2] = entry->Location;
1125         
1126         PacketOK = false;
1127         SendCommand(pkt, LN_LOC_COMMAND, 3);
1128         waitfor(PacketOK, 0);
1129         if ((PacketData[3] != 0xc9) ||
1130             (PacketData[4] != 0x1a)) {
1131                 fprintf(stderr, "Something is very wrong with GetPhonebookLocation\n");
1132                 return GE_BUSY;
1133         }
1134         ddprintf("type= %x\n", PacketData[5]);
1135         ddprintf("location= %x\n", PacketData[6]);
1136         ddprintf("status= %x\n", PacketData[7]);
1137         for (i=8; PacketData[i]; i++) {
1138                 ddprintf("%c", PacketData[i]);
1139         }
1140         strcpy(entry->Name, (void *)&PacketData[8]);
1141         i++;
1142         strcpy(entry->Number, (void *)&PacketData[i]);
1143         for (; PacketData[i]; i++) {
1144                 ddprintf("%c", PacketData[i]);
1145         }
1146         ddprintf("\n");
1147         entry->Empty = false;
1148         entry->Group = 0;
1149
1150         return (GE_NONE);
1151 }
1152
1153 /* Routine to write phonebook location in phone. Designed to be called by
1154    application code. Will block until location is written or timeout
1155    occurs. */
1156
1157 static GSM_Error
1158 WritePhonebookLocation(GSM_PhonebookEntry *entry)
1159 {
1160         u8  pkt[999] = {0x1b, 0 /* 1 == phone */, 0};
1161
1162         pkt[1] = 3 + (entry->MemoryType != GMT_ME);
1163         pkt[2] = entry->Location;
1164         strcpy(&pkt[3], entry->Name);
1165         strcpy(&pkt[3+strlen(entry->Name)+1], entry->Number);
1166         
1167         PacketOK = false;
1168         SendCommand(pkt, LN_LOC_COMMAND, 3+strlen(entry->Number)+strlen(entry->Name)+2);
1169         waitfor(PacketOK, 0);
1170         printf("okay?\n");
1171         if ((PacketData[3] != 0xc9) ||
1172             (PacketData[4] != 0x1b)) {
1173                 fprintf(stderr, "Something is very wrong with WritePhonebookLocation\n");
1174                 return GE_BUSY;
1175         }
1176         printf("type= %x\n", PacketData[5]);
1177         printf("location= %x\n", PacketData[6]);
1178         printf("status= %x\n", PacketData[7]);
1179         return (GE_NONE);
1180 }
1181
1182 static GSM_Error
1183 GetSMSStatus(GSM_SMSMemoryStatus *Status)
1184 {
1185         Status->Unread = 0;
1186         Status->Number = 5;
1187         return GE_NONE;
1188 }
1189
1190
1191 GSM_Functions N2110_Functions = {
1192         Initialise,
1193         Terminate,
1194         GetPhonebookLocation,
1195         WritePhonebookLocation,
1196         NULL,
1197         NULL,
1198         GetMemoryStatus,
1199         GetSMSStatus,
1200         NULL,
1201         NULL,
1202         GetSMSMessage,
1203         DeleteSMSMessage,
1204         NULL,
1205         NULL,
1206         GetRFLevel,
1207         GetBatteryLevel,
1208         NULL,
1209         NULL,
1210         NULL,
1211         NULL,
1212         NULL,
1213         NULL,
1214         NULL,
1215         PNOK_GetManufacturer,
1216         NULL,
1217         NULL,
1218         NULL,
1219         NULL,
1220         NULL,
1221         NULL,
1222         NULL,
1223         NULL,
1224         NULL,
1225         NULL,
1226         NULL,
1227         NULL,
1228         NULL,
1229         NULL,
1230         NULL,
1231         NULL,
1232         NULL,
1233         NULL,
1234         NULL,
1235         NULL,
1236         SendRLPFrame,
1237         NULL,
1238         EnableDisplayOutput,
1239         NULL,
1240         NULL,
1241         NULL,
1242         NULL,
1243         SetKey,
1244         HandleString,
1245         NULL
1246 };
1247
1248 #endif
1249
1250 static GSM_Error link_Loop(struct timeval *tm)
1251 {
1252         POLLIT;
1253         return GE_NONE;
1254 }
1255
1256 GSM_Error P2110_Functions(GSM_Operation op, GSM_Data *data, GSM_Statemachine *state)
1257 {
1258         GSM_Error err = GE_NONE;
1259
1260         printf("Asked for %d\n", op);
1261         switch (op) {
1262         case GOP_Init:
1263                 state->Link.Loop = link_Loop;
1264                 break;
1265         case GOP_Identify:
1266         case GOP_GetModel:
1267         case GOP_GetRevision:
1268                 if (!Model) err = GetVersionInfo();
1269                 if (err) break;
1270                 if (data->Model) strncpy(data->Model, Model, 64);
1271                 if (data->Revision) strncpy(data->Revision, Revision, 64);
1272                 break;
1273         case GOP_GetBatteryLevel:
1274                 err = GetBatteryLevel(data->BatteryUnits, data->BatteryLevel);
1275                 break;
1276         case GOP_GetRFLevel:
1277                 err = GetRFLevel(data->RFUnits, data->RFLevel);
1278                 break;
1279 #if 0
1280         case GOP_GetMemoryStatus:
1281                 err = N2110_GetMemoryStatus(data, state);
1282                 break;
1283 #endif
1284         case GOP_DisplayOutput:
1285                 printf("DisplayOutput(%px)\n", data->OutputFn);
1286                 OutputFn = data->OutputFn;
1287                 printf("Enable\n");
1288                 err = EnableDisplayOutput(state);
1289                 break;
1290         case GOP_GetSMS:
1291 #if 0
1292                 SMS_Slave(state);       /* FIXME!!! */
1293 #endif
1294                 msleep(100);
1295                 err = GetSMSMessage(data->SMSMessage);
1296                 break;
1297         case GOP_DeleteSMS:
1298                 err = SMS(data->SMSMessage, 3);
1299                 break;
1300         case GOP_ReadPhonebook:
1301                 err = GetPhonebookLocation(data->PhonebookEntry);
1302                 break;
1303         case GOP_WritePhonebook:
1304                 err = WritePhonebookLocation(data->PhonebookEntry);
1305                 break;
1306         case GOP_GetAlarm:
1307                 err = SMS_Slave(state);         /* Dirty hack, Fallthrough */
1308                 break;
1309         default:
1310                 err = GE_NOTIMPLEMENTED;
1311         }
1312         return err;
1313 }