From a64832cb5d54613c5b0de135790fd99c58afbe22 Mon Sep 17 00:00:00 2001 From: JIe Date: Sun, 29 Sep 2024 16:43:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E8=87=B3C++23,=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8std::expected=E6=9B=BF=E4=BB=A3std::optional,=20?= =?UTF-8?q?=E7=94=A8range=E6=9B=BF=E4=BB=A3for,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 7 +- include/serial.h | 367 +++++++++++++++++++++++------------------------ main.cc | 67 ++++++--- 3 files changed, 233 insertions(+), 208 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66e0588..195c52d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,12 @@ cmake_minimum_required(VERSION 3.26) set(PROJECT_N demo) project(${PROJECT_N} VERSION 1.0) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -include_directories(${CMAKE_SOURCE_DIR}/include) - +include_directories(${CMAKE_SOURCE_DIR}/include/) +include_directories(${CMAKE_SOURCE_DIR}/third/) add_executable(${PROJECT_N} ${CMAKE_SOURCE_DIR}/third/serialib.cpp diff --git a/include/serial.h b/include/serial.h index d421100..1f76971 100644 --- a/include/serial.h +++ b/include/serial.h @@ -1,205 +1,194 @@ #ifndef SERIAL_H #define SERIAL_H -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include -#include "../third/serialib.h" +#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 -{ +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(); +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); } - return portArray; + 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; } - template - concept SupportString = requires { - std::is_same_v; - std::is_same_v; - }; + bool IsOpen() { return ser.isDeviceOpen(); } - 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; - } - } + 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 = 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(); + char *buffer = new char[availableSize + 1]; + std::memset(buffer, 0, availableSize); + auto size = ser.readBytes(buffer, availableSize, timeout); + + if (size > 0) { + buffer[size] = '\0'; + std::string response = std::string(buffer); + Log("Receive: " + response); + delete[] buffer; + if (removeEcho) + response.replace(0, reallyCommand.length(), ""); + return response; + } + delete[] buffer; + 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, T expect = "OK", int timeout = 200) { + 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; + } +}; +} // namespace serial #endif // SERIAL_H diff --git a/main.cc b/main.cc index d01a202..c4d967b 100644 --- a/main.cc +++ b/main.cc @@ -1,24 +1,59 @@ -#include "include/serial.h" -#include +#include #include +#include +#include +#include +#include + +#include "include/serial.h" +#undef max using namespace std::literals::chrono_literals; +using namespace serial; +namespace ranges = std::ranges; +namespace views = std::views; -void PrintLog(const std::string& msg){ - std::cout<> portName; + std::cin.ignore(std::numeric_limits::max(), '\n'); + serial.OpenDevice(portName); serial.SetLogCallBack(PrintLog); - if(!serial.OpenDevice(R"(\\.\COM11)", 115200)){ - std::cout<<"Open device failed"<( + endTime - startTime) + .count() + << std::endl; + } else { + auto resp = serial.GetAtResponse(command); + auto endTime = std::chrono::system_clock::now(); + std::cout << "dura: " + << std::chrono::duration_cast( + endTime - startTime) + .count() + << std::endl; + std::cout << resp.value_or("Send Command Fail") << std::endl; + } } - auto startTime = std::chrono::system_clock::now(); - // auto res = serial.GetAtUntil("AT+CFUN=1","OK", 200); - // std::cout<(endTime-startTime).count(); + return 0; }