Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| find_usb_serial_port.h |
|
||||
| |
|
||||
| Finds the serial port path(s) of USB serial port devices|
|
||||
| given the USB VID and PID of the device |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
std::vector<std::string *> find_usb_serial_port(unsigned short vid, unsigned short pid);
|
||||
@@ -0,0 +1,147 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| find_usb_serial_port_linux.cpp |
|
||||
| |
|
||||
| Finds the serial port path(s) of USB serial port devices|
|
||||
| given the USB VID and PID of the device |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "find_usb_serial_port.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/*---------------------------------------------------------------------*\
|
||||
| |
|
||||
| find_usb_serial_port |
|
||||
| |
|
||||
| This function returns the name of the first USB serial port matching|
|
||||
| the given USB product and vendor ID. |
|
||||
| |
|
||||
| vid: Vendor ID code |
|
||||
| pid: Product ID code |
|
||||
| |
|
||||
| returns: std::string containing port name "COMx" or "/dev/ttyX" |
|
||||
| |
|
||||
\*---------------------------------------------------------------------*/
|
||||
|
||||
std::vector<std::string *> find_usb_serial_port(unsigned short vid, unsigned short pid)
|
||||
{
|
||||
std::vector<std::string *> ret_vector;
|
||||
std::string * tmp_string;
|
||||
DIR* dir;
|
||||
char symlink_path[1024] = {0};
|
||||
struct dirent* ent;
|
||||
char vid_pid[10] = {0}; //Store VID/PID
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Open /sys/class/tty |
|
||||
\*-----------------------------------------------------------------*/
|
||||
dir = opendir("/sys/class/tty");
|
||||
|
||||
if(dir == NULL)
|
||||
{
|
||||
return ret_vector;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Loop through all symlinks in /sys/class/tty directory to find |
|
||||
| paths with "usb" in them. These links should have the USB device |
|
||||
| index which can be used to find the VID/PID |
|
||||
\*-----------------------------------------------------------------*/
|
||||
ent = readdir(dir);
|
||||
|
||||
while(ent != NULL)
|
||||
{
|
||||
if(ent->d_type == DT_LNK)
|
||||
{
|
||||
char tty_path[1024];
|
||||
strcpy(tty_path, "/sys/class/tty/");
|
||||
strcat(tty_path, ent->d_name);
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| readlink() does not null-terminate, so manually terminate it |
|
||||
\*-----------------------------------------------------------------*/
|
||||
ssize_t link_path_size = readlink(tty_path, symlink_path, 1024);
|
||||
if(link_path_size < 0 || link_path_size >= 1024)
|
||||
{
|
||||
/*-----------------------------------------------------------------*\
|
||||
| readlink failed or buffer too small, skip this device |
|
||||
\*-----------------------------------------------------------------*/
|
||||
ent = readdir(dir);
|
||||
continue;
|
||||
}
|
||||
symlink_path[link_path_size] = '\0';
|
||||
|
||||
char * usb_string = strstr(symlink_path, "usb");
|
||||
|
||||
if(usb_string != NULL)
|
||||
{
|
||||
char * usb_dev = strstr(usb_string, "/");
|
||||
usb_dev++;
|
||||
char * usb_end = strstr(usb_dev, "/tty");
|
||||
*usb_end = '\0';
|
||||
|
||||
usb_end = strrchr(usb_dev, '/');
|
||||
*usb_end = '\0';
|
||||
|
||||
char usb_path[1024];
|
||||
|
||||
strcpy(usb_path, "/sys/bus/usb/devices/");
|
||||
strcat(usb_path, usb_dev);
|
||||
|
||||
char vendor_path[1024];
|
||||
char product_path[1024];
|
||||
|
||||
strcpy(vendor_path, usb_path);
|
||||
strcat(vendor_path, "/idVendor");
|
||||
|
||||
strcpy(product_path, usb_path);
|
||||
strcat(product_path, "/idProduct");
|
||||
|
||||
std::ifstream vendor_file;
|
||||
std::ifstream product_file;
|
||||
std::string vendor_string;
|
||||
std::string product_string;
|
||||
|
||||
vendor_file.open(vendor_path);
|
||||
product_file.open(product_path);
|
||||
|
||||
std::getline(vendor_file, vendor_string);
|
||||
std::getline(product_file, product_string);
|
||||
|
||||
snprintf(vid_pid, 10, "%04x", vid);
|
||||
|
||||
if(strcmp(vid_pid, vendor_string.c_str()) == 0)
|
||||
{
|
||||
snprintf(vid_pid, 10, "%04x", pid);
|
||||
if(strcmp(vid_pid, product_string.c_str()) == 0)
|
||||
{
|
||||
char* port_string = NULL;
|
||||
for(int i = strlen(tty_path); i > 0; i--)
|
||||
{
|
||||
if(tty_path[i] == '/')
|
||||
{
|
||||
port_string = &tty_path[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp_string = new std::string("/dev/");
|
||||
tmp_string->append(port_string);
|
||||
|
||||
ret_vector.push_back(tmp_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ent = readdir(dir);
|
||||
}
|
||||
|
||||
|
||||
closedir(dir);
|
||||
return ret_vector;
|
||||
|
||||
} /* find_usb_serial_port() */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| find_usb_serial_port_macos.cpp |
|
||||
| |
|
||||
| Finds the serial port path(s) of USB serial port devices|
|
||||
| given the USB VID and PID of the device |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "find_usb_serial_port.h"
|
||||
|
||||
std::string exec(const char* cmd)
|
||||
{
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
FILE* pipe = popen(cmd, "r");
|
||||
|
||||
if(!pipe)
|
||||
{
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while(fgets(buffer, sizeof(buffer), pipe) != NULL)
|
||||
{
|
||||
result += buffer;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
pclose(pipe);
|
||||
throw;
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*\
|
||||
| |
|
||||
| find_usb_serial_port |
|
||||
| |
|
||||
| This function returns the name of the first USB serial port matching|
|
||||
| the given USB product and vendor ID. |
|
||||
| |
|
||||
| vid: Vendor ID code |
|
||||
| pid: Product ID code |
|
||||
| |
|
||||
| returns: std::string containing port name "COMx" or "/dev/ttyX" |
|
||||
| |
|
||||
\*---------------------------------------------------------------------*/
|
||||
|
||||
std::vector<std::string *> find_usb_serial_port(unsigned short vid, unsigned short pid)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Strings to search for in ioreg output |
|
||||
\*-----------------------------------------------------*/
|
||||
#define IO_CALLOUT_STR "\"IOCalloutDevice\" ="
|
||||
#define ID_VENDOR_STR "\"idVendor\" = "
|
||||
#define ID_PRODUCT_STR "\"idProduct\" = "
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Return variables |
|
||||
\*-----------------------------------------------------*/
|
||||
std::vector<std::string *> ret_vector;
|
||||
std::string * tmp_string;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Execute command to list USB devices |
|
||||
| |
|
||||
| Top level entry lines in ioreg output start with |
|
||||
| "+-o". Start the string with an extra newline so |
|
||||
| that we can search for "\n+-0" to identify only hits |
|
||||
| at the beginning of a line. |
|
||||
\*-----------------------------------------------------*/
|
||||
std::string out_string = "\n" + exec("ioreg -r -c IOUSBHostDevice -l");
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Append desired VID and PID to search strings |
|
||||
\*-----------------------------------------------------*/
|
||||
std::string vid_string = ID_VENDOR_STR + std::to_string(vid);
|
||||
std::string pid_string = ID_PRODUCT_STR + std::to_string(pid);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Start position counter at 0 |
|
||||
\*-----------------------------------------------------*/
|
||||
std::size_t pos = 0;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Loop through ioreg output, loop exits when "\n+-o" |
|
||||
| string cannot be found. |
|
||||
\*-----------------------------------------------------*/
|
||||
while(1)
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| Variables to store positions in string |
|
||||
\*-------------------------------------------------*/
|
||||
std::size_t next_pos;
|
||||
std::size_t vid_pos;
|
||||
std::size_t pid_pos;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Search for the next 2 iterations of "\n+-o" so |
|
||||
| that we can check if hits are in between them |
|
||||
\*-------------------------------------------------*/
|
||||
pos = out_string.find("\n+-o", pos);
|
||||
next_pos = out_string.find("\n+-o", pos + 1);
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Search for the vendor and product ID strings in |
|
||||
| and verify that they are between pos and next_pos |
|
||||
\*-------------------------------------------------*/
|
||||
vid_pos = out_string.find(vid_string, pos);
|
||||
pid_pos = out_string.find(pid_string, pos);
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Verify that VID/PID matches are within this |
|
||||
| device block by checking that their positions are |
|
||||
| less than next_pos. If next_pos is invalid, |
|
||||
| this is the last block, in which case check if |
|
||||
| VID/PID positions are valid. |
|
||||
\*-------------------------------------------------*/
|
||||
if(((vid_pos < next_pos) && (pid_pos < next_pos)) || ((pos == std::string::npos) && (vid_pos != std::string::npos) && (pid_pos != std::string::npos)))
|
||||
{
|
||||
/*---------------------------------------------*\
|
||||
| Variables to store positions in string |
|
||||
\*---------------------------------------------*/
|
||||
std::size_t dev_pos;
|
||||
std::size_t start_pos;
|
||||
std::size_t end_pos;
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Look for the IO callout device tag and then |
|
||||
| get the start and end positions of its value |
|
||||
\*---------------------------------------------*/
|
||||
dev_pos = out_string.find(IO_CALLOUT_STR, pos + 1);
|
||||
start_pos = out_string.find("\"", dev_pos + sizeof(IO_CALLOUT_STR)) + 1;
|
||||
end_pos = out_string.find("\"\n", start_pos);
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Ensure the IO callout device tag is within |
|
||||
| this device's section |
|
||||
\*---------------------------------------------*/
|
||||
if(dev_pos < next_pos)
|
||||
{
|
||||
tmp_string = new std::string(out_string.substr(start_pos, end_pos-start_pos));
|
||||
ret_vector.push_back(tmp_string);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| If we've reached the end of the string, break out |
|
||||
| of the loop |
|
||||
\*-------------------------------------------------*/
|
||||
if(pos == std::string::npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Increment position |
|
||||
\*-------------------------------------------------*/
|
||||
pos++;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Return vector of detected strings |
|
||||
\*-----------------------------------------------------*/
|
||||
return(ret_vector);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| find_usb_serial_port_win.cpp |
|
||||
| |
|
||||
| Finds the serial port path(s) of USB serial port devices|
|
||||
| given the USB VID and PID of the device |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "find_usb_serial_port.h"
|
||||
|
||||
#include <initguid.h>
|
||||
#include <windows.h>
|
||||
#include <Setupapi.h>
|
||||
|
||||
//Buffer length
|
||||
#define BUFF_LEN 20
|
||||
|
||||
#pragma comment (lib, "Setupapi.lib")
|
||||
#pragma comment(lib, "advapi32")
|
||||
|
||||
/*---------------------------------------------------------------------*\
|
||||
| |
|
||||
| find_usb_serial_port |
|
||||
| |
|
||||
| This function returns the name of the first USB serial port matching|
|
||||
| the given USB product and vendor ID. |
|
||||
| |
|
||||
| vid: Vendor ID code |
|
||||
| pid: Product ID code |
|
||||
| |
|
||||
| returns: std::string containing port name "COMx" or "/dev/ttyX" |
|
||||
| |
|
||||
\*---------------------------------------------------------------------*/
|
||||
|
||||
std::vector<std::string *> find_usb_serial_port(unsigned short vid, unsigned short pid)
|
||||
{
|
||||
std::vector<std::string *> ret_vector;
|
||||
std::string * tmp_string;
|
||||
HDEVINFO DeviceInfoSet;
|
||||
DWORD DeviceIndex = 0;
|
||||
SP_DEVINFO_DATA DeviceInfoData;
|
||||
const char * DevEnum = "USB";
|
||||
char ExpectedDeviceId[80] = {0}; //Store hardware id
|
||||
char vid_pid[10] = {0}; //Store VID/PID
|
||||
char szBuffer[1024] = {0};
|
||||
DEVPROPTYPE ulPropertyType;
|
||||
DWORD dwSize = 0;
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Create device hardware id |
|
||||
| "vid_ABCD&pid_CDEF" |
|
||||
\*-----------------------------------------------------------------*/
|
||||
strcpy(ExpectedDeviceId, "USB\\VID_");
|
||||
snprintf(vid_pid, 10, "%04X", vid);
|
||||
strcat(ExpectedDeviceId, vid_pid);
|
||||
strcat(ExpectedDeviceId, "&PID_");
|
||||
snprintf(vid_pid, 10, "%04X", pid);
|
||||
strcat(ExpectedDeviceId, vid_pid);
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| SetupDiGetClassDevs returns a handle to a device information set |
|
||||
\*-----------------------------------------------------------------*/
|
||||
DeviceInfoSet = SetupDiGetClassDevs( NULL, DevEnum, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
||||
|
||||
if (DeviceInfoSet == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return ret_vector;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Set up Device Info Data |
|
||||
\*-----------------------------------------------------------------*/
|
||||
memset(&DeviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
|
||||
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Receive information about an enumerated device |
|
||||
\*-----------------------------------------------------------------*/
|
||||
while (SetupDiEnumDeviceInfo( DeviceInfoSet, DeviceIndex, &DeviceInfoData))
|
||||
{
|
||||
DeviceIndex++;
|
||||
|
||||
/*-------------------------------------------------------------*\
|
||||
| Retrieves a specified Plug and Play device property |
|
||||
\*-------------------------------------------------------------*/
|
||||
if (SetupDiGetDeviceRegistryProperty (DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize))
|
||||
{
|
||||
HKEY hDeviceRegistryKey;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Check if the string for this device property matches |
|
||||
| our expected device string |
|
||||
\*-----------------------------------------------------*/
|
||||
if(strncmp(ExpectedDeviceId, szBuffer, 21) == 0)
|
||||
{
|
||||
hDeviceRegistryKey = SetupDiOpenDevRegKey(DeviceInfoSet, &DeviceInfoData,DICS_FLAG_GLOBAL, 0,DIREG_DEV, KEY_READ);
|
||||
if (hDeviceRegistryKey == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
char pszPortName[BUFF_LEN];
|
||||
DWORD dwSize = sizeof(pszPortName);
|
||||
DWORD dwType = 0;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Read in the name of the port |
|
||||
\*-----------------------------------------------------*/
|
||||
if( (RegQueryValueEx(hDeviceRegistryKey,"PortName", NULL, &dwType, (LPBYTE) pszPortName, &dwSize) == ERROR_SUCCESS) && (dwType == REG_SZ))
|
||||
{
|
||||
if(strncmp(pszPortName, "COM", 3) == 0)
|
||||
{
|
||||
tmp_string = new std::string(pszPortName);
|
||||
ret_vector.push_back(tmp_string);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the key now that we are finished with it
|
||||
RegCloseKey(hDeviceRegistryKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DeviceInfoSet)
|
||||
{
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
|
||||
return ret_vector;
|
||||
|
||||
} /* find_usb_serial_port() */
|
||||
@@ -0,0 +1,878 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port.cpp |
|
||||
| |
|
||||
| Cross Platform Serial COM Library for Windows and Linux |
|
||||
| This library provides access to serial ports with a |
|
||||
| common API for both Windows and Linux systems |
|
||||
| |
|
||||
| Adam Honse (calcprogrammer1@gmail.com) 21 Jan 2013 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "filesystem.h"
|
||||
#include "serial_port.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <regex>
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| getSerialPorts |
|
||||
| |
|
||||
| Returns the list of available serial ports in the |
|
||||
| system |
|
||||
\*---------------------------------------------------------*/
|
||||
std::vector<std::string> serial_port::getSerialPorts()
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*\
|
||||
| Ported from https://github.com/nkinar/GetComPortList/blob/master/GetComPortList.cpp |
|
||||
\*-----------------------------------------------------------------------------------*/
|
||||
std::vector<std::string> port_list;
|
||||
#if defined (_WIN32) || defined( _WIN64)
|
||||
const uint32_t CHAR_NUM = 1024;
|
||||
const uint32_t MAX_PORTS = 255;
|
||||
const std::string COM_STR = "COM";
|
||||
|
||||
char path[CHAR_NUM];
|
||||
|
||||
for(uint32_t k = 0; k < MAX_PORTS; k++)
|
||||
{
|
||||
std::string port_name = COM_STR + std::to_string(k);
|
||||
|
||||
DWORD test = QueryDosDevice(port_name.c_str(), path, CHAR_NUM);
|
||||
|
||||
if(test == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
port_list.push_back(port_name);
|
||||
}
|
||||
#endif
|
||||
#if defined (__linux__)
|
||||
const std::string DEV_PATH = "/dev/serial/by-id";
|
||||
try
|
||||
{
|
||||
filesystem::path p(DEV_PATH);
|
||||
|
||||
if(!filesystem::exists(DEV_PATH))
|
||||
{
|
||||
return port_list;
|
||||
}
|
||||
|
||||
for(filesystem::directory_entry de: filesystem::directory_iterator(p))
|
||||
{
|
||||
if(filesystem::is_symlink(de.symlink_status()))
|
||||
{
|
||||
filesystem::path symlink_points_at = filesystem::read_symlink(de);
|
||||
port_list.push_back(std::string("/dev/")+symlink_points_at.filename().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const filesystem::filesystem_error &ex)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
const std::string DEV_PATH = "/dev";
|
||||
const std::regex base_regex(R"(\/dev\/(tty|cu)\..*)");
|
||||
try
|
||||
{
|
||||
filesystem::path p(DEV_PATH);
|
||||
|
||||
if(!filesystem::exists(DEV_PATH))
|
||||
{
|
||||
return port_list;
|
||||
}
|
||||
|
||||
for(filesystem::directory_entry de: filesystem::directory_iterator(p))
|
||||
{
|
||||
filesystem::path canonical_path = filesystem::canonical(de);
|
||||
std::string name = canonical_path.generic_string();
|
||||
std::smatch res;
|
||||
|
||||
std::regex_search(name, res, base_regex);
|
||||
|
||||
if(res.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
port_list.push_back(canonical_path.generic_string());
|
||||
}
|
||||
}
|
||||
catch(const filesystem::filesystem_error &ex)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
std::sort(port_list.begin(), port_list.end());
|
||||
|
||||
return port_list;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port (constructor) |
|
||||
| The default constructor does not initialize the serial |
|
||||
| port |
|
||||
\*---------------------------------------------------------*/
|
||||
serial_port::serial_port()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Set default port configuration but do not open |
|
||||
\*-----------------------------------------------------*/
|
||||
this->baud_rate = 9600;
|
||||
this->parity = SERIAL_PORT_PARITY_NONE;
|
||||
this->size = SERIAL_PORT_SIZE_8;
|
||||
this->stop_bits = SERIAL_PORT_STOP_BITS_1;
|
||||
this->flow_control = false;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port (constructor) |
|
||||
| When created with port information, the constructor |
|
||||
| will automatically open port <name> at baud rate <baud>|
|
||||
\*---------------------------------------------------------*/
|
||||
serial_port::serial_port(const char * name, unsigned int baud)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Set default port configuration and open |
|
||||
\*-----------------------------------------------------*/
|
||||
this->baud_rate = baud;
|
||||
this->parity = SERIAL_PORT_PARITY_NONE;
|
||||
this->size = SERIAL_PORT_SIZE_8;
|
||||
this->stop_bits = SERIAL_PORT_STOP_BITS_1;
|
||||
this->flow_control = false;
|
||||
|
||||
serial_open(name);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port (constructor) |
|
||||
| When created with port information, the constructor |
|
||||
| will automatically open port <name> at baud rate <baud>|
|
||||
| with the given port configuration |
|
||||
\*---------------------------------------------------------*/
|
||||
serial_port::serial_port
|
||||
(
|
||||
const char * name,
|
||||
unsigned int baud,
|
||||
serial_port_parity parity,
|
||||
serial_port_size size,
|
||||
serial_port_stop_bits stop_bits,
|
||||
bool flow_control
|
||||
)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Set default port configuration and open |
|
||||
\*-----------------------------------------------------*/
|
||||
this->baud_rate = baud;
|
||||
this->parity = parity;
|
||||
this->size = size;
|
||||
this->stop_bits = stop_bits;
|
||||
this->flow_control = flow_control;
|
||||
|
||||
serial_open(name);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| ~serial_port (destructor) |
|
||||
| Closes the port before destroying the object |
|
||||
\*---------------------------------------------------------*/
|
||||
serial_port::~serial_port()
|
||||
{
|
||||
serial_close();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| 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()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial port opening |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
// On Windows, ports above 9 need to have "\\.\" prepended to their path. For ports below 9, this is optional.
|
||||
// https://support.microsoft.com/en-us/topic/howto-specify-serial-ports-larger-than-com9-db9078a5-b7b6-bf00-240f-f749ebfd913e
|
||||
char full_path[100];
|
||||
snprintf(full_path, sizeof(full_path), "\\\\.\\%s", port_name);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = CreateFile(full_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if(file_descriptor == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
SetupComm(file_descriptor, 1, 128);
|
||||
GetCommState(file_descriptor, &dcb);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
dcb.BaudRate = baud_rate;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
dcb.Parity = NOPARITY;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
dcb.Parity = ODDPARITY;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
dcb.Parity = EVENPARITY;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
dcb.ByteSize = 8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
dcb.ByteSize = 7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
dcb.ByteSize = 6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
dcb.ByteSize = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
dcb.StopBits = TWOSTOPBITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
dcb.fAbortOnError = FALSE; //Abort on error
|
||||
dcb.fOutX = FALSE; //XON/XOFF off for transmit
|
||||
dcb.fInX = FALSE; //XON/XOFF off for receive
|
||||
dcb.fOutxCtsFlow = FALSE; //Turn off CTS flow control
|
||||
dcb.fOutxDsrFlow = FALSE; //Turn off DSR flow control
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE; //Disable DTR control
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
SetCommState(file_descriptor, &dcb);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port timeouts |
|
||||
\*-----------------------------------------*/
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
timeouts.ReadIntervalTimeout = 50;
|
||||
timeouts.ReadTotalTimeoutConstant = 50;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 10;
|
||||
timeouts.WriteTotalTimeoutConstant = 50;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||
|
||||
SetCommTimeouts(file_descriptor, &timeouts);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial port opening |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write with no delay |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
if(file_descriptor < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set an advisory lock on the port and |
|
||||
| abort port setup if already locked |
|
||||
\*-----------------------------------------*/
|
||||
if(flock(file_descriptor, LOCK_EX | LOCK_NB) < 0)
|
||||
{
|
||||
close(file_descriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
struct termios2 options;
|
||||
ioctl(file_descriptor, TCGETS2, &options);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CBAUD;
|
||||
options.c_cflag |= CBAUDEX;
|
||||
|
||||
options.c_ispeed = baud_rate;
|
||||
options.c_ospeed = baud_rate;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CSIZE;
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
options.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
options.c_cflag |= CS5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
options.c_cflag |= CSTOPB;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
options.c_cflag |= CRTSCTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
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_lflag &= ~IEXTEN; // Disable input processing
|
||||
|
||||
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
|
||||
options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
|
||||
|
||||
options.c_oflag &= ~OPOST; // Disable output processing;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
ioctl(file_descriptor, TCSETS2, &options);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial port opening |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write with no delay |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
if(file_descriptor < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
struct termios options;
|
||||
tcgetattr(file_descriptor, &options);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CSIZE;
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
options.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
options.c_cflag |= CS5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
options.c_cflag |= CSTOPB;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
options.c_cflag |= CRTSCTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
options.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO);
|
||||
|
||||
options.c_iflag &= ~(INLCR | ICRNL);
|
||||
options.c_iflag |= IGNPAR | IGNBRK;
|
||||
|
||||
options.c_oflag &= ~(OPOST | ONLCR | OCRNL);
|
||||
|
||||
options.c_cc[VTIME] = 1;
|
||||
options.c_cc[VMIN] = 0;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
if(tcsetattr(file_descriptor, TCSANOW, &options) < 0)
|
||||
{
|
||||
close(file_descriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
ioctl(file_descriptor, IOSSIOSPEED, &baud_rate);
|
||||
|
||||
printf("Port opened fd %d", file_descriptor);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Return true if successful |
|
||||
\*-----------------------------------------------------*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_open |
|
||||
| Opens the serial port <name> without changing stored |
|
||||
| baud rate |
|
||||
\*---------------------------------------------------------*/
|
||||
bool serial_port::serial_open(const char * name)
|
||||
{
|
||||
return serial_open(name, baud_rate);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_open |
|
||||
| Opens the serial port <name> at baud rate <baud> |
|
||||
\*---------------------------------------------------------*/
|
||||
bool serial_port::serial_open(const char* name, unsigned int baud)
|
||||
{
|
||||
snprintf(port_name,sizeof(port_name),"%s",name);
|
||||
baud_rate = baud;
|
||||
return serial_open();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_close |
|
||||
| Closes the serial port |
|
||||
\*---------------------------------------------------------*/
|
||||
void serial_port::serial_close()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial close |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
CloseHandle(file_descriptor);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial close |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
flock(file_descriptor, LOCK_UN | LOCK_NB);
|
||||
close(file_descriptor);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial close |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
close(file_descriptor);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_read |
|
||||
| Reads <length> bytes from the serial port into <buffer>|
|
||||
| Returns the number of bytes actually read |
|
||||
| If less than <length> 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
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial read |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
int bytesread;
|
||||
bytesread = read(file_descriptor, buffer, length);
|
||||
return bytesread;
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial read |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
int bytesread;
|
||||
bytesread = read(file_descriptor, buffer, length);
|
||||
return bytesread;
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Return 0 on unsupported platforms |
|
||||
\*-----------------------------------------------------*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_write |
|
||||
| Writes <length> bytes to the serial port from <buffer> |
|
||||
| Returns the number of bytes actually written |
|
||||
| Does not check for null-termination, so if <length> is |
|
||||
| greater than the number of bytes in <buffer>, it will |
|
||||
| read past <buffer> 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
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| 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
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial write |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
int byteswritten;
|
||||
printf("serial write fd %d", file_descriptor);
|
||||
printf("tcdrain %d\r\n",tcdrain(file_descriptor));
|
||||
printf("write %d\r\n", byteswritten = write(file_descriptor, buffer, length));
|
||||
printf("tcdrain %d\r\n", tcdrain(file_descriptor));
|
||||
return byteswritten;
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Return 0 on unsupported platforms |
|
||||
\*-----------------------------------------------------*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_flush |
|
||||
\*---------------------------------------------------------*/
|
||||
void serial_port::serial_flush_rx()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
PurgeComm(file_descriptor, PURGE_RXABORT | PURGE_RXCLEAR);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
tcflush(file_descriptor, TCIFLUSH);
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifdef __linux__
|
||||
tcflush(file_descriptor, TCOFLUSH);
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
tcflush(file_descriptor, TCOFLUSH);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_break |
|
||||
\*---------------------------------------------------------*/
|
||||
void serial_port::serial_break()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
SetCommBreak(file_descriptor);
|
||||
Sleep(1);
|
||||
ClearCommBreak(file_descriptor);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
//Send break for at least 1 ms
|
||||
ioctl(file_descriptor, TIOCSBRK);
|
||||
usleep(1000);
|
||||
ioctl(file_descriptor, TIOCCBRK);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
//Send break for at least 1 ms
|
||||
ioctl(file_descriptor, TIOCSBRK);
|
||||
usleep(1000);
|
||||
ioctl(file_descriptor, TIOCCBRK);
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_port::serial_set_dtr(bool dtr)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial set DTR |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
if(dtr)
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, SETDTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, CLRDTR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial set DTR |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
const int DTRFLAG = TIOCM_DTR;
|
||||
if(dtr)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &DTRFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &DTRFLAG);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial set DTR |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
const int DTRFLAG = TIOCM_DTR;
|
||||
if(dtr)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &DTRFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &DTRFLAG);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_port::serial_set_rts(bool rts)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
if(rts)
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, SETRTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, CLRRTS);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
const int RTSFLAG = TIOCM_RTS;
|
||||
if(rts)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &RTSFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &RTSFLAG);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
const int RTSFLAG = TIOCM_RTS;
|
||||
if(rts)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &RTSFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &RTSFLAG);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port.h |
|
||||
| |
|
||||
| Cross Platform Serial COM Library for Windows and Linux |
|
||||
| This library provides access to serial ports with a |
|
||||
| common API for both Windows and Linux systems |
|
||||
| |
|
||||
| Adam Honse (calcprogrammer1@gmail.com) 21 Jan 2013 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#ifndef SERIAL_PORT_H
|
||||
#define SERIAL_PORT_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
/*---------------------------------------------------------*\
|
||||
| Windows interferes with std::max unless NOMINMAX defined |
|
||||
\*---------------------------------------------------------*/
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
//these types are redefined in asm/termios.h
|
||||
//to prevent compiler errors from multply
|
||||
//defining them, use a #define to rename them -
|
||||
//essentially to undef them before they are redefined
|
||||
#define winsize undefine_winsize
|
||||
#define termio undefine_termio
|
||||
#define termios undefine_termios
|
||||
#define sgttyb undefine_sgttyb
|
||||
#define tchars undefine_tchars
|
||||
#define ltchars undefine_ltchars
|
||||
|
||||
#include <asm/termios.h>
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
//ppc has c_ispeed/c_ospeed in termios and termios2 doesn't exist
|
||||
#if defined(__powerpc__)
|
||||
#define termios2 termios
|
||||
#define TCGETS2 TCGETS
|
||||
#define TCSETS2 TCSETS
|
||||
#endif
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <IOKit/serial/ioss.h>
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Serial Port Enums |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
typedef unsigned int serial_port_parity;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_PARITY_NONE = 0, /* No parity */
|
||||
SERIAL_PORT_PARITY_ODD = 1, /* Odd parity */
|
||||
SERIAL_PORT_PARITY_EVEN = 2, /* Even parity */
|
||||
};
|
||||
|
||||
typedef unsigned int serial_port_size;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_SIZE_8 = 0, /* 8 bits per byte */
|
||||
SERIAL_PORT_SIZE_7 = 1, /* 7 bits per byte */
|
||||
SERIAL_PORT_SIZE_6 = 2, /* 6 bits per byte */
|
||||
SERIAL_PORT_SIZE_5 = 3, /* 5 bits per byte */
|
||||
};
|
||||
|
||||
typedef unsigned int serial_port_stop_bits;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_STOP_BITS_1 = 0, /* 1 stop bit */
|
||||
SERIAL_PORT_STOP_BITS_2 = 1, /* 2 stop bits */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| 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:
|
||||
static std::vector<std::string> getSerialPorts();
|
||||
|
||||
serial_port();
|
||||
serial_port(const char * name, unsigned int baud);
|
||||
serial_port(const char * name,
|
||||
unsigned int baud,
|
||||
serial_port_parity parity,
|
||||
serial_port_size size,
|
||||
serial_port_stop_bits stop_bits,
|
||||
bool flow_control);
|
||||
|
||||
~serial_port();
|
||||
|
||||
bool serial_open();
|
||||
bool serial_open(const char* name);
|
||||
bool serial_open(const char* name, unsigned int baud);
|
||||
|
||||
void serial_close();
|
||||
|
||||
void serial_set_baud(unsigned int baud);
|
||||
int serial_get_baud();
|
||||
|
||||
int serial_read(char * buffer, int length);
|
||||
|
||||
int serial_write(char * buffer, int length);
|
||||
|
||||
void serial_flush_rx();
|
||||
void serial_flush_tx();
|
||||
void serial_break();
|
||||
|
||||
void serial_set_dtr(bool dtr);
|
||||
void serial_set_rts(bool rts);
|
||||
|
||||
int serial_available();
|
||||
|
||||
private:
|
||||
char port_name[1024];
|
||||
unsigned int baud_rate;
|
||||
serial_port_parity parity;
|
||||
serial_port_size size;
|
||||
serial_port_stop_bits stop_bits;
|
||||
bool flow_control;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE file_descriptor;
|
||||
DCB dcb;
|
||||
#else
|
||||
int file_descriptor;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user