/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2017. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #include "HAL/OSSerialPort.h" #include #include #include #include #include #include #include #include "HAL/Errors.h" #include "HAL/cpp/SerialHelper.h" static int portHandles[4]{-1, -1, -1, -1}; static std::chrono::milliseconds portTimeouts[4]{ std::chrono::milliseconds(0), std::chrono::milliseconds(0), std::chrono::milliseconds(0), std::chrono::milliseconds(0)}; extern "C" { void HAL_InitializeOSSerialPort(HAL_SerialPort port, int32_t* status) { std::string portName; hal::SerialHelper serialHelper; portName = serialHelper.GetOSSerialPortName(port, status); if (*status < 0) { return; } int fs = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (fs == -1) { *status = HAL_SERIAL_PORT_OPEN_ERROR; return; } portHandles[port] = fs; struct termios options; tcgetattr(fs, &options); options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; options.c_iflag = 0; options.c_oflag = 0; options.c_lflag = 0; tcflush(fs, TCIFLUSH); tcsetattr(fs, TCSANOW, &options); } void HAL_SetOSSerialBaudRate(HAL_SerialPort port, int32_t baud, int32_t* status) { int baudRate = -1; switch (baud) { case 9600: baudRate = B9600; break; case 19200: baudRate = B19200; break; case 38400: baudRate = B38400; break; case 57600: baudRate = B57600; break; case 115200: baudRate = B115200; break; default: *status = PARAMETER_OUT_OF_RANGE; return; } struct termios options; tcgetattr(portHandles[port], &options); auto set = cfsetospeed(&options, baudRate); if (set != 0) { *status = HAL_SERIAL_PORT_ERROR; return; } set = tcsetattr(portHandles[port], TCSANOW, &options); if (set != 0) { *status = HAL_SERIAL_PORT_ERROR; return; } } void HAL_SetOSSerialDataBits(HAL_SerialPort port, int32_t bits, int32_t* status) { int numBits = -1; switch (bits) { case 5: numBits = CS5; break; case 6: numBits = CS6; break; case 7: numBits = CS7; break; case 8: numBits = CS8; break; default: *status = PARAMETER_OUT_OF_RANGE; return; } struct termios options; tcgetattr(portHandles[port], &options); options.c_cflag &= ~CSIZE; options.c_cflag |= numBits; auto set = tcsetattr(portHandles[port], TCSANOW, &options); if (set != 0) { *status = HAL_SERIAL_PORT_ERROR; return; } } void HAL_SetOSSerialParity(HAL_SerialPort port, int32_t parity, int32_t* status) { // Just set none parity struct termios options; tcgetattr(portHandles[port], &options); options.c_cflag &= ~PARENB; auto set = tcsetattr(portHandles[port], TCSANOW, &options); if (set != 0) { *status = HAL_SERIAL_PORT_ERROR; return; } } void HAL_SetOSSerialStopBits(HAL_SerialPort port, int32_t stopBits, int32_t* status) { // Force 1 stop bit struct termios options; tcgetattr(portHandles[port], &options); options.c_cflag &= ~CSTOPB; auto set = tcsetattr(portHandles[port], TCSANOW, &options); if (set != 0) { *status = HAL_SERIAL_PORT_ERROR; return; } } void HAL_SetOSSerialWriteMode(HAL_SerialPort port, int32_t mode, int32_t* status) { // No op } void HAL_SetOSSerialFlowControl(HAL_SerialPort port, int32_t flow, int32_t* status) { // No op } void HAL_SetOSSerialTimeout(HAL_SerialPort port, double timeout, int32_t* status) { // Convert to millis int t = timeout / 1000; portTimeouts[port] = std::chrono::milliseconds(t); } void HAL_EnableOSSerialTermination(HAL_SerialPort port, char terminator, int32_t* status) { // \n is hardcoded for now. Will fix later // Seems like a VISA only setting, need to check } void HAL_DisableOSSerialTermination(HAL_SerialPort port, int32_t* status) { // Seems like a VISA only setting, need to check } void HAL_SetOSSerialReadBufferSize(HAL_SerialPort port, int32_t size, int32_t* status) { // No op } void HAL_SetOSSerialWriteBufferSize(HAL_SerialPort port, int32_t size, int32_t* status) { // No op } int32_t HAL_GetOSSerialBytesReceived(HAL_SerialPort port, int32_t* status) { int bytes = 0; ioctl(portHandles[port], FIONREAD, &bytes); return bytes; } int32_t HAL_ReadOSSerial(HAL_SerialPort port, char* buffer, int32_t count, int32_t* status) { auto endTime = std::chrono::steady_clock::now() + portTimeouts[port]; int bytesRead = 0; unsigned char buf[256]; do { int rx = read(portHandles[port], buf, count - bytesRead); std::memcpy(&buffer[bytesRead], buf, rx); bytesRead += rx; if (bytesRead >= count) break; llvm::StringRef tmp(buffer, bytesRead); auto loc = tmp.find('\n'); if (loc != llvm::StringRef::npos) { bytesRead = loc; break; } } while (std::chrono::steady_clock::now() < endTime); return bytesRead; } int32_t HAL_WriteOSSerial(HAL_SerialPort port, const char* buffer, int32_t count, int32_t* status) { return write(portHandles[port], buffer, count); } void HAL_FlushOSSerial(HAL_SerialPort port, int32_t* status) { tcdrain(portHandles[port]); } void HAL_ClearOSSerial(HAL_SerialPort port, int32_t* status) { tcflush(portHandles[port], TCIOFLUSH); } void HAL_CloseOSSerial(HAL_SerialPort port, int32_t* status) { close(portHandles[port]); } }