Files
MotionCore/MotionCore/OSerialBus.cpp
T

138 lines
3.6 KiB
C++
Executable File

#include "OSerialBus.h"
#include <iostream>
#ifdef WINDOWS
OSerialBus::OSerialBus(const std::wstring& comPort, int baudRate) noexcept:
comPort(comPort),
baudRate(baudRate)
{
serialHandle = CreateFileW(normalizePort(comPort).c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (serialHandle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
std::wcerr << L"Unable to open serial port file " << normalizePort(comPort) << L"! Error: " << (int)err << std::endl;
return;
}
DCB serialParams = { 0 };
serialParams.DCBlength = sizeof(serialParams);
if (!GetCommState(serialHandle, &serialParams)) {
DWORD err = GetLastError();
std::wcerr << L"Unable to get comm state of port " << normalizePort(comPort) << L"! Is the port busy? Error: " << (int)err << std::endl;
return;
}
serialParams.BaudRate = baudRate;
serialParams.ByteSize = 8;
serialParams.Parity = NOPARITY;
serialParams.StopBits = ONESTOPBIT;
serialParams.fParity = FALSE;
serialParams.fBinary = TRUE;
serialParams.fOutxCtsFlow = FALSE;
serialParams.fOutxDsrFlow = FALSE;
serialParams.fOutX = FALSE;
serialParams.fInX = FALSE;
serialParams.fRtsControl = RTS_CONTROL_DISABLE;
serialParams.fDtrControl = DTR_CONTROL_DISABLE;
if (!SetCommState(serialHandle, &serialParams)) {
DWORD err = GetLastError();
std::wcerr << L"Unable to set comm state of port " << normalizePort(comPort) << L"! Is the port busy? Error: " << (int)err << std::endl;
return;
}
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 50;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (!SetCommTimeouts(serialHandle, &timeouts)) {
DWORD err = GetLastError();
std::wcerr << L"Unable to set comm timeouts of port " << normalizePort(comPort) << L"! Is the port busy? Error: " << (int)err << std::endl;
return;
}
open = true;
}
OSerialBus::OSerialBus(OSerialBus&& other) noexcept:
comPort(other.comPort),
baudRate(other.baudRate),
serialHandle(other.serialHandle),
open(other.open)
{
other.serialHandle = INVALID_HANDLE_VALUE;
other.open = false;
}
bool OSerialBus::isOpen() const noexcept
{
return open;
}
bool OSerialBus::close() noexcept
{
if (!isOpen()) {
return true;
}
return CloseHandle(serialHandle);
}
bool OSerialBus::send(const std::string& line) noexcept
{
// Important: this relies on chartype of line being 1 byte long!
const char* data = line.data();
std::size_t remaining = line.size();
while (remaining > 0) {
DWORD bytesWritten = 0;
if (!WriteFile(serialHandle, data, (DWORD)remaining, &bytesWritten, nullptr)) {
return false;
}
if (bytesWritten == 0) {
return false;
}
data += bytesWritten;
remaining -= bytesWritten;
}
return true;
}
bool OSerialBus::sendl(const std::string& line) noexcept
{
if (!send(line)) {
return false;
}
return send("\n");
}
OSerialBus& OSerialBus::operator<<(const std::string& in)
{
if (!send(in)) {
throw std::runtime_error("Failed to write to COM port!");
}
return *this;
}
std::wstring OSerialBus::normalizePort(const std::wstring& port) noexcept
{
// If port string already includes prefix, return as-is
if (port == L"\\\\.\\") {
return port;
}
// If the first 3 chars in the portstring are COM, prefix the prefix
if (_wcsnicmp(port.c_str(), L"COM", 3) == 0) {
return std::wstring(L"\\\\.\\") + port;
}
return port;
}
#endif