This commit was manufactured by cvs2svn to create tag
[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 #ifndef WIN32
12   #include "devices/unixserial.h"
13   #include "devices/unixirda.h"
14   #include "devices/tekram.h"
15   #include <sys/ioctl.h>
16   #include <pthread.h>
17   #include <termios.h>
18   #include <signal.h>
19   #include <errno.h>
20 #else
21   #include <windows.h>
22   #include "devices/winserial.h"
23 #endif
24
25 #include "gsm-api.h"
26 #include "devices/device.h"
27 #include "files/cfgreader.h"
28
29 #include <string.h>
30
31 #ifdef VC6
32   /* for VC6 make scripts save VERSION constant in mversion.h file */
33   #include "mversion.h"
34 #endif
35
36 char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH]={0x00};
37
38 bool duringwrite;
39
40 #ifndef WIN32
41
42 char *lockfile;
43
44 //pthread_t Thread;
45 #if defined(__svr4__) || defined(__FreeBSD__)
46   pthread_t selThread;
47 #endif
48
49 int device_portfd = -1;
50
51 #define max_buf_len 128
52 #define lock_path "/var/lock/LCK.."
53
54 /* Lock the device. Return allocated string with a lock name */
55 char *lock_device(const char* port)
56 {
57         char *lock_file = NULL;
58         char buffer[max_buf_len];
59         const char *aux = rindex(port, '/');
60         int fd, len = strlen(aux) + strlen(lock_path);
61
62         /* Remove leading '/' */
63         if (aux) aux++;
64         else aux = port;
65
66         memset(buffer, 0, sizeof(buffer));
67         lock_file = calloc(len + 1, 1);
68         if (!lock_file) {
69                 fprintf(stderr, _("Out of memory error while locking device\n"));
70                 return NULL;
71         }
72         /* I think we don't need to use strncpy, as we should have enough
73          * buffer due to strlen results
74          */
75         strcpy(lock_file, lock_path);
76         strcat(lock_file, aux);
77
78         /* Check for the stale lockfile.
79          * The code taken from minicom by Miquel van Smoorenburg */
80         if ((fd = open(lock_file, O_RDONLY)) >= 0) {
81                 char buf[max_buf_len];
82                 int pid, n = 0;
83
84                 n = read(fd, buf, sizeof(buf) - 1);
85                 close(fd);
86                 if (n > 0) {
87                         pid = -1;
88                         if (n == 4)
89                                 /* Kermit-style lockfile. */
90                                 pid = *(int *)buf;
91                         else {
92                                 /* Ascii lockfile. */
93                                 buf[n] = 0;
94                                 sscanf(buf, "%d", &pid);
95                         }
96                         if (pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH) {
97                                 fprintf(stderr, _("Lockfile %s is stale. Overriding it..\n"), lock_file);
98                                 sleep(1);
99                                 if (unlink(lock_file) == -1) {
100                                         fprintf(stderr, _("Overriding failed, please check the permissions\n"));
101                                         fprintf(stderr, _("Cannot lock device\n"));
102                                         goto failed;
103                                 }
104                         } else {
105                                 fprintf(stderr, _("Device already locked.\n"));
106                                 goto failed;
107                         }
108                 }
109                 /* this must not happen. because we could open the file   */
110                 /* no wrong permissions are set. only reason could be     */
111                 /* flock/lockf or a empty lockfile due to a broken binary */
112                 /* which is more likely (like gnokii 0.4.0pre11 ;-)       */
113                 if (n == 0) {
114                         fprintf(stderr, _("Unable to read lockfile %s.\n"), lock_file);
115                         fprintf(stderr, _("Please check for reason and remove the lockfile by hand.\n"));
116                         fprintf(stderr, _("Cannot lock device\n"));
117                         goto failed;
118                 }
119         }
120
121         /* Try to create a new file, with 0644 mode */
122         fd = open(lock_file, O_CREAT | O_EXCL | O_WRONLY, 0644);
123         if (fd == -1) {
124                 if (errno == EEXIST)
125                         fprintf(stderr, _("Device seems to be locked by unknown process\n"));
126                 else if (errno == EACCES)
127                         fprintf(stderr, _("Please check permission on lock directory\n"));
128                 else if (errno == ENOENT)
129                         fprintf(stderr, _("Cannot create lockfile %s. Please check for existence of path"), lock_file);
130                 goto failed;
131         }
132         sprintf(buffer, "%10ld gnokii\n", (long)getpid());
133         write(fd, buffer, strlen(buffer));
134         close(fd);
135         return lock_file;
136 failed:
137         free(lock_file);
138         return NULL;
139 }
140
141 /* Removes lock and frees memory */
142 bool unlock_device(char *lock_file)
143 {
144         int err;
145
146         if (!lock_file) {
147 //              fprintf(stderr, _("Cannot unlock device\n"));
148                 return false;
149         }
150         err = unlink(lock_file);
151         free(lock_file);
152         return (err + 1);
153 }
154
155 /*
156  * Structure to store the filedescriptor we use.
157  *
158  */
159 int device_getfd(void)
160 {
161   return device_portfd;
162 }
163
164 int device_open(__const char *__file, int __with_odd_parity) {
165   struct CFG_Header *cfg_info;
166   char *aux;    
167
168   cfg_info=CFG_FindGnokiirc();
169   if (cfg_info!=NULL) {
170     aux = CFG_Get(cfg_info, "global", "use_locking");
171     if (aux) {
172       if (!strcmp(aux, "yes")) {
173         lockfile = lock_device(__file);
174         if (!lockfile) return false;
175       }
176     }
177   }
178   
179   switch (CurrentConnectionType) {
180     case GCT_Tekram:
181       device_portfd = tekram_open(__file);
182       break;
183     case GCT_Irda:
184       device_portfd = irda_open();
185       break;
186     default:
187       device_portfd = serial_opendevice(__file, __with_odd_parity, true, false);
188       break;
189   }
190   
191   return (device_portfd >= 0);
192 }
193
194 void device_close(void)
195 {
196   AppendLogText("CLOSE\n",false);
197
198   /* Now wait for thread to terminate. */
199   //pthread_join(Thread, NULL);
200
201   unlock_device(lockfile);
202   
203   switch (CurrentConnectionType) {
204     case GCT_Tekram: tekram_close(device_portfd); break;
205     case GCT_Irda  :   irda_close(device_portfd); break;
206     default        : serial_close(device_portfd); break;
207   }
208
209   PortDevice[0]=0x00;
210 }
211
212 void device_reset(void) {
213 }
214
215 void device_setdtrrts(int __dtr, int __rts)
216 {
217   switch (CurrentConnectionType) {
218     case GCT_Tekram:
219     case GCT_Irda:
220       break;
221     default:
222       serial_setdtrrts(device_portfd, __dtr, __rts);
223 #ifdef DEBUG
224       device_dumpserial();
225 #endif
226       break;
227   }
228 }
229
230 void device_changespeed(int __speed)
231 {
232   switch (CurrentConnectionType) {
233     case GCT_Irda:
234       break;
235     case GCT_Tekram:
236       tekram_changespeed(device_portfd, __speed);
237       break;
238     default:
239       serial_changespeed(device_portfd, __speed);
240 #ifdef DEBUG
241       fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed);
242 #endif
243       break;
244   }
245 }
246
247 size_t device_read(__ptr_t __buf, size_t __nbytes)
248 {
249   switch (CurrentConnectionType) {
250     case GCT_Tekram: return (tekram_read(device_portfd, __buf, __nbytes)); break;
251     case GCT_Irda  : return (  irda_read(device_portfd, __buf, __nbytes)); break;
252     default        : return (serial_read(device_portfd, __buf, __nbytes)); break;
253   }
254 }
255
256 size_t device_write(__const __ptr_t __buf, size_t __n) {
257   u8 buffer[300];
258   size_t mysize;
259   
260   while (duringwrite) {}
261
262   memcpy(buffer,__buf,__n);
263   AppendLog(buffer,__n,true);
264
265   duringwrite=true;
266   switch (CurrentConnectionType) {
267     case GCT_Irda  : mysize =   irda_write(device_portfd, __buf, __n); break;
268     case GCT_Tekram: mysize = tekram_write(device_portfd, __buf, __n); break;      
269     default        : mysize = serial_write(device_portfd, __buf, __n); break;
270   }
271   duringwrite=false;
272   return mysize;
273 }
274
275 #ifdef DEBUG
276 void device_dumpserial(void)
277 {
278   int PortFD;
279   unsigned int Flags=0;
280
281   PortFD = device_getfd();
282
283   ioctl(PortFD, TIOCMGET, &Flags);
284
285   fprintf(stdout, _("Serial device:"));
286   fprintf(stdout,  _(" DTR is %s"), Flags&TIOCM_DTR?_("up"):_("down"));
287   fprintf(stdout, _(", RTS is %s"), Flags&TIOCM_RTS?_("up"):_("down"));
288   fprintf(stdout, _(", CAR is %s"), Flags&TIOCM_CAR?_("up"):_("down"));
289   fprintf(stdout, _(", CTS is %s\n"), Flags&TIOCM_CTS?_("up"):_("down"));
290 }
291 #endif /* DEBUG */
292
293 void SigHandler(int status)
294 {
295
296   unsigned char buffer[2048];
297
298   int count, res;
299
300   res = device_read(buffer, 255);
301
302   for (count = 0; count < res ; count ++) {
303     Protocol->StateMachine(buffer[count]);
304   }
305 }
306
307
308 #if defined(__svr4__) || defined(__FreeBSD__)
309 /* thread for handling incoming data */
310 void SelectLoop() {
311   int err;
312   fd_set readfds;
313   struct timeval timeout;
314
315   FD_ZERO(&readfds);
316   FD_SET(device_portfd,&readfds);
317   /* set timeout to 15 seconds */
318   timeout.tv_sec=15;
319   timeout.tv_usec=0;
320   while (!CurrentRequestTerminate) {
321     err=select(device_portfd+1,&readfds,NULL,NULL,&timeout);
322     if ( err > 0 ) {
323       /* call singal handler to process incoming data */
324       SigHandler(0);
325       /* refresh timeout, just for linux :-( */\r
326       /* required for irda */
327       timeout.tv_sec=15;\r
328     } else {
329       if (err == -1)
330       perror("Error in SelectLoop");
331     }
332   }
333 }
334 #endif
335
336 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
337 {
338   int result;
339
340   char text[100];
341
342 #if defined(__svr4__) || defined(__FreeBSD__)
343   int rtn;
344 #else
345   struct sigaction sig_io;
346 #endif
347
348 #ifdef DEBUG
349       if ((strstr(GSM_Info->IrdaModels,"decode")!=NULL) &&  (CurrentConnectionType == GCT_Irda))
350        {
351          printf("DEBUG and Irda decode Model -> not realy open ;-)\n");
352          return true;
353        }
354 #endif 
355
356   if (PortDevice[0]!=0x00) return true;
357
358   duringwrite=false;
359   
360   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
361
362 #ifdef DEBUG
363   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
364 #endif
365
366   strcpy(text,"\n\n\nMygnokii ");
367   sprintf(text+strlen(text), "%s",VERSION);
368   strcpy(text+strlen(text),"\n");
369   AppendLogText(text,false);
370
371   strcpy(text,"Port ");
372   strcpy(text+strlen(text),PortDevice);
373   strcpy(text+strlen(text),"\n");
374   AppendLogText(text,false);
375
376   strcpy(text,"Connection ");
377   switch (con) {
378     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
379     case GCT_Infrared:strcpy(text+strlen(text),"infrared");break;
380     case GCT_Irda    :strcpy(text+strlen(text),"irda sockets");break;
381     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
382     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
383     case GCT_Tekram  :strcpy(text+strlen(text),"Tekram");break;
384     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
385     default          :strcpy(text+strlen(text),"unknown");break;
386   }
387   strcpy(text+strlen(text),"\n");
388   AppendLogText(text,false);
389
390   /* Ralf Thelen: In this moment there is NO method of communication,
391    which require keepalive packets and GSM->KeepAlive is
392    always NULL_KeepAlive, I comment this thread, */
393
394   /* Create and start main thread. */
395 //  rtn = pthread_create(&Thread, NULL,(void*)GSM->KeepAlive, (void *)NULL);
396 //
397 //  if (rtn != 0) {
398 //    fprintf(stdout,_("Error\n"));  
399 //    return false;
400 //  }
401
402 #if defined(__svr4__) || defined(__FreeBSD__)
403 #else
404         /* Set up and install handler before enabling async IO on port. */
405         sig_io.sa_handler = SigHandler;
406         sig_io.sa_flags = 0;
407         sigaction (SIGIO, &sig_io, NULL);
408 #endif
409
410     /* Open device. */
411     result = device_open(PortDevice, with_odd_parity);
412     
413     if (!result) {
414       fprintf(stdout,_("Error\n"));  
415       return false;
416     }
417
418 #if defined(__svr4__) || defined(__FreeBSD__)
419     /* create a thread to handle incoming data from mobile phone */
420     rtn=pthread_create(&selThread,NULL,(void*)SelectLoop,(void*)NULL);
421     if (rtn != 0) {
422       fprintf(stdout,_("Error\n"));  
423       return false;
424     }
425 #endif
426
427   return true;
428 }
429
430 /* ---------------- RTH:   #ifdef WIN32 ------------------ */  
431
432 #else
433
434   extern HANDLE hPhone;
435
436 void device_close(void)
437 {
438   AppendLogText("CLOSE\n",false);
439
440   CloseConnection();
441
442   PortDevice[0]=0x00;
443 }
444
445 #ifdef DEBUG
446 void device_dumpserial(void)
447 {
448   DCB dcb;
449   
450   dcb.DCBlength = sizeof(DCB);
451   GetCommState(hPhone, &dcb);
452
453   fprintf(stdout, _("Serial device:"));
454   fprintf(stdout,  _(" DTR is "));
455   switch (dcb.fDtrControl) {
456     case DTR_CONTROL_ENABLE   : fprintf(stdout,  _("up"));       break;
457     case DTR_CONTROL_DISABLE  : fprintf(stdout,  _("down"));     break;
458     case DTR_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake"));break;
459   }
460   fprintf(stdout, _(", RTS is "));
461   switch (dcb.fRtsControl) {
462     case RTS_CONTROL_ENABLE   : fprintf(stdout,  _("up\n"));       break;
463     case RTS_CONTROL_DISABLE  : fprintf(stdout,  _("down\n"));     break;
464     case RTS_CONTROL_HANDSHAKE: fprintf(stdout,  _("handshake\n"));break;
465     case RTS_CONTROL_TOGGLE   : fprintf(stdout,  _("toggle\n"));   break;
466   }
467 }
468 #endif /* DEBUG */
469
470 void device_setdtrrts(int __dtr, int __rts)
471 {
472   DCB dcb;
473   
474   dcb.DCBlength = sizeof(DCB);
475   GetCommState(hPhone, &dcb);
476
477   if (__dtr==1) dcb.fDtrControl = DTR_CONTROL_ENABLE;
478            else dcb.fDtrControl = DTR_CONTROL_DISABLE;
479
480    if (__rts==1) dcb.fRtsControl = RTS_CONTROL_ENABLE;
481             else dcb.fRtsControl = RTS_CONTROL_DISABLE;
482
483    SetCommState(hPhone, &dcb);
484
485 #ifdef DEBUG
486   device_dumpserial();
487 #endif
488 }
489
490 void device_changespeed(int __speed)
491 {
492
493   DCB dcb;
494
495   dcb.DCBlength = sizeof(DCB);
496   GetCommState(hPhone, &dcb);
497
498   switch (__speed) {
499     case 115200: dcb.BaudRate=CBR_115200; break;
500     case 19200 : dcb.BaudRate=CBR_19200;  break;
501     case 9600  : dcb.BaudRate=CBR_9600;   break;
502    }
503    
504    SetCommState(hPhone, &dcb);
505
506 #ifdef DEBUG
507    fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed);
508 #endif
509 }
510
511 bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con)
512 {
513   DCB dcb;
514   char text[100];
515
516   int rtn;
517
518   if (PortDevice[0]!=0x00) return true;  
519
520   duringwrite=false;
521   strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH);
522
523 #ifdef DEBUG
524   fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice);
525 #endif
526
527   strcpy(text,"\n\n\nMygnokii ");
528   sprintf(text+strlen(text), "%s",VERSION);
529   strcpy(text+strlen(text),"\n");
530   AppendLogText(text,false);
531
532   strcpy(text,"Port ");
533   strcpy(text+strlen(text),PortDevice);
534   strcpy(text+strlen(text),"\n");
535   AppendLogText(text,false);
536
537   strcpy(text,"Connection ");
538   switch (con) {
539     case GCT_FBUS    :strcpy(text+strlen(text),"FBUS");break;
540     case GCT_Infrared:strcpy(text+strlen(text),"infrared");break;
541     case GCT_Irda    :strcpy(text+strlen(text),"irda sockets");break;
542     case GCT_MBUS    :strcpy(text+strlen(text),"MBUS");break;
543     case GCT_DLR3    :strcpy(text+strlen(text),"DLR3");break;
544     case GCT_Tekram  :strcpy(text+strlen(text),"Tekram");break;
545     case GCT_AT      :strcpy(text+strlen(text),"AT");break;
546     default          :strcpy(text+strlen(text),"unknown");break;
547   }
548   strcpy(text+strlen(text),"\n");
549   AppendLogText(text,false);
550
551   CurrentDisableKeepAlive = true;
552
553   /* Create and start main thread. */
554   rtn = ! OpenConnection(PortDevice, Protocol->StateMachine, GSM->KeepAlive);
555
556   if (rtn != 0) {
557
558     fprintf(stdout,_("Error\n"));  
559     return false;
560   } else {
561     CurrentDisableKeepAlive = false;
562   }
563
564   if (with_odd_parity) {
565     dcb.DCBlength = sizeof(DCB);
566     GetCommState(hPhone, &dcb);
567
568     dcb.Parity=ODDPARITY;
569
570     SetCommState(hPhone, &dcb);
571   }
572   
573   return true;
574 }
575
576 size_t device_write(const __ptr_t __buf, size_t __n) {
577   int i;
578   while (duringwrite) {}
579   duringwrite=true;
580   AppendLog(__buf,__n,true);
581   i=WriteCommBlock(__buf,__n);
582   duringwrite=false;
583   if (i) return __n; else return 0;
584 }
585
586 #endif /*WIN32*/