make DMP generic enough for all vectors
This commit is contained in:
parent
53b6345038
commit
3e0cfe4868
311
acn/dmp.cpp
311
acn/dmp.cpp
|
@ -28,71 +28,14 @@ namespace ACN {
|
|||
namespace DMP {
|
||||
|
||||
/**
|
||||
* @brief address_type::streamSize
|
||||
* @return
|
||||
*/
|
||||
size_t address_type::streamSize() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_type::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void address_type::iStream(PDU::Stream stream)
|
||||
{
|
||||
uint8_t val;
|
||||
*stream >> val;
|
||||
|
||||
z_reserved = (val >> 7) & 0b1;
|
||||
relative = (val >> 6) & 0b1;
|
||||
type = (data_type)((val >> 4) & 0b11);
|
||||
x_reserved = (val >> 2) & 0b11;
|
||||
width = (address_length)(val & 0b11);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_type::oStream
|
||||
* @return
|
||||
*/
|
||||
void address_type::oStream(PDU::Stream stream) const
|
||||
{
|
||||
uint8_t val = 0;
|
||||
val |= relative << 6;
|
||||
val |= type << 4;
|
||||
val |= width;
|
||||
*stream << val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range::range
|
||||
* @param stream
|
||||
* @param t
|
||||
* @param l
|
||||
*/
|
||||
range::range(PDU::Stream stream, const data_type t, const address_length l)
|
||||
{
|
||||
address = read(stream, l);
|
||||
if (t == SINGLE) return;
|
||||
incriment = read(stream, l);
|
||||
count = read(stream, l);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range::read
|
||||
* @brief range::read_
|
||||
* @param stream
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
uint32_t range::read(PDU::Stream stream, const address_length length)
|
||||
uint32_t range::read_(PDU::Stream stream)
|
||||
{
|
||||
switch (length) {
|
||||
switch (length_) {
|
||||
case ONE:
|
||||
return stream->readType<uint8_t>();
|
||||
case TWO:
|
||||
|
@ -105,14 +48,168 @@ uint32_t range::read(PDU::Stream stream, const address_length length)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range::write_
|
||||
* @param stream
|
||||
* @param val
|
||||
*/
|
||||
void range::write_(PDU::Stream stream, const uint32_t& val) const
|
||||
{
|
||||
switch (length_) {
|
||||
case ONE:
|
||||
stream->writeType<uint8_t>(val);
|
||||
case TWO:
|
||||
stream->writeType<uint16_t>(val);
|
||||
case FOUR:
|
||||
stream->writeType<uint32_t>(val);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t range::streamSize() const
|
||||
{
|
||||
auto count = [this] () {
|
||||
switch (type_) {
|
||||
case SINGLE:
|
||||
return 1;
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
return count() * address_width(length_);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void range::iStream(PDU::Stream stream)
|
||||
{
|
||||
address = read_(stream);
|
||||
if (type_ == SINGLE) return;
|
||||
incriment = read_(stream);
|
||||
count = read_(stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range::oStream
|
||||
* @param stream
|
||||
*/
|
||||
void range::oStream(PDU::Stream stream) const
|
||||
{
|
||||
write_(stream, address);
|
||||
if (type_ == SINGLE) return;
|
||||
write_(stream, incriment);
|
||||
write_(stream, count);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief dmp_set_data::streamSize
|
||||
* @return
|
||||
*/
|
||||
size_t dmp_set_data::streamSize() const
|
||||
size_t address_pair_list::streamSize() const
|
||||
{
|
||||
/// TODO: verify size of data
|
||||
return 71;
|
||||
size_t s = 0;
|
||||
for (const auto & [range, vect] : properties)
|
||||
{
|
||||
s += range.streamSize();
|
||||
s += vect.size();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range_data::iStream
|
||||
*/
|
||||
void address_pair_list::iStream(PDU::Stream stream)
|
||||
{
|
||||
while(stream->good()) {
|
||||
// Property Address
|
||||
range pr(type_->type, type_->width);
|
||||
pr.iStream(stream);
|
||||
|
||||
if (!stream->good() || pr.count * pr.incriment > stream->available()) {
|
||||
stream->setstate(std::ios_base::failbit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Property Data
|
||||
std::vector<uint8_t> pd;
|
||||
pd.resize(pr.address, 0);
|
||||
for (uint32_t i = 0; i < pr.count * pr.incriment; i ++)
|
||||
pd.push_back(stream->readType<uint8_t>());
|
||||
|
||||
// Property Fields
|
||||
properties.push_back(address_data_pair(pr, pd));
|
||||
|
||||
//set EOF if buffer insufficient for another property range
|
||||
if (stream->available() < address_width(type_->width) *
|
||||
(type_->type == SINGLE? 1 : 3))
|
||||
stream->setstate(std::ios_base::eofbit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief range_data::oStream
|
||||
*/
|
||||
void address_pair_list::oStream(PDU::Stream stream) const
|
||||
{
|
||||
for (const auto & [range, vect] : properties)
|
||||
{
|
||||
range.oStream(stream);
|
||||
for (uint8_t d : vect)
|
||||
*stream << d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_list::streamSize
|
||||
* @return
|
||||
*/
|
||||
size_t address_list::streamSize() const
|
||||
{
|
||||
size_t s = 0;
|
||||
for (const auto & range : addresses)
|
||||
s += range.streamSize();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_list::iStream
|
||||
*/
|
||||
void address_list::iStream(PDU::Stream stream)
|
||||
{
|
||||
while(stream->good())
|
||||
{
|
||||
// Property Address
|
||||
range pr(type_->type, type_->width);
|
||||
pr.iStream(stream);
|
||||
addresses.push_back(pr);
|
||||
|
||||
//set EOF if buffer insufficient for another property range
|
||||
if (stream->available() < address_width(type_->width) *
|
||||
(type_->type == SINGLE? 1 : 3))
|
||||
stream->setstate(std::ios_base::eofbit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_list::oStream
|
||||
*/
|
||||
void address_list::oStream(PDU::Stream stream) const
|
||||
{
|
||||
for (const auto & addr : addresses)
|
||||
addr.oStream(stream);
|
||||
}
|
||||
|
||||
|
||||
|
@ -137,53 +234,57 @@ void Pdu::iStream(PDU::Stream stream)
|
|||
|
||||
createHeader<address_type>();
|
||||
|
||||
if (!flags_.hasData)
|
||||
return;
|
||||
|
||||
auto header = static_cast<address_type*>(this->header());
|
||||
|
||||
auto dataIsAddressList = [this, header] () {
|
||||
data_ = new address_list(header);
|
||||
data_->iStream(stream_);
|
||||
};
|
||||
|
||||
auto dataIsAdddresPairList = [this, header] () {
|
||||
data_ = new address_pair_list(header);
|
||||
data_->iStream(stream_);
|
||||
};
|
||||
|
||||
switch(vector()) {
|
||||
case SET_PROPERTY:
|
||||
readSetData();
|
||||
case GET_PROPERTY:
|
||||
dataIsAddressList();
|
||||
break;
|
||||
default:
|
||||
case SET_PROPERTY:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case GET_PROPERTY_REPLY:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case EVENT:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
dataIsAddressList();
|
||||
break;
|
||||
case UNSUBSCRIBE:
|
||||
dataIsAddressList();
|
||||
break;
|
||||
case GET_PROPERTY_FAIL:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case SET_PROPERTY_FAIL:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case SUBSCRIBE_ACCEPT:
|
||||
dataIsAddressList();
|
||||
break;
|
||||
case SUBSCRIBE_REJECT:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
case SYNC_EVENT:
|
||||
dataIsAdddresPairList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Pdu::readSetData
|
||||
*/
|
||||
void Pdu::readSetData()
|
||||
{
|
||||
if (!flags_.hasData)
|
||||
return;
|
||||
|
||||
createData<dmp_set_data>();
|
||||
|
||||
auto header = static_cast<address_type*>(this->header());
|
||||
auto data = static_cast<dmp_set_data*>(data_);
|
||||
|
||||
while(stream_->good()) {
|
||||
// Property Address
|
||||
range pr(stream_, header->type, header->width);
|
||||
|
||||
if (!stream_->good() || pr.count * pr.incriment > stream_->available()) {
|
||||
stream_->setstate(std::ios_base::failbit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Property Data
|
||||
std::vector<uint8_t> pd;
|
||||
pd.resize(pr.address, 0);
|
||||
for (uint32_t i = 0; i < pr.count * pr.incriment; i ++)
|
||||
pd.push_back(stream_->readType<uint8_t>());
|
||||
|
||||
// Property Fields
|
||||
set_property fields(pr, pd);
|
||||
data->properties.push_back(fields);
|
||||
|
||||
//set EOF if buffer insufficient for another property range
|
||||
if (stream_->available() < header->width * (header->type == SINGLE? 1 : 3))
|
||||
stream_->setstate(std::ios_base::eofbit);
|
||||
}
|
||||
}
|
||||
|
||||
} // DMP
|
||||
} // ACN
|
||||
|
|
128
acn/dmp.h
128
acn/dmp.h
|
@ -36,10 +36,10 @@ namespace DMP {
|
|||
* @brief 5.1.4 Address and Data Types
|
||||
*/
|
||||
enum data_type {
|
||||
SINGLE = 0b00, // 0
|
||||
RANGE = 0b01, // 1
|
||||
ARRAY = 0b10, // 2
|
||||
SERIES = 0b11 // 3
|
||||
SINGLE = 0b00, //!< Non-range address, Single data item
|
||||
RANGE = 0b01, //!< Range address, Single data item
|
||||
ARRAY = 0b10, //!< Range address, Array of equal size data items
|
||||
SERIES = 0b11 //!< Range address, Series of mixed size data items
|
||||
};
|
||||
|
||||
|
||||
|
@ -54,48 +54,110 @@ enum address_length {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief address_width
|
||||
* @param l
|
||||
* @return
|
||||
*/
|
||||
inline unsigned int address_width(const address_length& l)
|
||||
{
|
||||
switch (l) {
|
||||
case ONE: return 1;
|
||||
case TWO: return 2;
|
||||
case FOUR: return 4;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief The address_type struct
|
||||
*/
|
||||
struct address_type : PDU::pdu_header {
|
||||
bool z_reserved : 1; // Z
|
||||
bool relative : 1; // R
|
||||
data_type type : 2; // D1, D0
|
||||
uint8_t x_reserved : 2; // X1, X0
|
||||
address_length width : 2; // A1, A0
|
||||
size_t streamSize() const override;
|
||||
void iStream(PDU::Stream) override;
|
||||
void oStream(PDU::Stream) const override;
|
||||
struct address_type
|
||||
: PDU::pdu_header
|
||||
{
|
||||
union {
|
||||
uint8_t byte = 0;
|
||||
struct __attribute__((packed)) {
|
||||
address_length width : 2; // A1, A0
|
||||
uint8_t x_reserved : 2; // X1, X0
|
||||
data_type type : 2; // D1, D0
|
||||
bool relative : 1; // R
|
||||
bool z_reserved : 1; // Z
|
||||
};
|
||||
};
|
||||
|
||||
size_t streamSize() const override { return 1; }
|
||||
void iStream(PDU::Stream s) override { *s >> byte; }
|
||||
void oStream(PDU::Stream s) const override { *s << byte; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 5.1.5 The range struct
|
||||
*/
|
||||
struct range {
|
||||
struct range
|
||||
: PDU::pdu_stream_object
|
||||
{
|
||||
range(const data_type t, const address_length l)
|
||||
: type_(t)
|
||||
, length_(l)
|
||||
{};
|
||||
uint32_t address = 0;
|
||||
uint32_t incriment = 0;
|
||||
uint32_t count = 0;
|
||||
range(PDU::Stream, const data_type, const address_length);
|
||||
|
||||
size_t streamSize() const override;
|
||||
void iStream(PDU::Stream) override;
|
||||
void oStream(PDU::Stream) const override;
|
||||
|
||||
private:
|
||||
uint32_t read(PDU::Stream, const address_length);
|
||||
const data_type type_;
|
||||
const address_length length_;
|
||||
uint32_t read_(PDU::Stream);
|
||||
void write_(PDU::Stream, const uint32_t&) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief set_property
|
||||
*/
|
||||
typedef std::pair<range, std::vector<uint8_t>> set_property;
|
||||
typedef std::pair<range, std::vector<uint8_t>> address_data_pair;
|
||||
|
||||
|
||||
/**
|
||||
* @brief The dmp_set_data struct
|
||||
* @brief The address_pair_list struct
|
||||
*/
|
||||
struct dmp_set_data : PDU::pdu_data {
|
||||
std::vector<set_property> properties;
|
||||
struct address_pair_list
|
||||
: PDU::pdu_data
|
||||
{
|
||||
address_pair_list(const address_type* t) : type_(t) {};
|
||||
std::vector<address_data_pair> properties;
|
||||
|
||||
size_t streamSize() const override;
|
||||
void iStream(PDU::Stream) override {};
|
||||
void oStream(PDU::Stream) const override {};
|
||||
void iStream(PDU::Stream) override;
|
||||
void oStream(PDU::Stream) const override;
|
||||
|
||||
private:
|
||||
const address_type* type_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The address_list struct
|
||||
*/
|
||||
struct address_list
|
||||
: PDU::pdu_data
|
||||
{
|
||||
address_list(const address_type* t) : type_(t) {};
|
||||
std::vector<range> addresses;
|
||||
|
||||
size_t streamSize() const override;
|
||||
void iStream(PDU::Stream) override;
|
||||
void oStream(PDU::Stream) const override;
|
||||
|
||||
private:
|
||||
const address_type* type_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -103,22 +165,22 @@ struct dmp_set_data : PDU::pdu_data {
|
|||
* @brief 7 Response Messages
|
||||
*/
|
||||
enum failure_reason {
|
||||
NONSPECIFIC = 1, // Non-specific or non-DMP reason.
|
||||
NOT_PROPERTY = 2, // The address does not correspond to a property.
|
||||
WRITE_ONLY = 3, // The property’s value may not be read.
|
||||
NOT_WRITABLE = 4, // The property’s value may not be written.
|
||||
DATA_ERROR = 5, // The data does not correspond to the property.
|
||||
SUBSCIRPTION_NOT_SUPPORTED = 10, // Subscriptions on the specified property are not supported by the device.
|
||||
NO_SUBSCRIPTIONS_SUPPORTED = 11, // Subscriptions not supported on any property.
|
||||
INSUFFICIENT_RESOURCES = 12, // The component cannot support more subscriptions due to resource limitations
|
||||
UNAVAILABLE = 13 // The property’s value is not available due to restrictions imposed by device specific functionality (e.g., access permission mechanisms).
|
||||
NONSPECIFIC = 1, //!< Non-specific or non-DMP reason.
|
||||
NOT_PROPERTY = 2, //!< The address does not correspond to a property.
|
||||
WRITE_ONLY = 3, //!< The property’s value may not be read.
|
||||
NOT_WRITABLE = 4, //!< The property’s value may not be written.
|
||||
DATA_ERROR = 5, //!< The data does not correspond to the property.
|
||||
SUBSCIRPTION_NOT_SUPPORTED = 10, //!< Subscriptions on the specified property are not supported by the device.
|
||||
NO_SUBSCRIPTIONS_SUPPORTED = 11, //!< Subscriptions not supported on any property.
|
||||
INSUFFICIENT_RESOURCES = 12, //!< The component cannot support more subscriptions due to resource limitations
|
||||
UNAVAILABLE = 13 //!< The property’s value is not available due to restrictions imposed by device specific functionality (e.g., access permission mechanisms).
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 13.1 Protocol Codes
|
||||
*/
|
||||
static const uint32_t DMP_PROTOCOL_ID = 2; // PDU protocol value
|
||||
static const uint32_t DMP_PROTOCOL_ID = 2; //!< protocol vector
|
||||
|
||||
// 13.2 Message Codes
|
||||
static const uint8_t GET_PROPERTY = 1;
|
||||
|
@ -143,8 +205,6 @@ class Pdu
|
|||
public:
|
||||
Pdu();
|
||||
void iStream(PDU::Stream) override;
|
||||
private:
|
||||
void readSetData();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -105,26 +105,15 @@ void Universe::set(std::shared_ptr<DMP::Pdu> dmp,
|
|||
// Receivers shall discard the packet if the received value is not 0xa1.
|
||||
if (!dmp->header())
|
||||
return;
|
||||
#if defined(RTTI_ENABLED)
|
||||
auto type = dynamic_cast<ACN::DMP::address_type*>(dmp->header());
|
||||
#else
|
||||
auto type = static_cast<ACN::DMP::address_type*>(dmp->header());
|
||||
#endif
|
||||
if (!type->z_reserved) return; // needs to be true, but why?
|
||||
if (type->relative) return;
|
||||
if (type->type != ACN::DMP::ARRAY) return;
|
||||
if (type->x_reserved != 0) return;
|
||||
if (type->width != ACN::DMP::TWO) return;
|
||||
|
||||
// only act on the first property pair in the data
|
||||
if (!dmp->data())
|
||||
return;
|
||||
|
||||
#if defined(RTTI_ENABLED)
|
||||
auto set_data = dynamic_cast<ACN::DMP::dmp_set_data*>(dmp->data());
|
||||
#else
|
||||
auto set_data = static_cast<ACN::DMP::dmp_set_data*>(dmp->data());
|
||||
#endif
|
||||
auto set_data = static_cast<ACN::DMP::address_pair_list*>(dmp->data());
|
||||
const auto& [range, data] = set_data->properties.front();
|
||||
|
||||
// 7.4 First Property Address
|
||||
|
|
Loading…
Reference in New Issue