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