/* G N O K I I A Linux/Unix toolset and driver for Nokia mobile phones. Released under the terms of the GNU GPL, see file COPYING for more details. */ #include "config.h" #ifndef WIN32 #include "devices/unixserial.h" #include #include #include #include #else #include #include "devices/winserial.h" #endif #include "gsm-api.h" #include "devices/device.h" #include #ifdef VC6 /* for VC6 make scripts save VERSION constant in mversion.h file */ #include "mversion.h" #endif static char PortDevice[GSM_MAX_DEVICE_NAME_LENGTH]={0x00}; static bool duringwrite; #ifndef WIN32 //pthread_t Thread; #if defined(__svr4__) || defined(__FreeBSD__) pthread_t selThread; #endif int device_portfd = -1; /* * Structure to store the filedescriptor we use. * */ #ifdef DEBUG static int device_getfd(void) { return device_portfd; } #endif /* DEBUG */ static int device_open(__const char *__file, int __with_odd_parity) { switch (CurrentConnectionType) { default: device_portfd = serial_opendevice(__file, __with_odd_parity, true, false); break; } return (device_portfd >= 0); } void device_close(void) { AppendLogText("CLOSE\n",false); /* Now wait for thread to terminate. */ //pthread_join(Thread, NULL); switch (CurrentConnectionType) { default : serial_close(device_portfd); break; } PortDevice[0]=0x00; } #ifndef UCLINUX void device_reset(void) { } #endif /* UCLINUX */ #ifdef DEBUG static void device_dumpserial(void); #endif /* DEBUG */ void device_setdtrrts(int __dtr, int __rts) { switch (CurrentConnectionType) { default: serial_setdtrrts(device_portfd, __dtr, __rts); #ifdef DEBUG device_dumpserial(); #endif break; } } void device_changespeed(int __speed) { switch (CurrentConnectionType) { default: serial_changespeed(device_portfd, __speed); #ifdef DEBUG fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed); #endif break; } } static size_t device_read(__ptr_t __buf, size_t __nbytes) { switch (CurrentConnectionType) { default : return (serial_read(device_portfd, __buf, __nbytes)); break; } } size_t device_write(__const __ptr_t __buf, size_t __n) { u8 buffer[300]; size_t mysize; while (duringwrite) { fprintf(stderr,"device_write: reentrance violation!\n"); _exit(1); } memcpy(buffer,__buf,__n); AppendLog(buffer,__n,true); duringwrite=true; switch (CurrentConnectionType) { default : mysize = serial_write(device_portfd, __buf, __n); break; } duringwrite=false; if (mysize!=__n) fprintf(stderr,"WARNING: device_write(__n=%ld)=%ld\n",(long)__n,(long)mysize); return mysize; } #ifdef DEBUG static void device_dumpserial(void) { int PortFD; unsigned int Flags=0; PortFD = device_getfd(); ioctl(PortFD, TIOCMGET, &Flags); fprintf(stdout, _("Serial device:")); fprintf(stdout, _(" DTR is %s"), Flags&TIOCM_DTR?_("up"):_("down")); fprintf(stdout, _(", RTS is %s"), Flags&TIOCM_RTS?_("up"):_("down")); fprintf(stdout, _(", CAR is %s"), Flags&TIOCM_CAR?_("up"):_("down")); fprintf(stdout, _(", CTS is %s\n"), Flags&TIOCM_CTS?_("up"):_("down")); } #endif /* DEBUG */ static char SigHandler_buffer[255]; void SigHandler(int status) { int count, res; LIVE_DISABLE; LIVE; res = device_read(SigHandler_buffer, sizeof(SigHandler_buffer)); for (count = 0; count < res ; count ++) { Protocol->StateMachine(SigHandler_buffer[count]); } LIVE_ENABLE; } #ifdef UCLINUX void usleep_watchdevice(unsigned long usecs) { int err; fd_set readfds; struct timeval target,timeout; if (gettimeofday(&target/*tv*/,NULL/*tz*/)) perror("usleep_watchdevice()/gettimeofday(2) init"); target.tv_usec+=usecs%1000000; target.tv_sec +=usecs/1000000 + (target.tv_usec/1000000); target.tv_usec%=1000000; for (;;) FD_ZERO(&readfds); if (device_portfd>=0) FD_SET(device_portfd,&readfds); if (gettimeofday(&timeout/*tv*/,NULL/*tz*/)) perror("usleep_watchdevice()/gettimeofday(2) loop"); if (target.tv_sec < timeout.tv_sec) return; timeout.tv_sec =target.tv_sec - timeout.tv_sec; if (target.tv_usec < timeout.tv_usec) { target.tv_usec+=1000000; if (target.tv_sec <= 0) return; target.tv_sec--; } timeout.tv_usec=target.tv_usec - timeout.tv_usec; err=select((device_portfd<0 ? 0 : device_portfd+1),&readfds,NULL,NULL,&timeout); if ( err > 0 ) { if (device_portfd>=0 && FD_ISSET(device_portfd,&readfds)) { /* call singal handler to process incoming data */ SigHandler(0); } } else { if (err == -1) perror("Error in SelectLoop"); } } #endif #if defined(__svr4__) || defined(__FreeBSD__) /* thread for handling incoming data */ void SelectLoop() { int err; fd_set readfds; struct timeval timeout; FD_ZERO(&readfds); FD_SET(device_portfd,&readfds); /* set timeout to 15 seconds */ timeout.tv_sec=15; timeout.tv_usec=0; while (!CurrentRequestTerminate) { err=select(device_portfd+1,&readfds,NULL,NULL,&timeout); if ( err > 0 ) { /* call singal handler to process incoming data */ SigHandler(0); /* refresh timeout, just for linux :-( */ /* required for irda */ timeout.tv_sec=15; } else { if (err == -1) perror("Error in SelectLoop"); } } } #endif bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con) { int result; char text[100]; #ifndef UCLINUX #if defined(__svr4__) || defined(__FreeBSD__) int rtn; #else struct sigaction sig_io; #endif #endif /* UCLINUX */ #ifndef UCLINUX #ifdef DEBUG if ((strstr(GSM_Info->IrdaModels,"decode")!=NULL) && (CurrentConnectionType == GCT_Irda)) { printf("DEBUG and Irda decode Model -> not realy open ;-)\n"); return true; } #endif #endif /* UCLINUX */ if (PortDevice[0]!=0x00) return true; duringwrite=false; strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH); #ifdef DEBUG fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice); #endif strcpy(text,"\n\n\nMygnokii "); sprintf(text+strlen(text), "%s",VERSION); strcpy(text+strlen(text),"\n"); AppendLogText(text,false); strcpy(text,"Port "); strcpy(text+strlen(text),PortDevice); strcpy(text+strlen(text),"\n"); AppendLogText(text,false); strcpy(text,"Connection "); switch (con) { case GCT_FBUS :strcpy(text+strlen(text),"FBUS");break; #ifndef UCLINUX case GCT_MBUS :strcpy(text+strlen(text),"MBUS");break; case GCT_DLR3 :strcpy(text+strlen(text),"DLR3");break; case GCT_AT :strcpy(text+strlen(text),"AT");break; default :strcpy(text+strlen(text),"unknown");break; #endif /* UCLINUX */ } strcpy(text+strlen(text),"\n"); AppendLogText(text,false); /* Ralf Thelen: In this moment there is NO method of communication, which require keepalive packets and GSM->KeepAlive is always NULL_KeepAlive, I comment this thread, */ /* Create and start main thread. */ // rtn = pthread_create(&Thread, NULL,(void*)GSM->KeepAlive, (void *)NULL); // // if (rtn != 0) { // fprintf(stdout,_("Error\n")); // return false; // } #ifndef UCLINUX #if defined(__svr4__) || defined(__FreeBSD__) #else /* Set up and install handler before enabling async IO on port. */ sig_io.sa_handler = SigHandler; sig_io.sa_flags = 0; sigaction (SIGIO, &sig_io, NULL); #endif #endif /* UCLINUX */ /* Open device. */ result = device_open(PortDevice, with_odd_parity); if (!result) { fprintf(stdout,_("Error\n")); return false; } #ifndef UCLINUX #if defined(__svr4__) || defined(__FreeBSD__) /* create a thread to handle incoming data from mobile phone */ rtn=pthread_create(&selThread,NULL,(void*)SelectLoop,(void*)NULL); if (rtn != 0) { fprintf(stdout,_("Error\n")); return false; } #endif #endif /* UCLINUX */ return true; } /* ---------------- RTH: #ifdef WIN32 ------------------ */ #else extern HANDLE hPhone; void device_close(void) { AppendLogText("CLOSE\n",false); CloseConnection(); PortDevice[0]=0x00; } #ifdef DEBUG void device_dumpserial(void) { DCB dcb; dcb.DCBlength = sizeof(DCB); GetCommState(hPhone, &dcb); fprintf(stdout, _("Serial device:")); fprintf(stdout, _(" DTR is ")); switch (dcb.fDtrControl) { case DTR_CONTROL_ENABLE : fprintf(stdout, _("up")); break; case DTR_CONTROL_DISABLE : fprintf(stdout, _("down")); break; case DTR_CONTROL_HANDSHAKE: fprintf(stdout, _("handshake"));break; } fprintf(stdout, _(", RTS is ")); switch (dcb.fRtsControl) { case RTS_CONTROL_ENABLE : fprintf(stdout, _("up\n")); break; case RTS_CONTROL_DISABLE : fprintf(stdout, _("down\n")); break; case RTS_CONTROL_HANDSHAKE: fprintf(stdout, _("handshake\n"));break; case RTS_CONTROL_TOGGLE : fprintf(stdout, _("toggle\n")); break; } } #endif /* DEBUG */ void device_setdtrrts(int __dtr, int __rts) { DCB dcb; dcb.DCBlength = sizeof(DCB); GetCommState(hPhone, &dcb); if (__dtr==1) dcb.fDtrControl = DTR_CONTROL_ENABLE; else dcb.fDtrControl = DTR_CONTROL_DISABLE; if (__rts==1) dcb.fRtsControl = RTS_CONTROL_ENABLE; else dcb.fRtsControl = RTS_CONTROL_DISABLE; SetCommState(hPhone, &dcb); #ifdef DEBUG device_dumpserial(); #endif } void device_changespeed(int __speed) { DCB dcb; dcb.DCBlength = sizeof(DCB); GetCommState(hPhone, &dcb); switch (__speed) { case 115200: dcb.BaudRate=CBR_115200; break; case 19200 : dcb.BaudRate=CBR_19200; break; case 9600 : dcb.BaudRate=CBR_9600; break; } SetCommState(hPhone, &dcb); #ifdef DEBUG fprintf(stdout,_("Serial device: changing speed to %i\n"),__speed); #endif } bool StartConnection (char *port_device, bool with_odd_parity, GSM_ConnectionType con) { DCB dcb; char text[100]; int rtn; if (PortDevice[0]!=0x00) return true; duringwrite=false; strncpy(PortDevice, port_device, GSM_MAX_DEVICE_NAME_LENGTH); #ifdef DEBUG fprintf(stdout,_("Opening \"%s\" device...\n"),PortDevice); #endif strcpy(text,"\n\n\nMygnokii "); sprintf(text+strlen(text), "%s",VERSION); strcpy(text+strlen(text),"\n"); AppendLogText(text,false); strcpy(text,"Port "); strcpy(text+strlen(text),PortDevice); strcpy(text+strlen(text),"\n"); AppendLogText(text,false); strcpy(text,"Connection "); switch (con) { case GCT_FBUS :strcpy(text+strlen(text),"FBUS");break; case GCT_MBUS :strcpy(text+strlen(text),"MBUS");break; case GCT_DLR3 :strcpy(text+strlen(text),"DLR3");break; case GCT_AT :strcpy(text+strlen(text),"AT");break; default :strcpy(text+strlen(text),"unknown");break; } strcpy(text+strlen(text),"\n"); AppendLogText(text,false); CurrentDisableKeepAlive = true; /* Create and start main thread. */ rtn = ! OpenConnection(PortDevice, Protocol->StateMachine, GSM->KeepAlive); if (rtn != 0) { fprintf(stdout,_("Error\n")); return false; } else { CurrentDisableKeepAlive = false; } if (with_odd_parity) { dcb.DCBlength = sizeof(DCB); GetCommState(hPhone, &dcb); dcb.Parity=ODDPARITY; SetCommState(hPhone, &dcb); } return true; } size_t device_write(const __ptr_t __buf, size_t __n) { int i; while (duringwrite) {} duringwrite=true; AppendLog(__buf,__n,true); i=WriteCommBlock(__buf,__n); duringwrite=false; if (i) return __n; else return 0; } #endif /*WIN32*/