From 0f5c1da12f912120b40f8401d3c61eb18feb9d0b Mon Sep 17 00:00:00 2001 From: illyum <90023277+itzilly@users.noreply.github.com> Date: Fri, 16 Aug 2024 02:17:43 -0600 Subject: [PATCH] (Feat): Implement DMX Engine --- src/DmxWriter.cpp | 11 +++++ src/DmxWriter.h | 19 ++++++++ src/dmx.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++++++ src/dmx.h | 37 +++++++++++++-- 4 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/DmxWriter.cpp create mode 100644 src/DmxWriter.h diff --git a/src/DmxWriter.cpp b/src/DmxWriter.cpp new file mode 100644 index 0000000..1c93eb3 --- /dev/null +++ b/src/DmxWriter.cpp @@ -0,0 +1,11 @@ +// +// Created by illyum on 8/16/2024. +// + +#include "DmxWriter.h" + +DmxWriter::DmxWriter(DMXEngine& engine) : dmxEngine(engine) {} + +void DmxWriter::setChannel(int channel, unsigned char value) { + dmxEngine.setChannelValue(channel, value); +} \ No newline at end of file diff --git a/src/DmxWriter.h b/src/DmxWriter.h new file mode 100644 index 0000000..21def5f --- /dev/null +++ b/src/DmxWriter.h @@ -0,0 +1,19 @@ +// +// Created by illyum on 8/16/2024. +// + +#ifndef DMXWRITER_H +#define DMXWRITER_H + +#include "dmx.h" + +class DmxWriter { +public: + DmxWriter(DMXEngine& engine); + void setChannel(int channel, unsigned char value); + +private: + DMXEngine& dmxEngine; +}; + +#endif // DMXWRITER_H \ No newline at end of file diff --git a/src/dmx.cpp b/src/dmx.cpp index bb545f6..623b792 100644 --- a/src/dmx.cpp +++ b/src/dmx.cpp @@ -1,3 +1,117 @@ // // Created by illyum on 8/15/2024. // + +#include "dmx.h" +#include +#include +#include +#include "windows.h" + +DMXEngine::DMXEngine(const char* portName, int baudRate, int dataSize) + : running(false), buffer(dataSize, 0) { + hSerial = CreateFileA(portName, GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (hSerial == INVALID_HANDLE_VALUE) { + std::cerr << "Error opening " << portName << " port" << std::endl; + exit(EXIT_FAILURE); + } + + configurePort(); +} + +DMXEngine::~DMXEngine() { + if (running) { + stop(); + } + CloseHandle(hSerial); +} + +void DMXEngine::configurePort() { + DCB dcbSerialParams = { 0 }; + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + if (!GetCommState(hSerial, &dcbSerialParams)) { + std::cerr << "Error getting COM port state" << std::endl; + CloseHandle(hSerial); + exit(EXIT_FAILURE); + } + + dcbSerialParams.BaudRate = 250000; + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = TWOSTOPBITS; + dcbSerialParams.Parity = NOPARITY; + + if (!SetCommState(hSerial, &dcbSerialParams)) { + std::cerr << "Error setting COM port state" << std::endl; + CloseHandle(hSerial); + exit(EXIT_FAILURE); + } + + COMMTIMEOUTS timeouts = { 0 }; + timeouts.ReadIntervalTimeout = 50; + timeouts.ReadTotalTimeoutConstant = 50; + timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + + if (!SetCommTimeouts(hSerial, &timeouts)) { + std::cerr << "Error setting COM port timeouts" << std::endl; + CloseHandle(hSerial); + exit(EXIT_FAILURE); + } +} + +void DMXEngine::start() { + running = true; + dmxThread = std::thread(dmxThreadFunc, this); +} + +void DMXEngine::stop() { + running = false; + if (dmxThread.joinable()) { + dmxThread.join(); + } + + DMXEngine::dumpZeros(); +} + + +void DMXEngine::setChannelValue(int channel, unsigned char value) { + if (channel >= 0 && channel < buffer.size()) { + buffer[channel] = value; + } +} + +void DMXEngine::sendDMXData() { + while (running) { + // Break condition + EscapeCommFunction(hSerial, SETBREAK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + EscapeCommFunction(hSerial, CLRBREAK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // MAB + + DWORD bytesWritten; + unsigned char startCode = 0; + WriteFile(hSerial, &startCode, 1, &bytesWritten, NULL); + WriteFile(hSerial, buffer.data(), buffer.size(), &bytesWritten, NULL); + + std::this_thread::sleep_for(std::chrono::milliseconds(25)); + } +} + +void DMXEngine::dumpZeros() { + std::fill(buffer.begin(), buffer.end(), 0); + + EscapeCommFunction(hSerial, SETBREAK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + EscapeCommFunction(hSerial, CLRBREAK); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // MAB + + DWORD bytesWritten; + unsigned char startCode = 0; + WriteFile(hSerial, &startCode, 1, &bytesWritten, NULL); + WriteFile(hSerial, buffer.data(), buffer.size(), &bytesWritten, NULL); +} + +void DMXEngine::dmxThreadFunc(DMXEngine* engine) { + engine->sendDMXData(); +} diff --git a/src/dmx.h b/src/dmx.h index 7e4d23b..eceb48f 100644 --- a/src/dmx.h +++ b/src/dmx.h @@ -2,7 +2,38 @@ // Created by illyum on 8/15/2024. // -#ifndef RAYLIBDMX_DMX_H -#define RAYLIBDMX_DMX_H +#ifndef DMX_H +#define DMX_H -#endif //RAYLIBDMX_DMX_H +#include +#include +#include +#include + +struct DMXFixture { + unsigned char r, g, b; + int channel; +}; + +class DMXEngine { +public: + explicit DMXEngine(const char* portName, int baudRate = 250000, int dataSize = 512); + ~DMXEngine(); + + void start(); + void stop(); + void setChannelValue(int channel, unsigned char value); + +private: + void sendDMXData(); + void dumpZeros(); + void configurePort(); + static void dmxThreadFunc(DMXEngine* engine); + + void* hSerial; + std::atomic running; + std::vector buffer; + std::thread dmxThread; +}; + +#endif // DMX_H