mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
233 lines
6.1 KiB
C++
233 lines
6.1 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* 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 <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#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]);
|
|
}
|
|
}
|