mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 05:05:19 -05:00
fix: Many issues and code style of the TTY console
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
#include <thread>
|
||||
#include <jthread.hpp>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
#include <wolv/container/interval_tree.hpp>
|
||||
|
||||
namespace hex::plugin::windows {
|
||||
|
||||
@@ -17,68 +19,64 @@ namespace hex::plugin::windows {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::wstring, std::wstring>> m_comPorts;
|
||||
void drawConsole();
|
||||
|
||||
std::vector<std::pair<std::wstring, std::wstring>> getAvailablePorts() const;
|
||||
bool connect();
|
||||
bool disconnect();
|
||||
|
||||
void transmitData(std::vector<char> &data);
|
||||
|
||||
void* m_portHandle = reinterpret_cast<void*>(-1);
|
||||
std::jthread m_receiveThread;
|
||||
|
||||
int m_selectedPort = 0;
|
||||
int m_selectedBaudRate = 11; // 115200
|
||||
int m_selectedNumBits = 3; // 8
|
||||
int m_selectedStopBits = 0; // 1
|
||||
int m_selectedParityBits = 0; // None
|
||||
bool m_hasCTSFlowControl = false; // No
|
||||
|
||||
bool m_shouldAutoScroll = true;
|
||||
|
||||
std::mutex m_receiveBufferMutex;
|
||||
std::vector<char> m_receiveDataBuffer, m_transmitDataBuffer;
|
||||
std::vector<u32> m_wrapPositions;
|
||||
bool m_transmitting = false;
|
||||
private:
|
||||
struct Port {
|
||||
std::string name;
|
||||
std::wstring path;
|
||||
};
|
||||
|
||||
constexpr static std::array BaudRates = {
|
||||
"110",
|
||||
"300",
|
||||
"600",
|
||||
"1200",
|
||||
"2400",
|
||||
"4800",
|
||||
"9600",
|
||||
"14400",
|
||||
"19200",
|
||||
"38400",
|
||||
"57600",
|
||||
"115200",
|
||||
"128000",
|
||||
"256000"
|
||||
110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
|
||||
};
|
||||
|
||||
constexpr static std::array NumBits = {
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8"
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8
|
||||
};
|
||||
|
||||
constexpr static std::array StopBits = {
|
||||
"1",
|
||||
"1.5",
|
||||
"2.0"
|
||||
enum class StopBits : u8 {
|
||||
_1_0 = ONESTOPBIT,
|
||||
_1_5 = ONE5STOPBITS,
|
||||
_2_0 = TWOSTOPBITS
|
||||
};
|
||||
|
||||
constexpr static std::array ParityBits = {
|
||||
"None",
|
||||
"Odd",
|
||||
"Even",
|
||||
"Mark",
|
||||
"Space"
|
||||
enum class ParityBits {
|
||||
None = NOPARITY,
|
||||
Odd = ODDPARITY,
|
||||
Even = EVENPARITY,
|
||||
Mark = MARKPARITY,
|
||||
Space = SPACEPARITY
|
||||
};
|
||||
|
||||
std::vector<Port> getAvailablePorts() const;
|
||||
bool connect();
|
||||
bool disconnect();
|
||||
|
||||
void transmitData(const std::string &data);
|
||||
|
||||
void* m_portHandle = INVALID_HANDLE_VALUE;
|
||||
std::jthread m_receiveThread;
|
||||
|
||||
u32 m_selectedPortIndex = 0;
|
||||
i32 m_selectedBaudRate = 115200;
|
||||
i32 m_selectedNumBits = 8;
|
||||
StopBits m_selectedStopBits = StopBits::_1_0;
|
||||
ParityBits m_selectedParityBits = ParityBits::None;
|
||||
bool m_hasCTSFlowControl = false;
|
||||
|
||||
bool m_shouldAutoScroll = true;
|
||||
i64 m_scrollPosition = 0;
|
||||
|
||||
std::mutex m_receiveBufferMutex;
|
||||
std::vector<std::string> m_receiveLines;
|
||||
std::vector<ImColor> m_receiveLinesColor;
|
||||
std::string m_transmitDataBuffer;
|
||||
bool m_transmitting = false;
|
||||
std::vector<Port> m_comPorts;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace hex::plugin::windows {
|
||||
|
||||
ViewTTYConsole::ViewTTYConsole() : View::Window("hex.windows.view.tty_console.name", ICON_VS_TERMINAL) {
|
||||
m_comPorts = getAvailablePorts();
|
||||
m_selectedPortIndex = 0;
|
||||
m_transmitDataBuffer.resize(0xFFF, 0x00);
|
||||
m_receiveDataBuffer.reserve(0xFFF);
|
||||
m_receiveDataBuffer.push_back(0x00);
|
||||
}
|
||||
|
||||
void ViewTTYConsole::drawContent() {
|
||||
@@ -28,54 +25,58 @@ namespace hex::plugin::windows {
|
||||
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, connected);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, connected ? 0.5F : 1.0F);
|
||||
|
||||
ImGui::Combo(
|
||||
"hex.windows.view.tty_console.port"_lang, &m_selectedPort, [](void *data, int idx) {
|
||||
auto &ports = *static_cast<std::vector<std::pair<std::string, std::string>> *>(data);
|
||||
|
||||
return ports[idx].first.c_str();
|
||||
},
|
||||
&m_comPorts,
|
||||
m_comPorts.size());
|
||||
if (ImGui::BeginCombo("hex.windows.view.tty_console.port"_lang, m_comPorts.empty() ? "" : m_comPorts[m_selectedPortIndex].name.c_str())) {
|
||||
for (u32 i = 0; i < m_comPorts.size(); i++) {
|
||||
const auto &port = m_comPorts[i];
|
||||
if (ImGui::Selectable(port.name.c_str(), m_selectedPortIndex == i)) {
|
||||
m_selectedPortIndex = i;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.windows.view.tty_console.reload"_lang))
|
||||
if (ImGui::Button("hex.windows.view.tty_console.reload"_lang)) {
|
||||
m_comPorts = getAvailablePorts();
|
||||
m_selectedPortIndex = 0;
|
||||
}
|
||||
|
||||
ImGui::Combo(
|
||||
"hex.windows.view.tty_console.baud"_lang, &m_selectedBaudRate, [](void *data, int idx) {
|
||||
std::ignore = data;
|
||||
if (ImGui::BeginCombo("hex.windows.view.tty_console.baud"_lang, std::to_string(m_selectedBaudRate).c_str())) {
|
||||
for (auto baudRate : BaudRates) {
|
||||
if (ImGui::Selectable(std::to_string(baudRate).c_str(), m_selectedBaudRate == baudRate)) {
|
||||
m_selectedBaudRate = baudRate;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
return ViewTTYConsole::BaudRates[idx];
|
||||
},
|
||||
nullptr,
|
||||
ViewTTYConsole::BaudRates.size());
|
||||
if (ImGui::BeginCombo("hex.windows.view.tty_console.num_bits"_lang, std::to_string(m_selectedNumBits).c_str())) {
|
||||
for (auto numBits : NumBits) {
|
||||
if (ImGui::Selectable(std::to_string(numBits).c_str(), m_selectedBaudRate == numBits)) {
|
||||
m_selectedBaudRate = numBits;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::Combo(
|
||||
"hex.windows.view.tty_console.num_bits"_lang, &m_selectedNumBits, [](void *data, int idx) {
|
||||
std::ignore = data;
|
||||
|
||||
return ViewTTYConsole::NumBits[idx];
|
||||
},
|
||||
nullptr,
|
||||
ViewTTYConsole::NumBits.size());
|
||||
|
||||
ImGui::Combo(
|
||||
"hex.windows.view.tty_console.stop_bits"_lang, &m_selectedStopBits, [](void *data, int idx) {
|
||||
std::ignore = data;
|
||||
|
||||
return ViewTTYConsole::StopBits[idx];
|
||||
},
|
||||
nullptr,
|
||||
ViewTTYConsole::StopBits.size());
|
||||
|
||||
ImGui::Combo(
|
||||
"hex.windows.view.tty_console.parity_bits"_lang, &m_selectedParityBits, [](void *data, int idx) {
|
||||
std::ignore = data;
|
||||
|
||||
return ViewTTYConsole::ParityBits[idx];
|
||||
},
|
||||
nullptr,
|
||||
ViewTTYConsole::ParityBits.size());
|
||||
constexpr static std::array StopBitsStrings = { "1", "1.5", "2" };
|
||||
if (ImGui::BeginCombo( "hex.windows.view.tty_console.stop_bits"_lang, StopBitsStrings[u32(m_selectedStopBits)])) {
|
||||
for (u32 i = 0; i < StopBitsStrings.size(); i++) {
|
||||
if (ImGui::Selectable(StopBitsStrings[i], m_selectedStopBits == StopBits(i))) {
|
||||
m_selectedStopBits = StopBits(i);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
constexpr static std::array ParityBitsStrings = { "None", "Odd", "Even", "Mark", "Space" };
|
||||
if (ImGui::BeginCombo( "hex.windows.view.tty_console.parity_bits"_lang, ParityBitsStrings[u32(m_selectedParityBits)])) {
|
||||
for (u32 i = 0; i < ParityBitsStrings.size(); i++) {
|
||||
if (ImGui::Selectable(ParityBitsStrings[i], m_selectedParityBits == ParityBits(i))) {
|
||||
m_selectedParityBits = ParityBits(i);
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::Checkbox("hex.windows.view.tty_console.cts"_lang, &m_hasCTSFlowControl);
|
||||
|
||||
@@ -98,50 +99,19 @@ namespace hex::plugin::windows {
|
||||
if (ImGui::Button("hex.windows.view.tty_console.clear"_lang)) {
|
||||
std::scoped_lock lock(m_receiveBufferMutex);
|
||||
|
||||
m_receiveDataBuffer.clear();
|
||||
m_wrapPositions.clear();
|
||||
m_receiveLines.clear();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("hex.windows.view.tty_console.auto_scroll"_lang, &m_shouldAutoScroll);
|
||||
|
||||
ImGuiExt::Header("hex.windows.view.tty_console.console"_lang);
|
||||
|
||||
auto consoleSize = ImMax(ImGui::GetContentRegionAvail(), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5));
|
||||
consoleSize.y -= ImGui::GetTextLineHeight() + ImGui::GetStyle().FramePadding.y * 4;
|
||||
if (ImGui::BeginChild("##scrolling", consoleSize, true, ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(m_wrapPositions.size(), ImGui::GetTextLineHeight());
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1));
|
||||
while (clipper.Step()) {
|
||||
std::scoped_lock lock(m_receiveBufferMutex);
|
||||
|
||||
for (int i = clipper.DisplayStart + 1; i < clipper.DisplayEnd; i++) {
|
||||
ImGui::TextUnformatted(m_receiveDataBuffer.data() + m_wrapPositions[i - 1], m_receiveDataBuffer.data() + m_wrapPositions[i]);
|
||||
}
|
||||
|
||||
if (!m_receiveDataBuffer.empty() && !m_wrapPositions.empty())
|
||||
if (static_cast<size_t>(clipper.DisplayEnd) >= m_wrapPositions.size() - 1)
|
||||
ImGui::TextUnformatted(m_receiveDataBuffer.data() + m_wrapPositions.back());
|
||||
|
||||
if (m_shouldAutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
||||
ImGui::SetScrollHereY(0.0F);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
this->drawConsole();
|
||||
|
||||
ImGui::PushItemWidth(-1);
|
||||
if (ImGui::InputText("##transmit", m_transmitDataBuffer.data(), m_transmitDataBuffer.size() - 2, ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
auto size = strlen(m_transmitDataBuffer.data());
|
||||
|
||||
m_transmitDataBuffer[size + 0] = '\n';
|
||||
m_transmitDataBuffer[size + 1] = 0x00;
|
||||
|
||||
this->transmitData(m_transmitDataBuffer);
|
||||
if (ImGui::InputText("##transmit", m_transmitDataBuffer, ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||
this->transmitData(m_transmitDataBuffer + "\r\n");
|
||||
m_transmitDataBuffer.clear();
|
||||
ImGui::SetKeyboardFocusHere(0);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
@@ -151,33 +121,56 @@ namespace hex::plugin::windows {
|
||||
|
||||
if (ImGui::BeginPopup("ConsoleMenu")) {
|
||||
|
||||
static std::vector<char> buffer(2, 0x00);
|
||||
if (ImGui::MenuItem("hex.windows.view.tty_console.send_etx"_lang, "CTRL + C")) {
|
||||
buffer[0] = 0x03;
|
||||
this->transmitData(buffer);
|
||||
this->transmitData({ 0x03 });
|
||||
}
|
||||
if (ImGui::MenuItem("hex.windows.view.tty_console.send_eot"_lang, "CTRL + D")) {
|
||||
buffer[0] = 0x04;
|
||||
this->transmitData(buffer);
|
||||
this->transmitData({ 0x04 });
|
||||
}
|
||||
if (ImGui::MenuItem("hex.windows.view.tty_console.send_sub"_lang, "CTRL + Z")) {
|
||||
buffer[0] = 0x1A;
|
||||
this->transmitData(buffer);
|
||||
this->transmitData({ 0x1A });
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::wstring, std::wstring>> ViewTTYConsole::getAvailablePorts() const {
|
||||
std::vector<std::pair<std::wstring, std::wstring>> result;
|
||||
void ViewTTYConsole::drawConsole() {
|
||||
ImGuiExt::Header("hex.windows.view.tty_console.console"_lang);
|
||||
|
||||
auto consoleSize = ImMax(ImGui::GetContentRegionAvail(), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5));
|
||||
consoleSize.y -= ImGui::GetTextLineHeight() + ImGui::GetStyle().FramePadding.y * 4;
|
||||
if (ImGui::BeginChild("##scrolling", consoleSize, true, ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(m_receiveLines.size(), ImGui::GetTextLineHeight());
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1));
|
||||
while (clipper.Step()) {
|
||||
std::scoped_lock lock(m_receiveBufferMutex);
|
||||
|
||||
for (int i = clipper.DisplayStart + 1; i < clipper.DisplayEnd; i++) {
|
||||
ImGui::TextUnformatted(m_receiveLines[i].c_str());
|
||||
}
|
||||
|
||||
if (m_shouldAutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
|
||||
ImGui::SetScrollHereY(0.0F);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
|
||||
std::vector<ViewTTYConsole::Port> ViewTTYConsole::getAvailablePorts() const {
|
||||
std::vector<Port> result;
|
||||
std::vector<wchar_t> buffer(0xFFF, 0x00);
|
||||
|
||||
for (u16 portNumber = 0; portNumber <= 255; portNumber++) {
|
||||
std::wstring port = L"COM" + std::to_wstring(portNumber);
|
||||
|
||||
if (::QueryDosDeviceW(port.c_str(), buffer.data(), buffer.size()) != 0) {
|
||||
result.emplace_back(port, buffer.data());
|
||||
result.emplace_back(utf16ToUtf8(port), L"\\\\.\\" + port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,22 +178,25 @@ namespace hex::plugin::windows {
|
||||
}
|
||||
|
||||
bool ViewTTYConsole::connect() {
|
||||
if (m_comPorts.empty() || static_cast<size_t>(m_selectedPort) >= m_comPorts.size()) {
|
||||
if (m_comPorts.empty() || static_cast<size_t>(m_selectedPortIndex) >= m_comPorts.size()) {
|
||||
ui::ToastError::open("hex.windows.view.tty_console.no_available_port"_lang);
|
||||
return true; // If false, connect_error error popup will override this error popup
|
||||
return true;
|
||||
}
|
||||
m_portHandle = ::CreateFileW((LR"(\\.\)" + m_comPorts[m_selectedPort].first).c_str(),
|
||||
m_portHandle = ::CreateFileW(m_comPorts[m_selectedPortIndex].path.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
if (m_portHandle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
auto closeHandle = SCOPE_GUARD { CloseHandle(m_portHandle); };
|
||||
auto closeHandle = SCOPE_GUARD {
|
||||
CloseHandle(m_portHandle);
|
||||
m_portHandle = INVALID_HANDLE_VALUE;
|
||||
};
|
||||
|
||||
if (!::SetupComm(m_portHandle, 10000, 10000))
|
||||
return false;
|
||||
@@ -211,10 +207,10 @@ namespace hex::plugin::windows {
|
||||
if (!::GetCommState(m_portHandle, &serialParams))
|
||||
return false;
|
||||
|
||||
serialParams.BaudRate = std::stoi(ViewTTYConsole::BaudRates[m_selectedBaudRate]);
|
||||
serialParams.ByteSize = std::stoi(ViewTTYConsole::NumBits[m_selectedNumBits]);
|
||||
serialParams.StopBits = m_selectedStopBits;
|
||||
serialParams.Parity = m_selectedParityBits;
|
||||
serialParams.BaudRate = m_selectedBaudRate;
|
||||
serialParams.ByteSize = m_selectedNumBits;
|
||||
serialParams.StopBits = u32(m_selectedStopBits);
|
||||
serialParams.Parity = u32(m_selectedParityBits);
|
||||
serialParams.fOutxCtsFlow = m_hasCTSFlowControl;
|
||||
|
||||
if (!::SetCommState(m_portHandle, &serialParams))
|
||||
@@ -237,23 +233,23 @@ namespace hex::plugin::windows {
|
||||
OVERLAPPED overlapped = { };
|
||||
|
||||
overlapped.hEvent = ::CreateEvent(nullptr, true, false, nullptr);
|
||||
ON_SCOPE_EXIT { ::CloseHandle(&overlapped); };
|
||||
ON_SCOPE_EXIT { ::CloseHandle(overlapped.hEvent); };
|
||||
|
||||
auto addByte = [this](char byte) {
|
||||
auto addByte = [&, this](char byte) {
|
||||
std::scoped_lock lock(m_receiveBufferMutex);
|
||||
|
||||
if (byte >= 0x20 && byte <= 0x7E) {
|
||||
m_receiveDataBuffer.back() = byte;
|
||||
m_receiveDataBuffer.push_back(0x00);
|
||||
} else if (byte == '\n' || byte == '\r') {
|
||||
if (m_receiveDataBuffer.empty())
|
||||
return;
|
||||
|
||||
u32 wrapPos = m_receiveDataBuffer.size() - 1;
|
||||
|
||||
if (m_wrapPositions.empty() || m_wrapPositions.back() != wrapPos)
|
||||
m_wrapPositions.push_back(wrapPos);
|
||||
if (m_receiveLines.empty())
|
||||
m_receiveLines.emplace_back();
|
||||
if (std::isprint(byte)) {
|
||||
m_receiveLines.back().push_back(byte);
|
||||
} else if (byte == '\n') {
|
||||
m_receiveLines.emplace_back();
|
||||
} else if (byte == '\r') {
|
||||
// Ignore carriage return
|
||||
} else {
|
||||
m_receiveLines.back() += hex::format("<{:02X}>", static_cast<unsigned char>(byte));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
while (!token.stop_requested()) {
|
||||
@@ -261,16 +257,16 @@ namespace hex::plugin::windows {
|
||||
|
||||
char byte = 0;
|
||||
if (!waitingOnRead) {
|
||||
if (::ReadFile(m_portHandle, &byte, sizeof(char), &bytesRead, &overlapped)) {
|
||||
if (::ReadFile(m_portHandle, &byte, sizeof(char), &bytesRead, &overlapped) && bytesRead > 0) {
|
||||
addByte(byte);
|
||||
} else if (::GetLastError() == ERROR_IO_PENDING) {
|
||||
waitingOnRead = true;
|
||||
}
|
||||
} else {
|
||||
byte = 0;
|
||||
byte = 0;
|
||||
switch (::WaitForSingleObject(overlapped.hEvent, 500)) {
|
||||
case WAIT_OBJECT_0:
|
||||
if (::GetOverlappedResult(m_portHandle, &overlapped, &bytesRead, false)) {
|
||||
if (::GetOverlappedResult(m_portHandle, &overlapped, &bytesRead, false) && bytesRead > 0) {
|
||||
addByte(byte);
|
||||
waitingOnRead = false;
|
||||
}
|
||||
@@ -286,39 +282,30 @@ namespace hex::plugin::windows {
|
||||
|
||||
bool ViewTTYConsole::disconnect() {
|
||||
::SetCommMask(m_portHandle, EV_TXEMPTY);
|
||||
m_receiveThread.request_stop();
|
||||
m_receiveThread.join();
|
||||
|
||||
::CloseHandle(m_portHandle);
|
||||
m_portHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (m_receiveThread.joinable()) {
|
||||
m_receiveThread.request_stop();
|
||||
m_receiveThread.join();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewTTYConsole::transmitData(std::vector<char> &data) {
|
||||
void ViewTTYConsole::transmitData(const std::string &data) {
|
||||
if (m_transmitting)
|
||||
return;
|
||||
|
||||
TaskManager::createBackgroundTask("hex.windows.view.tty_console.task.transmitting", [&, this](auto&) {
|
||||
OVERLAPPED overlapped = { };
|
||||
m_transmitting = true;
|
||||
|
||||
overlapped.hEvent = ::CreateEvent(nullptr, true, false, nullptr);
|
||||
ON_SCOPE_EXIT { ::CloseHandle(&overlapped); };
|
||||
DWORD bytesWritten = 0;
|
||||
if (!::WriteFile(m_portHandle, data.data(), data.size(), &bytesWritten, nullptr)) {
|
||||
log::error("Failed to write data to serial port: {}", formatSystemError(::GetLastError()));
|
||||
}
|
||||
|
||||
m_transmitting = true;
|
||||
|
||||
DWORD bytesWritten = 0;
|
||||
if (!::WriteFile(m_portHandle, data.data(), strlen(data.data()), &bytesWritten, &overlapped)) {
|
||||
if (::GetLastError() == ERROR_IO_PENDING) {
|
||||
::GetOverlappedResult(m_portHandle, &overlapped, &bytesWritten, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesWritten > 0)
|
||||
data[0] = 0x00;
|
||||
|
||||
m_transmitting = false;
|
||||
});
|
||||
m_transmitting = false;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user