1
0
Fork 0

stream IO for the API

This commit is contained in:
Kevin Matz 2023-04-02 19:42:32 -04:00
parent 8e41fc72c2
commit 8f3d704d5a
3 changed files with 332 additions and 29 deletions

View File

@ -6,8 +6,15 @@ add_library(ENTTEC::Pro ALIAS ${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PUBLIC
pro.h
PRIVATE
pro.cpp
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
LCP::BufferStream
LCP::DMX
)
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -0,0 +1,238 @@
/*
pro.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 "dmx.h"
#include "pro.h"
namespace ENTTEC::Pro {
void MsgProgramFlashPageRequest::iStream(std::shared_ptr<bufferstream> stream)
{
if (stream->available() < sizeof(page))
return stream->setstate(std::ios_base::failbit);
stream->read(page, sizeof(page));
if (!stream->available())
stream->setstate(std::ios_base::eofbit);
};
void MsgProgramFlashPageRequest::oStream(std::shared_ptr<bufferstream> stream) const
{
stream->write(page, sizeof(page));
};
void MsgProgramFlashPageReply::iStream(std::shared_ptr<bufferstream> stream)
{
uint8_t buffer[sizeof(SUCCESS_OK)];
success = false;
if (stream->available() < sizeof(buffer))
return stream->setstate(std::ios_base::failbit);
stream->read(buffer, sizeof(buffer));
if (!stream->available())
stream->setstate(std::ios_base::eofbit);
success = !std::memcmp(buffer, SUCCESS_OK, sizeof(buffer));
};
void MsgProgramFlashPageReply::oStream(std::shared_ptr<bufferstream> stream) const
{
if (success)
stream->write(reinterpret_cast<const uint8_t*>(SUCCESS_OK), sizeof(SUCCESS_OK));
else
stream->write(reinterpret_cast<const uint8_t*>(SUCCESS_FAIL), sizeof(SUCCESS_FAIL));
};
void MsgGetWidgetParametersRequest::iStream(std::shared_ptr<bufferstream> stream)
{
*stream >> size;
};
void MsgGetWidgetParametersRequest::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << size;
};
void MsgGetWidgetParametersReply::iStream(std::shared_ptr<bufferstream> stream)
{
*stream >> fw_rev;
*stream >> fw_type;
*stream >> break_time;
*stream >> mab_time;
*stream >> rate;
if (!stream->eof()) {
std::vector<uint8_t> buffer;
stream->read(buffer.data(), USER_CONFIGURATION_MAX);
std::copy(buffer.begin(), buffer.end(), std::back_inserter(user_data));
}
};
void MsgGetWidgetParametersReply::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << fw_rev;
*stream << fw_type;
*stream << break_time;
*stream << mab_time;
*stream << rate;
stream->write(user_data.data(), std::min(user_data.size(), USER_CONFIGURATION_MAX));
};
void MsgSetWidgetParametersRequest::iStream(std::shared_ptr<bufferstream> stream)
{
uint16_t size;
*stream >> size;
*stream >> break_time;
*stream >> mab_time;
*stream >> rate;
if (size)
{
std::vector<uint8_t> buffer;
stream->read(buffer.data(), USER_CONFIGURATION_MAX);
std::copy(buffer.begin(), buffer.end(), std::back_inserter(user_data));
}
};
void MsgSetWidgetParametersRequest::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << (uint16_t)user_data.size();
*stream << break_time;
*stream << mab_time;
*stream << rate;
stream->write(user_data.data(), std::min(user_data.size(), USER_CONFIGURATION_MAX));
};
void MsgRecievedDmxPacket::iStream(std::shared_ptr<bufferstream> stream)
{
*stream >> rx_corrupted;
stream->read(data.data(), DMX::E111_LAST_SLOT + 1);
};
void MsgRecievedDmxPacket::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << rx_corrupted;
stream->write(data.data(), std::min(data.size(), DMX::E111_LAST_SLOT + 1));
};
void MsgOutputOnlySendDMX::iStream(std::shared_ptr<bufferstream> stream)
{
stream->read(data.data(), DMX::E111_LAST_SLOT + 1);
};
void MsgOutputOnlySendDMX::oStream(std::shared_ptr<bufferstream> stream) const
{
stream->write(data.data(), std::min(data.size(), DMX::E111_LAST_SLOT + 1));
for (size_t i = data.size(); i <= DMX_LAST_SLOT_MIN; i++)
*stream << (uint8_t) 0;
};
void MsgSendRDMData::iStream(std::shared_ptr<bufferstream> stream)
{
stream->read(data.data(), DMX::E111_LAST_SLOT + 1);
};
void MsgSendRDMData::oStream(std::shared_ptr<bufferstream> stream) const
{
stream->write(data.data(), std::min(data.size(), DMX::E111_LAST_SLOT + 1));
};
void MsgRecieveDMXOnChange::iStream(std::shared_ptr<bufferstream> stream)
{
uint8_t val;
*stream >> val;
if (val)
mode = RxNotifyOnChange;
else
mode = RxNotifyAlways;
};
void MsgRecieveDMXOnChange::oStream(std::shared_ptr<bufferstream> stream) const
{
if (mode == RxNotifyOnChange)
*stream << (uint8_t)1;
else
*stream << (uint8_t)0;
};
void MsgRecievedDMXChanged::iStream(std::shared_ptr<bufferstream> stream)
{
*stream >> start;
stream->read(changed, sizeof(changed));
stream->read(data.data(), 40);
};
void MsgRecievedDMXChanged::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << start;
stream->write(changed, sizeof(changed));
stream->write(data.data(), std::min(data.size(), (size_t)40));
};
void MsgGetWidgetSerialReply::iStream(std::shared_ptr<bufferstream> stream)
{
*stream >> serial;
};
void MsgGetWidgetSerialReply::oStream(std::shared_ptr<bufferstream> stream) const
{
*stream << serial;
};
void MsgSendRDMDiscovery::iStream(std::shared_ptr<bufferstream> stream)
{
stream->read(request, sizeof(request));
};
void MsgSendRDMDiscovery::oStream(std::shared_ptr<bufferstream> stream) const
{
stream->write(request, sizeof(request));
};
} // namespace ENTTEC::Pro

View File

@ -23,23 +23,26 @@
*/
#pragma once
#include <bufferstream.h>
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
namespace ENTTEC {
namespace PRO {
namespace ENTTEC::Pro {
struct ApplicationMessage;
struct MessageData;
/**
* @brief Application Message Format
*
* \cite DMXUSBPro The PC based application program communicates with the Widget.
*/
struct Message {
uint8_t label; //!< Label to identify the type of message.
std::shared_ptr<ApplicationMessage> message; //!< Data
struct Message
{
uint8_t label; //!< "OpCode" Label to identify the type of message.
std::shared_ptr<MessageData> data; //!< Data
};
const uint8_t START_DELIMITER = 0x7e; //!< Start of message delimiter
@ -79,11 +82,12 @@ enum MESSAGE_LABEL {
/**
* @brief The ApplicationMessage class
* @brief The MessageData class
*
* Base type of each message data.
*/
struct ApplicationMessage
struct MessageData
: public streamable
{
};
@ -95,8 +99,11 @@ struct ApplicationMessage
* enable reprogramming of the Widget firmware.
*/
struct MsgReprogramFirmware
: public ApplicationMessage
: public MessageData
{
size_t streamSize() const override { return 0; };
void iStream(std::shared_ptr<bufferstream>) override {};
void oStream(std::shared_ptr<bufferstream>) const override{};
};
@ -108,9 +115,13 @@ struct MsgReprogramFirmware
* the firmware binary file.
*/
struct MsgProgramFlashPageRequest
: public ApplicationMessage
: public MessageData
{
uint8_t page[64]; //!< One page of firmware binary file.
size_t streamSize() const override { return 64; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -121,9 +132,13 @@ struct MsgProgramFlashPageRequest
* Program Flash Page request.
*/
struct MsgProgramFlashPageReply
: public ApplicationMessage
: public MessageData
{
bool success; //!< Success character array product
bool success; //!< Success character array product
size_t streamSize() const override { return 4; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
const char SUCCESS_OK[4] = {'T','R','U','E'}; //!< Firmware page write success
@ -136,12 +151,16 @@ const char SUCCESS_FAIL[4] = {'F','A','L','S'}; //!< Firmware page write failure
* \cite DMXUSBPro This message requests the Widget configuration.
*/
struct MsgGetWidgetParametersRequest
: public ApplicationMessage
: public MessageData
{
uint16_t user_configuration_size = 0; //!< user configuration size in bytes
uint16_t size = 0; //!< user configuration size in bytes
size_t streamSize() const override { return 2; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
const uint16_t USER_CONFIGURATION_MAX = 508; //!< maximum user configuration size
const size_t USER_CONFIGURATION_MAX = 508; //!< maximum user configuration size
/**
@ -151,7 +170,7 @@ const uint16_t USER_CONFIGURATION_MAX = 508; //!< maximum user configuration siz
* Widget Parameters request.
*/
struct MsgGetWidgetParametersReply
: public ApplicationMessage
: public MessageData
{
union {
uint16_t version;
@ -164,6 +183,10 @@ struct MsgGetWidgetParametersReply
uint8_t mab_time; //!< interval count of the DMX output MARK AFTER BREAK
uint8_t rate; //!< DMX output rate in packets per second.
std::vector<uint8_t> user_data; //!< user defined configuration data
size_t streamSize() const override { return 5 + user_data.size(); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
const float DMX_BREAK_INTERVAL = 10.67; //!< microseconds, resolution of the BREAK interval
@ -184,12 +207,16 @@ const uint8_t DMX_RATE_MAX = 40; //!< minimum DMX refresh rate
* \cite DMXUSBPro This message sets the Widget configuration.
*/
struct MsgSetWidgetParametersRequest
: public ApplicationMessage
: public MessageData
{
uint8_t break_time; //!< interval count of the DMX output BREAK
uint8_t mab_time; //!< interval count of the DMX output MARK AFTER BREAK
uint8_t rate; //!< DMX output rate in packets per second.
std::vector<uint8_t> user_data; //!< user defined configuration data
size_t streamSize() const override { return 5 + user_data.size(); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -201,7 +228,7 @@ struct MsgSetWidgetParametersRequest
* mode is 'Send always'.
*/
struct MsgRecievedDmxPacket
: public ApplicationMessage
: public MessageData
{
union {
uint8_t rx_corrupted; //!< When this is 0, the DMX data is valid.
@ -211,9 +238,15 @@ struct MsgRecievedDmxPacket
};
};
std::vector<uint8_t> data; //!< Received DMX data beginning with the start code.
size_t streamSize() const override { return 1 + data.size(); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
const size_t DMX_LAST_SLOT_MIN = 24; //!< length of the shortest supported universe
/**
* @brief 8. Output Only Send DMX Packet Request (Label=6)
*
@ -221,12 +254,15 @@ struct MsgRecievedDmxPacket
* of the Widget DMX port at the configured DMX output rate.
*/
struct MsgOutputOnlySendDMX
: public ApplicationMessage
: public MessageData
{
std::vector<uint8_t> data; //!< DMX data to send, beginning with the start code.
size_t streamSize() const override { return std::max(data.size(), DMX_LAST_SLOT_MIN + 1); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
const uint8_t DMX_LAST_SLOT_MIN = 24; //!< length of the shortest supported universe
/**
@ -237,9 +273,13 @@ const uint8_t DMX_LAST_SLOT_MIN = 24; //!< length of the shortest supporte
* DMX packets can be received.
*/
struct MsgSendRDMData
: public ApplicationMessage
: public MessageData
{
std::vector<uint8_t> data; //!< RDM data to send, beginning with the start code.
size_t streamSize() const override { return data.size(); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -259,9 +299,13 @@ enum DMX_RX_MODE {
* by sending this message.
*/
struct MsgRecieveDMXOnChange
: public ApplicationMessage
: public MessageData
{
DMX_RX_MODE mode = RxNotifyAlways; //!< Always (default), or OnChange
size_t streamSize() const override { return 1; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -273,11 +317,15 @@ struct MsgRecieveDMXOnChange
* Change mode is 'Send on data change only'.
*/
struct MsgRecievedDMXChanged
: public ApplicationMessage
: public MessageData
{
uint8_t start; //!< Start changed byte number.
uint8_t changed[5]; //!< Changed bit array.
std::vector<uint8_t> data; //!< Changed DMX data byte data.
size_t streamSize() const override { return 6 + data.size(); };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -287,8 +335,11 @@ struct MsgRecievedDMXChanged
* \cite DMXUSBPro This message requests the Widget serial number.
*/
struct MsgGetWidgetSerialRequest
: public ApplicationMessage
: public MessageData
{
size_t streamSize() const override { return 0; };
void iStream(std::shared_ptr<bufferstream>) override {};
void oStream(std::shared_ptr<bufferstream>) const override{};
};
@ -299,9 +350,13 @@ struct MsgGetWidgetSerialRequest
* Serial Number request.
*/
struct MsgGetWidgetSerialReply
: public ApplicationMessage
: public MessageData
{
uint32_t serial; //!< BCD serial number.
size_t streamSize() const override { return 4; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
@ -312,10 +367,13 @@ struct MsgGetWidgetSerialReply
* out of the Widget DMX port, and then receive an RDM Discovery Response.
*/
struct MsgSendRDMDiscovery
: public ApplicationMessage
: public MessageData
{
uint8_t request[38]; //!< DISC_UNIQUE_BRANCH RDM request packet to send.
size_t streamSize() const override { return 38; };
void iStream(std::shared_ptr<bufferstream>) override;
void oStream(std::shared_ptr<bufferstream>) const override;
};
} // namespace PRO
} // namespace ENTTEC
} // namespace ENTTEC::Pro