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