1
0
Fork 0

make DMP generic enough for all vectors

This commit is contained in:
Kevin Matz 2021-08-15 21:43:36 -04:00
parent 53b6345038
commit 3e0cfe4868
3 changed files with 301 additions and 151 deletions

View File

@ -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
View File

@ -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 propertys value may not be read.
NOT_WRITABLE = 4, // The propertys 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 propertys 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 propertys value may not be read.
NOT_WRITABLE = 4, //!< The propertys 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 propertys 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();
};

View File

@ -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