diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index 526f9cb..16281be 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -214,6 +214,7 @@ bool VortexEditor::init(HINSTANCE hInst) m_window.addCallback(ID_EDIT_CLEAR_PATTERN, handleMenusCallback); m_window.addCallback(ID_OPTIONS_TRANSMIT_DUO, handleMenusCallback); m_window.addCallback(ID_OPTIONS_TRANSMIT_INFRARED, handleMenusCallback); + m_window.addCallback(ID_OPTIONS_RECEIVE_FROM_DUO, handleMenusCallback); m_window.addCallback(ID_EDIT_UNDO, handleMenusCallback); m_window.addCallback(ID_EDIT_REDO, handleMenusCallback); m_window.addCallback(ID_FILE_PULL, handleMenusCallback); @@ -276,6 +277,20 @@ bool VortexEditor::init(HINSTANCE hInst) { FCONTROL | FVIRTKEY, 'U', ID_OPTIONS_TRANSMIT_DUO }, // ctrl + i { FCONTROL | FVIRTKEY, 'I', ID_OPTIONS_TRANSMIT_INFRARED }, + // ctrl + k + { FCONTROL | FVIRTKEY, 'K', ID_OPTIONS_RECEIVE_FROM_DUO }, + // ctrl + 1 + { FCONTROL | FVIRTKEY, '1', ID_COLORSET_RANDOM_MONOCHROMATIC }, + // ctrl + 2 + { FCONTROL | FVIRTKEY, '2', ID_COLORSET_RANDOM_COMPLIMENTARY }, + // ctrl + 3 + { FCONTROL | FVIRTKEY, '3', ID_COLORSET_RANDOM_TRIADIC }, + // ctrl + 4 + { FCONTROL | FVIRTKEY, '4', ID_COLORSET_RANDOM_SQUARE }, + // ctrl + 5 + { FCONTROL | FVIRTKEY, '5', ID_COLORSET_RANDOM_PENTADIC }, + // ctrl + 6 + { FCONTROL | FVIRTKEY, '6', ID_COLORSET_RANDOM_RAINBOW }, }; m_accelTable = CreateAcceleratorTable(accelerators, sizeof(accelerators) / sizeof(accelerators[0])); if (!m_accelTable) { @@ -401,6 +416,9 @@ void VortexEditor::handleMenus(uintptr_t hMenu) case ID_OPTIONS_TRANSMIT_INFRARED: transmitIR(nullptr); return; + case ID_OPTIONS_RECEIVE_FROM_DUO: + receiveVL(nullptr); + return; case ID_TOOLS_COLOR_PICKER: m_colorPicker.show(); return; @@ -915,7 +933,7 @@ void VortexEditor::pull(VWindow *window) // now immediately tell it what to do port->writeData(EDITOR_VERB_PULL_MODES); stream.clear(); - if (!port->readModes(stream) || !stream.size()) { + if (!port->readByteStream(stream) || !stream.size()) { debug("Couldn't read anything"); return; } @@ -1120,6 +1138,44 @@ void VortexEditor::transmitIR(VWindow *window) { } +void VortexEditor::receiveVL(VWindow *window) +{ + VortexPort *port = nullptr; + if (!isConnected() || !getCurPort(&port)) { + return; + } + int sel = m_modeListBox.getSelection(); + if (sel < 0 || !isConnected()) { + return; + } + // now unserialize the stream of data that was read + ByteStream curMode; + if (!m_vortex.getCurMode(curMode) || curMode.size() <= 4) { + // error! + // TODO: abort + return; + } + // now immediately tell it what to do + port->writeData(EDITOR_VERB_LISTEN_VL); + // listen for he mode + ByteStream stream; + stream.clear(); + if (!port->readByteStream(stream) || !stream.size()) { + debug("Couldn't read anything"); + return; + } + m_vortex.setLedCount(2); + m_vortex.addNewMode(stream); + // read data again + port->expectData(EDITOR_VERB_LISTEN_VL_ACK); + // refresh + refreshModeList(); + // select the new mode + m_modeListBox.setSelection(m_vortex.numModes() - 1); + m_ledsMultiListBox.setSelection(0); + refreshLedList(); +} + void VortexEditor::selectMode(VWindow *window) { int sel = m_modeListBox.getSelection(); diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index b11e3ca..1c1e2aa 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -114,6 +114,7 @@ class VortexEditor void exportMode(VWindow *window); void transmitVL(VWindow *window); void transmitIR(VWindow *window); + void receiveVL(VWindow *window); void selectMode(VWindow *window); void demoCurMode(); void clearDemo(); diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index a2ab9bb..10b8615 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -85,12 +85,12 @@ BEGIN END POPUP "Random Colorset" BEGIN - MENUITEM "Monochromatic", ID_COLORSET_RANDOM_MONOCHROMATIC - MENUITEM "Complimentary", ID_COLORSET_RANDOM_COMPLIMENTARY - MENUITEM "Triadic", ID_COLORSET_RANDOM_TRIADIC - MENUITEM "Square", ID_COLORSET_RANDOM_SQUARE - MENUITEM "Pentadic", ID_COLORSET_RANDOM_PENTADIC - MENUITEM "Rainbow", ID_COLORSET_RANDOM_RAINBOW + MENUITEM "Monochromatic\tctrl+1", ID_COLORSET_RANDOM_MONOCHROMATIC + MENUITEM "Complimentary\tctrl+2", ID_COLORSET_RANDOM_COMPLIMENTARY + MENUITEM "Triadic\tctrl+3", ID_COLORSET_RANDOM_TRIADIC + MENUITEM "Square\tctrl+4", ID_COLORSET_RANDOM_SQUARE + MENUITEM "Pentadic\tctrl+5", ID_COLORSET_RANDOM_PENTADIC + MENUITEM "Rainbow\tctrl+6", ID_COLORSET_RANDOM_RAINBOW END END POPUP "Tools" @@ -101,6 +101,7 @@ BEGIN BEGIN MENUITEM "Transmit to Duo\tctrl+u", ID_OPTIONS_TRANSMIT_DUO MENUITEM "Transmit Infrared\tctrl+i", ID_OPTIONS_TRANSMIT_INFRARED + MENUITEM "Receive from Duo\tctrl+k", ID_OPTIONS_RECEIVE_FROM_DUO END POPUP "Help" BEGIN diff --git a/VortexEditor/VortexPort.cpp b/VortexEditor/VortexPort.cpp index 912f1fc..4452378 100644 --- a/VortexEditor/VortexPort.cpp +++ b/VortexEditor/VortexPort.cpp @@ -1,312 +1,312 @@ -#include "VortexPort.h" - -#include "VortexEditor.h" - -#include "Serial/ByteStream.h" - -using namespace std; - -uint32_t g_counter = 0; - -// uncomment this to turn on send debug messages -//#define DEBUG_SENDING - -#ifdef DEBUG_SENDING -#define debug_send(...) printf(__VA_ARGS__) -#else -#define debug_send(...) -#endif - -VortexPort::VortexPort() : - m_serialPort(), - m_hThread(nullptr), - m_portActive(false) -{ -} - -VortexPort::VortexPort(const std::string &portName) : - m_serialPort(portName), - m_hThread(nullptr), - m_portActive(false) -{ -} - -VortexPort::VortexPort(VortexPort &&other) noexcept : - VortexPort() -{ - *this = std::move(other); -} - -VortexPort::~VortexPort() -{ - if (m_hThread) { - TerminateThread(m_hThread, 0); - CloseHandle(m_hThread); - m_hThread = nullptr; - } -} - -void VortexPort::operator=(VortexPort &&other) noexcept -{ - m_serialPort = std::move(other.m_serialPort); - m_portActive = other.m_portActive; - m_hThread = other.m_hThread; - - other.m_portActive = false; - other.m_hThread = nullptr; -} - -bool VortexPort::tryBegin() -{ - //return true; - if (m_hThread != nullptr) { - // don't try because there's already a begin() thread waiting - return false; - } - ByteStream stream; - if (!isConnected()) { - setActive(false); - return false; - } - // try to read the handshake - if (!readData(stream)) { - // no handshake or goodbye so just return whether currently active - return m_portActive; - } - // validate the handshake is correct - if (!parseHandshake(stream)) { - // failure - return false; - } - setActive(true); - return true; -} - -void VortexPort::listen() -{ - // do not spawn a thread if there is already one - if (m_hThread) { - return; - } - // spawn a new listener thread - m_hThread = CreateThread(NULL, 0, begin, this, 0, NULL); -} - -bool VortexPort::isConnected() const -{ - return m_serialPort.isConnected(); -} - -bool VortexPort::isActive() const -{ - return m_portActive; -} - -ArduinoSerial &VortexPort::port() -{ - return m_serialPort; -} - -void VortexPort::setActive(bool active) -{ - m_portActive = active; -} - -// amount of data ready -int VortexPort::bytesAvailable() -{ - return m_serialPort.bytesAvailable(); -} - -int VortexPort::readData(ByteStream &stream) -{ - uint32_t avail = bytesAvailable(); - // if there's data already just extend, otherwise init - if (!avail || !stream.extend(avail)) { - return 0; - } - debug_send("%u %x < Reading data %u\n", g_counter++, GetCurrentThreadId(), avail); - uint32_t amt = m_serialPort.readData((void *)(stream.data() + stream.size()), avail); - debug_send("%u %x << Read data %u: %s\n", g_counter++, GetCurrentThreadId(), amt, stream.data() + stream.size()); - // hack to increase ByteStream size - **(uint32_t **)&stream += amt; - return amt; -} - -int VortexPort::waitData(ByteStream &stream) -{ - int len = 0; - DWORD bytesRead = 0; - uint8_t byte = 0; - debug_send("%u %x < Waiting data\n", g_counter++, GetCurrentThreadId()); - // Try to read 1 byte so we block till data arrives - if (!m_serialPort.rawRead(&byte, 1)) { - return 0; - } - debug_send("%u %x << Waited 1 byte data\n", g_counter++, GetCurrentThreadId()); - // insert the byte into the output stream - stream.serialize(byte); - // check how much more data is avail - int data = bytesAvailable(); - if (data > 0) { - // read the rest of the data into the stream - readData(stream); - } - debug_send("%u %x << Waited data: %s\n", g_counter++, GetCurrentThreadId(), stream.data()); - return stream.size(); -} - -int VortexPort::writeData(const std::string &message) -{ - debug_send("%u %x > Writing message: %s\n", g_counter++, GetCurrentThreadId(), message.c_str()); - // just print the buffer - int rv = m_serialPort.writeData((uint8_t *)message.c_str(), message.size()); - debug_send("%u %x >> Wrote message: %s\n", g_counter++, GetCurrentThreadId(), message.c_str()); - return rv; -} - -int VortexPort::writeData(ByteStream &stream) -{ - debug_send("%u %x > Writing buf: %u\n", g_counter++, GetCurrentThreadId(), stream.rawSize()); - // write the data into the serial port - uint32_t size = stream.rawSize(); - // create a new ByteStream that will contain the size + full stream - ByteStream buf(size + sizeof(size)); - // serialize the size into the buf - buf.serialize(size); - // append the raw data of the input stream (crc/flags/size/buffer) - buf.append(ByteStream(size, (const uint8_t *)stream.rawData())); - // We must send the whole buffer in one go, cannot send size first - // NOTE: when I sent this in two sends it would actually cause the arduino - // to only receive the size and not the buffer. It worked fine in the test - // framework but not for arduino serial. So warning, always send in one chunk. - // Even when I flushed the file buffers it didn't fix it. - if (!m_serialPort.writeData(buf.data(), buf.size())) { - printf("BIG ERROR ~~~~~~~~~~~~~\n"); - return 0; - } -#ifdef DEBUG_SENDING - debug_send("%u %x >> Written buf: %u\n", g_counter++, GetCurrentThreadId(), buf.size()); - debug_send("\t"); - for (uint32_t i = 0; i < buf.size(); ++i) { - debug_send("%02x ", buf.data()[i]); - if ((i + 1) % 32 == 0) { - debug_send("\n\t"); - } - } - debug_send("\n"); -#endif - return buf.size(); -} - -bool VortexPort::expectData(const std::string &data) -{ - debug_send("%u %x << Expecting data: %s\n", g_counter++, GetCurrentThreadId(), data.c_str()); - ByteStream stream; - readInLoop(stream); - if (stream.size() < data.size()) { - return false; - } - debug_send("%u %x < Got expected data: %s\n", g_counter++, GetCurrentThreadId(), stream.data()); - if (data != (char *)stream.data()) { - return false; - } - return true; -} - -bool VortexPort::readInLoop(ByteStream &outStream, uint32_t timeoutMs) -{ - outStream.clear(); - uint32_t start = GetTickCount(); - debug_send("%u %x < Reading in loop\n", g_counter++, GetCurrentThreadId()); - while ((start + timeoutMs) >= GetTickCount()) { - if (!readData(outStream)) { - // error? - continue; - } - if (!outStream.size()) { - continue; - } - debug_send("%u %x << Read in loop: %s\n", g_counter++, GetCurrentThreadId(), outStream.data()); - return true; - } - debug_send("%u %x << Reading in loop failed\n", g_counter++, GetCurrentThreadId()); - return false; -} - -bool VortexPort::parseHandshake(const ByteStream &handshake) -{ - string handshakeStr = (char *)handshake.data(); - debug_send("%u %x = Parsing handshake: [%s]\n", g_counter++, GetCurrentThreadId(), handshakeStr.c_str()); - // if there is a goodbye message then the gloveset just left the editor - // menu and we cannot send it messages anymore - if (handshakeStr.find(EDITOR_VERB_GOODBYE) == (handshakeStr.size() - (sizeof(EDITOR_VERB_GOODBYE) - 1))) { - setActive(false); - g_pEditor->triggerRefresh(); - // if still connected, return to listening - if (isConnected()) { - listen(); - } - debug_send("%u %x == Parsed handshake: Goodbye\n", g_counter++, GetCurrentThreadId()); - return false; - } - // TODO: Parse the device info out of handshake - debug_send("%u %x == Parsed handshake: Good\n", g_counter++, GetCurrentThreadId()); - // check the handshake for valid datastart // looks good - return true; -} - -bool VortexPort::readModes(ByteStream &outModes) -{ - uint32_t size = 0; - // first check how much is in the serial port - int32_t amt = 0; - debug_send("%u %x < Reading modes\n", g_counter++, GetCurrentThreadId()); - // wait till amount available is enough - while (m_serialPort.bytesAvailable() < sizeof(size)); - debug_send("%u %x << Reading modes avail %u\n", g_counter++, GetCurrentThreadId(), m_serialPort.bytesAvailable()); - // read the size out of the serial port - m_serialPort.readData((void *)&size, sizeof(size)); - if (!size || size > 4096) { - return false; - } - // init outmodes so it's big enough - outModes.init(size); - uint32_t amtRead = 0; - do { - // read straight into the raw buffer, this will always have enough - // space because outModes is big enough to hold the entire data - uint8_t *readPos = ((uint8_t *)outModes.rawData()) + amtRead; - amtRead += m_serialPort.readData((void *)readPos, size); - } while (amtRead < size); - debug_send("%u %x << Read modes %u\n", g_counter++, GetCurrentThreadId(), amtRead); - return true; -} - -DWORD __stdcall VortexPort::begin(void *ptr) -{ - VortexPort *port = (VortexPort *)ptr; - if (!port) { - return 0; - } - ByteStream handshake; - while (!port->m_portActive) { - // wait for the handshake data indefinitely - int32_t actual = port->waitData(handshake); - if (!actual || !handshake.size()) { - continue; - } - // validate it - if (!port->parseHandshake(handshake)) { - // failure - continue; - } - port->m_portActive = true; - } - // send a message to trigger a UI refresh - g_pEditor->triggerRefresh(); - // cleanup this thread this function is running in - CloseHandle(port->m_hThread); - port->m_hThread = nullptr; - return 0; -} +#include "VortexPort.h" + +#include "VortexEditor.h" + +#include "Serial/ByteStream.h" + +using namespace std; + +uint32_t g_counter = 0; + +// uncomment this to turn on send debug messages +//#define DEBUG_SENDING + +#ifdef DEBUG_SENDING +#define debug_send(...) printf(__VA_ARGS__) +#else +#define debug_send(...) +#endif + +VortexPort::VortexPort() : + m_serialPort(), + m_hThread(nullptr), + m_portActive(false) +{ +} + +VortexPort::VortexPort(const std::string &portName) : + m_serialPort(portName), + m_hThread(nullptr), + m_portActive(false) +{ +} + +VortexPort::VortexPort(VortexPort &&other) noexcept : + VortexPort() +{ + *this = std::move(other); +} + +VortexPort::~VortexPort() +{ + if (m_hThread) { + TerminateThread(m_hThread, 0); + CloseHandle(m_hThread); + m_hThread = nullptr; + } +} + +void VortexPort::operator=(VortexPort &&other) noexcept +{ + m_serialPort = std::move(other.m_serialPort); + m_portActive = other.m_portActive; + m_hThread = other.m_hThread; + + other.m_portActive = false; + other.m_hThread = nullptr; +} + +bool VortexPort::tryBegin() +{ + //return true; + if (m_hThread != nullptr) { + // don't try because there's already a begin() thread waiting + return false; + } + ByteStream stream; + if (!isConnected()) { + setActive(false); + return false; + } + // try to read the handshake + if (!readData(stream)) { + // no handshake or goodbye so just return whether currently active + return m_portActive; + } + // validate the handshake is correct + if (!parseHandshake(stream)) { + // failure + return false; + } + setActive(true); + return true; +} + +void VortexPort::listen() +{ + // do not spawn a thread if there is already one + if (m_hThread) { + return; + } + // spawn a new listener thread + m_hThread = CreateThread(NULL, 0, begin, this, 0, NULL); +} + +bool VortexPort::isConnected() const +{ + return m_serialPort.isConnected(); +} + +bool VortexPort::isActive() const +{ + return m_portActive; +} + +ArduinoSerial &VortexPort::port() +{ + return m_serialPort; +} + +void VortexPort::setActive(bool active) +{ + m_portActive = active; +} + +// amount of data ready +int VortexPort::bytesAvailable() +{ + return m_serialPort.bytesAvailable(); +} + +int VortexPort::readData(ByteStream &stream) +{ + uint32_t avail = bytesAvailable(); + // if there's data already just extend, otherwise init + if (!avail || !stream.extend(avail)) { + return 0; + } + debug_send("%u %x < Reading data %u\n", g_counter++, GetCurrentThreadId(), avail); + uint32_t amt = m_serialPort.readData((void *)(stream.data() + stream.size()), avail); + debug_send("%u %x << Read data %u: %s\n", g_counter++, GetCurrentThreadId(), amt, stream.data() + stream.size()); + // hack to increase ByteStream size + **(uint32_t **)&stream += amt; + return amt; +} + +int VortexPort::waitData(ByteStream &stream) +{ + int len = 0; + DWORD bytesRead = 0; + uint8_t byte = 0; + debug_send("%u %x < Waiting data\n", g_counter++, GetCurrentThreadId()); + // Try to read 1 byte so we block till data arrives + if (!m_serialPort.rawRead(&byte, 1)) { + return 0; + } + debug_send("%u %x << Waited 1 byte data\n", g_counter++, GetCurrentThreadId()); + // insert the byte into the output stream + stream.serialize(byte); + // check how much more data is avail + int data = bytesAvailable(); + if (data > 0) { + // read the rest of the data into the stream + readData(stream); + } + debug_send("%u %x << Waited data: %s\n", g_counter++, GetCurrentThreadId(), stream.data()); + return stream.size(); +} + +int VortexPort::writeData(const std::string &message) +{ + debug_send("%u %x > Writing message: %s\n", g_counter++, GetCurrentThreadId(), message.c_str()); + // just print the buffer + int rv = m_serialPort.writeData((uint8_t *)message.c_str(), message.size()); + debug_send("%u %x >> Wrote message: %s\n", g_counter++, GetCurrentThreadId(), message.c_str()); + return rv; +} + +int VortexPort::writeData(ByteStream &stream) +{ + debug_send("%u %x > Writing buf: %u\n", g_counter++, GetCurrentThreadId(), stream.rawSize()); + // write the data into the serial port + uint32_t size = stream.rawSize(); + // create a new ByteStream that will contain the size + full stream + ByteStream buf(size + sizeof(size)); + // serialize the size into the buf + buf.serialize(size); + // append the raw data of the input stream (crc/flags/size/buffer) + buf.append(ByteStream(size, (const uint8_t *)stream.rawData())); + // We must send the whole buffer in one go, cannot send size first + // NOTE: when I sent this in two sends it would actually cause the arduino + // to only receive the size and not the buffer. It worked fine in the test + // framework but not for arduino serial. So warning, always send in one chunk. + // Even when I flushed the file buffers it didn't fix it. + if (!m_serialPort.writeData(buf.data(), buf.size())) { + printf("BIG ERROR ~~~~~~~~~~~~~\n"); + return 0; + } +#ifdef DEBUG_SENDING + debug_send("%u %x >> Written buf: %u\n", g_counter++, GetCurrentThreadId(), buf.size()); + debug_send("\t"); + for (uint32_t i = 0; i < buf.size(); ++i) { + debug_send("%02x ", buf.data()[i]); + if ((i + 1) % 32 == 0) { + debug_send("\n\t"); + } + } + debug_send("\n"); +#endif + return buf.size(); +} + +bool VortexPort::expectData(const std::string &data) +{ + debug_send("%u %x << Expecting data: %s\n", g_counter++, GetCurrentThreadId(), data.c_str()); + ByteStream stream; + readInLoop(stream); + if (stream.size() < data.size()) { + return false; + } + debug_send("%u %x < Got expected data: %s\n", g_counter++, GetCurrentThreadId(), stream.data()); + if (data != (char *)stream.data()) { + return false; + } + return true; +} + +bool VortexPort::readInLoop(ByteStream &outStream, uint32_t timeoutMs) +{ + outStream.clear(); + uint32_t start = GetTickCount(); + debug_send("%u %x < Reading in loop\n", g_counter++, GetCurrentThreadId()); + while ((start + timeoutMs) >= GetTickCount()) { + if (!readData(outStream)) { + // error? + continue; + } + if (!outStream.size()) { + continue; + } + debug_send("%u %x << Read in loop: %s\n", g_counter++, GetCurrentThreadId(), outStream.data()); + return true; + } + debug_send("%u %x << Reading in loop failed\n", g_counter++, GetCurrentThreadId()); + return false; +} + +bool VortexPort::parseHandshake(const ByteStream &handshake) +{ + string handshakeStr = (char *)handshake.data(); + debug_send("%u %x = Parsing handshake: [%s]\n", g_counter++, GetCurrentThreadId(), handshakeStr.c_str()); + // if there is a goodbye message then the gloveset just left the editor + // menu and we cannot send it messages anymore + if (handshakeStr.find(EDITOR_VERB_GOODBYE) == (handshakeStr.size() - (sizeof(EDITOR_VERB_GOODBYE) - 1))) { + setActive(false); + g_pEditor->triggerRefresh(); + // if still connected, return to listening + if (isConnected()) { + listen(); + } + debug_send("%u %x == Parsed handshake: Goodbye\n", g_counter++, GetCurrentThreadId()); + return false; + } + // TODO: Parse the device info out of handshake + debug_send("%u %x == Parsed handshake: Good\n", g_counter++, GetCurrentThreadId()); + // check the handshake for valid datastart // looks good + return true; +} + +bool VortexPort::readByteStream(ByteStream &outModes) +{ + uint32_t size = 0; + // first check how much is in the serial port + int32_t amt = 0; + debug_send("%u %x < Reading modes\n", g_counter++, GetCurrentThreadId()); + // wait till amount available is enough + while (m_serialPort.bytesAvailable() < sizeof(size)); + debug_send("%u %x << Reading modes avail %u\n", g_counter++, GetCurrentThreadId(), m_serialPort.bytesAvailable()); + // read the size out of the serial port + m_serialPort.readData((void *)&size, sizeof(size)); + if (!size || size > 4096) { + return false; + } + // init outmodes so it's big enough + outModes.init(size); + uint32_t amtRead = 0; + do { + // read straight into the raw buffer, this will always have enough + // space because outModes is big enough to hold the entire data + uint8_t *readPos = ((uint8_t *)outModes.rawData()) + amtRead; + amtRead += m_serialPort.readData((void *)readPos, size); + } while (amtRead < size); + debug_send("%u %x << Read modes %u\n", g_counter++, GetCurrentThreadId(), amtRead); + return true; +} + +DWORD __stdcall VortexPort::begin(void *ptr) +{ + VortexPort *port = (VortexPort *)ptr; + if (!port) { + return 0; + } + ByteStream handshake; + while (!port->m_portActive) { + // wait for the handshake data indefinitely + int32_t actual = port->waitData(handshake); + if (!actual || !handshake.size()) { + continue; + } + // validate it + if (!port->parseHandshake(handshake)) { + // failure + continue; + } + port->m_portActive = true; + } + // send a message to trigger a UI refresh + g_pEditor->triggerRefresh(); + // cleanup this thread this function is running in + CloseHandle(port->m_hThread); + port->m_hThread = nullptr; + return 0; +} diff --git a/VortexEditor/VortexPort.h b/VortexEditor/VortexPort.h index d179b27..100d9f8 100644 --- a/VortexEditor/VortexPort.h +++ b/VortexEditor/VortexPort.h @@ -1,49 +1,49 @@ -#pragma once - -#include "ArduinoSerial.h" - -#include - -class VortexPort -{ -public: - VortexPort(); - VortexPort(const std::string &portName); - VortexPort(VortexPort &&other) noexcept; - ~VortexPort(); - void operator=(VortexPort &&other) noexcept; - bool tryBegin(); - void listen(); - bool isConnected() const; - bool isActive() const; - ArduinoSerial &port(); - // set whether active or not - void setActive(bool active); - // amount of data ready - int bytesAvailable(); - // read out any available data - int readData(ByteStream &stream); - // wait till data arrives then read it out - int waitData(ByteStream &stream); - // write a message to the port - int writeData(const std::string &message); - // write a buffer of binary data to the port - int writeData(ByteStream &stream); - // wait for some data - bool expectData(const std::string &data); - // read data in a loop - bool readInLoop(ByteStream &outStream, uint32_t timeoutMs = 5000); - // helper to validate a handshake message - bool parseHandshake(const ByteStream &handshakewindow); - // read out the full list of modes - bool readModes(ByteStream &outModes); -private: - // the raw serial connection - ArduinoSerial m_serialPort; - // a handle to the thread that waits for the initial handshake - HANDLE m_hThread; - // whether the port is 'active' ie the handshake has been received - bool m_portActive; - // thread func to wait and begin a port connection - static DWORD __stdcall begin(void *ptr); -}; +#pragma once + +#include "ArduinoSerial.h" + +#include + +class VortexPort +{ +public: + VortexPort(); + VortexPort(const std::string &portName); + VortexPort(VortexPort &&other) noexcept; + ~VortexPort(); + void operator=(VortexPort &&other) noexcept; + bool tryBegin(); + void listen(); + bool isConnected() const; + bool isActive() const; + ArduinoSerial &port(); + // set whether active or not + void setActive(bool active); + // amount of data ready + int bytesAvailable(); + // read out any available data + int readData(ByteStream &stream); + // wait till data arrives then read it out + int waitData(ByteStream &stream); + // write a message to the port + int writeData(const std::string &message); + // write a buffer of binary data to the port + int writeData(ByteStream &stream); + // wait for some data + bool expectData(const std::string &data); + // read data in a loop + bool readInLoop(ByteStream &outStream, uint32_t timeoutMs = 5000); + // helper to validate a handshake message + bool parseHandshake(const ByteStream &handshakewindow); + // read out the full list of modes + bool readByteStream(ByteStream &outModes); +private: + // the raw serial connection + ArduinoSerial m_serialPort; + // a handle to the thread that waits for the initial handshake + HANDLE m_hThread; + // whether the port is 'active' ie the handshake has been received + bool m_portActive; + // thread func to wait and begin a port connection + static DWORD __stdcall begin(void *ptr); +}; diff --git a/VortexEditor/resource.h b/VortexEditor/resource.h index dbe9323..e2ccbfc 100644 --- a/VortexEditor/resource.h +++ b/VortexEditor/resource.h @@ -16,10 +16,6 @@ #define ID_HELP_HELP 40010 #define ID_FILE_CONNECT 40011 #define ID_FILE_REFRESH 40012 -#define ID_COLORSET_RANDOMIZETRIADIC 40016 -#define ID_COLORSET_RANDOMIZE 40017 -#define ID_COLORSET_RANDOMIZE_TRIADIC 40028 -#define ID_COLORSET_RANDOMIZE_COMPLIMENTARY 40029 #define ID_COLORSET_RANDOM_COMPLIMENTARY 40030 #define ID_COLORSET_RANDOM_MONOCHROMATIC 40031 #define ID_COLORSET_RANDOM_TRIADIC 40032 @@ -46,13 +42,16 @@ #define ID_OPTIONS_TRANSMITMODEIR 40054 #define ID_OPTIONS_TRANSMIT_DUO 40055 #define ID_OPTIONS_TRANSMIT_INFRARED 40056 +#define ID_OPTIONS_RECEIVEFROMDUO 40057 +#define ID_OPTIONS_RECEIVE_FROM_DUO 40058 +#define ID_OPTIONS_RECEIVE_DUO 40059 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40057 +#define _APS_NEXT_COMMAND_VALUE 40060 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif