#ifndef SERIAL_H #define SERIAL_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "serialib.h" using namespace std::literals::chrono_literals; namespace ranges = std::ranges; namespace views = std::views; namespace serial { static std::vector GetUsbPorts() { std::vector portArray; std::string comname; std::string showname; ranges::for_each(views::iota(1, 256), [&](int i) { std::format_to(std::back_inserter(comname), "\\\\.\\COM{}", i); std::format_to(std::back_inserter(showname), "COM{}", i); 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]] SerialErrorCode { SUCCESS, TIMEOUT, SETTIMEOUTERROR, WRITEINGERROR, READINGERROR, }; class Serial { private: serialib ser; const char *endChar = "\r\n"; std::function logCallBack; bool removeEcho = true; public: Serial() = default; ~Serial() { CloseDevice(); } Serial(const Serial &other) = delete; Serial(Serial &&other) = delete; Serial &operator=(const Serial &other) = delete; Serial &operator=(Serial &&other) = delete; auto SetRemoveEcho(bool remove) { removeEcho = remove; } static std::string GetTimeNow() { auto now = std::chrono::system_clock::now(); auto now_c = std::chrono::system_clock::to_time_t(now); char buffer[32]; auto _ = ctime_s(buffer, 32, &now_c); return buffer; } bool IsOpen() { return ser.isDeviceOpen(); } template bool OpenDeviceDelay(T portName, unsigned int baudRate, int delay) { std::this_thread::sleep_for(std::chrono::seconds(delay)); return OpenDevice(portName, baudRate); } template bool OpenDevice(T portName, unsigned int bauds = 115200, int delayTime = 0) { std::string reallyPortName; std::format_to(std::back_inserter(reallyPortName), "\\\\.\\{}", portName); std::this_thread::sleep_for(std::chrono::milliseconds(delayTime)); if (ser.isDeviceOpen()) return true; int code = ser.openDevice(reallyPortName.c_str(), bauds); if (code == 1) { return true; } else { return false; } } void Log(const std::string &log) const { if (logCallBack) { auto msg = GetTimeNow() + " " + log; logCallBack(msg); } } void SetLogCallBack(const std::function &callBack) { logCallBack = callBack; } void CloseDevice() { if (!ser.isDeviceOpen()) return; ser.closeDevice(); } template std::expected DelayGetResponse(int delayTime, T command, int timeout = 50) { std::this_thread::sleep_for(std::chrono::milliseconds(delayTime)); return GetAtResponse(command, timeout); } template std::expected GetAtResponse(T command, int timeout = 50) { 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); std::this_thread::sleep_for(10ms); auto availableSize = ser.available(); auto buffer = std::make_unique(availableSize + 1); std::memset(buffer.get(), 0, availableSize); auto size = ser.readBytes(buffer.get(), availableSize, timeout); if (size > 0) { buffer[size] = '\0'; std::string response = std::string(buffer); Log("Receive: " + response); if (removeEcho) response.replace(0, reallyCommand.length(), ""); return response; } return std::unexpected(SerialErrorCode::TIMEOUT); } template auto GetAtResponseRepeat(T command, int timeout = 200, int repeatTime = 1) -> void { for (int i = 0; i <= repeatTime; i++) { auto _ = GetAtResponse(command, timeout); } } template bool GetAtUntil(T command, Args... expect) { 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 = std::make_unique(availableSize + 1); auto size = ser.readBytes(buffer.get(), availableSize, timeout); buffer[size] = '\0'; auto str = std::string(buffer.get()); if (size > 0) Log("Receive: " + str); if (((str.find(expect) != std::string::npos) && ...)) { return true; } } return false; } }; } // namespace serial #endif // SERIAL_H