2023-04-02 22:47:50 -04:00
|
|
|
/*
|
|
|
|
widget.cpp
|
|
|
|
|
|
|
|
Copyright (c) 2023 Kevin Matz (kevin.matz@gmail.com)
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "widget.h"
|
|
|
|
|
2023-04-06 09:43:41 -04:00
|
|
|
#include <chrono>
|
|
|
|
|
2023-04-03 09:58:26 -04:00
|
|
|
namespace ENTTEC {
|
2023-04-02 22:47:50 -04:00
|
|
|
|
|
|
|
Widget::Widget()
|
2023-04-03 16:43:37 -04:00
|
|
|
: serial_number(0) // SN# 0 for emulated devices
|
|
|
|
, firmware_version(2<<8) // emulated devices support RDM
|
2023-04-05 12:39:12 -04:00
|
|
|
, tx_break_intervals(17) // 181.4 us by default
|
|
|
|
, tx_mab_intervals(10) // 106.7 us by default
|
|
|
|
, tx_rate(40) // 40 packets/s, by default
|
2023-04-09 19:31:56 -04:00
|
|
|
, usb_mode(USBunknown)
|
2023-04-06 09:39:29 -04:00
|
|
|
, rx_update_mode_(Pro::RxNotifyAlways)
|
2023-04-06 08:34:35 -04:00
|
|
|
, token_data_changed_(nullptr)
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Widget::~Widget()
|
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-02 22:47:50 -04:00
|
|
|
case USBdevice:
|
|
|
|
Widget::halt();
|
|
|
|
break;
|
|
|
|
case USBhost:
|
2023-04-05 08:10:59 -04:00
|
|
|
Widget::close();
|
2023-04-02 22:47:50 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Begin operating as a USB Device
|
2023-04-03 16:43:37 -04:00
|
|
|
*
|
|
|
|
* The base class method should be called from all inheriting overrides.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
|
|
|
void Widget::init()
|
|
|
|
{
|
2023-04-06 09:53:42 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-09 19:31:56 -04:00
|
|
|
usb_mode = USBdevice;
|
2023-04-06 09:53:42 -04:00
|
|
|
}
|
|
|
|
setModeBridge();
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Stop operating as a USB Device
|
2023-04-03 16:43:37 -04:00
|
|
|
*
|
|
|
|
* The base class method should be called from all inheriting overrides.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
|
|
|
void Widget::halt()
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-09 19:31:56 -04:00
|
|
|
usb_mode = USBunknown;
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Begin operating on the USB Host
|
2023-04-03 16:43:37 -04:00
|
|
|
*
|
|
|
|
* The base class method should be called from all inheriting overrides.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
2023-04-05 08:10:59 -04:00
|
|
|
void Widget::open()
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
2023-04-06 09:44:54 -04:00
|
|
|
if (getSerialNumber(500)) // check for valid call/response from device
|
|
|
|
{
|
2023-04-06 09:45:39 -04:00
|
|
|
{
|
2023-04-06 09:44:54 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-09 19:31:56 -04:00
|
|
|
usb_mode = USBhost; // note connected state
|
2023-04-06 09:45:39 -04:00
|
|
|
}
|
2023-04-06 09:53:42 -04:00
|
|
|
setModeBridge();
|
2023-04-06 09:45:39 -04:00
|
|
|
getParameters(0, 500); // retrieve widget metadata
|
2023-04-06 09:44:54 -04:00
|
|
|
}
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Stop operating on the USB Host
|
2023-04-03 16:43:37 -04:00
|
|
|
*
|
|
|
|
* The base class method should be called from all inheriting overrides.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
2023-04-05 08:10:59 -04:00
|
|
|
void Widget::close()
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-09 19:31:56 -04:00
|
|
|
usb_mode = USBunknown;
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 12:41:13 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::setModeController
|
|
|
|
*/
|
|
|
|
void Widget::setModeController()
|
|
|
|
{
|
|
|
|
sendDmx();
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
token_data_changed_ = onDataChange([this](DMX::Universe*){sendDmx();});
|
2023-04-05 12:41:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::setModeBridge
|
|
|
|
* @param mode
|
|
|
|
*/
|
|
|
|
void Widget::setModeBridge(Pro::DMX_RX_MODE mode)
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
token_data_changed_ = nullptr;
|
|
|
|
rx_update_mode_ = mode;
|
|
|
|
}
|
2023-04-05 12:41:13 -04:00
|
|
|
auto msg = std::make_shared<Pro::MsgRecieveDMXOnChange>();
|
|
|
|
msg->mode = mode;
|
|
|
|
sendMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-06 08:33:57 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::serialNumber
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
uint32_t Widget::serialNumber() const
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
return serial_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::firmwareVersion
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
uint16_t Widget::firmwareVersion() const
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
return firmware_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::txBreakTime
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
double Widget::txBreakTime() const
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
return tx_break_intervals * Pro::DMX_BREAK_INTERVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 09:19:16 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::setTxBreakTime
|
|
|
|
* @param time
|
|
|
|
*/
|
|
|
|
void Widget::setTxBreakTime(double time)
|
|
|
|
{
|
|
|
|
setTxBreakIntervals(time / Pro::DMX_BREAK_INTERVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::setTxBreakIntervals
|
|
|
|
* @param count
|
|
|
|
*/
|
|
|
|
void Widget::setTxBreakIntervals(uint8_t count)
|
|
|
|
{
|
|
|
|
count = std::max(count, Pro::DMX_BREAK_MIN);
|
|
|
|
count = std::min(count, Pro::DMX_BREAK_MAX);
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-05 09:19:16 -04:00
|
|
|
tx_break_intervals = count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-06 08:33:57 -04:00
|
|
|
/**
|
|
|
|
* @brief txMabTime
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
double Widget::txMabTime() const
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
return tx_mab_intervals * Pro::DMX_MAB_INTERVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 09:19:16 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::setTxMabTime
|
|
|
|
* @param time
|
|
|
|
*/
|
|
|
|
void Widget::setTxMabTime(double time)
|
|
|
|
{
|
|
|
|
setTxMabIntervals(time / Pro::DMX_MAB_INTERVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::setTxMabIntervals
|
|
|
|
* @param count
|
|
|
|
*/
|
|
|
|
void Widget::setTxMabIntervals(uint8_t count)
|
|
|
|
{
|
|
|
|
count = std::max(count, Pro::DMX_MAB_MIN);
|
|
|
|
count = std::min(count, Pro::DMX_MAB_MAX);
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-05 09:19:16 -04:00
|
|
|
tx_mab_intervals = count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-06 08:33:57 -04:00
|
|
|
/**
|
|
|
|
* @brief txRate
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
uint8_t Widget::txRate() const
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
return tx_rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 09:19:16 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::setTxRate
|
|
|
|
* @param rate
|
|
|
|
*/
|
|
|
|
void Widget::setTxRate(uint8_t rate)
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-05 09:19:16 -04:00
|
|
|
tx_rate = std::min(rate, Pro::DMX_RATE_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-06 10:43:42 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::writeFirmware
|
|
|
|
* @param data
|
|
|
|
* @param size
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
bool Widget::writeFirmware(const uint8_t *data, const size_t size)
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* While the API documents the message formats, there is little discussion of the
|
|
|
|
* implimentation for updating firmware. As such, do nothing and return false.
|
|
|
|
*/
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// reboot the device into the fw loader
|
|
|
|
rebootBootloader();
|
|
|
|
|
|
|
|
auto msg = std::make_shared<Pro::MsgProgramFlashPageRequest>();
|
|
|
|
std::future<bool> ftr;
|
|
|
|
bool success;
|
|
|
|
for (uint i = 0; i < size / sizeof(msg->page);)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
reply_firmwarePage_ = std::promise<bool>(); // expect a reply to this message
|
|
|
|
ftr = reply_firmwarePage_.get_future();
|
|
|
|
}
|
|
|
|
std::copy(data + (i*sizeof(msg->page)), data + ((i+1)*sizeof(msg->page)), msg->page);
|
|
|
|
sendMessage(msg);
|
|
|
|
success = ftr.get();
|
|
|
|
if (success)
|
|
|
|
i++; // page write was successful, do the next.
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-09 19:43:54 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::MessageDataFactory
|
|
|
|
* @param label
|
|
|
|
* @param mode
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
std::shared_ptr<Pro::MessageData> Widget::MessageDataFactory(Pro::MESSAGE_LABEL label,
|
|
|
|
OperatingMode mode)
|
|
|
|
{
|
|
|
|
switch (label) {
|
|
|
|
case Pro::OpReprogramFirmware:
|
|
|
|
return std::make_shared<Pro::MsgReprogramFirmware>();
|
|
|
|
case Pro::OpProgramFlashPage:
|
|
|
|
switch (mode) {
|
|
|
|
case USBdevice:
|
|
|
|
return std::make_shared<Pro::MsgProgramFlashPageReply>();
|
|
|
|
case USBhost:
|
|
|
|
return std::make_shared<Pro::MsgProgramFlashPageRequest>();
|
|
|
|
default:
|
|
|
|
return std::make_shared<Pro::MsgNoop>();
|
|
|
|
}
|
|
|
|
case Pro::OpGetWidgetParameters:
|
|
|
|
switch (mode) {
|
|
|
|
case USBdevice:
|
|
|
|
return std::make_shared<Pro::MsgGetWidgetParametersReply>();
|
|
|
|
case USBhost:
|
|
|
|
return std::make_shared<Pro::MsgGetWidgetParametersRequest>();
|
|
|
|
default:
|
|
|
|
return std::make_shared<Pro::MsgNoop>();
|
|
|
|
}
|
|
|
|
case Pro::OpSetWidgetParameters:
|
|
|
|
return std::make_shared<Pro::MsgSetWidgetParametersRequest>();
|
|
|
|
case Pro::OpRecievedDmxPacket:
|
|
|
|
return std::make_shared<Pro::MsgRecievedDmxPacket>();
|
|
|
|
case Pro::OpOutputOnlySendDMX:
|
|
|
|
return std::make_shared<Pro::MsgOutputOnlySendDMX>();
|
|
|
|
case Pro::OpSendRDMData:
|
|
|
|
return std::make_shared<Pro::MsgSendRDMData>();
|
|
|
|
case Pro::OpRecieveDMXOnChange:
|
|
|
|
return std::make_shared<Pro::MsgRecieveDMXOnChange>();
|
|
|
|
case Pro::OpRecievedDMXChanged:
|
|
|
|
return std::make_shared<Pro::MsgRecievedDMXChanged>();
|
|
|
|
case Pro::OpGetWidgetSerial:
|
|
|
|
switch (mode) {
|
|
|
|
case USBdevice:
|
|
|
|
return std::make_shared<Pro::MsgGetWidgetSerialReply>();
|
|
|
|
case USBhost:
|
|
|
|
return std::make_shared<Pro::MsgGetWidgetSerialRequest>();
|
|
|
|
default:
|
|
|
|
return std::make_shared<Pro::MsgNoop>();
|
|
|
|
}
|
|
|
|
case Pro::OpSendRDMDiscovery:
|
|
|
|
return std::make_shared<Pro::MsgSendRDMDiscovery>();
|
|
|
|
default:
|
|
|
|
return std::make_shared<Pro::MsgNoop>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-02 22:47:50 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::routeRxMessage
|
|
|
|
* @param msg
|
|
|
|
*/
|
2023-04-03 16:42:48 -04:00
|
|
|
void Widget::routeRxMessage(std::shared_ptr<Pro::MessageData> msg)
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
2023-04-06 12:22:26 -04:00
|
|
|
switch (msg->label)
|
|
|
|
{
|
|
|
|
case Pro::OpNoop:
|
2023-04-09 19:51:01 -04:00
|
|
|
rxMsgHello();
|
2023-04-06 12:22:26 -04:00
|
|
|
break;
|
2023-04-02 22:47:50 -04:00
|
|
|
case Pro::OpReprogramFirmware:
|
2023-04-09 19:51:01 -04:00
|
|
|
rxMsgReprogramFirmware();
|
2023-04-02 22:47:50 -04:00
|
|
|
break;
|
|
|
|
case Pro::OpProgramFlashPage:
|
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-02 22:47:50 -04:00
|
|
|
case USBdevice:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgProgramFlashPageRequest>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgProgramFlashPageRequest(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case USBhost:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgProgramFlashPageReply>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgProgramFlashPageReply(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpGetWidgetParameters:
|
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-02 22:47:50 -04:00
|
|
|
case USBdevice:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgGetWidgetParametersRequest>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgGetWidgetParametersRequest(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case USBhost:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgGetWidgetParametersReply>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgGetWidgetParametersReply(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpSetWidgetParameters:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgSetWidgetParametersRequest>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgSetWidgetParametersRequest(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpRecievedDmxPacket:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgRecievedDmxPacket>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgRecievedDmxPacket(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpOutputOnlySendDMX:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgOutputOnlySendDMX>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgOutputOnlySendDMX(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpSendRDMData:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgSendRDMData>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgSendRDMData(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpRecieveDMXOnChange:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgRecieveDMXOnChange>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgRecieveDMXOnChange(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpRecievedDMXChanged:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgRecievedDMXChanged>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgRecievedDMXChanged(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpGetWidgetSerial:
|
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-02 22:47:50 -04:00
|
|
|
case USBdevice:
|
2023-04-09 19:51:01 -04:00
|
|
|
rxMsgGetWidgetSerialRequest();
|
2023-04-02 22:47:50 -04:00
|
|
|
break;
|
|
|
|
case USBhost:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgGetWidgetSerialReply>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgGetWidgetSerialReply(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Pro::OpSendRDMDiscovery:
|
|
|
|
{
|
2023-04-03 16:42:48 -04:00
|
|
|
auto data = std::static_pointer_cast<Pro::MsgSendRDMDiscovery>(msg);
|
2023-04-02 22:47:50 -04:00
|
|
|
rxMsgSendRDMDiscovery(data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::sendMessage
|
|
|
|
* @param msg
|
2023-04-03 16:43:37 -04:00
|
|
|
*
|
|
|
|
* The base class method is to discard the message.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
2023-04-03 16:42:48 -04:00
|
|
|
void Widget::sendMessage(std::shared_ptr<Pro::MessageData> msg) const
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
|
|
|
(void)msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 08:54:43 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::rebootBootloader
|
2023-04-06 10:42:39 -04:00
|
|
|
*
|
|
|
|
* USB devices should override this method to do something meaningful to their state.
|
2023-04-05 08:54:43 -04:00
|
|
|
*/
|
|
|
|
void Widget::rebootBootloader()
|
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-06 10:42:39 -04:00
|
|
|
case USBhost:
|
|
|
|
{
|
|
|
|
auto msg = std::make_shared<Pro::MsgReprogramFirmware>();
|
|
|
|
sendMessage(msg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2023-04-05 08:54:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 08:42:50 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::getSerialNumber
|
2023-04-06 09:43:41 -04:00
|
|
|
* @param timeout Milliseconds to block while waiting for the device to reply.
|
|
|
|
* @return True if the serial number has been updated.
|
2023-04-05 08:42:50 -04:00
|
|
|
*/
|
2023-04-06 09:43:41 -04:00
|
|
|
bool Widget::getSerialNumber(int timeout)
|
2023-04-05 08:42:50 -04:00
|
|
|
{
|
2023-04-06 10:11:33 -04:00
|
|
|
auto msg = std::make_shared<Pro::MsgGetWidgetSerialRequest>();
|
|
|
|
std::future<bool> ftr;
|
2023-04-06 09:43:41 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-06 10:11:33 -04:00
|
|
|
reply_serialNumber_ = std::promise<bool>(); // expect a reply to this message
|
|
|
|
ftr = reply_serialNumber_.get_future();
|
2023-04-06 09:43:41 -04:00
|
|
|
}
|
2023-04-06 10:11:33 -04:00
|
|
|
|
2023-04-05 08:42:50 -04:00
|
|
|
sendMessage(msg);
|
2023-04-06 10:11:33 -04:00
|
|
|
|
|
|
|
switch (ftr.wait_for(std::chrono::milliseconds(timeout))) {
|
2023-04-06 09:43:41 -04:00
|
|
|
case std::future_status::ready:
|
|
|
|
return true;
|
|
|
|
case std::future_status::timeout:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2023-04-05 08:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::getParameters
|
|
|
|
* @param user_length
|
2023-04-06 09:43:41 -04:00
|
|
|
* @param timeout Milliseconds to block while waiting for the device to reply.
|
|
|
|
* @return True if the parameters has been updated.
|
2023-04-05 08:42:50 -04:00
|
|
|
*/
|
2023-04-06 09:43:41 -04:00
|
|
|
bool Widget::getParameters(size_t user_length, int timeout)
|
2023-04-05 08:42:50 -04:00
|
|
|
{
|
2023-04-06 10:11:33 -04:00
|
|
|
auto msg = std::make_shared<Pro::MsgGetWidgetParametersRequest>();
|
|
|
|
std::future<bool> ftr;
|
2023-04-06 09:43:41 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
reply_parameters_ = std::promise<bool>(); // expect a reply to this message
|
2023-04-06 10:11:33 -04:00
|
|
|
ftr = reply_parameters_.get_future();
|
2023-04-06 09:43:41 -04:00
|
|
|
}
|
2023-04-06 10:11:33 -04:00
|
|
|
|
2023-04-05 08:42:50 -04:00
|
|
|
msg->size = std::min(user_length, Pro::USER_CONFIGURATION_MAX);
|
|
|
|
sendMessage(msg);
|
2023-04-06 10:11:33 -04:00
|
|
|
|
|
|
|
switch (ftr.wait_for(std::chrono::milliseconds(timeout))) {
|
2023-04-06 09:43:41 -04:00
|
|
|
case std::future_status::ready:
|
|
|
|
return true;
|
|
|
|
case std::future_status::timeout:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2023-04-05 08:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::setParameters
|
|
|
|
*/
|
2023-04-05 08:55:18 -04:00
|
|
|
void Widget::setParameters() const
|
2023-04-05 08:42:50 -04:00
|
|
|
{
|
|
|
|
auto msg = std::make_shared<Pro::MsgSetWidgetParametersRequest>();
|
2023-04-06 08:33:57 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
msg->break_time = tx_break_intervals;
|
|
|
|
msg->mab_time = tx_mab_intervals;
|
|
|
|
msg->rate = tx_rate;
|
|
|
|
msg->user_data = user_configuration;
|
|
|
|
}
|
2023-04-05 08:42:50 -04:00
|
|
|
sendMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-05 12:41:13 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::sendDmx
|
|
|
|
* @param trimmed
|
|
|
|
*/
|
|
|
|
void Widget::sendDmx(bool trimmed) const
|
|
|
|
{
|
|
|
|
auto msg = std::make_shared<Pro::MsgOutputOnlySendDMX>();
|
|
|
|
msg->data = std::vector<uint8_t>();
|
|
|
|
uint16_t l = null_start_data.size() - 1;
|
|
|
|
if (trimmed)
|
|
|
|
for (l = null_start_data.size() - 1; l > 0 && null_start_data[l] == 0; --l) {};
|
2023-04-06 08:33:57 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_data);
|
|
|
|
std::copy(null_start_data.begin(), null_start_data.begin() + l + 1, msg->data.begin());
|
|
|
|
}
|
2023-04-05 12:41:13 -04:00
|
|
|
sendMessage(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-06 12:22:26 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgHello
|
|
|
|
*/
|
2023-04-09 19:51:01 -04:00
|
|
|
void Widget::rxMsgHello()
|
2023-04-06 12:22:26 -04:00
|
|
|
{
|
2023-04-09 19:31:56 -04:00
|
|
|
switch (usb_mode) {
|
2023-04-06 12:22:26 -04:00
|
|
|
case USBdevice:
|
2023-04-09 19:51:01 -04:00
|
|
|
sendMessage(std::make_shared<Pro::MsgNoop>()); // mirror the message back to the host
|
2023-04-06 12:22:26 -04:00
|
|
|
break;
|
|
|
|
case USBhost:
|
|
|
|
reply_hello_.set_value(true); // device was polite
|
|
|
|
break;
|
|
|
|
default:
|
2023-04-06 12:39:18 -04:00
|
|
|
reply_hello_.set_value(false); // anonyomous hello?
|
2023-04-06 12:22:26 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-02 22:47:50 -04:00
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgReprogramFirmware
|
|
|
|
*/
|
2023-04-09 19:51:01 -04:00
|
|
|
void Widget::rxMsgReprogramFirmware()
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
2023-04-06 10:42:39 -04:00
|
|
|
rebootBootloader();
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgProgramFlashPageRequest
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgProgramFlashPageRequest(std::shared_ptr<Pro::MsgProgramFlashPageRequest> msg)
|
|
|
|
{
|
2023-04-03 20:09:55 -04:00
|
|
|
auto reply = std::make_shared<Pro::MsgProgramFlashPageReply>();
|
2023-04-05 06:56:23 -04:00
|
|
|
reply->success = writeFwPage(msg->page);
|
2023-04-03 20:09:55 -04:00
|
|
|
sendMessage(reply);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgProgramFlashPageReply
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgProgramFlashPageReply(std::shared_ptr<Pro::MsgProgramFlashPageReply> msg)
|
|
|
|
{
|
2023-04-06 10:43:42 -04:00
|
|
|
reply_firmwarePage_.set_value(msg->success);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgGetWidgetParametersRequest
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgGetWidgetParametersRequest(std::shared_ptr<Pro::MsgGetWidgetParametersRequest> msg)
|
|
|
|
{
|
2023-04-03 20:12:01 -04:00
|
|
|
auto reply = std::make_shared<Pro::MsgGetWidgetParametersReply>();
|
2023-04-06 08:33:57 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
reply->break_time = tx_break_intervals;
|
|
|
|
reply->mab_time = tx_mab_intervals;
|
|
|
|
reply->rate = tx_rate;
|
|
|
|
reply->user_data = std::vector<uint8_t>(user_configuration);
|
|
|
|
}
|
2023-04-03 20:12:01 -04:00
|
|
|
reply->user_data.resize(msg->size, 0);
|
|
|
|
|
|
|
|
sendMessage(reply);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgGetWidgetParametersReply
|
|
|
|
* @param msg
|
2023-04-05 09:19:16 -04:00
|
|
|
*
|
|
|
|
* No sanity checking is performed on the values in the reply.
|
2023-04-02 22:47:50 -04:00
|
|
|
*/
|
|
|
|
void Widget::rxMsgGetWidgetParametersReply(std::shared_ptr<Pro::MsgGetWidgetParametersReply> msg)
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-03 20:12:01 -04:00
|
|
|
firmware_version = msg->version;
|
|
|
|
tx_break_intervals = msg->break_time;
|
|
|
|
tx_mab_intervals = msg->mab_time;
|
|
|
|
tx_rate = msg->rate;
|
|
|
|
user_configuration = std::vector<uint8_t>(msg->user_data);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgSetWidgetParametersRequest
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgSetWidgetParametersRequest(std::shared_ptr<Pro::MsgSetWidgetParametersRequest> msg)
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-05 09:19:16 -04:00
|
|
|
setTxBreakIntervals(msg->break_time);
|
|
|
|
setTxMabIntervals(msg->mab_time);
|
|
|
|
setTxRate(msg->rate);
|
2023-04-03 20:12:01 -04:00
|
|
|
user_configuration = std::vector<uint8_t>(msg->user_data);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgRecievedDmxPacket
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgRecievedDmxPacket(std::shared_ptr<Pro::MsgRecievedDmxPacket> msg)
|
|
|
|
{
|
2023-04-05 12:41:13 -04:00
|
|
|
switch (msg->data[0]) {
|
|
|
|
case DMX::E111_NULL_START:
|
|
|
|
setData(msg->data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
setAltData(msg->data);
|
|
|
|
break;
|
|
|
|
}
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgOutputOnlySendDMX
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgOutputOnlySendDMX(std::shared_ptr<Pro::MsgOutputOnlySendDMX> msg)
|
|
|
|
{
|
2023-04-05 12:41:13 -04:00
|
|
|
switch (msg->data[0]) {
|
|
|
|
case DMX::E111_NULL_START:
|
|
|
|
setData(msg->data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgSendRDMData
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgSendRDMData(std::shared_ptr<Pro::MsgSendRDMData> msg)
|
|
|
|
{
|
|
|
|
(void)msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgRecieveDMXOnChange
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgRecieveDMXOnChange(std::shared_ptr<Pro::MsgRecieveDMXOnChange> msg)
|
|
|
|
{
|
2023-04-05 12:41:13 -04:00
|
|
|
setData(std::vector<uint8_t>(DMX::E111_LAST_SLOT+1, 0)); // clear dimmer data
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-05 12:41:13 -04:00
|
|
|
rx_update_mode_ = msg->mode;
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgRecievedDMXChanged
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgRecievedDMXChanged(std::shared_ptr<Pro::MsgRecievedDMXChanged> msg)
|
|
|
|
{
|
|
|
|
(void)msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgGetWidgetSerialRequest
|
|
|
|
*/
|
2023-04-09 19:51:01 -04:00
|
|
|
void Widget::rxMsgGetWidgetSerialRequest()
|
2023-04-02 22:47:50 -04:00
|
|
|
{
|
2023-04-03 20:11:25 -04:00
|
|
|
auto reply = std::make_shared<Pro::MsgGetWidgetSerialReply>();
|
2023-04-06 08:33:57 -04:00
|
|
|
{
|
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
|
|
|
reply->serial = serial_number;
|
|
|
|
}
|
2023-04-03 20:11:25 -04:00
|
|
|
sendMessage(reply);
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgGetWidgetSerialReply
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgGetWidgetSerialReply(std::shared_ptr<Pro::MsgGetWidgetSerialReply> msg)
|
|
|
|
{
|
2023-04-06 08:33:57 -04:00
|
|
|
std::scoped_lock lock(mtx_metadata_);
|
2023-04-03 20:11:25 -04:00
|
|
|
serial_number = msg->serial;
|
2023-04-02 22:47:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Widget::rxMsgSendRDMDiscovery
|
|
|
|
* @param msg
|
|
|
|
*/
|
|
|
|
void Widget::rxMsgSendRDMDiscovery(std::shared_ptr<Pro::MsgSendRDMDiscovery> msg)
|
|
|
|
{
|
|
|
|
(void)msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-04-03 09:58:26 -04:00
|
|
|
} // namespace ENTTEC
|