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