Esempio n. 1
0
File: serial.c Progetto: biiont/gpsd
int gpsd_serial_open(struct gps_device_t *session)
/* open a device for access to its data */
{
    mode_t mode = (mode_t) O_RDWR;

    session->sourcetype = gpsd_classify(session->gpsdata.dev.path);
    session->servicetype = service_sensor;

    /*@ -boolops -type @*/
    if (session->context->readonly
	|| (session->sourcetype <= source_blockdev)) {
	mode = (mode_t) O_RDONLY;
	gpsd_report(LOG_INF,
		    "opening read-only GPS data source type %d and at '%s'\n",
		    (int)session->sourcetype, session->gpsdata.dev.path);
    } else {
	gpsd_report(LOG_INF,
		    "opening GPS data source type %d at '%s'\n",
		    (int)session->sourcetype, session->gpsdata.dev.path);
    }
    /*@ +boolops +type @*/
#ifdef HAVE_BLUEZ
    if (bachk(session->gpsdata.dev.path) == 0) {
        session->gpsdata.gps_fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
        struct sockaddr_rc addr = { 0 };
        addr.rc_family = AF_BLUETOOTH;
        addr.rc_channel = (uint8_t) 1;
        str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr);
        if (connect(session->gpsdata.gps_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
	    if (errno != EINPROGRESS && errno != EAGAIN) {
		gpsd_report(LOG_ERROR, "bluetooth socket connect failed: %s\n",
			    strerror(errno));
		return -1;
	    }
	    gpsd_report(LOG_ERROR, "bluetooth socket connect in progress or again : %s\n",
			strerror(errno));
        }
	(void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode | O_NONBLOCK);
	gpsd_report(LOG_PROG, "bluez device open success: %s %s\n",
		    session->gpsdata.dev.path, strerror(errno));
    } else 
#endif /* BLUEZ */
    {
        if ((session->gpsdata.gps_fd =
	     open(session->gpsdata.dev.path,
		      (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) {
            gpsd_report(LOG_ERROR,
			    "device open failed: %s - retrying read-only\n",
			    strerror(errno));
	    if ((session->gpsdata.gps_fd =
		 open(session->gpsdata.dev.path,
			  O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) {
		gpsd_report(LOG_ERROR, "read-only device open failed: %s\n",
				strerror(errno));
		return -1;
	    }
	    gpsd_report(LOG_PROG, "file device open success: %s\n",
			strerror(errno));
	}
    }

    /*
     * Ideally we want to exclusion-lock the device before doing any reads.
     * It would have been best to do this at open(2) time, but O_EXCL
     * doesn't work wuthout O_CREAT.
     *
     * We have to make an exception for ptys, which are intentionally
     * opened by another process on the master side, otherwise we'll
     * break all our regression tests.
     */
    if (session->sourcetype != source_pty) {
	/*
	 * Try to block other processes from using this device while we
	 * have it open (later opens should return EBUSY).  Won't work
	 * against anything with root privileges, alas.
	 */
	(void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL);

#ifdef __linux__
	/*
	 * Don't touch devices already opened by another process.
	 */
	if (fusercount(session->gpsdata.dev.path) > 1) {
            gpsd_report(LOG_ERROR, 
			"%s already opened by another process\n",
			session->gpsdata.dev.path);
	    (void)close(session->gpsdata.gps_fd);
	    session->gpsdata.gps_fd = -1;
	    return -1;
	}
#endif /* __linux__ */
    }

#ifdef FIXED_PORT_SPEED
    session->saved_baud = FIXED_PORT_SPEED;
#endif

    if (session->saved_baud != -1) {
	/*@i@*/ (void)
	    cfsetispeed(&session->ttyset, (speed_t) session->saved_baud);
	/*@i@*/ (void)
	    cfsetospeed(&session->ttyset, (speed_t) session->saved_baud);
	(void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset);
	(void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
    }

    session->packet.type = BAD_PACKET;
    if (isatty(session->gpsdata.gps_fd) != 0) {
	/* Save original terminal parameters */
	if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0)
	    return -1;
	(void)memcpy(&session->ttyset,
		     &session->ttyset_old, sizeof(session->ttyset));
	/*
	 * Only block until we get at least one character, whatever the
	 * third arg of read(2) says.
	 */
	/*@ ignore @*/
	memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc));
	session->ttyset.c_cc[VMIN] = 1;
	/*@ end @*/
	/*
	 * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav
	 * 200 (and possibly other USB GPSes) gets completely hosed
	 * in the presence of flow control.  Thus, turn off CRTSCTS.
	 */
	session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS);
	session->ttyset.c_cflag |= CREAD | CLOCAL;
	session->ttyset.c_iflag = session->ttyset.c_oflag =
	    session->ttyset.c_lflag = (tcflag_t) 0;

#ifndef FIXED_PORT_SPEED
	session->baudindex = 0;
#endif /* FIXED_PORT_SPEED */
	gpsd_set_speed(session, gpsd_get_speed(&session->ttyset_old), 'N', 1);
    }
    gpsd_report(LOG_SPIN, "open(%s) -> %d in gpsd_serial_open()\n",
		session->gpsdata.dev.path, session->gpsdata.gps_fd);
    return session->gpsdata.gps_fd;
}
Esempio n. 2
0
int gpsd_serial_open(struct gps_device_t *session)
/* open a device for access to its data
 * return: the opened file descriptor
 *         PLACEHOLDING_FD - for /dev/ppsX
 *         UNALLOCATED_FD - for open failure
 */

{
    mode_t mode = (mode_t) O_RDWR;

    session->sourcetype = gpsd_classify(session->gpsdata.dev.path);
    session->servicetype = service_sensor;

    /* we may need to hold on to this slot without opening the device */
    if (source_pps == session->sourcetype) {
	(void)gpsd_switch_driver(session, "PPS");
	return PLACEHOLDING_FD;
    }

    if (session->context->readonly
	|| (session->sourcetype <= source_blockdev)) {
	mode = (mode_t) O_RDONLY;
	gpsd_log(&session->context->errout, LOG_INF,
		 "opening read-only GPS data source type %d and at '%s'\n",
		 (int)session->sourcetype, session->gpsdata.dev.path);
    } else {
	gpsd_log(&session->context->errout, LOG_INF,
		 "opening GPS data source type %d at '%s'\n",
		 (int)session->sourcetype, session->gpsdata.dev.path);
    }
#ifdef ENABLE_BLUEZ
    if (bachk(session->gpsdata.dev.path) == 0) {
        struct sockaddr_rc addr = { 0, *BDADDR_ANY, 0};
        session->gpsdata.gps_fd = socket(AF_BLUETOOTH,
					 SOCK_STREAM,
					 BTPROTO_RFCOMM);
        addr.rc_family = AF_BLUETOOTH;
        addr.rc_channel = (uint8_t) 1;
        (void) str2ba(session->gpsdata.dev.path, &addr.rc_bdaddr);
        if (connect(session->gpsdata.gps_fd, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
	    if (errno != EINPROGRESS && errno != EAGAIN) {
		(void)close(session->gpsdata.gps_fd);
		gpsd_log(&session->context->errout, LOG_ERROR,
			 "bluetooth socket connect failed: %s\n",
			 strerror(errno));
		return UNALLOCATED_FD;
	    }
	    gpsd_log(&session->context->errout, LOG_ERROR,
		     "bluetooth socket connect in progress or again : %s\n",
		     strerror(errno));
        }
	(void)fcntl(session->gpsdata.gps_fd, F_SETFL, (int)mode);
	gpsd_log(&session->context->errout, LOG_PROG,
		 "bluez device open success: %s %s\n",
		 session->gpsdata.dev.path, strerror(errno));
    } else
#endif /* BLUEZ */
    {
	/*
	 * We open with O_NONBLOCK because we want to now get hung if
	 * the clocal flag is off, but we don't want to stay in that mode.
	 */
        if ((session->gpsdata.gps_fd =
	     open(session->gpsdata.dev.path, (int)(mode | O_NONBLOCK | O_NOCTTY))) == -1) {
            gpsd_log(&session->context->errout, LOG_ERROR,
		     "device open of %s failed: %s - retrying read-only\n",
		     session->gpsdata.dev.path,
		     strerror(errno));
	    if ((session->gpsdata.gps_fd =
		 open(session->gpsdata.dev.path, O_RDONLY | O_NONBLOCK | O_NOCTTY)) == -1) {
		gpsd_log(&session->context->errout, LOG_ERROR,
			 "read-only device open of %s failed: %s\n",
			 session->gpsdata.dev.path,
			 strerror(errno));
		return UNALLOCATED_FD;
	    }

	    gpsd_log(&session->context->errout, LOG_PROG,
		     "file device open of %s succeeded: %s\n",
		     session->gpsdata.dev.path,
		     strerror(errno));
	}
    }

    /*
     * Ideally we want to exclusion-lock the device before doing any reads.
     * It would have been best to do this at open(2) time, but O_EXCL
     * doesn't work without O_CREAT.
     *
     * We have to make an exception for ptys, which are intentionally
     * opened by another process on the master side, otherwise we'll
     * break all our regression tests.
     *
     * We also exclude bluetooth device because the bluetooth daemon opens them.
     */
    if (!(session->sourcetype == source_pty || session->sourcetype == source_bluetooth)) {
#ifdef TIOCEXCL
	/*
	 * Try to block other processes from using this device while we
	 * have it open (later opens should return EBUSY).  Won't work
	 * against anything with root privileges, alas.
	 */
	(void)ioctl(session->gpsdata.gps_fd, (unsigned long)TIOCEXCL);
#endif /* TIOCEXCL */

#ifdef __linux__
	/*
	 * Don't touch devices already opened by another process.
	 */
	if (fusercount(session->gpsdata.dev.path) > 1) {
            gpsd_log(&session->context->errout, LOG_ERROR,
		     "%s already opened by another process\n",
		     session->gpsdata.dev.path);
	    (void)close(session->gpsdata.gps_fd);
	    session->gpsdata.gps_fd = UNALLOCATED_FD;
	    return UNALLOCATED_FD;
	}
#endif /* __linux__ */
    }

#ifdef FIXED_PORT_SPEED
    session->saved_baud = FIXED_PORT_SPEED;
#endif

    if (session->saved_baud != -1) {
	(void)cfsetispeed(&session->ttyset, (speed_t)session->saved_baud);
	(void)cfsetospeed(&session->ttyset, (speed_t)session->saved_baud);
	(void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset);
	(void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH);
    }

    session->lexer.type = BAD_PACKET;
    if (isatty(session->gpsdata.gps_fd) != 0) {
	/* Save original terminal parameters */
	if (tcgetattr(session->gpsdata.gps_fd, &session->ttyset_old) != 0)
	    return UNALLOCATED_FD;
	session->ttyset = session->ttyset_old;
	memset(session->ttyset.c_cc, 0, sizeof(session->ttyset.c_cc));
	//session->ttyset.c_cc[VTIME] = 1;
	/*
	 * Tip from Chris Kuethe: the FIDI chip used in the Trip-Nav
	 * 200 (and possibly other USB GPSes) gets completely hosed
	 * in the presence of flow control.  Thus, turn off CRTSCTS.
	 *
	 * This is not ideal.  Setting no parity here will mean extra
	 * initialization time for some devices, like certain Trimble
	 * boards, that want 7O2 or other non-8N1 settings. But starting
	 * the hunt loop at 8N1 will minimize the average sync time
	 * over all devices.
	 */
	session->ttyset.c_cflag &= ~(PARENB | PARODD | CRTSCTS | CSTOPB);
	session->ttyset.c_cflag |= CREAD | CLOCAL;
	session->ttyset.c_iflag = session->ttyset.c_oflag =
	    session->ttyset.c_lflag = (tcflag_t) 0;

#ifndef FIXED_PORT_SPEED
	session->baudindex = 0;
#endif /* FIXED_PORT_SPEED */
	gpsd_set_speed(session,
#ifdef FIXED_PORT_SPEED
		       FIXED_PORT_SPEED,
#else
		       gpsd_get_speed_old(session),
#endif /* FIXED_PORT_SPEED */
		       'N',
#ifdef FIXED_STOP_BITS
		       FIXED_STOP_BITS
#else
		       1
#endif /* FIXED_STOP_BITS */
	    );
    }

    /* Switch back to blocking I/O now that CLOCAL is set. */
    {
	int oldfl = fcntl(session->gpsdata.gps_fd, F_GETFL);
	if (oldfl != -1)
	    (void)fcntl(session->gpsdata.gps_fd, F_SETFL, oldfl & ~O_NONBLOCK);
    }


    /* required so parity field won't be '\0' if saved speed matches */
    if (session->sourcetype <= source_blockdev) {
	session->gpsdata.dev.parity = 'N';
	session->gpsdata.dev.stopbits = 1;
    }

    gpsd_log(&session->context->errout, LOG_SPIN,
	     "open(%s) -> %d in gpsd_serial_open()\n",
	     session->gpsdata.dev.path, session->gpsdata.gps_fd);
    return session->gpsdata.gps_fd;
}