6 A Linux/Unix toolset and driver for Nokia mobile phones.
8 Released under the terms of the GNU GPL, see file COPYING for more details.
10 This file provides a virtual modem interface to the GSM phone by calling
11 code in gsm-api.c, at-emulator.c and datapump.c. The code here provides
12 the overall framework and coordinates switching between command mode
13 (AT-emulator) and "online" mode where the data pump code translates data
14 from/to the GSM handset and the modem data/fax stream.
22 /* This is the right way to include stdlib with __USE_XOPEN defined */
24 # define _XOPEN_SOURCE 500
25 # include <features.h>
35 #include <sys/types.h>
44 #include "gsm-common.h"
45 #include "data/at-emulator.h"
46 #include "data/datapump.h"
47 #include "data/virtmodem.h"
48 #include "data/rlp-common.h"
50 /* Global variables */
52 //extern bool TerminateThread;
57 int PtyRDFD; /* File descriptor for reading and writing to/from */
58 int PtyWRFD; /* pty interface - only different in debug mode. */
60 bool UseSTDIO; /* Use STDIO for debugging purposes instead of pty */
64 bool RequestTerminate;
67 /* If initialised in debug mode, stdin/out is used instead
68 of ptys for interface. */
69 bool VM_Initialise(char *model,char *port, char *initlength, GSM_ConnectionType connection, char *bindir, bool debug_mode, bool GSMInit,char *synchronizetime)
75 RequestTerminate = false;
77 if (debug_mode == true) {
86 fprintf (stderr , "Initialising GSM\n");
88 if ((VM_GSMInitialise(model, port, initlength, connection, synchronizetime) != GE_NONE)) {
89 fprintf (stderr, _("VM_Initialise - VM_GSMInitialise failed!\n"));
96 if (VM_PtySetup(bindir) < 0) {
97 fprintf (stderr, _("VM_Initialise - VM_PtySetup failed!\n"));
101 if (ATEM_Initialise(PtyRDFD, PtyWRFD, model, port) != true) {
102 fprintf (stderr, _("VM_Initialise - ATEM_Initialise failed!\n"));
106 if (DP_Initialise(PtyRDFD, PtyWRFD) != true) {
107 fprintf (stderr, _("VM_Initialise - DP_Initialise failed!\n"));
111 /* Create and start thread, */
112 rtn = pthread_create(&Thread, NULL, (void *) VM_ThreadLoop, (void *)NULL);
114 if (rtn == EAGAIN || rtn == EINVAL) {
120 void VM_ThreadLoop(void)
125 /* Note we can't use signals here as they are already used
126 in the FBUS code. This may warrant changing the FBUS
127 code around sometime to use select instead to free up
128 the SIGIO handler for mainline code. */
133 while (!RequestTerminate) {
136 } else { /* If we are in data mode, leave it to datapump to get the data */
138 res=poll(&ufds,1,500);
141 case 0: /* Timeout */
145 perror("VM_ThreadLoop - select");
149 if (ufds.revents==POLLIN) {
151 } else usleep(500); /* Probably the file has been closed */
159 /* Application should call VM_Terminate to shut down
160 the virtual modem thread */
161 void VM_Terminate(void)
164 /* Request termination of thread */
165 RequestTerminate = true;
167 /* Now wait for thread to terminate. */
168 pthread_join(Thread, NULL);
176 /* Open pseudo tty interface and (in due course create a symlink
177 to be /dev/gnokii etc. ) */
179 int VM_PtySetup(char *bindir)
182 char mgnokiidev[200];
187 strncpy(mgnokiidev, bindir, 200);
188 strcat(mgnokiidev, "/");
190 strncat(mgnokiidev, "mgnokiidev", 200 - strlen(bindir));
193 PtyRDFD = STDIN_FILENO;
194 PtyWRFD = STDOUT_FILENO;
198 PtyRDFD = VM_GetMasterPty(&slave_name);
200 fprintf (stderr, _("Couldn't open pty!\n"));
205 /* Check we haven't been installed setuid root for some reason
206 if so, don't create /dev/gnokii */
207 if (getuid() != geteuid()) {
208 fprintf(stderr, _("gnokiid should not be installed setuid root!\n"));
213 fprintf (stderr, _("Slave pty is %s, calling %s to create /dev/gnokii.\n"), slave_name, mgnokiidev);
216 /* Create command line, something line ./mkgnokiidev ttyp0 */
217 sprintf(cmdline, "%s %s", mgnokiidev, slave_name);
219 /* And use system to call it. */
220 err = system (cmdline);
226 /* Handler called when characters received from serial port.
227 calls state machine code to process it. */
228 void VM_CharHandler(void)
230 unsigned char buffer[255];
234 /* If we are in command mode, get the character, otherwise leave it */
236 if (CommandMode && ATEM_Initialised) {
238 res = read(PtyRDFD, buffer, 255);
240 /* A returned value of -1 means something serious has gone wrong - so quit!! */
241 /* Note that file closure etc. should have been dealt with in ThreadLoop */
244 // TerminateThread=true;
248 ATEM_HandleIncomingData(buffer, res);
252 /* Initialise GSM interface, returning GSM_Error as appropriate */
253 GSM_Error VM_GSMInitialise(char *model, char *port, char *initlength, GSM_ConnectionType connection, char *synchronizetime)
258 /* Initialise the code for the GSM interface. */
260 error = GSM_Initialise(model,port, initlength, connection, RLP_DisplayF96Frame, synchronizetime);
262 if (error != GE_NONE) {
263 fprintf(stderr, _("GSM/FBUS init failed! (Unknown model ?). Quitting.\n"));
267 /* First (and important!) wait for GSM link to be active. We allow 10
270 while (count++ < 200 && *GSM_LinkOK == false) {
274 if (*GSM_LinkOK == false) {
275 fprintf (stderr, _("Hmmm... GSM_LinkOK never went true. Quitting. \n"));
283 Takes a double-indirect character pointer in which to put a slave
284 name, and returns an integer file descriptor. If it returns < 0, an
285 error has occurred. Otherwise, it has returned the master pty
286 file descriptor, and fills in *name with the name of the
287 corresponding slave pty. Once the slave pty has been opened,
288 you are responsible to free *name. Code is from Developling Linux
289 Applications by Troan and Johnson */
292 int VM_GetMasterPty(char **name) {
294 #ifdef USE_UNIX98PTYS
297 master = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
299 err = grantpt(master);
300 err = err || unlockpt(master);
302 *name = ptsname(master);
307 #else /* USE_UNIX98PTYS */
309 /* default to returning error */
312 /* create a dummy name to fill in */
313 *name = strdup("/dev/ptyXX");
315 /* search for an unused pty */
316 for (i=0; i<16 && master <= 0; i++) {
317 for (j=0; j<16 && master <= 0; j++) {
318 (*name)[8] = "pqrstuvwxyzPQRST"[i];
319 (*name)[9] = "0123456789abcdef"[j];
320 /* open the master pty */
321 if ((master = open(*name, O_RDWR | O_NOCTTY | O_NONBLOCK )) < 0) {
322 if (errno == ENOENT) {
323 /* we are out of pty devices */
330 if ((master < 0) && (i == 16) && (j == 16)) {
331 /* must have tried every pty unsuccessfully */
336 /* By substituting a letter, we change the master pty
337 * name into the slave pty name.
341 #endif /* USE_UNIX98PTYS */