#ifndef SERIAL_H #define SERIAL_H #include #include #include #include #include #include #include #include #include #include #include "../third/serialib.h" using namespace std::literals::chrono_literals; namespace serial { static std::vector GetUsbPorts() { std::vector portArray; std::string comname; std::string showname; for (int i = 0; i <= 256; i++) { std::format_to(std::back_inserter(comname), "\\\\.\\COM{}", i); std::format_to(std::back_inserter(showname), "COM{}", i); // 创建或者打开一个文件或者I/O设备,如执行成功,则返回文件句柄 INVALID_HANDLE_VALUE 表示出错 const HANDLE m_handle = ::CreateFileA(comname.c_str(), static_cast(GENERIC_WRITE) | GENERIC_READ, 0U, nullptr, OPEN_EXISTING, 0U, nullptr ); if (m_handle != INVALID_HANDLE_VALUE) { portArray.push_back(showname); CloseHandle(m_handle); } comname.clear(); showname.clear(); } return portArray; } template concept SupportString = requires { std::is_same_v; std::is_same_v; }; enum class [[maybe_unused]] ErrorCode { SUCCESS, TIMEOUT, SETTIMEOUTERROR, WRITEINGERROR, READINGERROR, }; class Serial { private: serialib ser; const char *endChar = "\r\n"; std::function logCallBack; public: Serial() = default; std::string GetTimeNow() { auto now = std::chrono::system_clock::now(); auto now_c = std::chrono::system_clock::to_time_t(now); char buffer[32]; ctime_s(buffer, 32, &now_c); return std::string(buffer); } bool IsOpen(){ return ser.isDeviceOpen(); } template bool OpenDevice(T portName, unsigned int bauds = 115200) { std::string reallyPortName; std::format_to(std::back_inserter(reallyPortName), "\\\\.\\{}", portName); if(ser.isDeviceOpen()) return true; int code; code = ser.openDevice(reallyPortName.c_str(), bauds); if (code == 1) { return true; } else { return false; } } void Log(const std::string &log) { if (logCallBack) { auto msg = GetTimeNow() + " " + log + "\n"; logCallBack(msg); } } void SetLogCallBack(std::function callBack) { logCallBack = callBack; } void CloseDevice() { if(!ser.isDeviceOpen()) return; ser.closeDevice(); } ~Serial() = default; template std::optional DelayGetResponse(int delayTime, T command, int timeout = 50){ std::this_thread::sleep_for(std::chrono::milliseconds(delayTime)); return GetAtResponse(command, timeout); } template std::optional GetAtResponse(T command, int timeout = 50) { ser.flushReceiver(); std::string reallyCommand; std::string response; if constexpr (std::is_same_v) { reallyCommand = command + endChar; } else { reallyCommand = std::string(command) + endChar; } ser.writeString(reallyCommand.c_str()); Log("Send: " + reallyCommand); std::this_thread::sleep_for(10ms); auto availableSize = ser.available(); char *buffer = new char[availableSize + 1]; std::memset(buffer, 0, availableSize); auto size = ser.readBytes(buffer, availableSize, timeout); if (size > 0) { buffer[size] = '\0'; response = std::string(buffer); Log("Receive: " + response); delete[] buffer; return response; } delete[] buffer; return std::nullopt; } template bool GetAtUntil(T command, T expect = "OK", int timeout = 50) { auto endTime = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout); ser.flushReceiver(); std::string reallyCommand; if constexpr (std::is_same_v) { reallyCommand = command + endChar; } else { reallyCommand = std::string(command) + endChar; } ser.writeString(reallyCommand.c_str()); Log("Send : " + reallyCommand); while (std::chrono::system_clock::now() < endTime) { std::this_thread::sleep_for(10ms); auto availableSize = ser.available(); auto buffer = new char[availableSize + 1]; auto size = ser.readBytes(buffer, availableSize, timeout); buffer[size] = '\0'; auto str = std::string(buffer); delete[] buffer; if (size > 0) Log("Receive: " + str); if (str.find(expect) != std::string::npos) { return true; } } return false; } }; } #endif // SERIAL_H