适用于Windiws平台的上位机通信,利用windows API
可以获取下位机指定类型设备数量, 完整的rcr校验算法,灵活设计AP
当谈到嵌入式系统和串口通信时,C++是一个强大的选择。在这篇博客中,我们将探讨如何使用C++与嵌入式设备进行串口通信,以及如何构建一个简单的串口通信应用程序。
串口通信是一种用于在计算机和外部设备之间传输数据的通信方式。在嵌入式系统中,串口通信通常用于与传感器、执行器和其他外围设备进行通信。
本文介绍了如何使用C++与嵌入式设备进行串口通信,并提供了一个简单的示例应用程序。通过这种方式,您可以轻松地与嵌入式系统进行通信,并控制其行为。串口通信是嵌入式系统中常用的通信方式之一,将有助于您开发更加强大和灵活的嵌入式应用程序。
步骤1:包含必要的头文件
#include "serialport.h"
#include <iostream>
步骤2:初始化串口
SerialPort *d = nullptr;
void Motor_Init() {
d = new SerialPort();
// 设置串口参数,如波特率、数据位、校验位等
d->setBaudRate(SerialPort::Baud115200);
d->setDataBits(SerialPort::Data8);
d->setParity(SerialPort::NoParity);
d->setStopBits(SerialPort::OneStop);
d->setFlowControl(SerialPort::NoFlowControl);
}
步骤3:打开串口并发送/接收数据
bool Motor_Open(int index, const signalCount &count, const signalLock &lock = nullptr, void *context = nullptr) {
// 串口打开及数据处理逻辑
}
bool Motor_SetParam(int index, unsigned char step) {
// 向下位机发送指令
}
bool Motor_GetParam(int index, bool *lock) {
// 从下位机获取数据
}
步骤4:关闭串口
void Motor_UnInit() { delete d; }
如何定义使用:
示例应用程序
#include "serialport.h"
#include <iostream>
SerialPort *d = nullptr;
// 定义回调函数
typedef void(*signalCount)(float, void *);
typedef void(*signalLock)(bool, void *);
static inline bool crc16_XMODEM(const unsigned char *data, unsigned char *cs) {
unsigned short crc = SerialPort::crc16Check(data, 4, 0x1021, 0x0000, 0x0000, false, false);
unsigned char high = (crc >> 8) & 0xFF;
unsigned char low = crc & 0xFF;
if (*cs == high && *(cs + 1) == low)return true;
*cs = high;
*(cs + 1) = low;
return false;
}
// 初始库
void Motor_Init() {
if(d) return;
d = new SerialPort();
d->setBaudRate(SerialPort::Baud115200);
d->setDataBits(SerialPort::Data8);
d->setParity(SerialPort::NoParity);
d->setStopBits(SerialPort::OneStop);
d->setFlowControl(SerialPort::NoFlowControl);
}
// 反初始
void Motor_UnInit() { delete d; }
/*!
* 确认 0,4,7 是和下位机相同的才被认可是查找的设备
* 这个取决于和下位机的协议 如果协议认为 1,2 这里 verify便是1,2
* @return 有效设备数量
*/
int Motor_Count() {
static unsigned char define[8] = {0x8e, 0x01, 0x7b, 0x00, 0x0b, 0x1f, 0xae, 0x8e};
return d->serialCount(define, 8, {0, 4, 7});
}
// 获取串口号
int Motor_Port(int index) { return d->serialPort(index); }
// 串口设备是否打开
bool Motor_IsOpen(int index) { return d->serialIsOpen(index); }
bool Motor_Open(int index, const signalCount &count, const signalLock &lock = nullptr, void *context = nullptr) {
// 下位机有数据上来时会触发这个函数
return d->serialOpen(index, [count, lock, context](int port, unsigned char *data) {
// crc 校验
if (crc16_XMODEM(data, &data[4])) {
switch (data[2]) {
case 0x7b:
if (count)
count(0x7b, context);
break;
case 0x7c:
if (lock)lock(true, context);
break;
default:
break;
}
}
}, 8);
}
/*!
* 向下位机发送指令
* 这里crc 校验 写入数据不需要下位机的数据 传递 nullptr,只需要对 第0,1,7 是相同的证明下位机收到了这个指令。
* @param index
* @param step
* @return
*/
bool Motor_SetParam(int index, unsigned char step) {
unsigned char define[8] = {0x8e, 0x01, step, 0x00, 0x00, 0x00, 0x00, 0x00};
crc16_XMODEM(define, &define[4]);
return d->serialWrite(index, define, 8, nullptr, {0, 1, 7});
}
/*!
* 向下位机设备发送指令
* crc 校验 需要下位机数据 传递buffer
* @param index
* @param lock
* @return
*/
bool Motor_GetParam(int index, bool *lock) {
static unsigned char define[8] = {0x8e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char buffer[8];
bool result = d->serialWrite(index, define, 8, buffer, {0, 1, 7});
if (result && crc16_XMODEM(buffer, &buffer[4]))*lock = static_cast<bool >(buffer[2]);
return result;
}
int main() {
Motor_Init();
int count = Motor_Count();
for (int i = 0; i < count; ++i) {
std::cout << "Index(" << i << ")" << "-Port(COM" << Motor_Port(i) << ")" << std::endl;
}
// 打开索引第0个设备
int serial_index = 0;
if (Motor_IsOpen(serial_index)) {
std::cout << "设备已打开" << std::endl;
return 0;
}
if (Motor_Open(serial_index,
[](float count, void *context) {
// 如果是C++ 将上下文转成你的对象。注意这里的上下文取决于你传递的上下文指针
// auto *instance = static_cast<MyClass *>(context);
// instance->MyFunction(count);
std::cout << "count" << count << std::endl;
},
[](bool lock, void *context) {
std::cout << "lock" << lock << std::endl;
}, nullptr)//这里传递上下文 如果你是C++ 传递this 指针
) {
std::cout << "设备打开成功!" << std::endl;
} else {
std::cout << "设备打开失败!" << std::endl;
return 0;
}
if (Motor_SetParam(serial_index, 0x04)) {
std::cout << "写入参数成功!" << std::endl;
} else {
std::cout << "写入参数失败!" << std::endl;
}
bool lock;
if (Motor_GetParam(serial_index, &lock)) {
std::cout << "读取参数成功!" << lock << std::endl;
} else {
std::cout << "读取参数失败!" << std::endl;
}
Motor_UnInit();
return 0;
}
//serialport.h
#ifndef SOFTPETAL_SERIALPORT_H
#define SOFTPETAL_SERIALPORT_H
#define S_D(Class) \
private: \
Class(const Class &) = delete;\
Class &operator=(const Class &) = delete;\
friend class Class##Private ; \
Class##Private * const d;
#define S_Q(Class) \
private: \
Class##Private(const Class##Private &) = delete; \
Class##Private(Class##Private &&) = delete;\
Class##Private &operator=(const Class##Private &) = delete; \
Class##Private& operator=(Class##Private&&)= delete;\
friend Class;\
Class * const q;
#include <functional>
using callbackFunction = std::function<void(int, unsigned char *)>;
class SerialPort {
S_D(SerialPort)
public:
//波特率
enum BaudRate {
Baud110 = 110,
Baud300 = 300,
Baud600 = 600,
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud14400 = 14400,
Baud19200 = 19200,
Baud38400 = 38400,
Baud56000 = 56000,
Baud57600 = 57600,
Baud115200 = 115200,
Baud128000 = 128000,
Baud256000 = 256000,
};
//数据位
enum DataBits {
Data5 = 5,
Data6 = 6,
Data7 = 7,
Data8 = 8,
};
//校验位
enum Parity {
NoParity,
OddParity,
EvenParity,
MarkParity,
SpaceParity,
};
//停止位
enum StopBits {
OneStop,
OneAndHalfStop,
TwoStop,
};
//流控制
enum FlowControl {
NoFlowControl,
HardwareControl,
SoftwareControl
};
/**
* 计算给定数据的CRC校验值。
*
* @param data 指向需要进行CRC校验的数据的指针。
* @param len 需要进行CRC校验的数据长度。
* @param polynomial CRC的多项式,用于生成CRC的检查值。
* @param initial CRC的初始值。
* @param finalXor CRC计算结束时与之进行异或的值。
* @param input 指示数据是否是按位输入。如果为true,则数据按位输入;如果为false,则数据按字节输入。
* @param result 指示CRC的计算结果是否按位返回。如果为true,则结果按位返回;如果为false,则结果按字节返回。
* @return 返回计算得到的CRC校验值。
*/
static unsigned char crc8Check(const unsigned char *data, int len,
unsigned char polynomial,
unsigned char initial,
unsigned char finalXor,
bool input, bool result);
static unsigned short crc16Check(const unsigned char *data, int len,
unsigned short polynomial,
unsigned short initial,
unsigned short finalXor,
bool input, bool result);
static unsigned int crc32Check(const unsigned char *data, int len,
unsigned int polynomial,
unsigned int initial,
unsigned int finalXor,
bool input, bool result);
#if 0
static inline bool crc16_XMODEM(const unsigned char *data, unsigned char *cs, unsigned char len) {
unsigned short crc = crc16Check(data, len, 0x1021, 0x0000, 0x0000, false, false);
unsigned char high = (crc >> 8) & 0xFF;
unsigned char low = crc & 0xFF;
if (*cs == high && *(cs + 1) == low)return true;
*cs = high;
*(cs + 1) = low;
return false;
}
#endif
public:
explicit SerialPort();
~SerialPort();
void setBaudRate(BaudRate baud);
void setDataBits(DataBits data);
void setParity(Parity parity);
void setStopBits(StopBits stop);
void setFlowControl(FlowControl flow);
/*!
* 获取指定设备数量
* @param data 握手数据
* @param len 数据长度
* @param verify 对接确认位 比如下位机 第4个和第5个要和 data 相同 才被认可是要查找的设备
* @param time 发送data后等待下位机回复的时间
* @return 有效数量
*/
int serialCount(unsigned char *data, int len,
const std::vector<int> &verify = std::vector<int>(),
unsigned long time = 30);
// 获取串口号
[[nodiscard]] int serialPort(int index) const;
// 串口是否打开
[[nodiscard]] bool serialIsOpen(int index) const;
/*!
* 打开设备
* @param index 按照serialCount() 获得的索引打开
* @param callback 回调函数 打开后下位机有数据会通过这个函数告知
* @param len 下位机发送的长度
* @return 是否打开成功
*/
bool serialOpen(int index, const callbackFunction &callback, int len);
// 关闭串口
void serialClose(int index);
/*!
* 写入数据
* @param index 按照serialCount() 获得的索引写入
* @param order 需要写入的数据指令
* @param len 数据长度
* @param buffer 写入后需要下位机的回复,如果不需要 传递 nullptr
* @param verify 对接确认位 比如下位机 第4个和第5个要和 data 相同 才被认可是下位机确认收到
* @param reissue 如果没有得到下位机的回复会重发。默认重发3次
* @param time 发送data后等待下位机恢复时间
* @return 是否写入成功
*/
bool serialWrite(int index,
unsigned char *order,
int len,
unsigned char *buffer,
const std::vector<int> &verify = std::vector<int>(),
int reissue = 3,
unsigned long time = 30);
};
/*!
* crc 校验表
unsigned char data[] = {0xee, 0x01, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b};
printf("CRC8 -> %02x\n", SerialPort::crc8Check(data, 22, 0x07, 0x00, 0x00, false, false));
printf("CRC16_XMODEM -> %02x\n", SerialPort::crc16Check(data, 22, 0x1021, 0x0000, 0x0000, false, false));
printf("CRC32_MPEG2 -> %02x\n", SerialPort::crc32Check(data, 22, 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false));
Name Polynomial Initial FinalXor Input Result
CRC8 0x07 0x00 0x00 false false
CRC8_SAE_J1850 0x1D 0xFF 0xFF false false
CRC8_SAE_J1850_ZERO 0x1D 0x00 0x00 false false
CRC8_8H2F 0x2F 0xFF 0xFF false false
CRC8_CDMA2000 0x9B 0xFF 0x00 false false
CRC8_DARC 0x39 0x00 0x00 true true
CRC8_DVB_S2 0xD5 0x00 0x00 false false
CRC8_EBU 0x1D 0xFF 0x00 true true
CRC8_ICODE 0x1D 0xFD 0x00 false false
CRC8_ITU 0x07 0x00 0x55 false false
CRC8_MAXIM 0x31 0x00 0x00 true true
CRC8_ROHC 0x07 0xFF 0x00 true true
CRC8_WCDMA 0x9B 0x00 0x00 true true
CRC16_CCIT_ZERO 0x1021 0x0000 0x0000 false false
CRC16_ARC 0x8005 0x0000 0x0000 true true
CRC16_AUG_CCITT 0x1021 0x1D0F 0x0000 false false
CRC16_BUYPASS 0x8005 0x0000 0x0000 false false
CRC16_CCITT_FALSE 0x1021 0xFFFF 0x0000 false false
CRC16_CDMA2000 0xC867 0xFFFF 0x0000 false false
CRC16_DDS_110 0x8005 0x800D 0x0000 false false
CRC16_DECT_R 0x0589 0x0000 0x0001 false false
CRC16_DECT_X 0x0589 0x0000 0x0000 false false
CRC16_DNP 0x3D65 0x0000 0xFFFF true true
CRC16_EN_13757 0x3D65 0x0000 0xFFFF false false
CRC16_GENIBUS 0x1021 0xFFFF 0xFFFF false false
CRC16_MAXIM 0x8005 0x0000 0xFFFF true true
CRC16_MCRF4XX 0x1021 0xFFFF 0x0000 true true
CRC16_RIELLO 0x1021 0xB2AA 0x0000 true true
CRC16_T10_DIF 0x8BB7 0x0000 0x0000 false false
CRC16_TELEDISK 0xA097 0x0000 0x0000 false false
CRC16_TMS37157 0x1021 0x89EC 0x0000 true true
CRC16_USB 0x8005 0xFFFF 0xFFFF true true
CRC16_A 0x1021 0xC6C6 0x0000 true true
CRC16_KERMIT 0x1021 0x0000 0x0000 true true
CRC16_MODBUS 0x8005 0xFFFF 0x0000 true true
CRC16_X_25 0x1021 0xFFFF 0xFFFF true true
CRC16_XMODEM 0x1021 0x0000 0x0000 false false
CRC32 0x04C11DB7 0xFFFFFFFF 0xFFFFFFFF true true
CRC32_BZIP2 0x04C11DB7 0xFFFFFFFF 0xFFFFFFFF false false
CRC32_C 0x1EDC6F41 0xFFFFFFFF 0xFFFFFFFF true true
CRC32_D 0xA833982B 0xFFFFFFFF 0xFFFFFFFF true true
CRC32_MPEG2 0x04C11DB7 0xFFFFFFFF 0x00000000 false false
CRC32_POSIX 0x04C11DB7 0x00000000 0xFFFFFFFF false false
CRC32_Q 0x814141AB 0x00000000 0x00000000 false false
CRC32_JAMCRC 0x04C11DB7 0xFFFFFFFF 0x00000000 true true
CRC32_XFER 0x000000AF 0x00000000 0x00000000 false false
*/
#endif //SOFTPETAL_SERIALPORT_H
// serialport.cpp
#include "serialport.h"
#include <windows.h>
#include <tchar.h>
#include <thread>
#include <iostream>
#include <algorithm>
#include <mutex>
#include <cassert>
class HandleInfo {
// 串口号
const int m_HandlePort;
// 串口句柄
HANDLE m_Handle{nullptr};
// 串口是否打开
bool m_HandleOpen{false};
// 回调函数
callbackFunction m_FuncPtr = nullptr;
std::thread m_Thread;
bool m_KillThread{false};
// 线程锁
std::mutex m_ThreadMutex;
public:
explicit HandleInfo(int port) : m_HandlePort(port) {};
~HandleInfo() { handleClose(); }
HandleInfo() = delete;
HandleInfo(const HandleInfo &) = delete;
HandleInfo(HandleInfo &&) = delete;
HandleInfo &operator=(const HandleInfo &) = delete;
HandleInfo &operator=(HandleInfo &&) = delete;
[[nodiscard]] inline bool handleIsOpen() const { return (m_Handle && m_HandleOpen); }
[[nodiscard]] int handlePort() const { return m_HandlePort; }
inline bool handleOpen(HANDLE handle, const callbackFunction &callback, int len) {
handleClose();
if (handle) {
m_FuncPtr = callback;
m_Handle = handle;
m_HandleOpen = true;
m_KillThread = true;
m_Thread = std::thread(&HandleInfo::processEvent, this, len);
}
return handleIsOpen();
}
inline bool handleWrite(unsigned char *order,
int len,
unsigned char *buffer,
const std::vector<int> &verify = std::vector<int>(),
int reissue = 3,
unsigned long time = 30) {
if (reissue < 1)return false;
m_ThreadMutex.lock();
if (handleWrite(m_Handle, order, len)) {
auto *mandate = new unsigned char[len];
std::this_thread::sleep_for(std::chrono::milliseconds(time));
if (handleRead(m_Handle, mandate, len)) {
bool isVerify = true;
for (int v: verify) {
if (mandate[v] != order[v]) {
isVerify = false;
break;
}
}
if (isVerify) {
m_ThreadMutex.unlock();
if (buffer != nullptr)memcpy(buffer, mandate, len);
delete[] mandate;
return true;
}
}
delete[] mandate;
}
m_ThreadMutex.unlock();
return handleWrite(order, len, buffer, verify, reissue - 1, time);
}
inline void handleClose() {
m_KillThread = false;
if (m_Thread.joinable())m_Thread.join();
CloseHandle(m_Handle);
m_Handle = nullptr;
m_HandleOpen = false;
}
void processEvent(int len) {
auto *buffer = new unsigned char[len];
while (m_KillThread) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
m_ThreadMutex.lock();
handleRead(m_Handle, buffer, len);
m_ThreadMutex.unlock();
// 如果收到的是空数据不发送 否则触发回调函数
if (buffer[0] == 0x00)continue;
m_FuncPtr(m_HandlePort, buffer);
}
delete[] buffer;
}
static inline HANDLE handleOpen(const TCHAR *name,
SerialPort::BaudRate baud,
SerialPort::DataBits data,
SerialPort::Parity parity,
SerialPort::StopBits stop,
SerialPort::FlowControl flow) {
HANDLE handle = CreateFile(
name,//串口名
GENERIC_READ | GENERIC_WRITE, // 读写
0, //独占方式,串口不支持共享
nullptr, // 安全属性指针,默认值为NULL
OPEN_EXISTING, //打开现有的串口文件
0, //0:同步方式,FILE_FLAG_OVERLAPPED:异步方式
nullptr);//用于复制文件句柄,默认值为NULL,对串口而言该参数必须置为NULL
if (handle == INVALID_HANDLE_VALUE) return nullptr;
// 配置参数
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
dcbSerialParams.BaudRate = baud; // 波特率
dcbSerialParams.ByteSize = data; // 每个字节使用8位
dcbSerialParams.Parity = parity; // 无奇偶校验
dcbSerialParams.StopBits = stop; // 1个停止位
dcbSerialParams.fDtrControl = flow; // 控制流
if (!SetCommState(handle, &dcbSerialParams)) return nullptr;
// 超时处理,单位:毫秒
//总超时=时间系数×读或写的字符数+时间常量
COMMTIMEOUTS TimeOuts;
TimeOuts.ReadIntervalTimeout = 1; //指定在接收到连续字符之间的最大时间间隔(毫秒),当此时间间隔过去而没有接收到新数据时,读操作将返回。
TimeOuts.ReadTotalTimeoutMultiplier = 1; //指定每个字符的等待时间的倍率。实际超时时间为该倍率乘以接收到的字符数乘以 ReadTotalTimeoutConstant 的值。
TimeOuts.ReadTotalTimeoutConstant = 1; //指定在读操作期间的固定超时时间。如果在读取每个字符之间的时间间隔内没有接收到新数据,则此时间将开始递增
TimeOuts.WriteTotalTimeoutMultiplier = 1; //指定每个字符的等待时间的倍率。实际超时时间为该倍率乘以要发送的字符数乘以 WriteTotalTimeoutConstant 的值
TimeOuts.WriteTotalTimeoutConstant = 1; //指定在写操作期间的固定超时时间。
if (!SetCommTimeouts(handle, &TimeOuts)) return nullptr;
PurgeComm(handle, PURGE_TXCLEAR | PURGE_RXCLEAR);//清空串口缓冲区
return handle;
}
static inline bool handleWrite(HANDLE handle, unsigned char *data, int len) {
DWORD bytes;
return WriteFile(handle, data, len, &bytes, nullptr);
}
static inline bool handleRead(HANDLE hSerial, unsigned char *data, int len) {
DWORD bytes;
std::memset(data, 0, len);
return ReadFile(hSerial, // 串口句柄
data, // 数据缓冲区地址
len, // 要读取的最大字节数
&bytes, // DWORD*,用于接收成功读取的字节数
nullptr); // NULL为同步发送,OVERLAPPED*为异步发送
}
static inline unsigned char reverse8(unsigned char data) {
unsigned char temp = 0;
for (int i = 0; i < 8; i++) temp |= ((data >> i) & 0x01) << (7 - i);
return temp;
};
static inline unsigned short reverse16(unsigned short data) {
unsigned short temp = 0;
for (int i = 0; i < 16; i++) temp |= ((data >> i) & 0x01) << (15 - i);
return temp;
};
static inline unsigned int reverse32(unsigned int data) {
unsigned int temp = 0;
for (int i = 0; i < 32; i++) temp |= ((data >> i) & 0x01) << (31 - i);
return temp;
};
};
class SerialPortPrivate {
S_Q(SerialPort)
SerialPort::BaudRate m_BaudRate{SerialPort::Baud115200};
SerialPort::DataBits m_DataBits{SerialPort::Data8};
SerialPort::Parity m_Parity{SerialPort::NoParity};
SerialPort::StopBits m_StopBits{SerialPort::OneStop};
SerialPort::FlowControl m_FlowControl{SerialPort::NoFlowControl};
std::vector<HandleInfo *> m_HandleInfos;
explicit SerialPortPrivate(SerialPort *ptr) : q(ptr) {}
[[nodiscard]] inline HandleInfo *instances(int index) const {
assert(index < m_HandleInfos.size() && "Index out of bounds");
if (index < m_HandleInfos.size())return m_HandleInfos[index];
return nullptr;
};
};
unsigned char SerialPort::crc8Check(const unsigned char *data, int len, unsigned char polynomial, unsigned char initial,
unsigned char finalXor, bool input, bool result) {
unsigned char temp;
for (; len > 0; len--) {
temp = *data++;
if (input) temp = HandleInfo::reverse8(temp);
initial ^= temp;
for (int i = 0; i < 8; i++)
initial = (initial & 0x80) ? (initial << 1) ^ polynomial : initial << 1;
}
if (result) initial = HandleInfo::reverse8(initial);
return initial ^ finalXor;
}
unsigned short
SerialPort::crc16Check(const unsigned char *data, int len, unsigned short polynomial, unsigned short initial,
unsigned short finalXor, bool input, bool result) {
unsigned char temp;
for (; len > 0; len--) {
temp = *data++;
if (input) temp = HandleInfo::reverse8(temp);
initial ^= (temp << 8);
for (int i = 0; i < 8; i++)
initial = (initial & 0x8000) ? (initial << 1) ^ polynomial : initial << 1;
}
if (result) initial = HandleInfo::reverse16(initial);
return initial ^ finalXor;
}
unsigned int SerialPort::crc32Check(const unsigned char *data, int len, unsigned int polynomial, unsigned int initial,
unsigned int finalXor, bool input, bool result) {
unsigned char temp;
for (; len > 0; len--) {
temp = *data++;
if (input) temp = HandleInfo::reverse8(temp);
initial ^= (temp << 24);
for (int i = 0; i < 8; i++) initial = (initial & 0x80000000) ? (initial << 1) ^ polynomial : initial << 1;
}
if (result) initial = HandleInfo::reverse32(initial);
return initial ^ finalXor;
}
SerialPort::SerialPort() : d(new SerialPortPrivate(this)) {}
SerialPort::~SerialPort() {
for (auto &handle: d->m_HandleInfos)delete handle;
delete d;
}
void SerialPort::setBaudRate(SerialPort::BaudRate baud) { d->m_BaudRate = baud; }
void SerialPort::setDataBits(SerialPort::DataBits data) { d->m_DataBits = data; }
void SerialPort::setParity(SerialPort::Parity parity) { d->m_Parity = parity; }
void SerialPort::setStopBits(SerialPort::StopBits stop) { d->m_StopBits = stop; }
void SerialPort::setFlowControl(SerialPort::FlowControl flow) { d->m_FlowControl = flow; }
int SerialPort::serialCount(unsigned char *data, int len, const std::vector<int> &verify, unsigned long time) {
auto *buffer = new unsigned char[len];
std::vector<HandleInfo *> closed;
for (int i = 1; i < 256; i++) {
TCHAR name[256];
_stprintf_s(name, 256, _T(R"(\\.\COM%d)"), i);
HANDLE handle = HandleInfo::handleOpen(name,
d->m_BaudRate,
d->m_DataBits,
d->m_Parity,
d->m_StopBits,
d->m_FlowControl);
if (handle) {
if (HandleInfo::handleWrite(handle, data, len)) {
std::this_thread::sleep_for(std::chrono::milliseconds(time));
if (HandleInfo::handleRead(handle, buffer, len)) {
bool isVerify = true;
for (int v: verify) {
if (buffer[v] != data[v]) {
isVerify = false;
break;
}
}
if (isVerify) {
#ifdef _DEBUG
std::wcout << name << "\t";
for (int di = 0; di < len; ++di) printf("%02x ", buffer[di]);
printf("\n");
#endif
closed.push_back(new HandleInfo(i));
}
}
}
CloseHandle(handle);
}
}
delete[]buffer;
for (auto &info: d->m_HandleInfos) {
if (info->handleIsOpen()) closed.push_back(info);
else delete info;
}
std::sort(closed.begin(), closed.end(),
[](HandleInfo *a, HandleInfo *b) {
return a->handlePort() < b->handlePort();
});
d->m_HandleInfos = closed;
return static_cast<int>(closed.size());
}
int SerialPort::serialPort(int index) const {
HandleInfo *d_ptr = d->instances(index);
if (d_ptr)return d_ptr->handlePort();
return 0;
}
bool SerialPort::serialIsOpen(int index) const {
HandleInfo *d_ptr = d->instances(index);
if (d_ptr)return d_ptr->handleIsOpen();
return false;
}
bool SerialPort::serialOpen(int index, const callbackFunction &callback, int len) {
HandleInfo *d_ptr = d->instances(index);
bool result = false;
if (d_ptr) {
TCHAR name[256];
_stprintf_s(name, 256, _T(R"(\\.\COM%d)"), d_ptr->handlePort());
HANDLE handle = HandleInfo::handleOpen(name,
d->m_BaudRate,
d->m_DataBits,
d->m_Parity,
d->m_StopBits,
d->m_FlowControl);
result = d_ptr->handleOpen(handle, callback, len);
}
return result;
}
void SerialPort::serialClose(int index) {
HandleInfo *d_ptr = d->instances(index);
if (d_ptr) d_ptr->handleClose();
}
bool SerialPort::serialWrite(int index, unsigned char *order, int len,
unsigned char *buffer, const std::vector<int> &verify,
int reissue, unsigned long time) {
bool result = false;
HandleInfo *d_ptr = d->instances(index);
if (d_ptr) result = d_ptr->handleWrite(order, len, buffer, verify, reissue, time);
return result;
}