⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unixserial.c

📁 NOKIA手机开发包
💻 C
字号:
/*  $Id: unixserial.c,v 1.36 2004/04/13 08:58:00 pkot Exp $  G N O K I I  A Linux/Unix toolset and driver for Nokia mobile phones.  This file is part of gnokii.  Gnokii is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.  Gnokii is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.  You should have received a copy of the GNU General Public License  along with gnokii; if not, write to the Free Software  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  Copyright (C) 1999, 2000 Hugh Blemings & Pavel Jan韐 ml.*/#include "misc.h"#include "gnokii.h"#include "gnokii-internal.h"/* Do not compile this file under Win32 systems. */#ifndef WIN32#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <limits.h>#include <string.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/wait.h>#include <termios.h>#include "devices/unixserial.h"#ifdef HAVE_SYS_IOCTL_COMPAT_H#  include <sys/ioctl_compat.h>#endif#ifdef HAVE_SYS_SELECT_H#  include <sys/select.h>#endif#ifdef HAVE_SYS_MODEM_H#  include <sys/modem.h>#endif#ifdef HAVE_SYS_FILIO_H#  include <sys/filio.h>#endif/* If the target operating system does not have cfsetspeed, we can emulate   it. */#ifndef HAVE_CFSETSPEED#  if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED)#    define cfsetspeed(t, speed) \	    (cfsetispeed(t, speed) || cfsetospeed(t, speed))#  elsestatic int cfsetspeed(struct termios *t, int speed){#    ifdef HAVE_TERMIOS_CSPEED	t->c_ispeed = speed;	t->c_ospeed = speed;#    else	t->c_cflag |= speed;#    endif			/* HAVE_TERMIOS_CSPEED */	return 0;}#  endif			/* HAVE_CFSETISPEED && HAVE_CFSETOSPEED */#endif				/* HAVE_CFSETSPEED */#ifndef O_NONBLOCK#  define O_NONBLOCK  0#endif/* Structure to backup the setting of the terminal. */struct termios serial_termios;/* Script handling: */static void device_script_cfgfunc(const char *section, const char *key, const char *value){#if !defined(__svr4__)#  if defined(HAVE_SETENV)	setenv(key, value, 1 /* overwrite */); /* errors ignored */#  else	char *str;	asprintf(&str, "%s=%s", key, value);	putenv(str);#  endif#endif}int device_script(int fd, const char *section, struct gn_statemachine *state){	pid_t pid;	const char *scriptname;	int status;	if (!strcmp(section, "connect_script"))		scriptname = state->config.connect_script;	else		scriptname = state->config.disconnect_script;	if (scriptname[0] == '\0')		return 0;	errno = 0;	switch ((pid = fork())) {	case -1:		fprintf(stderr, _("device_script(\"%s\"): fork() failure: %s!\n"), scriptname, strerror(errno));		return -1;	case 0: /* child */		cfg_foreach(gn_cfg_info, section, device_script_cfgfunc);		errno = 0;		if (dup2(fd, 0) != 0 || dup2(fd, 1) != 1 || close(fd)) {			fprintf(stderr, _("device_script(\"%s\"): file descriptor prepare: %s\n"), scriptname, strerror(errno));			_exit(-1);		}		/* FIXME: close all open descriptors - how to track them?		 */		execl("/bin/sh", "sh", "-c", scriptname, NULL);		fprintf(stderr, _("device_script(\"%s\"): execute script: %s\n"), scriptname, strerror(errno));		_exit(-1);		/* NOTREACHED */	default:		if (pid == waitpid(pid, &status, 0 /* options */) && WIFEXITED(status) && !WEXITSTATUS(status))			return 0;		fprintf(stderr, _("device_script(\"%s\"): child script failure: %s, exit code=%d\n"), scriptname,			(WIFEXITED(status) ? _("normal exit") : _("abnormal exit")),			(WIFEXITED(status) ? WEXITSTATUS(status) : -1));		errno = EIO;		return -1;	}	/* NOTREACHED */}int serial_close(int fd, struct gn_statemachine *state);/* Open the serial port and store the settings. */int serial_open(const char *file, int oflag){	int fd;	int retcode;	fd = open(file, oflag);	if (fd == -1) {		perror("Gnokii serial_open: open");		return -1;	}	retcode = tcgetattr(fd, &serial_termios);	if (retcode == -1) {		perror("Gnokii serial_open:tcgetattr");		/* Don't call serial_close since serial_termios is not valid */		close(fd);		return -1;	}	return fd;}/* Close the serial port and restore old settings. */int serial_close(int fd, struct gn_statemachine *state){	/* handle config file disconnect_script:	 */	if (device_script(fd, "disconnect_script", state) == -1)		fprintf(stderr, _("Gnokii serial_close: disconnect_script\n"));	if (fd >= 0) {#if 1 /* HACK */		serial_termios.c_cflag |= HUPCL;	/* production == 1 */#else		serial_termios.c_cflag &= ~HUPCL;	/* debugging  == 0 */#endif		tcsetattr(fd, TCSANOW, &serial_termios);	}	return close(fd);}/* Open a device with standard options. * Use value (-1) for "with_hw_handshake" if its specification is required from the user. */int serial_opendevice(const char *file, int with_odd_parity,		      int with_async, int with_hw_handshake,		      struct gn_statemachine *state){	int fd;	int retcode;	struct termios tp;	/* Open device */	/* O_NONBLOCK MUST be used here as the CLOCAL may be currently off	 * and if DCD is down the "open" syscall would be stuck wating for DCD.	 */	fd = serial_open(file, O_RDWR | O_NOCTTY | O_NONBLOCK);	if (fd < 0) return fd;	/* Initialise the port settings */	memcpy(&tp, &serial_termios, sizeof(struct termios));	/* Set port settings for canonical input processing */	tp.c_cflag = B0 | CS8 | CLOCAL | CREAD | HUPCL;	if (with_odd_parity) {		tp.c_cflag |= (PARENB | PARODD);		tp.c_iflag = 0;	} else		tp.c_iflag = IGNPAR;#ifdef CRTSCTS	if (state->config.hardware_handshake)		tp.c_cflag |= CRTSCTS;	else		tp.c_cflag &= ~CRTSCTS;#endif	tp.c_oflag = 0;	tp.c_lflag = 0;	tp.c_cc[VMIN] = 1;	tp.c_cc[VTIME] = 0;	retcode = tcflush(fd, TCIFLUSH);	if (retcode == -1) {		perror("Gnokii serial_opendevice: tcflush");		serial_close(fd, state);		return -1;	}	retcode = tcsetattr(fd, TCSANOW, &tp);	if (retcode == -1) {		perror("Gnokii serial_opendevice: tcsetattr");		serial_close(fd, state);		return -1;	}	if (serial_changespeed(fd, state->config.serial_baudrate, state) != GN_ERR_NONE)		serial_changespeed(fd, 19200 /* default value */, state);	/* We need to turn off O_NONBLOCK now (we have CLOCAL set so it is safe).	 * When we run some device script it really doesn't expect NONBLOCK!	 */	retcode = fcntl(fd, F_SETFL, 0);	if (retcode == -1) {		perror("Gnokii serial_opendevice: fnctl(F_SETFL)");		serial_close(fd, state);		return -1;	}	/* handle config file connect_script:	 */	if (device_script(fd, "connect_script", state) == -1) {		fprintf(stderr,"Gnokii serial_opendevice: connect_script\n");		serial_close(fd, state);		return -1;	}	/* Allow process/thread to receive SIGIO */#if !(__unices__)	retcode = fcntl(fd, F_SETOWN, getpid());	if (retcode == -1) {		perror("Gnokii serial_opendevice: fnctl(F_SETOWN)");		serial_close(fd, state);		return -1;	}#endif	/* Make filedescriptor asynchronous. */	/* We need to supply FNONBLOCK (or O_NONBLOCK) again as it would get reset	 * by F_SETFL as a side-effect!	 */#ifdef FNONBLOCK	retcode = fcntl(fd, F_SETFL, (with_async ? FASYNC : 0) | FNONBLOCK);#else#  ifdef FASYNC	retcode = fcntl(fd, F_SETFL, (with_async ? FASYNC : 0) | O_NONBLOCK);#  else	retcode = fcntl(fd, F_SETFL, O_NONBLOCK);	if (retcode != -1)		retcode = ioctl(fd, FIOASYNC, &with_async);#  endif#endif	if (retcode == -1) {		perror("Gnokii serial_opendevice: fnctl(F_SETFL)");		serial_close(fd, state);		return -1;	}	return fd;}/* Set the DTR and RTS bit of the serial device. */void serial_setdtrrts(int fd, int dtr, int rts, struct gn_statemachine *state){	unsigned int flags;	flags = TIOCM_DTR;	if (dtr)		ioctl(fd, TIOCMBIS, &flags);	else		ioctl(fd, TIOCMBIC, &flags);	flags = TIOCM_RTS;	if (rts)		ioctl(fd, TIOCMBIS, &flags);	else		ioctl(fd, TIOCMBIC, &flags);}int serial_select(int fd, struct timeval *timeout, struct gn_statemachine *state){	fd_set readfds;	FD_ZERO(&readfds);	FD_SET(fd, &readfds);	return select(fd + 1, &readfds, NULL, NULL, timeout);}static int serial_wselect(int fd, struct timeval *timeout, struct gn_statemachine *state){	fd_set writefds;	FD_ZERO(&writefds);	FD_SET(fd, &writefds);	return select(fd + 1, NULL, &writefds, NULL, timeout);}/* Change the speed of the serial device. * RETURNS: Success */gn_error serial_changespeed(int fd, int speed, struct gn_statemachine *state){	gn_error retcode = GN_ERR_NONE;#ifndef SGTTY	struct termios t;#else	struct sgttyb t;#endif	int new_speed = B9600;	switch (speed) {	case 9600:		new_speed = B9600;		break;	case 19200:		new_speed = B19200;		break;	case 38400:		new_speed = B38400;		break;	case 57600:		new_speed = B57600;		break;	case 115200:		new_speed = B115200;		break;	default:		fprintf(stderr, _("Serial port speed %d not supported!\n"), speed);		return GN_ERR_NOTSUPPORTED;	}#ifndef SGTTY	if (tcgetattr(fd, &t)) retcode = GN_ERR_INTERNALERROR;	if (cfsetspeed(&t, new_speed) == -1) {		dprintf("Serial port speed setting failed\n");		retcode = GN_ERR_INTERNALERROR;	}	tcsetattr(fd, TCSADRAIN, &t);#else	if (ioctl(fd, TIOCGETP, &t)) retcode = GN_ERR_INTERNALERROR;	t.sg_ispeed = new_speed;	t.sg_ospeed = new_speed;	if (ioctl(fd, TIOCSETN, &t)) retcode = GN_ERR_INTERNALERROR;#endif	return retcode;}/* Read from serial device. */size_t serial_read(int fd, __ptr_t buf, size_t nbytes, struct gn_statemachine *state){	return read(fd, buf, nbytes);}#if !defined(TIOCMGET) && defined(TIOCMODG)#  define TIOCMGET TIOCMODG#endifstatic void check_dcd(int fd){#ifdef TIOCMGET	int mcs;	if (ioctl(fd, TIOCMGET, &mcs) || !(mcs & TIOCM_CAR)) {		fprintf(stderr, _("ERROR: Modem DCD is down and global/require_dcd parameter is set!\n"));		exit(EXIT_FAILURE);		/* Hard quit of all threads */	}#else	/* Impossible!! (eg. Coherent) */#endif}/* Write to serial device. */size_t serial_write(int fd, const __ptr_t buf, size_t n, struct gn_statemachine *state){	size_t r = 0, bs;	ssize_t got;#ifndef TIOCMGET	if (state->config.require_dcd)		fprintf(stderr, _("WARNING: global/require_dcd argument was set but it is not supported on this system!\n"));#endif	if (state->config.require_dcd)		check_dcd(fd);	while (n > 0) {		bs = (state->config.serial_write_usleep < 0) ? n : 1;		got = write(fd, buf + r, bs);		if (got == 0) {			dprintf("Serial write: oops, zero byte has written!\n");		} else if (got < 0) {			if (errno == EINTR) continue;			if (errno != EAGAIN) {				dprintf("Serial write: write error %d\n", errno);				return -1;			}			dprintf("Serial write: transmitter busy, waiting\n");			serial_wselect(fd, NULL, state);			dprintf("Serial write: transmitter ready\n");			continue;		}		n -= got;		r += got;		if (state->config.serial_write_usleep > 0)			usleep(state->config.serial_write_usleep);	}	return r;}gn_error serial_nreceived(int fd, int *n, struct gn_statemachine *state){	if (ioctl(fd, FIONREAD, n)) {		dprintf("serial_nreceived: cannot get the received data size\n");		return GN_ERR_INTERNALERROR;	}	return GN_ERR_NONE;}gn_error serial_flush(int fd, struct gn_statemachine *state){	if (tcdrain(fd)) {		dprintf("serial_flush: cannot flush serial device\n");		return GN_ERR_INTERNALERROR;	}	return GN_ERR_NONE;}#endif /* WIN32 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -