eb81b25d7fe3ae63e388ce25bf157224975e0892
[gnokii.git] / common / devices / device.c
1 /*
2
3   G N O K I I
4
5   A Linux/Unix toolset and driver for Nokia mobile phones.
6
7   Released under the terms of the GNU GPL, see file COPYING for more details.
8
9 */
10
11 #include "config.h"
12
13 #ifndef WIN32
14   #include "devices/unixserial.h"
15   #include <sys/ioctl.h>
16   #include <termios.h>
17   #include <signal.h>
18   #include <errno.h>
19 #else
20   #include <windows.h>
21   #include "devices/winserial.h"
22 #endif
23
24 #include "gsm-api.h"
25 #include "devices/device.h"
26
27 #include <string.h>
28
29 #ifdef VC6
30   /* for VC6 make scripts save VERSION constant in mversion.h file */
31   #include "mversion.h"
32 #endif
33
34 static char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH]={0x00};
35
36 static bool duringwrite;
37
38 #ifndef WIN32
39
40 //pthread_t Thread;
41 #if defined(__svr4__) || defined(__FreeBSD__)
42   pthread_t selThread;
43 #endif
44
45 static int device_portfd = -1;
46
47 /*
48  * Structure to store the filedescriptor we use.
49  *
50  */
51 #ifdef DEBUG
52 static int device_getfd(void)
53 {
54   return device_portfd;
55 }
56 #endif /* DEBUG */
57
58 static int device_open(__const char *__file, int __with_odd_parity) {
59
60   switch (CurrentConnectionType) {
61     default:
62       device_portfd = serial_opendevice(__file, __with_odd_parity, true, false);
63       break;
64   }
65   
66   return (device_portfd >= 0);
67 }
68
69 void device_close(void)
70 {
71   AppendLogText("CLOSE\n",false);
72
73   /* Now wait for thread to terminate. */
74   //pthread_join(Thread, NULL);
75
76   switch (CurrentConnectionType) {
77     default        : serial_close(device_portfd); break;
78   }
79
80   PortDevice[0]=0x00;
81 }
82
83 #ifndef UCLINUX
84
85 void device_reset(void) {
86 }
87
88 #endif /* UCLINUX */
89
90 #ifdef DEBUG
91 static void device_dumpserial(void);
92 #endif /* DEBUG */
93
94 void device_setdtrrts(int __dtr, int __rts)
95 {
96   switch (CurrentConnectionType) {
97     default:
98       serial_setdtrrts(device_portfd, __dtr, __rts);
99 #ifdef DEBUG
100       device_dumpserial();
101 #endif
102       break;
103   }
104 }
105
106 void device_changespeed(int __speed)
107 {
108   switch (CurrentConnectionType) {
109     default:
110       serial_changespeed(device_portfd, __speed);
111 #ifdef DEBUG
112       fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed);
113 #endif
114       break;
115   }
116 }
117
118 static size_t device_read(__ptr_t __buf, size_t __nbytes)
119 {
120   switch (CurrentConnectionType) {
121     default        : return (serial_read(device_portfd, __buf, __nbytes)); break;
122   }
123 }
124
125 size_t device_write(__const __ptr_t __buf, size_t __n) {
126   u8 buffer[300];
127   size_t mysize;
128   
129   while (duringwrite) {}
130
131   memcpy(buffer,__buf,__n);
132   AppendLog(buffer,__n,true);
133
134   duringwrite=true;
135   switch (CurrentConnectionType) {
136     default        : mysize = serial_write(device_portfd, __buf, __n); break;
137   }
138   duringwrite=false;
139   return mysize;
140 }
141
142 #ifdef DEBUG
143 static void device_dumpserial(void)
144 {
145   int PortFD;
146   unsigned int Flags=0;
147
148   PortFD = device_getfd();
149
150   ioctl(PortFD, TIOCMGET, &Flags);
151
152   fprintf(stdout, _("Serial device:"));
153   fprintf(stdout,  _(" DTR is %s"), Flags&TIOCM_DTR?_("up"):_("down"));
154   fprintf(stdout, _(", RTS is %s"), Flags&TIOCM_RTS?_("up"):_("down"));
155   fprintf(stdout, _(", CAR is %s"), Flags&TIOCM_CAR?_("up"):_("down"));
156   fprintf(stdout, _(", CTS is %s\n"), Flags&TIOCM_CTS?_("up"):_("down"));
157 }
158 #endif /* DEBUG */
159
160 static void SigHandler(int status)
161 {
162
163   unsigned char buffer[2048];
164
165   int count, res;
166
167   res = device_read(buffer, 255);
168
169   for (count = 0; count < res ; count ++) {
170     Protocol->StateMachine(buffer[count]);
171   }
172 }
173
174
175 #if defined(__svr4__) || defined(__FreeBSD__)
176 /* thread for handling incoming data */
177 void SelectLoop() {
178   int err;
179   fd_set readfds;
180   struct timeval timeout;
181
182   FD_ZERO(&readfds);
183   FD_SET(device_portfd,&readfds);
184   /* set timeout to 15 seconds */
185   timeout.tv_sec=15;
186   timeout.tv_usec=0;
187   while (!CurrentRequestTerminate) {
188     err=select(device_portfd+1,&readfds,NULL,NULL,&timeout);
189     if ( err > 0 ) {
190       /* call singal handler to process incoming data */
191       SigHandler(0);
192       /* refresh timeout, just for linux :-( */\r
193       /* required for irda */
194       timeout.tv_sec=15;\r
195     } else {
196       if (err == -1)
197       perror("Error in SelectLoop");
198     }
199   }
200 }
201 #endif
202
203 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
204 {
205   int result;
206
207   char text[100];
208
209 #if defined(__svr4__) || defined(__FreeBSD__)
210   int rtn;
211 #else
212   struct sigaction sig_io;
213 #endif
214
215 #ifndef UCLINUX
216 #ifdef DEBUG
217       if ((strstr(GSM_Info->IrdaModels,"decode")!=NULL) &&  (CurrentConnectionType == GCT_Irda))
218        {
219          printf("DEBUG and Irda decode Model -> not realy open ;-)\n");
220          return true;
221        }
222 #endif 
223 #endif /* UCLINUX */
224
225   if (PortDevice[0]!=0x00) return true;
226
227   duringwrite=false;
228   
229   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
230
231 #ifdef DEBUG
232   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
233 #endif
234
235   strcpy(text,"\n\n\nMygnokii ");
236   sprintf(text+strlen(text), "%s",VERSION);
237   strcpy(text+strlen(text),"\n");
238   AppendLogText(text,false);
239
240   strcpy(text,"Port ");
241   strcpy(text+strlen(text),PortDevice);
242   strcpy(text+strlen(text),"\n");
243   AppendLogText(text,false);
244
245   strcpy(text,"Connection ");
246   switch (con) {
247     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
248 #ifndef UCLINUX
249     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
250     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
251     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
252     default          :strcpy(text+strlen(text),"unknown");break;
253 #endif /* UCLINUX */
254   }
255   strcpy(text+strlen(text),"\n");
256   AppendLogText(text,false);
257
258   /* Ralf Thelen: In this moment there is NO method of communication,
259    which require keepalive packets and GSM->KeepAlive is
260    always NULL_KeepAlive, I comment this thread, */
261
262   /* Create and start main thread. */
263 //  rtn = pthread_create(&Thread, NULL,(void*)GSM->KeepAlive, (void *)NULL);
264 //
265 //  if (rtn != 0) {
266 //    fprintf(stdout,_("Error\n"));  
267 //    return false;
268 //  }
269
270 #if defined(__svr4__) || defined(__FreeBSD__)
271 #else
272         /* Set up and install handler before enabling async IO on port. */
273         sig_io.sa_handler = SigHandler;
274         sig_io.sa_flags = 0;
275         sigaction (SIGIO, &sig_io, NULL);
276 #endif
277
278     /* Open device. */
279     result = device_open(PortDevice, with_odd_parity);
280     
281     if (!result) {
282       fprintf(stdout,_("Error\n"));  
283       return false;
284     }
285
286 #if defined(__svr4__) || defined(__FreeBSD__)
287     /* create a thread to handle incoming data from mobile phone */
288     rtn=pthread_create(&selThread,NULL,(void*)SelectLoop,(void*)NULL);
289     if (rtn != 0) {
290       fprintf(stdout,_("Error\n"));  
291       return false;
292     }
293 #endif
294
295   return true;
296 }
297
298 /* ---------------- RTH:   #ifdef WIN32 ------------------ */  
299
300 #else
301
302   extern HANDLE hPhone;
303
304 void device_close(void)
305 {
306   AppendLogText("CLOSE\n",false);
307
308   CloseConnection();
309
310   PortDevice[0]=0x00;
311 }
312
313 #ifdef DEBUG
314 void device_dumpserial(void)
315 {
316   DCB dcb;
317   
318   dcb.DCBlength = sizeof(DCB);
319   GetCommState(hPhone, &dcb);
320
321   fprintf(stdout, _("Serial device:"));
322   fprintf(stdout,  _(" DTR is "));
323   switch (dcb.fDtrControl) {
324     case DTR_CONTROL_ENABLE   : fprintf(stdout,  _("up"));       break;
325     case DTR_CONTROL_DISABLE  : fprintf(stdout,  _("down"));     break;
326     case DTR_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake"));break;
327   }
328   fprintf(stdout, _(", RTS is "));
329   switch (dcb.fRtsControl) {
330     case RTS_CONTROL_ENABLE   : fprintf(stdout,  _("up\n"));       break;
331     case RTS_CONTROL_DISABLE  : fprintf(stdout,  _("down\n"));     break;
332     case RTS_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake\n"));break;
333     case RTS_CONTROL_TOGGLE   : fprintf(stdout,  _("toggle\n"));   break;
334   }
335 }
336 #endif /* DEBUG */
337
338 void device_setdtrrts(int __dtr, int __rts)
339 {
340   DCB dcb;
341   
342   dcb.DCBlength = sizeof(DCB);
343   GetCommState(hPhone, &dcb);
344
345   if (__dtr==1) dcb.fDtrControl = DTR_CONTROL_ENABLE;
346            else dcb.fDtrControl = DTR_CONTROL_DISABLE;
347
348    if (__rts==1) dcb.fRtsControl = RTS_CONTROL_ENABLE;
349             else dcb.fRtsControl = RTS_CONTROL_DISABLE;
350
351    SetCommState(hPhone, &dcb);
352
353 #ifdef DEBUG
354   device_dumpserial();
355 #endif
356 }
357
358 void device_changespeed(int __speed)
359 {
360
361   DCB dcb;
362
363   dcb.DCBlength = sizeof(DCB);
364   GetCommState(hPhone, &dcb);
365
366   switch (__speed) {
367     case 115200: dcb.BaudRate=CBR_115200; break;
368     case 19200 : dcb.BaudRate=CBR_19200;  break;
369     case 9600  : dcb.BaudRate=CBR_9600;   break;
370    }
371    
372    SetCommState(hPhone, &dcb);
373
374 #ifdef DEBUG
375    fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed);
376 #endif
377 }
378
379 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
380 {
381   DCB dcb;
382   char text[100];
383
384   int rtn;
385
386   if (PortDevice[0]!=0x00) return true;  
387
388   duringwrite=false;
389   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
390
391 #ifdef DEBUG
392   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
393 #endif
394
395   strcpy(text,"\n\n\nMygnokii ");
396   sprintf(text+strlen(text), "%s",VERSION);
397   strcpy(text+strlen(text),"\n");
398   AppendLogText(text,false);
399
400   strcpy(text,"Port ");
401   strcpy(text+strlen(text),PortDevice);
402   strcpy(text+strlen(text),"\n");
403   AppendLogText(text,false);
404
405   strcpy(text,"Connection ");
406   switch (con) {
407     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
408     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
409     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
410     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
411     default          :strcpy(text+strlen(text),"unknown");break;
412   }
413   strcpy(text+strlen(text),"\n");
414   AppendLogText(text,false);
415
416   CurrentDisableKeepAlive = true;
417
418   /* Create and start main thread. */
419   rtn = ! OpenConnection(PortDevice, Protocol->StateMachine, GSM->KeepAlive);
420
421   if (rtn != 0) {
422
423     fprintf(stdout,_("Error\n"));  
424     return false;
425   } else {
426     CurrentDisableKeepAlive = false;
427   }
428
429   if (with_odd_parity) {
430     dcb.DCBlength = sizeof(DCB);
431     GetCommState(hPhone, &dcb);
432
433     dcb.Parity=ODDPARITY;
434
435     SetCommState(hPhone, &dcb);
436   }
437   
438   return true;
439 }
440
441 size_t device_write(const __ptr_t __buf, size_t __n) {
442   int i;
443   while (duringwrite) {}
444   duringwrite=true;
445   AppendLog(__buf,__n,true);
446   i=WriteCommBlock(__buf,__n);
447   duringwrite=false;
448   if (i) return __n; else return 0;
449 }
450
451 #endif /*WIN32*/