// HardwareSerial.cpp // // Copyright (C) 2015 Mike McCauley // $Id: HardwareSerial.cpp,v 1.3 2015/08/13 02:45:47 mikem Exp mikem $ #include #if (RH_PLATFORM == RH_PLATFORM_UNIX) #include #include #include #include #include #include #include #include HardwareSerial::HardwareSerial(const char* deviceName) : _deviceName(deviceName), _device(-1) { // Override device name from environment char* e = getenv("RH_HARDWARESERIAL_DEVICE_NAME"); if (e) _deviceName = e; } void HardwareSerial::begin(int baud) { if (openDevice()) setBaud(baud); } void HardwareSerial::end() { closeDevice(); } void HardwareSerial::flush() { tcdrain(_device); } int HardwareSerial::peek(void) { printf("HardwareSerial::peek not implemented\n"); return 0; } int HardwareSerial::available() { int bytes; if (ioctl(_device, FIONREAD, &bytes) != 0) { fprintf(stderr, "HardwareSerial::available ioctl failed: %s\n", strerror(errno)); return 0; } return bytes; } int HardwareSerial::read() { uint8_t data; ssize_t result = ::read(_device, &data, 1); if (result != 1) { fprintf(stderr, "HardwareSerial::read read failed: %s\n", strerror(errno)); return 0; } // printf("got: %02x\n", data); return data; } size_t HardwareSerial::write(uint8_t ch) { size_t result = ::write(_device, &ch, 1); if (result != 1) { fprintf(stderr, "HardwareSerial::write failed: %s\n", strerror(errno)); return 0; } // printf("sent: %02x\n", ch); return 1; // OK } bool HardwareSerial::openDevice() { if (_device == -1) closeDevice(); _device = open(_deviceName, O_RDWR | O_NOCTTY | O_NDELAY); if (_device == -1) { // Could not open the port. fprintf(stderr, "HardwareSerial::openDevice could not open %s: %s\n", _deviceName, strerror(errno)); return false; } // Device opened fcntl(_device, F_SETFL, 0); return true; } bool HardwareSerial::closeDevice() { if (_device != -1) close(_device); _device = -1; return true; } bool HardwareSerial::setBaud(int baud) { speed_t speed; // This is kind of ugly, but its prob better than a case if (baud == 50) speed = B50; else if (baud == 75) speed = B75; else if (baud == 110) speed = B110; else if (baud == 134) speed = B134; else if (baud == 150) speed = B150; else if (baud == 200) speed = B200; else if (baud == 300) speed = B300; else if (baud == 600) speed = B600; else if (baud == 1200) speed = B1200; else if (baud == 1800) speed = B1800; else if (baud == 2400) speed = B2400; else if (baud == 4800) speed = B4800; else if (baud == 9600) speed = B9600; else if (baud == 19200) speed = B19200; else if (baud == 38400) speed = B38400; else if (baud == 57600) speed = B57600; #ifdef B76800 else if (baud == 76800) // Not available on Linux speed = B76800; #endif else if (baud == 115200) speed = B115200; else if (baud == 230400) speed = B230400; #ifdef B460800 else if (baud == 460800) // Not available on OSX speed = B460800; #endif #ifdef B921600 else if (baud == 921600) // Not available on OSX speed = B921600; #endif else { fprintf(stderr, "HardwareSerial::setBaud: unsupported baud rate %d\n", baud); return false; } struct termios options; // Get current options if (tcgetattr(_device, &options) != 0) { fprintf(stderr, "HardwareSerial::setBaud: could not tcgetattr %s\n", strerror(errno)); return false; } // Set new speed options cfsetispeed(&options, speed); cfsetospeed(&options, speed); // Enable the receiver and set local mode... options.c_cflag |= (CLOCAL | CREAD); // Force mode to 8,N,1 // to be compatible with Arduino HardwareSerial // Should this be configurable? Prob not, must have 8 bits, dont need parity. options.c_cflag &= ~(PARENB | CSTOPB | CSIZE); options.c_cflag |= CS8; // Disable flow control and input character conversions options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | INLCR); // Raw input: options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Raw output options.c_oflag &= ~(OPOST | OCRNL | ONLCR); // Set the options in the port if (tcsetattr(_device, TCSANOW, &options) != 0) { fprintf(stderr, "HardwareSerial::setBaud: could not tcsetattr %s\n", strerror(errno)); return false; } _baud = baud; return true; } // Block until something is available void HardwareSerial::waitAvailable() { waitAvailableTimeout(0); // 0 = Wait forever } // Block until something is available or timeout expires bool HardwareSerial::waitAvailableTimeout(uint16_t timeout) { int max_fd; fd_set input; int result; FD_ZERO(&input); FD_SET(_device, &input); max_fd = _device + 1; if (timeout) { struct timeval timer; // Timeout is in milliseconds timer.tv_sec = timeout / 1000; timer.tv_usec = (timeout % 1000) * 1000; result = select(max_fd, &input, NULL, NULL, &timer); } else { result = select(max_fd, &input, NULL, NULL, NULL); } if (result < 0) fprintf(stderr, "HardwareSerial::waitAvailableTimeout: select failed %s\n", strerror(errno)); return result > 0; } #endif