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