6a28122881c3ce29006248de7f9042c786b309d4
[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 char SigHandler_buffer[255];
161
162 static void SigHandler(int status)
163 {
164   int count, res;
165
166   LIVE_DISABLE;
167   LIVE;
168
169   res = device_read(SigHandler_buffer, sizeof(SigHandler_buffer));
170
171   for (count = 0; count < res ; count ++) {
172     Protocol->StateMachine(SigHandler_buffer[count]);
173   }
174   LIVE_ENABLE;
175 }
176
177
178 #if defined(__svr4__) || defined(__FreeBSD__)
179 /* thread for handling incoming data */
180 void SelectLoop() {
181   int err;
182   fd_set readfds;
183   struct timeval timeout;
184
185   FD_ZERO(&readfds);
186   FD_SET(device_portfd,&readfds);
187   /* set timeout to 15 seconds */
188   timeout.tv_sec=15;
189   timeout.tv_usec=0;
190   while (!CurrentRequestTerminate) {
191     err=select(device_portfd+1,&readfds,NULL,NULL,&timeout);
192     if ( err > 0 ) {
193       /* call singal handler to process incoming data */
194       SigHandler(0);
195       /* refresh timeout, just for linux :-( */
196       /* required for irda */
197       timeout.tv_sec=15;
198     } else {
199       if (err == -1)
200       perror("Error in SelectLoop");
201     }
202   }
203 }
204 #endif
205
206 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
207 {
208   int result;
209
210   char text[100];
211
212 #if defined(__svr4__) || defined(__FreeBSD__)
213   int rtn;
214 #else
215   struct sigaction sig_io;
216 #endif
217
218 #ifndef UCLINUX
219 #ifdef DEBUG
220       if ((strstr(GSM_Info->IrdaModels,"decode")!=NULL) &&  (CurrentConnectionType == GCT_Irda))
221        {
222          printf("DEBUG and Irda decode Model -> not realy open ;-)\n");
223          return true;
224        }
225 #endif 
226 #endif /* UCLINUX */
227
228   if (PortDevice[0]!=0x00) return true;
229
230   duringwrite=false;
231   
232   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
233
234 #ifdef DEBUG
235   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
236 #endif
237
238   strcpy(text,"\n\n\nMygnokii ");
239   sprintf(text+strlen(text), "%s",VERSION);
240   strcpy(text+strlen(text),"\n");
241   AppendLogText(text,false);
242
243   strcpy(text,"Port ");
244   strcpy(text+strlen(text),PortDevice);
245   strcpy(text+strlen(text),"\n");
246   AppendLogText(text,false);
247
248   strcpy(text,"Connection ");
249   switch (con) {
250     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
251 #ifndef UCLINUX
252     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
253     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
254     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
255     default          :strcpy(text+strlen(text),"unknown");break;
256 #endif /* UCLINUX */
257   }
258   strcpy(text+strlen(text),"\n");
259   AppendLogText(text,false);
260
261   /* Ralf Thelen: In this moment there is NO method of communication,
262    which require keepalive packets and GSM->KeepAlive is
263    always NULL_KeepAlive, I comment this thread, */
264
265   /* Create and start main thread. */
266 //  rtn = pthread_create(&Thread, NULL,(void*)GSM->KeepAlive, (void *)NULL);
267 //
268 //  if (rtn != 0) {
269 //    fprintf(stdout,_("Error\n"));  
270 //    return false;
271 //  }
272
273 #if defined(__svr4__) || defined(__FreeBSD__)
274 #else
275         /* Set up and install handler before enabling async IO on port. */
276         sig_io.sa_handler = SigHandler;
277         sig_io.sa_flags = 0;
278         sigaction (SIGIO, &sig_io, NULL);
279 #endif
280
281     /* Open device. */
282     result = device_open(PortDevice, with_odd_parity);
283     
284     if (!result) {
285       fprintf(stdout,_("Error\n"));  
286       return false;
287     }
288
289 #if defined(__svr4__) || defined(__FreeBSD__)
290     /* create a thread to handle incoming data from mobile phone */
291     rtn=pthread_create(&selThread,NULL,(void*)SelectLoop,(void*)NULL);
292     if (rtn != 0) {
293       fprintf(stdout,_("Error\n"));  
294       return false;
295     }
296 #endif
297
298   return true;
299 }
300
301 /* ---------------- RTH:   #ifdef WIN32 ------------------ */  
302
303 #else
304
305   extern HANDLE hPhone;
306
307 void device_close(void)
308 {
309   AppendLogText("CLOSE\n",false);
310
311   CloseConnection();
312
313   PortDevice[0]=0x00;
314 }
315
316 #ifdef DEBUG
317 void device_dumpserial(void)
318 {
319   DCB dcb;
320   
321   dcb.DCBlength = sizeof(DCB);
322   GetCommState(hPhone, &dcb);
323
324   fprintf(stdout, _("Serial device:"));
325   fprintf(stdout,  _(" DTR is "));
326   switch (dcb.fDtrControl) {
327     case DTR_CONTROL_ENABLE   : fprintf(stdout,  _("up"));       break;
328     case DTR_CONTROL_DISABLE  : fprintf(stdout,  _("down"));     break;
329     case DTR_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake"));break;
330   }
331   fprintf(stdout, _(", RTS is "));
332   switch (dcb.fRtsControl) {
333     case RTS_CONTROL_ENABLE   : fprintf(stdout,  _("up\n"));       break;
334     case RTS_CONTROL_DISABLE  : fprintf(stdout,  _("down\n"));     break;
335     case RTS_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake\n"));break;
336     case RTS_CONTROL_TOGGLE   : fprintf(stdout,  _("toggle\n"));   break;
337   }
338 }
339 #endif /* DEBUG */
340
341 void device_setdtrrts(int __dtr, int __rts)
342 {
343   DCB dcb;
344   
345   dcb.DCBlength = sizeof(DCB);
346   GetCommState(hPhone, &dcb);
347
348   if (__dtr==1) dcb.fDtrControl = DTR_CONTROL_ENABLE;
349            else dcb.fDtrControl = DTR_CONTROL_DISABLE;
350
351    if (__rts==1) dcb.fRtsControl = RTS_CONTROL_ENABLE;
352             else dcb.fRtsControl = RTS_CONTROL_DISABLE;
353
354    SetCommState(hPhone, &dcb);
355
356 #ifdef DEBUG
357   device_dumpserial();
358 #endif
359 }
360
361 void device_changespeed(int __speed)
362 {
363
364   DCB dcb;
365
366   dcb.DCBlength = sizeof(DCB);
367   GetCommState(hPhone, &dcb);
368
369   switch (__speed) {
370     case 115200: dcb.BaudRate=CBR_115200; break;
371     case 19200 : dcb.BaudRate=CBR_19200;  break;
372     case 9600  : dcb.BaudRate=CBR_9600;   break;
373    }
374    
375    SetCommState(hPhone, &dcb);
376
377 #ifdef DEBUG
378    fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed);
379 #endif
380 }
381
382 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
383 {
384   DCB dcb;
385   char text[100];
386
387   int rtn;
388
389   if (PortDevice[0]!=0x00) return true;  
390
391   duringwrite=false;
392   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
393
394 #ifdef DEBUG
395   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
396 #endif
397
398   strcpy(text,"\n\n\nMygnokii ");
399   sprintf(text+strlen(text), "%s",VERSION);
400   strcpy(text+strlen(text),"\n");
401   AppendLogText(text,false);
402
403   strcpy(text,"Port ");
404   strcpy(text+strlen(text),PortDevice);
405   strcpy(text+strlen(text),"\n");
406   AppendLogText(text,false);
407
408   strcpy(text,"Connection ");
409   switch (con) {
410     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
411     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
412     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
413     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
414     default          :strcpy(text+strlen(text),"unknown");break;
415   }
416   strcpy(text+strlen(text),"\n");
417   AppendLogText(text,false);
418
419   CurrentDisableKeepAlive = true;
420
421   /* Create and start main thread. */
422   rtn = ! OpenConnection(PortDevice, Protocol->StateMachine, GSM->KeepAlive);
423
424   if (rtn != 0) {
425
426     fprintf(stdout,_("Error\n"));  
427     return false;
428   } else {
429     CurrentDisableKeepAlive = false;
430   }
431
432   if (with_odd_parity) {
433     dcb.DCBlength = sizeof(DCB);
434     GetCommState(hPhone, &dcb);
435
436     dcb.Parity=ODDPARITY;
437
438     SetCommState(hPhone, &dcb);
439   }
440   
441   return true;
442 }
443
444 size_t device_write(const __ptr_t __buf, size_t __n) {
445   int i;
446   while (duringwrite) {}
447   duringwrite=true;
448   AppendLog(__buf,__n,true);
449   i=WriteCommBlock(__buf,__n);
450   duringwrite=false;
451   if (i) return __n; else return 0;
452 }
453
454 #endif /*WIN32*/