📄 nativeserial_darwin.cpp
字号:
//$Id: NativeSerial_darwin.cpp,v 1.1 2007/06/07 07:22:18 klueska Exp $/* "Copyright (c) 2000-2003 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement * is hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY * OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." *///@author Cory Sharp <cssharp@eecs.berkeley.edu>#include <stdexcept>#include <sstream>#include <iostream>#include <fstream>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <termios.h>#include <signal.h>#include <errno.h>#include "NativeSerialEnums.h"using namespace NativeSerialEnums;class comm_port_error : public std::runtime_error{ public: comm_port_error( const char* msg ): std::runtime_error(msg) { }};class NativeSerial{public: typedef std::string String;private: std::string m_portname; int m_fd; int m_events_in; int m_events_out; bool m_wait_for_events;protected: void note( std::string s ) { //std::cout << "NativeSerial_linux " << m_portname << ": " << s << std::endl; } String cat( const char* prefix, const String& err ) { return (prefix == NULL ? "" : String(prefix)+": ") + err; } void errno_wrap( bool error, const char* extra_err = NULL ) { if( error && (errno != 0) ) throw comm_port_error( cat(extra_err, strerror(errno)).c_str() ); } void block_on_read( bool block ) {note( "block_on_read begin" ); fcntl( m_fd, F_SETFL, (block ? 0 : FNDELAY) );note( "block_on_read end" ); } struct termios get_comm_state() {note( "get_comm_state begin" ); struct termios options; errno_wrap( tcgetattr( m_fd, &options ) == -1, "get_comm_state" );note( "get_comm_state end" ); return options; } int get_modem_status() {note( "get_modem_status begin" ); int status = 0; errno_wrap( ioctl( m_fd, TIOCMGET, &status ) == -1, "get_modem_status" );note( "get_modem_status end" ); return status; } void set_modem_status( int status ) {note( "set_modem_status begin" ); errno_wrap( ioctl( m_fd, TIOCMSET, &status ) == -1, "set_modem_status" );note( "set_modem_status end" ); } int baud_to_enum( int baud ) { switch( baud ) { case 0: return B0; case 50: return B50; case 75: return B75; case 110: return B110; case 134: return B134; case 150: return B150; case 200: return B200; case 300: return B300; case 600: return B600; case 1200: return B1200; case 1800: return B1800; case 2400: return B2400; case 4800: return B4800; case 9600: return B9600; case 19200: return B19200; case 38400: return B38400; case 57600: return B57600; case 115200: return B115200; case 230400: return B230400; } throw comm_port_error("baud_to_enum, bad baud rate"); } int enum_to_baud( int baudenum ) { switch( baudenum ) { case B0: return 0; case B50: return 50; case B75: return 75; case B110: return 110; case B134: return 134; case B150: return 150; case B200: return 200; case B300: return 300; case B600: return 600; case B1200: return 1200; case B1800: return 1800; case B2400: return 2400; case B4800: return 4800; case B9600: return 9600; case B19200: return 19200; case B38400: return 38400; case B57600: return 57600; case B115200: return 115200; case B230400: return 230400; } throw comm_port_error("enum_to_baud, bad baud rate"); }/* static DWORD map_events_to_win32( int event ) { DWORD ev = 0; if( event & DATA_AVAILABLE ) ev |= EV_RXCHAR; if( event & OUTPUT_EMPTY ) ev |= EV_TXEMPTY; if( event & CTS ) ev |= EV_CTS; if( event & DSR ) ev |= EV_DSR; if( event & RING_INDICATOR ) ev |= EV_RING; if( event & CARRIER_DETECT ) ev |= EV_RLSD; if( event & OVERRUN_ERROR ) ev |= EV_ERR; if( event & PARITY_ERROR ) ev |= EV_ERR; if( event & FRAMING_ERROR ) ev |= EV_ERR; if( event & BREAK_INTERRUPT ) ev |= EV_BREAK; return ev; } static int map_events_from_win32( DWORD ev, DWORD errors ) { int event = 0; if( ev & EV_RXCHAR ) event |= DATA_AVAILABLE; if( ev & EV_TXEMPTY ) event |= OUTPUT_EMPTY; if( ev & EV_CTS ) event |= CTS; if( ev & EV_DSR ) event |= DSR; if( ev & EV_RING ) event |= RING_INDICATOR; if( ev & EV_RLSD ) event |= CARRIER_DETECT; if( ev & EV_ERR ) { if( errors & CE_BREAK ) event |= BREAK_INTERRUPT; if( errors & CE_FRAME ) event |= FRAMING_ERROR; if( errors & CE_IOE ) throw comm_port_error("Win32 Comm IO Error"); if( errors & CE_MODE ) throw comm_port_error("Win32 Comm Invalid Mode"); if( errors & CE_OVERRUN ) event |= OVERRUN_ERROR; if( errors & CE_RXOVER ) event |= OVERRUN_ERROR; //?? okay if( errors & CE_RXPARITY ) event |= PARITY_ERROR; if( errors & CE_TXFULL ) event |= OVERRUN_ERROR; //?? okay } if( ev & EV_BREAK ) event |= BREAK_INTERRUPT; return event; }*/public: void setSerialPortParams( int baudrate, int databits, int stopbits, int parity ) {note( "setSerialPortParams begin" ); struct termios state = get_comm_state(); int baudenum = baud_to_enum(baudrate); errno_wrap( cfsetispeed( &state, baudenum ) == -1, "baudrate" ); errno_wrap( cfsetospeed( &state, baudenum ) == -1, "baudrate" ); //throw comm_port_error("nuthin"); state.c_cflag &= ~CSIZE; switch( databits ) { case 5: state.c_cflag |= CS5; break; case 6: state.c_cflag |= CS6; break; case 7: state.c_cflag |= CS7; break; case 8: default: state.c_cflag |= CS8; } if( stopbits == STOPBITS_2 ) state.c_cflag |= CSTOPB; else state.c_cflag &= ~CSTOPB; state.c_cflag |= PARENB; switch( parity ) { case NPARITY_EVEN: state.c_cflag &= ~PARODD; break; case NPARITY_ODD: state.c_cflag |= PARODD; break; case NPARITY_NONE: default: state.c_cflag &= ~PARENB; } errno_wrap( tcsetattr( m_fd, TCSANOW, &state ) == -1, "set_comm_state" );note( "setSerialPortParams end" ); } int getBaudRate() { struct termios state = get_comm_state(); return enum_to_baud( cfgetospeed( &state ) ); } int getDataBits() { switch( get_comm_state().c_cflag & CSIZE ) { case CS5: return 5; case CS6: return 6; case CS7: return 7; case CS8: default: return 8; } } int getStopBits() { int stop = get_comm_state().c_cflag; return (stop & CSTOPB) ? STOPBITS_2 : STOPBITS_1; } int getParity() { int parity = get_comm_state().c_cflag; if( parity & PARENB ) return (parity & PARODD) ? NPARITY_ODD : NPARITY_EVEN; return NPARITY_NONE; } int read( signed char* buffer, int off, int len ) {note( "read begin" ); int nread = ::read( m_fd, buffer+off, len ); errno_wrap( nread == -1, "read" );#if 0printf(" ... read:");for( int i=0; i<nread; i++ ) printf(" %02x",buffer[off+i]&255);printf("\n");#endifnote( "read end" ); return nread; } int write( const signed char* buffer, int off, int len ) {note( "write begin" ); int nwritten = ::write( m_fd, buffer+off, len ); errno_wrap( nwritten == -1, "write" );#if 0printf(" ... wrote:");for( int i=0; i<nwritten; i++ ) printf(" %02x",buffer[off+i]&255);printf("\n");#endifnote( "write end" ); return nwritten; } int read() { signed char byte; return (read(&byte,0,1) > 0) ? ((unsigned char)byte) : -1; } int write( int b ) { signed char byte = b; return write( &byte, 0, 1 ); } int available() {note( "available begin" ); int navail = 0; int rv = 0; errno_wrap( rv=ioctl( m_fd, FIONREAD, &navail ) == -1, "available" );//printf("... fionread=%d, rv=%d\n",navail,rv);note( "available end" ); return navail; } void notifyOn( int event, bool enable ) { if( enable ) m_events_in |= event; else m_events_in &= ~event; } bool isNotifyOn( int event ) { return (m_events_in & event) != 0; } bool waitForEvent() {note( "waitForEvent begin" ); fd_set input; struct timeval tv; m_events_out = 0; while( m_wait_for_events && (m_fd != -1) && (m_events_out == 0) ) { FD_ZERO( &input ); FD_SET( m_fd, &input ); tv.tv_sec = 0; tv.tv_usec = 100*1000; // 1ms is the minimum resolution, at best if( select( m_fd+1, &input, NULL, NULL, &tv ) == -1 ) { if( errno == EINTR ) break; errno_wrap( true, "waitForEvent.select" ); } if( FD_ISSET( m_fd, &input ) ) m_events_out |= DATA_AVAILABLE; } m_wait_for_events = true;note( "waitForEvent end" ); return (m_events_out != 0); } bool cancelWait() {note( "cancelWait begin" ); m_wait_for_events = false;note( "cancelWait end" ); } bool didEventOccur( int event ) { return (m_events_out & event) != 0; } void setDTR( bool high ) { if( high ) set_modem_status( get_modem_status() | TIOCM_DTR ); else set_modem_status( get_modem_status() & ~TIOCM_DTR ); } void setRTS( bool high ) { if( high ) set_modem_status( get_modem_status() | TIOCM_RTS ); else set_modem_status( get_modem_status() & ~TIOCM_RTS ); } bool isDTR() { return (get_modem_status() & TIOCM_DTR) != 0; } bool isRTS() { return (get_modem_status() & TIOCM_RTS) != 0; } bool isCTS() { return (get_modem_status() & TIOCM_CTS) != 0; } bool isDSR() { return (get_modem_status() & TIOCM_DSR) != 0; } bool isRI() { return (get_modem_status() & TIOCM_RI) != 0; } bool isCD() { return (get_modem_status() & TIOCM_CD) != 0; } void sendBreak( int millis ) { } NativeSerial( const char* portname ): m_fd(-1), m_events_in(0), m_events_out(0), m_wait_for_events(true) { m_portname = portname;note( "constructor begin" ); m_fd = open( portname, O_RDWR | O_NOCTTY | O_NONBLOCK ); errno_wrap( m_fd == -1, "open" );//std::cout << "NativeSerial constructor [1] " << portname << std::endl; block_on_read(false); // set default port parmeters struct termios options = get_comm_state(); // disable rts/cts, no parity bits, one stop bit, clear databits mask //local mode, enable receiver, 8 databits options.c_cflag = CLOCAL | CREAD | CS8; //raw mode options.c_lflag = 0; //disable software flow control, etc options.c_iflag = IGNPAR | IGNBRK; //raw output mode options.c_oflag = 0; //set thresholds options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 0; errno_wrap( tcflush( m_fd, TCIOFLUSH ) == -1, "flush" ); errno_wrap( tcsetattr( m_fd, TCSANOW, &options ) == -1, "setattr" ); setDTR(false); setRTS(false);note( "constructor end" ); } ~NativeSerial() {note( "destructor begin" ); close();note( "destructor end" ); } void close() {note( "close begin" );//std::cout << "NativeSerial_linux close fd=" << m_fd << std::endl; if( m_fd != -1 ) { cancelWait(); struct timeval tv = { tv_sec:0, tv_usec:1100 }; select( 0, NULL, NULL, NULL, &tv ); ::close( m_fd ); m_fd = -1; }note( "close end" ); } static std::string getTOSCommMap() { const char* env = getenv( "TOSCOMMMAP" ); return (env == NULL) ? "com1=/dev/ttyS0:usb1=/dev/ttyUSB0" : env; }};#include "TOSComm_wrap.cxx"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -