diff --git a/serial_port/serial_port.cpp b/serial_port/serial_port.cpp index 2ee7aef7..0d11b896 100644 --- a/serial_port/serial_port.cpp +++ b/serial_port/serial_port.cpp @@ -9,43 +9,54 @@ #include "serial_port.h" -//serial_port (constructor) -// The default constructor does not initialize the serial port +/*---------------------------------------------------------*\ +| serial_port (constructor) | +| The default constructor does not initialize the serial | +| port | +\*---------------------------------------------------------*/ serial_port::serial_port() { - //Set a default baud rate + /*-----------------------------------------------------*\ + | Set a default baud rate | + \*-----------------------------------------------------*/ baud_rate = 9600; } -//serial_port (constructor) -// When created with port information, the constructor -// will automatically open port at baud rate +/*---------------------------------------------------------*\ +| serial_port (constructor) | +| When created with port information, the constructor | +| will automatically open port at baud rate | +\*---------------------------------------------------------*/ serial_port::serial_port(const char * name, unsigned int baud) { serial_open(name, baud); } -//~serial_port (destructor) -// Closes the port before destroying the object +/*---------------------------------------------------------*\ +| ~serial_port (destructor) | +| Closes the port before destroying the object | +\*---------------------------------------------------------*/ serial_port::~serial_port() { serial_close(); } -//open -// Opens the serial port using stored information -// Sets the baud rate to the stored baud rate -// 8 data bits, no parity, one stop bit +/*---------------------------------------------------------*\ +| serial_open | +| Opens the serial port using stored information | +| Sets the baud rate to the stored baud rate | +| 8 data bits, no parity, one stop bit | +\*---------------------------------------------------------*/ bool serial_port::serial_open() { -// printf("SerialPort: Opening serial port %s at baud rate %d.\n", port_name, baud_rate); - + /*-----------------------------------------------------*\ + | Windows-specific code path for serial port opening | + \*-----------------------------------------------------*/ #ifdef _WIN32 file_descriptor = CreateFile(port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if((int)file_descriptor < 0) { -// printf("SerialPort: Port %s could not be opened: %d.\n", port_name, file_descriptor); return false; } @@ -73,16 +84,16 @@ bool serial_port::serial_open() timeouts.WriteTotalTimeoutConstant=50; timeouts.WriteTotalTimeoutMultiplier=10; SetCommTimeouts(file_descriptor, &timeouts); +#endif -#endif /* _WIN32 */ - + /*-----------------------------------------------------*\ + | Linux-specific code path for serial port opening | + \*-----------------------------------------------------*/ #ifdef __linux__ - file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY); if(file_descriptor < 0) { -// printf("SerialPort: Port %s could not be opened: %d.\n", port_name, file_descriptor); return false; } @@ -91,55 +102,97 @@ bool serial_port::serial_open() options.c_cflag &= ~CBAUD; options.c_cflag |= BOTHER; options.c_lflag &= ~ICANON; - options.c_lflag &= ~ECHO; // Disable echo - options.c_lflag &= ~ECHOE; // Disable erasure - options.c_lflag &= ~ECHONL; // Disable new-line echo - options.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP - options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl + options.c_lflag &= ~ECHO; // Disable echo + options.c_lflag &= ~ECHOE; // Disable erasure + options.c_lflag &= ~ECHONL; // Disable new-line echo + options.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP + options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl options.c_ispeed = baud_rate; options.c_ospeed = baud_rate; - options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes + options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes ioctl(file_descriptor, TCSETS2, &options); +#endif - //serial_struct ss; - //int closestSpeed; - //ioctl(file_descriptor, TIOCGSERIAL, &ss); - //ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST | ASYNCB_LOW_LATENCY; - //ss.custom_divisor = (ss.baud_base + (baud_rate / 2)) / baud_rate; - //if(ss.custom_divisor == 0) - //{ - // closestSpeed = baud_rate; - //} - //else - //{ - // closestSpeed = ss.baud_base / ss.custom_divisor; - //} + /*-----------------------------------------------------*\ + | MacOS-specific code path for serial port opening | + \*-----------------------------------------------------*/ +#ifdef __APPLE__ + file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY); - //if((float)closestSpeed < ((float)baud_rate * (98.0f/100.0f)) || (float)closestSpeed > ((float)baud_rate * (102.0f/100.0f))) - //{ -// printf("SerialPort: Cannot set %s to %d. Closest possible speed is %d.\n", port_name, baud_rate, closestSpeed); - //} - //else - //{ -// printf("SerialPort: %s speed set to %d.\n", port_name, baud_rate); - //} + if(file_descriptor < 0) + { + return false; + } - //fcntl(file_descriptor, F_SETFL, 0); -#endif /* __linux__ */ + struct termios options; + tcgetattr(file_descriptor, &options); + switch(baud_rate) + { + case 9600: + cfsetispeed(&options, B9600); + cfsetospeed(&options, B9600); + break; + case 19200: + cfsetispeed(&options, B19200); + cfsetospeed(&options, B19200); + break; + case 115200: + cfsetispeed(&options, B115200); + cfsetospeed(&options, B115200); + break; + case 38400: + cfsetispeed(&options, B38400); + cfsetospeed(&options, B38400); + break; + case 57600: + cfsetispeed(&options, B57600); + cfsetospeed(&options, B57600); + break; + default: + cfsetispeed(&options, B9600); + cfsetospeed(&options, B9600); + break; + } -// printf("SerialPort: Serial port %s opened successfully.\n", port_name); + /*-----------------------------------------------------*\ + | Configure other settings | + \*-----------------------------------------------------*/ + options.c_iflag &= ~(INLCR | ICRNL); + options.c_iflag |= IGNPAR | IGNBRK; + options.c_oflag &= ~(OPOST | ONLCR | OCRNL); + options.c_cflag &= ~(PARENB | PARODD | CSTOPB | CSIZE | CRTSCTS); + options.c_cflag |= CLOCAL | CREAD | CS8; + options.c_lflag &= ~(ICANON | ISIG | ECHO); + options.c_cc[VTIME] = 1; + options.c_cc[VMIN] = 0; + + if(tcsetattr(file_descriptor, TCSANOW, &options) < 0) + { + close(file_descriptor); + return false; + } +#endif + + /*-----------------------------------------------------*\ + | Return true if successful | + \*-----------------------------------------------------*/ return true; } -//open -// Opens the serial port without changing stored baud rate +/*---------------------------------------------------------*\ +| serial_open | +| Opens the serial port without changing stored | +| baud rate | +\*---------------------------------------------------------*/ bool serial_port::serial_open(const char * name) { return serial_open(name, baud_rate); } -//open -// Opens the serial port at baud rate +/*---------------------------------------------------------*\ +| serial_open | +| Opens the serial port at baud rate | +\*---------------------------------------------------------*/ bool serial_port::serial_open(const char* name, unsigned int baud) { strcpy(port_name, name); @@ -147,106 +200,155 @@ bool serial_port::serial_open(const char* name, unsigned int baud) return serial_open(); } -//close -// Closes the serial port +/*---------------------------------------------------------*\ +| serial_close | +| Closes the serial port | +\*---------------------------------------------------------*/ void serial_port::serial_close() { -// printf("SerialPort: Closing port %s.\n", port_name); + /*-----------------------------------------------------*\ + | Windows-specific code path for serial close | + \*-----------------------------------------------------*/ #ifdef _WIN32 -#endif /* _WIN32 */ +#endif + /*-----------------------------------------------------*\ + | Linux-specific code path for serial close | + \*-----------------------------------------------------*/ #ifdef __linux__ - close(file_descriptor); +#endif -#endif /* __linux__ */ + /*-----------------------------------------------------*\ + | MacOS-specific code path for serial close | + \*-----------------------------------------------------*/ +#ifdef __APPLE__ + close(file_descriptor); +#endif } -// read -// Reads bytes from the serial port into -// Returns the number of bytes actually read -// If less than bytes are available, it will read all -// available bytes +/*---------------------------------------------------------*\ +| serial_read | +| Reads bytes from the serial port into | +| Returns the number of bytes actually read | +| If less than bytes are available, it will read| +| all available bytes | +\*---------------------------------------------------------*/ int serial_port::serial_read(char * buffer, int length) { + /*-----------------------------------------------------*\ + | Windows-specific code path for serial read | + \*-----------------------------------------------------*/ #ifdef _WIN32 - DWORD bytesread; ReadFile(file_descriptor, buffer, length, &bytesread, NULL); return bytesread; +#endif -#endif /* _WIN32 */ - + /*-----------------------------------------------------*\ + | Linux-specific code path for serial read | + \*-----------------------------------------------------*/ #ifdef __linux__ - int bytesread; bytesread = read(file_descriptor, buffer, length); return bytesread; +#endif -#endif /* __linux__ */ + /*-----------------------------------------------------*\ + | MacOS-specific code path for serial read | + \*-----------------------------------------------------*/ +#ifdef __APPLE__ + int bytesread; + bytesread = read(file_descriptor, buffer, length); + return bytesread; +#endif - //printf("SerialPort: Read %d bytes on port %s.\n", bytesread, port_name); + /*-----------------------------------------------------*\ + | Return 0 on unsupported platforms | + \*-----------------------------------------------------*/ return 0; } -//write -// Writes bytes to the serial port from -// Returns the number of bytes actually written -// Does not check for null-termination, so if is -// greater than the number of bytes in , it will read -// past and may cause a segfault +/*---------------------------------------------------------*\ +| serial_write | +| Writes bytes to the serial port from | +| Returns the number of bytes actually written | +| Does not check for null-termination, so if is | +| greater than the number of bytes in , it will | +| read past and may cause a segfault | +\*---------------------------------------------------------*/ int serial_port::serial_write(char * buffer, int length) { + /*-----------------------------------------------------*\ + | Windows-specific code path for serial write | + \*-----------------------------------------------------*/ #ifdef _WIN32 - DWORD byteswritten; WriteFile(file_descriptor, buffer, length, &byteswritten, NULL); return byteswritten; +#endif -#endif /* _WIN32 */ - + /*-----------------------------------------------------*\ + | Linux-specific code path for serial write | + \*-----------------------------------------------------*/ #ifdef __linux__ - int byteswritten; tcdrain(file_descriptor); byteswritten = write(file_descriptor, buffer, length); tcdrain(file_descriptor); return byteswritten; +#endif -#endif /* __linux__ */ + /*-----------------------------------------------------*\ + | MacOS-specific code path for serial write | + \*-----------------------------------------------------*/ +#ifdef __APPLE__ + int byteswritten; + tcdrain(file_descriptor); + byteswritten = write(file_descriptor, buffer, length); + tcdrain(file_descriptor); + return byteswritten; +#endif - //printf("SerialPort: Wrote %d bytes on port %s.\n", byteswritten, port_name); + /*-----------------------------------------------------*\ + | Return 0 on unsupported platforms | + \*-----------------------------------------------------*/ return 0; } -//flush +/*---------------------------------------------------------*\ +| serial_flush | +\*---------------------------------------------------------*/ void serial_port::serial_flush_rx() { #ifdef _WIN32 - PurgeComm(file_descriptor, PURGE_RXABORT | PURGE_RXCLEAR); - -#endif /* _WIN32 */ +#endif #ifdef __linux__ - tcflush(file_descriptor, TCIFLUSH); +#endif -#endif /* __linux__ */ +#ifdef __APPLE__ + tcflush(file_descriptor, TCIFLUSH); +#endif } +/*---------------------------------------------------------*\ +| serial_flush_tx | +\*---------------------------------------------------------*/ void serial_port::serial_flush_tx() { #ifdef _WIN32 - PurgeComm(file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR); - -#endif /* _WIN32 */ +#endif #ifdef __linux__ - tcflush(file_descriptor, TCOFLUSH); +#endif -#endif /* __linux__ */ +#ifdef __APPLE__ + tcflush(file_descriptor, TCOFLUSH); +#endif } diff --git a/serial_port/serial_port.h b/serial_port/serial_port.h index 218d340a..2342f380 100644 --- a/serial_port/serial_port.h +++ b/serial_port/serial_port.h @@ -49,57 +49,57 @@ #endif /* __linux__ */ +#ifdef __APPLE__ -//Serial Port Class -//The reason for this class is that serial ports are treated differently -//on Windows and Linux. By creating a class, those differences can be -//made invisible to the program and make cross-platform usage easy +#include +#include +#include +#include +#endif /* __APPLE__ */ + +/*-------------------------------------------------------------------------*\ +| Serial Port Class | +| The reason for this class is that serial ports are treated differently | +| on Windows and Linux. By creating a class, those differences can be | +| made invisible to the program and make cross-platform usage easy | +\*-------------------------------------------------------------------------*/ class serial_port { - public: - serial_port(); - serial_port(const char * name, unsigned int baud); +public: + serial_port(); + serial_port(const char * name, unsigned int baud); - ~serial_port(); + ~serial_port(); - //Function to open the port - bool serial_open(); - bool serial_open(const char* name); - bool serial_open(const char* name, unsigned int baud); + bool serial_open(); + bool serial_open(const char* name); + bool serial_open(const char* name, unsigned int baud); - //Function to close the port - void serial_close(); + void serial_close(); - //Functions for controlling baud rate - void serial_set_baud(unsigned int baud); - int serial_get_baud(); + void serial_set_baud(unsigned int baud); + int serial_get_baud(); - //Function to read data from the port buffer - int serial_read(char * buffer, int length); + int serial_read(char * buffer, int length); - //Function to write data to the serial port - int serial_write(char * buffer, int length); + int serial_write(char * buffer, int length); - //Functions to flush the serial port rx and tx buffers - void serial_flush_rx(); - void serial_flush_tx(); + void serial_flush_rx(); + void serial_flush_tx(); - //Function to list the number of available bytes - int serial_available(); + int serial_available(); - private: - char port_name[1024]; - unsigned int baud_rate; +private: + char port_name[1024]; + unsigned int baud_rate; - #ifdef WIN32 - HANDLE file_descriptor; - DCB dcb; - - #else - - int file_descriptor; - #endif +#ifdef _WIN32 + HANDLE file_descriptor; + DCB dcb; +#else + int file_descriptor; +#endif }; #endif