From 635a07e2bfb1ee2d9ac6363684485b6a806b3cd0 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Sat, 6 Dec 2025 19:58:52 +0100 Subject: [PATCH] feat: OSerialBus --- .gitignore | 60 ++++++++++ MotionCore.sln | 31 ++++++ MotionCore/MainLoop.cpp | 5 + MotionCore/MainLoop.h | 7 ++ MotionCore/MotionCore.vcxproj | 153 ++++++++++++++++++++++++++ MotionCore/MotionCore.vcxproj.filters | 36 ++++++ MotionCore/OSerialBus.cpp | 110 ++++++++++++++++++ MotionCore/OSerialBus.h | 27 +++++ MotionCore/main.cpp | 18 +++ 9 files changed, 447 insertions(+) create mode 100755 .gitignore create mode 100755 MotionCore.sln create mode 100755 MotionCore/MainLoop.cpp create mode 100755 MotionCore/MainLoop.h create mode 100755 MotionCore/MotionCore.vcxproj create mode 100755 MotionCore/MotionCore.vcxproj.filters create mode 100755 MotionCore/OSerialBus.cpp create mode 100755 MotionCore/OSerialBus.h create mode 100755 MotionCore/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..16cd662 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# ------------------------- +# Visual Studio / MSBuild +# ------------------------- +.vs/ +*.VC.db +*.VC.opendb +*.VC.VC.opendb + +# User-spezifische Dateien +*.user +*.suo +*.userosscache +*.sln.docstates + +# Build-Verzeichnisse +Debug/ +DebugPublic/ +Release/ +x64/ +x86/ +Build/ +Bin/ +Obj/ +Out/ + +# CMake +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +*.cmake +out/ + +# Compilierte Artefakte +*.obj +*.pdb +*.idb +*.ilk +*.exe +*.dll +*.lib +*.exp +*.iobj +*.ipdb + +# Präkompilierte Header +*.pch + +# Log- und Temp-Dateien +*.log +*.tlog +*.tmp + +# Visual Studio Einstellungen +*.vcxproj.user + +# NuGet (falls genutzt) +packages/ + +# Crash Dumps +*.dmp diff --git a/MotionCore.sln b/MotionCore.sln new file mode 100755 index 0000000..6ca6eee --- /dev/null +++ b/MotionCore.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.33027.164 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MotionCore", "MotionCore\MotionCore.vcxproj", "{D095587F-5B2C-4701-8559-FD1769A78582}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D095587F-5B2C-4701-8559-FD1769A78582}.Debug|x64.ActiveCfg = Debug|x64 + {D095587F-5B2C-4701-8559-FD1769A78582}.Debug|x64.Build.0 = Debug|x64 + {D095587F-5B2C-4701-8559-FD1769A78582}.Debug|x86.ActiveCfg = Debug|Win32 + {D095587F-5B2C-4701-8559-FD1769A78582}.Debug|x86.Build.0 = Debug|Win32 + {D095587F-5B2C-4701-8559-FD1769A78582}.Release|x64.ActiveCfg = Release|x64 + {D095587F-5B2C-4701-8559-FD1769A78582}.Release|x64.Build.0 = Release|x64 + {D095587F-5B2C-4701-8559-FD1769A78582}.Release|x86.ActiveCfg = Release|Win32 + {D095587F-5B2C-4701-8559-FD1769A78582}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E4B52E92-E76E-4E0D-BFA6-8DE6CBD924FC} + EndGlobalSection +EndGlobal diff --git a/MotionCore/MainLoop.cpp b/MotionCore/MainLoop.cpp new file mode 100755 index 0000000..5d98500 --- /dev/null +++ b/MotionCore/MainLoop.cpp @@ -0,0 +1,5 @@ +#include "MainLoop.h" + +void MainLoop::run() +{ +} diff --git a/MotionCore/MainLoop.h b/MotionCore/MainLoop.h new file mode 100755 index 0000000..d4ab0da --- /dev/null +++ b/MotionCore/MainLoop.h @@ -0,0 +1,7 @@ +#pragma once + +class MainLoop +{ +public: + void run(); +}; diff --git a/MotionCore/MotionCore.vcxproj b/MotionCore/MotionCore.vcxproj new file mode 100755 index 0000000..dd3d49f --- /dev/null +++ b/MotionCore/MotionCore.vcxproj @@ -0,0 +1,153 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {d095587f-5b2c-4701-8559-fd1769a78582} + MotionCore + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);WINDOWS + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);WINDOWS + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);WINDOWS + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);WINDOWS + true + + + Console + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MotionCore/MotionCore.vcxproj.filters b/MotionCore/MotionCore.vcxproj.filters new file mode 100755 index 0000000..ce23d70 --- /dev/null +++ b/MotionCore/MotionCore.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + + + Headerdateien + + + Headerdateien + + + \ No newline at end of file diff --git a/MotionCore/OSerialBus.cpp b/MotionCore/OSerialBus.cpp new file mode 100755 index 0000000..c235eb7 --- /dev/null +++ b/MotionCore/OSerialBus.cpp @@ -0,0 +1,110 @@ +#include "OSerialBus.h" +#include + +#ifdef WINDOWS +OSerialBus::OSerialBus(const std::wstring& comPort, int baudRate): + comPort(comPort), + baudRate(baudRate) +{ + serialHandle = CreateFile(normalizePort(comPort).c_str(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (!serialHandle) { + std::wcerr << L"Unable to open serial port file " << normalizePort(comPort) << L"!" << std::endl; + return; + } + + DCB serialParams = { 0 }; + serialParams.DCBlength = sizeof(serialParams); + + if (!GetCommState(serialHandle, &serialParams)) { + std::wcerr << L"Unable to get comm state of port " << normalizePort(comPort) << L"! Is the port busy?" << std::endl; + return; + } + + serialParams.BaudRate = baudRate; + + if (!SetCommState(serialHandle, &serialParams)) { + std::wcerr << L"Unable to set comm state of port " << normalizePort(comPort) << L"! Is the port busy?" << std::endl; + return; + } + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 50; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + if (!SetCommTimeouts(serialHandle, &timeouts)) { + std::wcerr << L"Unable to set comm timeouts of port " << normalizePort(comPort) << L"! Is the port busy?" << std::endl; + return; + } + + open = true; +} + +bool OSerialBus::isOpen() const +{ + return open; +} + +bool OSerialBus::close() +{ + return CloseHandle(serialHandle); +} + +bool OSerialBus::send(const std::string& line) +{ + // Important: this relies on chartype of line being 1 byte long! + const char* data = line.data(); + std::size_t remaining = line.size(); + + while (remaining > 0) { + DWORD bytesWritten = 0; + + if (!WriteFile(serialHandle, data, (DWORD)remaining, &bytesWritten, nullptr)) { + return false; + } + if (bytesWritten == 0) { + return false; + } + + data += bytesWritten; + remaining -= bytesWritten; + } + + return true; +} + +bool OSerialBus::sendl(const std::string& line) +{ + if (!send(line)) { + return false; + } + return send("\n"); +} + +int OSerialBus::getBaudRate() const +{ + return baudRate; +} + +const std::wstring& OSerialBus::getComPort() const +{ + return comPort; +} + +std::wstring OSerialBus::normalizePort(const std::wstring& port) +{ + // If port string already includes prefix, return as-is + if (port == L"\\\\.\\") { + return port; + } + + // If the first 3 chars in the portstring are COM, prefix the prefix + if (_wcsnicmp(port.c_str(), L"COM", 3) == 0) { + return std::wstring(L"\\\\.\\") + port; + } + + return port; +} +#endif diff --git a/MotionCore/OSerialBus.h b/MotionCore/OSerialBus.h new file mode 100755 index 0000000..fe20327 --- /dev/null +++ b/MotionCore/OSerialBus.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +class OSerialBus +{ + #ifdef WINDOWS +public: + OSerialBus(const std::wstring& comPort, int baudRate = 9600); + + bool isOpen() const; + bool close(); + bool send(const std::string& line); + bool sendl(const std::string& line); + + int getBaudRate() const; + const std::wstring& getComPort() const; + +private: + static std::wstring normalizePort(const std::wstring& port); + + const std::wstring& comPort; + const int baudRate = 0; + HANDLE serialHandle; + bool open = false; + #endif // WINDOWS +}; diff --git a/MotionCore/main.cpp b/MotionCore/main.cpp new file mode 100755 index 0000000..d836d4d --- /dev/null +++ b/MotionCore/main.cpp @@ -0,0 +1,18 @@ +#include +#include "MainLoop.h" +#include "OSerialBus.h" + +int main() +{ + OSerialBus bus(L"COM4"); + if (!bus.isOpen()) { + std::cerr << "Serial bus is not open! Is the COM port busy?" << std::endl; + return -1; + } + bus.sendl("MA 1 120"); + + bus.close(); + + MainLoop mainloop; + mainloop.run(); +}