RDM API cleanup
This commit is contained in:
parent
29173eacf2
commit
9b27820873
|
@ -49,170 +49,124 @@ Device::Device(UID id, Device* parent)
|
|||
queued_statuses_.emplace(STATUS_WARNING, std::queue<StatusPtr>());
|
||||
queued_statuses_.emplace(STATUS_ERROR, std::queue<StatusPtr>());
|
||||
|
||||
Parameter *pid;
|
||||
|
||||
/// \cite RDM 9.2.3 Required Sub-Device Messages
|
||||
/// Devices supporting the use of sub-devices shall support the
|
||||
/// SUPPORTED_PARAMETERS message in order for the controller to determine
|
||||
/// which additional messages are supported by the sub-devices.
|
||||
parameters_.try_emplace(SUPPORTED_PARAMETERS, new Parameter());
|
||||
parameters_.at(SUPPORTED_PARAMETERS)->getAction(std::bind(
|
||||
&Device::actionGetSupportedParameters,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(SUPPORTED_PARAMETERS);
|
||||
pid->getAction(std::bind(&Device::actionGetSupportedParameters, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.3.4 Clear Status ID (CLEAR_STATUS_ID)
|
||||
/// This parameter is used to clear the status message queue.
|
||||
parameters_.try_emplace(CLEAR_STATUS_ID, new Parameter());
|
||||
parameters_.at(SUPPORTED_PARAMETERS)->setAction(std::bind(
|
||||
&Device::actionSetClearStatusId,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(CLEAR_STATUS_ID);
|
||||
pid->getAction(std::bind(&Device::actionSetClearStatusId, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.3.5 Get/Set Sub-Device Status Reporting Threshold
|
||||
/// (SUB_DEVICE_STATUS_REPORT_THRESHOLD)
|
||||
/// This parameter is used to set the verbosity of Sub-Device reporting using
|
||||
/// the Status Type codes as enumerated in Table A-4 .
|
||||
parameters_.try_emplace(SUB_DEVICE_STATUS_REPORT_THRESHOLD, new Parameter());
|
||||
parameters_.at(SUB_DEVICE_STATUS_REPORT_THRESHOLD)->getAction(std::bind(
|
||||
&Device::actionGetSubdeviceThreshold,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(SUB_DEVICE_STATUS_REPORT_THRESHOLD)->setAction(std::bind(
|
||||
&Device::actionSetSubdeviceThreshold,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(SUB_DEVICE_STATUS_REPORT_THRESHOLD);
|
||||
pid->getAction(std::bind(&Device::actionGetSubdeviceThreshold, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSetSubdeviceThreshold, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.1 Get Device Info (DEVICE_INFO)
|
||||
/// This parameter is used to retrieve a variety of information about the
|
||||
/// device that is normally required by a controller.
|
||||
parameters_.try_emplace(DEVICE_INFO, new Parameter());
|
||||
parameters_.at(DEVICE_INFO)->getAction(std::bind(
|
||||
&Device::actionGetDeviceInfo,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DEVICE_INFO);
|
||||
pid->getAction(std::bind(&Device::actionGetDeviceInfo, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.2 Get Product Detail ID List (PRODUCT_DETAIL_ID_LIST)
|
||||
/// This parameter shall be used for requesting technology details for a
|
||||
/// device.
|
||||
parameters_.try_emplace(PRODUCT_DETAIL_ID_LIST, new Parameter());
|
||||
parameters_.at(PRODUCT_DETAIL_ID_LIST)->getAction(std::bind(
|
||||
&Device::actionGetProductDetailIdList,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(PRODUCT_DETAIL_ID_LIST);
|
||||
pid->getAction(std::bind(&Device::actionGetProductDetailIdList, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.3 Get Device Model Description (DEVICE_MODEL_DESCRIPTION)
|
||||
/// This parameter provides a text description of up to 32 characters for the
|
||||
/// device model type.
|
||||
parameters_.try_emplace(DEVICE_MODEL_DESCRIPTION, new Parameter());
|
||||
parameters_.at(DEVICE_MODEL_DESCRIPTION)->getAction(std::bind(
|
||||
&Device::actionGetDevModelDescription,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DEVICE_MODEL_DESCRIPTION);
|
||||
pid->getAction(std::bind(&Device::actionGetDevModelDescription, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.4 Get Manufacturer Label (MANUFACTURER_LABEL)
|
||||
/// This parameter provides an ASCII text response with the Manufacturer name
|
||||
/// for the device of up to 32 characters.
|
||||
parameters_.try_emplace(MANUFACTURER_LABEL, new Parameter());
|
||||
parameters_.at(MANUFACTURER_LABEL)->getAction(std::bind(
|
||||
&Device::actionGetManufacturerLabel,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(MANUFACTURER_LABEL);
|
||||
pid->getAction(std::bind(&Device::actionGetManufacturerLabel, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.7 Get Language Capabilities (LANGUAGE_CAPABILITIES)
|
||||
/// This parameter is used to identify languages that the device supports for
|
||||
/// using the LANGUAGE parameter.
|
||||
parameters_.try_emplace(LANGUAGE_CAPABILITIES, new Parameter());
|
||||
parameters_.at(LANGUAGE_CAPABILITIES)->getAction(std::bind(
|
||||
&Device::actionGetLanguage,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(LANGUAGE_CAPABILITIES);
|
||||
pid->getAction(std::bind(&Device::actionGetLanguage, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.8 Get/Set Language (LANGUAGE)
|
||||
/// This parameter is used to change the language of the messages from
|
||||
/// the device.
|
||||
parameters_.try_emplace(LANGUAGE, new Parameter());
|
||||
parameters_.at(LANGUAGE)->getAction(std::bind(
|
||||
&Device::actionGetLanguage,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(LANGUAGE)->setAction(std::bind(
|
||||
&Device::actionSetLanguage,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(LANGUAGE);
|
||||
pid->getAction(std::bind(&Device::actionGetLanguage, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSetLanguage, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.5.9 Get Software Version Label (SOFTWARE_VERSION_LABEL)
|
||||
/// This parameter is used to get a descriptive ASCII text label for the
|
||||
/// device’s operating software version.
|
||||
parameters_.try_emplace(SOFTWARE_VERSION_LABEL, new Parameter());
|
||||
parameters_.at(SOFTWARE_VERSION_LABEL)->getAction(std::bind(
|
||||
&Device::actionGetSoftwareVersionLabel,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(SOFTWARE_VERSION_LABEL);
|
||||
pid->getAction(std::bind(&Device::actionGetSoftwareVersionLabel, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.6.1 Get/Set DMX512 Personality (DMX_PERSONALITY)
|
||||
/// This parameter is used to set the responder’s DMX512 Personality.
|
||||
parameters_.try_emplace(DMX_PERSONALITY, new Parameter());
|
||||
parameters_.at(DMX_PERSONALITY)->getAction(std::bind(
|
||||
&Device::actionGetDmxPersonality,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(DMX_PERSONALITY)->setAction(std::bind(
|
||||
&Device::actionSetDmxPersonality,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DMX_PERSONALITY);
|
||||
pid->getAction(std::bind(&Device::actionGetDmxPersonality, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSetDmxPersonality, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.6.2 Get DMX512 Personality Description (DMX_PERSONALITY_DESCRIPTION)
|
||||
/// This parameter is used to get a descriptive ASCII text label for a given
|
||||
/// DMX512 Personality.
|
||||
parameters_.try_emplace(DMX_PERSONALITY_DESCRIPTION, new Parameter());
|
||||
parameters_.at(DMX_PERSONALITY_DESCRIPTION)->getAction(std::bind(
|
||||
&Device::actionGetDmxPersonalityDesc,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DMX_PERSONALITY_DESCRIPTION);
|
||||
pid->getAction(std::bind(&Device::actionGetDmxPersonalityDesc, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.6.3 Get/Set DMX512 Starting Address (DMX_START_ADDRESS)
|
||||
/// This parameter is used to set or get the DMX512 start address.
|
||||
parameters_.try_emplace(DMX_START_ADDRESS, new Parameter());
|
||||
parameters_.at(DMX_START_ADDRESS)->getAction(std::bind(
|
||||
&Device::actionGetDmxStartAddress,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(DMX_START_ADDRESS)->setAction(std::bind(
|
||||
&Device::actionSetDmxStartAddress,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DMX_START_ADDRESS);
|
||||
pid->getAction(std::bind(&Device::actionGetDmxStartAddress, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSetDmxStartAddress, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.7.1 Get Sensor Definition (SENSOR_DEFINITION)
|
||||
/// This parameter is used to retrieve the definition of a specific sensor.
|
||||
parameters_.try_emplace(SENSOR_DEFINITION, new Parameter());
|
||||
parameters_.at(SENSOR_DEFINITION)->getAction(std::bind(
|
||||
&Device::actionSensorDispatch,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(SENSOR_DEFINITION);
|
||||
pid->getAction(std::bind(&Device::actionSensorDispatch, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.7.2 Get/Set Sensor (SENSOR_VALUE)
|
||||
/// This parameter shall be used to retrieve or reset sensor data.
|
||||
parameters_.try_emplace(SENSOR_VALUE, new Parameter());
|
||||
parameters_.at(SENSOR_VALUE)->getAction(std::bind(
|
||||
&Device::actionSensorDispatch,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(SENSOR_VALUE)->setAction(std::bind(
|
||||
&Device::actionSensorDispatch,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(SENSOR_VALUE);
|
||||
pid->getAction(std::bind(&Device::actionSensorDispatch, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSensorDispatch, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.7.3 Record Sensors (RECORD_SENSORS)
|
||||
/// This parameter instructs devices such as dimming racks that monitor load
|
||||
/// changes to store the current value for monitoring sensor changes.
|
||||
parameters_.try_emplace(RECORD_SENSORS, new Parameter());
|
||||
parameters_.at(RECORD_SENSORS)->setAction(std::bind(
|
||||
&Device::actionSensorDispatch,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(RECORD_SENSORS);
|
||||
pid->setAction(std::bind(&Device::actionSensorDispatch, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.11.1 Get/Set Identify Device (IDENTIFY_DEVICE)
|
||||
/// This parameter is used for the user to physically identify the device
|
||||
/// represented by the UID.
|
||||
parameters_.try_emplace(IDENTIFY_DEVICE, new Parameter());
|
||||
parameters_.at(IDENTIFY_DEVICE)->getAction(std::bind(
|
||||
&Device::actionGetIdentifyDevice,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(IDENTIFY_DEVICE)->setAction(std::bind(
|
||||
&Device::actionSetIdentifyDevice,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(IDENTIFY_DEVICE);
|
||||
pid->getAction(std::bind(&Device::actionGetIdentifyDevice, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Device::actionSetIdentifyDevice, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.11.2 Reset Device (RESET_DEVICE)
|
||||
/// This parameter is used to instruct the responder to reset itself.
|
||||
parameters_.try_emplace(RESET_DEVICE, new Parameter());
|
||||
parameters_.at(RESET_DEVICE)->setAction(std::bind(
|
||||
&Device::actionSetResetDevice,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(RESET_DEVICE);
|
||||
pid->setAction(std::bind(&Device::actionSetResetDevice, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
|
||||
|
@ -284,7 +238,22 @@ void Device::addProductDetailId(uint16_t id)
|
|||
{
|
||||
product_detail_list_.push_back(id);
|
||||
while (product_detail_list_.size() > 6)
|
||||
product_detail_list_.pop_front();
|
||||
product_detail_list_.pop_front();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Device::addParameter
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
Parameter *Device::addParameter(const PID id)
|
||||
{
|
||||
if (parameters_.count(id))
|
||||
return parameters_.at(id);
|
||||
|
||||
auto [it, _] = parameters_.emplace(id, new Parameter(id));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
|
@ -297,7 +266,7 @@ void Device::get(const MsgPtr message, MsgPtr response)
|
|||
{
|
||||
if (!actionPrep_(message, response))
|
||||
return;
|
||||
parameters_.at(message->parameterId)->get(message, response);
|
||||
parameters_.at(message->mdb.pid)->get(message, response);
|
||||
}
|
||||
|
||||
|
||||
|
@ -310,7 +279,7 @@ void Device::set(const MsgPtr message, MsgPtr response)
|
|||
{
|
||||
if (!actionPrep_(message, response))
|
||||
return;
|
||||
parameters_.at(message->parameterId)->set(message, response);
|
||||
parameters_.at(message->mdb.pid)->set(message, response);
|
||||
}
|
||||
|
||||
|
||||
|
@ -399,17 +368,17 @@ void Device::enqueueStatus(StatusPtr status)
|
|||
*/
|
||||
bool Device::actionPrep_(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!parameters_.count(message->parameterId))
|
||||
if (!parameters_.count(message->mdb.pid))
|
||||
{
|
||||
response->nak(NR_UNKNOWN_PID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (message->parameterId == last_rx_pid_)
|
||||
if (message->mdb.pid == last_rx_pid_)
|
||||
++ack_overflow_page;
|
||||
else {
|
||||
ack_overflow_page = 0;
|
||||
last_rx_pid_ = message->parameterId;
|
||||
last_rx_pid_ = message->mdb.pid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -421,9 +390,9 @@ bool Device::actionPrep_(const MsgPtr message, MsgPtr response)
|
|||
* @param response
|
||||
*/
|
||||
void Device::actionGetSupportedParameters(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
{
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
unsigned int count = parameters_.size();
|
||||
unsigned int length = count * sizeof(PID);
|
||||
|
@ -434,19 +403,19 @@ void Device::actionGetSupportedParameters(const MsgPtr message, MsgPtr response)
|
|||
first = 0;
|
||||
}
|
||||
|
||||
auto pid = parameters_.begin();
|
||||
if (first != 0)
|
||||
std::advance(pid, first);
|
||||
while (pid != parameters_.end() && response->mdb.pdl() < 0xfe)
|
||||
{
|
||||
response->appendParameterData(pid->first);
|
||||
pid++;
|
||||
}
|
||||
|
||||
if (length > 0xfe && ack_overflow_page != lastPage)
|
||||
response->responseType = RESPONSE_TYPE_ACK_OVERFLOW;
|
||||
else
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
|
||||
auto pid = parameters_.begin();
|
||||
if (first != 0)
|
||||
std::advance(pid, first);
|
||||
while (pid != parameters_.end() && response->length() < 0xfe)
|
||||
{
|
||||
response->appendData(pid->first);
|
||||
pid++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -457,20 +426,21 @@ void Device::actionGetSupportedParameters(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetDeviceInfo(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->appendParameterData(RDM_PROTOCOL_VERSION);
|
||||
response->appendParameterData(deviceModelID);
|
||||
response->appendParameterData(deviceProductCategory);
|
||||
response->appendParameterData(LIB_VERSION);
|
||||
response->appendParameterData(DMX::Device::footprint());
|
||||
response->appendParameterData(DMX::Device::personality());
|
||||
response->appendParameterData(DMX::Device::personalityCount());
|
||||
response->appendParameterData(DMX::Device::address());
|
||||
response->appendParameterData(subDeviceCount());
|
||||
response->appendParameterData<uint8_t>(sensors_.size());
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(RDM_PROTOCOL_VERSION);
|
||||
response->appendData(deviceModelID);
|
||||
response->appendData(deviceProductCategory);
|
||||
response->appendData(LIB_VERSION);
|
||||
response->appendData(DMX::Device::footprint());
|
||||
response->appendData(DMX::Device::personality());
|
||||
response->appendData(DMX::Device::personalityCount());
|
||||
response->appendData(DMX::Device::address());
|
||||
response->appendData(subDeviceCount());
|
||||
response->appendData<uint8_t>(sensors_.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -481,8 +451,8 @@ void Device::actionGetDeviceInfo(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetClearStatusId(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
for (auto& [_, queue] : queued_statuses_)
|
||||
while (!queue.empty())
|
||||
|
@ -499,11 +469,12 @@ void Device::actionSetClearStatusId(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetSubdeviceThreshold(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->appendParameterData(status_reporting_threshold_);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(status_reporting_threshold_);
|
||||
}
|
||||
|
||||
|
||||
|
@ -514,10 +485,10 @@ void Device::actionGetSubdeviceThreshold(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetSubdeviceThreshold(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint8_t threshold = message->data()->front();
|
||||
uint8_t threshold = message->mdb.pd.front();
|
||||
|
||||
switch (threshold) {
|
||||
case STATUS_ERROR:
|
||||
|
@ -551,15 +522,16 @@ void Device::actionSetSubdeviceThreshold(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetProductDetailIdList(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
if (product_detail_list_.empty())
|
||||
response->appendData(PRODUCT_DETAIL_NOT_DECLARED);
|
||||
response->appendParameterData(PRODUCT_DETAIL_NOT_DECLARED);
|
||||
else
|
||||
for (const auto detail : product_detail_list_)
|
||||
response->appendData(detail);
|
||||
response->appendParameterData(detail);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -569,13 +541,14 @@ void Device::actionGetProductDetailIdList(const MsgPtr message, MsgPtr response)
|
|||
* @param response
|
||||
*/
|
||||
void Device::actionGetDevModelDescription(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
{
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
for (size_t i = 0; i < deviceModelDescription.size() && i <= 32; i++)
|
||||
response->appendParameterData(deviceModelDescription.at(i));
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
for (size_t i = 0; i < deviceModelDescription.size() && i <= 32; i++)
|
||||
response->appendData(deviceModelDescription.at(i));
|
||||
}
|
||||
|
||||
|
||||
|
@ -586,12 +559,13 @@ void Device::actionGetDevModelDescription(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetManufacturerLabel(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
for (size_t i = 0; i < deviceManufacturerLabel.size() && i <= 32; i++)
|
||||
response->appendParameterData(deviceManufacturerLabel.at(i));
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
for (size_t i = 0; i < deviceManufacturerLabel.size() && i <= 32; i++)
|
||||
response->appendData(deviceManufacturerLabel.at(i));
|
||||
}
|
||||
|
||||
|
||||
|
@ -602,13 +576,13 @@ void Device::actionGetManufacturerLabel(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetLanguage(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->appendParameterData('e');
|
||||
response->appendParameterData('n');
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
std::string label = std::string("en");
|
||||
for (const auto c : label)
|
||||
response->appendData(c);
|
||||
}
|
||||
|
||||
|
||||
|
@ -619,18 +593,12 @@ void Device::actionGetLanguage(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetLanguage(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(2, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 2)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
std::string s;
|
||||
for (char c : *message->data())
|
||||
s += c;
|
||||
|
||||
if (s != "en")
|
||||
{
|
||||
response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
return;
|
||||
}
|
||||
if (message->mdb.pd[0] != 'e' ||
|
||||
message->mdb.pd[1] != 'n')
|
||||
return response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
}
|
||||
|
@ -643,13 +611,13 @@ void Device::actionSetLanguage(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetSoftwareVersionLabel(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
std::string label = std::string(LIB_VERSION_LABEL);
|
||||
for (size_t i = 0; i < label.size() && i <= 32; i++)
|
||||
response->appendData(label.at(i));
|
||||
response->appendParameterData(label.at(i));
|
||||
}
|
||||
|
||||
|
||||
|
@ -660,12 +628,12 @@ void Device::actionGetSoftwareVersionLabel(const MsgPtr message, MsgPtr response
|
|||
*/
|
||||
void Device::actionGetDmxPersonality(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(DMX::Device::personality());
|
||||
response->appendData(DMX::Device::personalityCount());
|
||||
response->appendParameterData(DMX::Device::personality());
|
||||
response->appendParameterData(DMX::Device::personalityCount());
|
||||
}
|
||||
|
||||
|
||||
|
@ -676,16 +644,13 @@ void Device::actionGetDmxPersonality(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetDmxPersonality(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint8_t mode = message->data()->front();
|
||||
uint8_t mode = message->mdb.pd.front();
|
||||
|
||||
if ( mode == 0 || mode > DMX::Device::personalityCount())
|
||||
{
|
||||
response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
return;
|
||||
}
|
||||
return response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
|
||||
setPersonality(mode);
|
||||
|
||||
|
@ -700,24 +665,22 @@ void Device::actionSetDmxPersonality(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetDmxPersonalityDesc(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint8_t mode = message->data()->front();
|
||||
uint8_t mode = message->mdb.pd.front();
|
||||
|
||||
if ( mode == 0 || mode > DMX::Device::personalityCount())
|
||||
{
|
||||
response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
return;
|
||||
}
|
||||
return response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(mode);
|
||||
response->appendData(personalities_.at(mode)->footprint());
|
||||
response->appendParameterData(mode);
|
||||
response->appendParameterData(personalities_.at(mode)->footprint());
|
||||
for (size_t i = 0; i < personalities_.at(mode)->description().size(); i++)
|
||||
{
|
||||
if (i > 32)
|
||||
break;
|
||||
response->appendData(personalities_.at(mode)->description().at(i));
|
||||
response->appendParameterData(personalities_.at(mode)->description().at(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -729,14 +692,14 @@ void Device::actionGetDmxPersonalityDesc(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetDmxStartAddress(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
if (footprint() == 0)
|
||||
response->appendData<uint16_t>(0xFFFF);
|
||||
response->appendParameterData<uint16_t>(0xFFFF);
|
||||
else
|
||||
response->appendData(address());
|
||||
response->appendParameterData(address());
|
||||
}
|
||||
|
||||
|
||||
|
@ -747,16 +710,14 @@ void Device::actionGetDmxStartAddress(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetDmxStartAddress(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(2, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 2)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint16_t addr = Message::readType<uint16_t>(*message->data(), 0);
|
||||
uint16_t addr = Message::readType<uint16_t>(message->mdb.pd, 0);
|
||||
|
||||
if (!setAddress(addr))
|
||||
{
|
||||
response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
return;
|
||||
}
|
||||
return response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
}
|
||||
|
||||
|
@ -768,12 +729,12 @@ void Device::actionSetDmxStartAddress(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSensorDispatch(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint8_t index = message->data()->front();
|
||||
uint8_t index = message->mdb.pd.front();
|
||||
|
||||
switch (message->commandClass) {
|
||||
switch (message->mdb.cc) {
|
||||
case GET_COMMAND:
|
||||
{
|
||||
if (index == 0xFF || index >= sensors_.size())
|
||||
|
@ -782,7 +743,7 @@ void Device::actionSensorDispatch(const MsgPtr message, MsgPtr response)
|
|||
return;
|
||||
}
|
||||
auto sensor = sensors_.at(index);
|
||||
switch (message->parameterId) {
|
||||
switch (message->mdb.pid) {
|
||||
case SENSOR_DEFINITION:
|
||||
sensor->actionGetSensorDefinition(index, response);
|
||||
break;
|
||||
|
@ -801,7 +762,7 @@ void Device::actionSensorDispatch(const MsgPtr message, MsgPtr response)
|
|||
}
|
||||
auto setSensor = [index, message, response](Sensor * sensor)
|
||||
{
|
||||
switch (message->parameterId) {
|
||||
switch (message->mdb.pid) {
|
||||
case SENSOR_VALUE:
|
||||
sensor->actionSetSensorValue(index, response);
|
||||
break;
|
||||
|
@ -828,11 +789,11 @@ void Device::actionSensorDispatch(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionGetIdentifyDevice(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData<uint8_t>(identifying_);
|
||||
response->appendParameterData<uint8_t>(identifying_);
|
||||
}
|
||||
|
||||
|
||||
|
@ -843,10 +804,10 @@ void Device::actionGetIdentifyDevice(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetIdentifyDevice(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
identify(message->data()->front());
|
||||
identify(message->mdb.pd.front());
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
}
|
||||
|
@ -859,10 +820,10 @@ void Device::actionSetIdentifyDevice(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Device::actionSetResetDevice(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
switch (message->data()->front()) {
|
||||
switch (message->mdb.pd.front()) {
|
||||
case 0x01:
|
||||
reset(false);
|
||||
break;
|
||||
|
@ -870,8 +831,7 @@ void Device::actionSetResetDevice(const MsgPtr message, MsgPtr response)
|
|||
reset(true);
|
||||
break;
|
||||
default:
|
||||
response->nak(NR_FORMAT_ERROR);
|
||||
return;
|
||||
return response->nak(NR_DATA_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
uint16_t subDeviceCount() const;
|
||||
void addProductDetailId(uint16_t);
|
||||
|
||||
Parameter* addParameter(const PID id);
|
||||
|
||||
void get(const MsgPtr message, MsgPtr response);
|
||||
void set(const MsgPtr message, MsgPtr response);
|
||||
|
||||
|
|
|
@ -37,55 +37,25 @@ Message::Message()
|
|||
|
||||
|
||||
/**
|
||||
* @brief Message::Message
|
||||
* @param obj
|
||||
* @brief Use a vector to populate the Message fields.
|
||||
* @param buffer
|
||||
*/
|
||||
Message::Message(const Message &obj)
|
||||
: source(obj.source)
|
||||
, destination(obj.destination)
|
||||
, transaction(obj.transaction)
|
||||
, portID(obj.portID)
|
||||
, messageCount(obj.messageCount)
|
||||
, subDevice(obj.subDevice)
|
||||
, parameterId(obj.parameterId)
|
||||
, failure_mode(0)
|
||||
void Message::read(const std::vector<uint8_t> &buffer)
|
||||
{
|
||||
data_.insert(data_.end(), obj.data()->begin(), obj.data()->end());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::Message
|
||||
* @param data
|
||||
*/
|
||||
Message::Message(const std::vector<uint8_t> &data)
|
||||
: failure_mode(0)
|
||||
{
|
||||
read(data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::read
|
||||
* @param data
|
||||
*/
|
||||
void Message::read(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (data.size() < 9) // SC + SC_SUB + LENGTH + DESTINATION
|
||||
{
|
||||
short_message = true;
|
||||
return;
|
||||
}
|
||||
/// \cite RDM 10.3 Collection of Queued and Status Messages
|
||||
/// Short Message - This field shall be incremented any time the message terminates (either
|
||||
/// due to a BREAK or timeout condition occurring) before a complete Destination UID has
|
||||
/// been received.
|
||||
if (buffer.size() < 9)
|
||||
short_message = true;
|
||||
|
||||
/// \cite RDM 6.2.1 START Code
|
||||
/// This field shall contain the defined RDM START Code (SC_RDM). Controllers
|
||||
/// and Responders shall always send SC_RDM in this slot, and any packet
|
||||
/// containing a value other than SC_RDM is outside the scope of this standard.
|
||||
if (data[0] != SC_RDM)
|
||||
{
|
||||
incorrect_sc = true;
|
||||
return;
|
||||
}
|
||||
if (buffer[0] != SC_RDM)
|
||||
incorrect_sc = true;
|
||||
|
||||
/// \cite RDM 6.2.2 Sub START Code
|
||||
/// This field shall contain the Sub-START Code within RDM that defines this
|
||||
|
@ -94,52 +64,52 @@ void Message::read(const std::vector<uint8_t> &data)
|
|||
/// identify the packet structure being used.
|
||||
/// Controllers shall always send SC_SUB_MESSAGE in this slot, and Responders
|
||||
/// shall ignore any packets containing other values.
|
||||
if (data[1] != SC_SUB_MESSAGE)
|
||||
{
|
||||
incorrect_sub_sc = true;
|
||||
return;
|
||||
}
|
||||
if (buffer[1] != SC_SUB_MESSAGE)
|
||||
incorrect_sub_sc = true;
|
||||
|
||||
/// \cite RDM 6.2.3 Message Length
|
||||
/// The Message Length value is defined as the number of slots in the RDM
|
||||
/// Packet including the START Code and excluding the Checksum. Each slot is
|
||||
/// an 8-bit value.
|
||||
/// The Message Length field points to the Checksum High Slot.
|
||||
uint8_t length = data[2];
|
||||
if (length + 2 != data.size())
|
||||
{
|
||||
length_mismatch = true;
|
||||
return;
|
||||
}
|
||||
uint8_t length = buffer[2];
|
||||
if (length + 2 != buffer.size())
|
||||
length_mismatch = true;
|
||||
|
||||
if (buffer.size() < 26) // RDM 6.2 Message Format w/ 0 parameter data length
|
||||
{
|
||||
do_not_send = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/// \cite RDM 6.2.4 Destination UID
|
||||
/// The Destination UID is the UID of the target device(s).
|
||||
destination.manufacturer = readType<uint16_t>(data, 3);
|
||||
destination.device = readType<uint32_t>(data, 5);
|
||||
destination.manufacturer = readType<uint16_t>(buffer, 3);
|
||||
destination.device = readType<uint32_t>(buffer, 5);
|
||||
|
||||
/// \cite RDM 6.2.5 Source UID
|
||||
/// The Source UID is the UID of the device originating this packet.
|
||||
source.manufacturer = readType<uint16_t>(data, 9);
|
||||
source.device = readType<uint32_t>(data, 11);
|
||||
source.manufacturer = readType<uint16_t>(buffer, 9);
|
||||
source.device = readType<uint32_t>(buffer, 11);
|
||||
|
||||
/// \cite RDM 6.2.6 Transaction Number (TN)
|
||||
/// Controller generated packets increment this field every time an RDM packet
|
||||
/// is transmitted.
|
||||
/// Responders shall reply with their Transaction Number set to the Transaction
|
||||
/// Number contained in the controller packet to which they are responding.
|
||||
transaction = data[15];
|
||||
tn = buffer[15];
|
||||
|
||||
/// \cite RDM 6.2.7 Port ID / Response Type
|
||||
/// This field serves different functions depending on whether the message is
|
||||
/// being generated by the controller or the responder.
|
||||
portID = data[16];
|
||||
portID = buffer[16];
|
||||
|
||||
/// \cite RDM 6.2.8 Message Count
|
||||
/// The message count field is used by a responder to indicate that additional
|
||||
/// data is now available for collection by a controller. This data (which
|
||||
/// might be unrelated to the current message transaction) should be collected
|
||||
/// by the controller using the GET:QUEUED_MESSAGE command.
|
||||
messageCount = data[17];
|
||||
messageCount = buffer[17];
|
||||
|
||||
/// \cite RDM 6.2.9 Sub-Device Field
|
||||
/// Sub-devices should be used in devices containing a repetitive number of
|
||||
|
@ -153,10 +123,10 @@ void Message::read(const std::vector<uint8_t> &data)
|
|||
/// not belong to any sub-device module.
|
||||
/// The Parameter ID designates which parameter on the sub-device is being
|
||||
/// addressed. The use of Sub-Devices is described further in Section 9.
|
||||
subDevice = readType<uint16_t>(data, 18);
|
||||
subDevice = readType<uint16_t>(buffer, 18);
|
||||
|
||||
/// \cite RDM 6.2.10.1 Command Class (CC)
|
||||
commandClass = data[20];
|
||||
mdb.cc = buffer[20];
|
||||
|
||||
/// \cite RDM 6.2.10.2 Parameter ID (PID)
|
||||
/// The Parameter ID is a 16-bit number that identifies a specific type of
|
||||
|
@ -165,84 +135,96 @@ void Message::read(const std::vector<uint8_t> &data)
|
|||
/// Manufacturer-specific parameter whose details are either published by the
|
||||
/// Manufacturer for third-party support or proprietary for the Manufacturer’s
|
||||
/// own use.
|
||||
parameterId = readType<uint16_t>(data, 21);
|
||||
mdb.pid = readType<uint16_t>(buffer, 21);
|
||||
|
||||
/// \cite RDM 6.2.10.3 Parameter Data Length (PDL)
|
||||
/// The Parameter Data Length (PDL) is the number of slots included in the
|
||||
/// Parameter Data area that it precedes. When this field is set to 0x00 it
|
||||
/// indicates that there is no Parameter Data following.
|
||||
uint8_t pdl = data[23];
|
||||
uint8_t pdl = buffer[23];
|
||||
|
||||
/// \cite RDM 6.2.10.4 Parameter Data (PD)
|
||||
/// The Parameter Data is of variable length.
|
||||
for (int i = 0; i < pdl; i++)
|
||||
appendData(data[24+i]);
|
||||
if (pdl && buffer.size() >= 26 + pdl)
|
||||
for (int i = 0; i < pdl; i++)
|
||||
appendParameterData(buffer[24+i]);
|
||||
|
||||
/// \cite RDM 6.2.11 Checksum
|
||||
/// If the checksum field in the packet does not match the calculated checksum,
|
||||
/// then the packet shall be discarded and no response sent.
|
||||
auto chksum = readType<uint16_t>(data, data.size() - 2);
|
||||
auto chksum = readType<uint16_t>(buffer, buffer.size() - 2);
|
||||
if (chksum != checksum())
|
||||
{
|
||||
checksum_fail = true;
|
||||
return;
|
||||
}
|
||||
checksum_fail = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::write
|
||||
* @param data
|
||||
* @brief Write the formatted Message fields to a vector.
|
||||
* @param buffer
|
||||
*
|
||||
* > \cite RDM 6.2 Packet Format
|
||||
* > All RDM packets shall use the following message structure, with the exception of the
|
||||
* > Discovery Unique Branch response message. The format of the Discovery Unique Branch
|
||||
* > message is detailed in Section 7.5 Discovery Unique Branch Message.
|
||||
*/
|
||||
void Message::write(std::vector<uint8_t> &data) const
|
||||
void Message::write(std::vector<uint8_t> &buffer) const
|
||||
{
|
||||
if (commandClass == DISCOVERY_COMMAND_RESPONSE &&
|
||||
parameterId == DISC_UNIQUE_BRANCH)
|
||||
{
|
||||
writeDiscBranch(data);
|
||||
return;
|
||||
}
|
||||
data.reserve(26 + length());
|
||||
data.push_back(SC_RDM);
|
||||
data.push_back(SC_SUB_MESSAGE);
|
||||
data.push_back(24 + length());
|
||||
writeType(data, destination.manufacturer);
|
||||
writeType(data, destination.device);
|
||||
writeType(data, source.manufacturer);
|
||||
writeType(data, source.device);
|
||||
data.push_back(transaction);
|
||||
data.push_back(portID);
|
||||
data.push_back(messageCount);
|
||||
writeType(data, subDevice);
|
||||
data.push_back(commandClass);
|
||||
writeType(data, parameterId);
|
||||
data.push_back(length());
|
||||
data.insert(data.end(), data_.begin(), data_.end());
|
||||
writeType(data, checksum());
|
||||
if (mdb.cc == DISCOVERY_COMMAND_RESPONSE &&
|
||||
mdb.pid == DISC_UNIQUE_BRANCH)
|
||||
return writeDiscBranch(buffer);
|
||||
|
||||
buffer.reserve(buffer.size() + 26 + mdb.pdl()); // pre-allocate necessary memory
|
||||
buffer.push_back(SC_RDM);
|
||||
buffer.push_back(SC_SUB_MESSAGE);
|
||||
buffer.push_back(24 + mdb.pdl());
|
||||
writeType(buffer, destination.manufacturer);
|
||||
writeType(buffer, destination.device);
|
||||
writeType(buffer, source.manufacturer);
|
||||
writeType(buffer, source.device);
|
||||
buffer.push_back(tn);
|
||||
buffer.push_back(portID);
|
||||
buffer.push_back(messageCount);
|
||||
writeType(buffer, subDevice);
|
||||
buffer.push_back(mdb.cc);
|
||||
writeType(buffer, mdb.pid);
|
||||
buffer.push_back(mdb.pdl());
|
||||
buffer.insert(buffer.end(), mdb.pd.begin(), mdb.pd.end());
|
||||
writeType(buffer, checksum());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::writeDiscBranch
|
||||
* @param data
|
||||
* @brief Write the specialized DISC_UNIQUE_BRANCH RESPONSE format'd fields to a vector.
|
||||
* @param buffer
|
||||
*
|
||||
* > \cite 7.5 Discovery Unique Branch Message.
|
||||
* > The response message has a number of exceptions to the normal Packet structure to minimize
|
||||
* > the effect of collisions on legacy devices from appearing as a BREAK, NULL START Code, and
|
||||
* > data. The format of the DISC_UNIQUE_BRANCH Response Packet is described in Table 7-1.
|
||||
*/
|
||||
void Message::writeDiscBranch(std::vector<uint8_t> &data) const
|
||||
void Message::writeDiscBranch(std::vector<uint8_t> &buffer) const
|
||||
{
|
||||
if (mdb.cc != DISCOVERY_COMMAND_RESPONSE ||
|
||||
mdb.pid != DISC_UNIQUE_BRANCH)
|
||||
return write(buffer);
|
||||
|
||||
buffer.reserve(buffer.size() + 24); // pre-allocate necessary memory
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
data.push_back(0xfe); //!< Response Preamble bytes
|
||||
data.push_back(0xaa); //!< Preamble separator byte
|
||||
buffer.push_back(0xfe); //!< Response Preamble bytes
|
||||
buffer.push_back(0xaa); //!< Preamble separator byte
|
||||
|
||||
uint16_t sum = 0;
|
||||
for (const auto &v : data_)
|
||||
for (const auto &v : mdb.pd)
|
||||
addSum_(sum, v);
|
||||
|
||||
std::vector<uint8_t> d = data_;
|
||||
std::vector<uint8_t> d = mdb.pd;
|
||||
writeType<uint16_t>(d, sum);
|
||||
|
||||
for ( uint8_t& v : d)
|
||||
{
|
||||
data.push_back(v | 0xaa);
|
||||
data.push_back(v | 0x55);
|
||||
buffer.push_back(v | 0xaa);
|
||||
buffer.push_back(v | 0x55);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,36 +235,19 @@ void Message::writeDiscBranch(std::vector<uint8_t> &data) const
|
|||
*/
|
||||
void Message::nak(uint16_t reason)
|
||||
{
|
||||
data_.clear();
|
||||
mdb.pd.clear();
|
||||
responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
appendData(reason);
|
||||
|
||||
appendParameterData(reason);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::data
|
||||
* @return
|
||||
*/
|
||||
const std::vector<uint8_t>* Message::data() const
|
||||
{
|
||||
return &data_;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::length
|
||||
* @return
|
||||
*/
|
||||
uint8_t Message::length() const
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::checksum
|
||||
* @brief \cite RDM 6.2.11 Checksum
|
||||
* @return
|
||||
*
|
||||
* \cite RDM The Checksum field is the unsigned, modulo 0x10000, 16-bit additive
|
||||
* checksum of the entire packet’s slot data, including START Code. The checksum
|
||||
* is an additive sum of the 8-bit fields into a 16-bit response value.
|
||||
*/
|
||||
uint16_t Message::checksum() const
|
||||
{
|
||||
|
@ -290,39 +255,22 @@ uint16_t Message::checksum() const
|
|||
|
||||
addSum_(sum, SC_RDM);
|
||||
addSum_(sum, SC_SUB_MESSAGE);
|
||||
addSum_(sum, 24 + length());
|
||||
addSum_(sum, 24 + mdb.pdl());
|
||||
addSum_(sum, source.manufacturer);
|
||||
addSum_(sum, source.device);
|
||||
addSum_(sum, destination.manufacturer);
|
||||
addSum_(sum, destination.device);
|
||||
addSum_(sum, transaction);
|
||||
addSum_(sum, tn);
|
||||
addSum_(sum, portID);
|
||||
addSum_(sum, messageCount);
|
||||
addSum_(sum, subDevice);
|
||||
addSum_(sum, commandClass);
|
||||
addSum_(sum, parameterId);
|
||||
addSum_(sum, length());
|
||||
for (const auto &val : data_)
|
||||
addSum_(sum, mdb.cc);
|
||||
addSum_(sum, mdb.pid);
|
||||
addSum_(sum, mdb.pdl());
|
||||
for (const auto &val : mdb.pd)
|
||||
addSum_(sum, val);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::requiredLength
|
||||
* @param length
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
bool Message::requiredLength(const size_t length, MsgPtr response) const
|
||||
{
|
||||
if (data_.size() != length)
|
||||
{
|
||||
response->nak(NR_FORMAT_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace RDM
|
||||
|
|
|
@ -32,34 +32,40 @@
|
|||
|
||||
namespace RDM {
|
||||
|
||||
struct Message;
|
||||
struct Message; //!< \cite RDM 6 Message Structure
|
||||
|
||||
using MsgPtr = std::shared_ptr<Message>; //!< valid RDM Message
|
||||
using MsgPtr = std::shared_ptr<Message>; //!< Managed RDM Message pointer.
|
||||
|
||||
/**
|
||||
* @brief The Message struct
|
||||
* @brief \cite RDM 6.2 Packet Format
|
||||
*
|
||||
* \cite RDM All RDM packets shall use the following message structure, with the exception
|
||||
* of the Discovery Unique Branch response message.
|
||||
*/
|
||||
struct Message
|
||||
{
|
||||
explicit Message();
|
||||
explicit Message(const Message &obj);
|
||||
explicit Message(const std::vector<uint8_t> &data);
|
||||
|
||||
void read(const std::vector<uint8_t> &data);
|
||||
void write(std::vector<uint8_t> &data) const;
|
||||
void nak(uint16_t reason);
|
||||
|
||||
UID source; //!< source UID
|
||||
UID destination; //!< destination UID
|
||||
uint8_t transaction; //!< transaction number
|
||||
UID destination; //!< \cite RDM 6.2.4 Destination UID
|
||||
UID source; //!< \cite RDM 6.2.5 Source UID
|
||||
uint8_t tn; //!< \cite RDM 6.2.6 Transaction Number (TN)
|
||||
union {
|
||||
uint8_t portID; //!< destination port
|
||||
uint8_t responseType; //!< type of response
|
||||
uint8_t portID; //!< \cite RDM 6.2.7.1 Port ID for Controller Generated Messages
|
||||
uint8_t responseType; //!< \cite RDM 6.2.7.2 Response Type for Responder Generated Messages
|
||||
};
|
||||
uint8_t messageCount; //!< message count number
|
||||
uint16_t subDevice; //!< destination subdevice
|
||||
uint8_t commandClass; //!< message command class
|
||||
PID parameterId; //!< PID
|
||||
uint8_t messageCount; //!< \cite RDM 6.2.8 Message Count
|
||||
uint16_t subDevice; //!< \cite RDM 6.2.9 Sub-Device Field
|
||||
|
||||
/// \cite RDM Table 6-4 shows the format of the Message Data Block portion
|
||||
/// of the data packet from Table 6-2.
|
||||
struct DataBlock {
|
||||
uint8_t cc; //!< \cite RDM 6.2.10.1 Command Class (CC)
|
||||
PID pid; //!< \cite RDM 6.2.10.2 Parameter ID (PID)
|
||||
uint8_t pdl() const {return pd.size();} //!< \cite RDM 6.2.10.3 Parameter Data Length (PDL) @return
|
||||
std::vector<uint8_t> pd; //!< \cite RDM 6.2.10.4 Parameter Data (PD)
|
||||
} mdb; //!< \cite RDM 6.2.10 Message Data Block (MDB)
|
||||
|
||||
uint16_t checksum() const; //!< \cite RDM 6.2.11 Checksum
|
||||
|
||||
union {
|
||||
uint8_t failure_mode;
|
||||
|
@ -73,55 +79,59 @@ struct Message
|
|||
};
|
||||
};
|
||||
|
||||
const std::vector<uint8_t>* data() const;
|
||||
uint8_t length() const;
|
||||
uint16_t checksum() const;
|
||||
bool requiredLength(const size_t length, MsgPtr response) const;
|
||||
void read(const std::vector<uint8_t> &buffer);
|
||||
void write(std::vector<uint8_t> &buffer) const;
|
||||
void nak(uint16_t reason);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
void writeDiscBranch(std::vector<uint8_t> &data) const;
|
||||
void writeDiscBranch(std::vector<uint8_t> &buffer) const;
|
||||
|
||||
public: // templates
|
||||
/**
|
||||
* @brief appendData
|
||||
* @param val
|
||||
*/
|
||||
template<typename T>
|
||||
void appendData(const T & val)
|
||||
{
|
||||
Message::writeType<T>(data_, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief readType
|
||||
* @param vect
|
||||
* @param start
|
||||
* @brief Big-Endian Read from std::vector
|
||||
* @param buffer
|
||||
* @param index
|
||||
* @return
|
||||
*
|
||||
* > \cite RDM 6.1 Byte Ordering
|
||||
* > All multi-byte data shall be transmitted in Big-Endian order.
|
||||
*/
|
||||
template<typename T>
|
||||
static T readType(const std::vector<uint8_t>& vect, size_t start)
|
||||
static T readType(const std::vector<uint8_t> &buffer, const size_t index)
|
||||
{
|
||||
if (vect.size() < sizeof(T))
|
||||
if (buffer.size() < sizeof(T))
|
||||
return 0;
|
||||
T ret = 0;
|
||||
auto data = reinterpret_cast<uint8_t*>(&ret);
|
||||
for (int i = sizeof(T); --i >= 0; )
|
||||
data[i] = vect[start + i];
|
||||
return ret;
|
||||
T val = 0;
|
||||
auto data = reinterpret_cast<uint8_t*>(&val);
|
||||
for (int i = 0; i < sizeof(T); i++)
|
||||
data[sizeof(T)-1-i] = buffer[index + i];
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief writeType
|
||||
* @param data
|
||||
* @brief Big-Endian Write to std::vector
|
||||
* @param buffer
|
||||
* @param val
|
||||
*
|
||||
* > \cite RDM 6.1 Byte Ordering
|
||||
* > All multi-byte data shall be transmitted in Big-Endian order.
|
||||
*/
|
||||
template<typename T>
|
||||
static void writeType(std::vector<uint8_t> &buffer, const T &val)
|
||||
{
|
||||
auto data = reinterpret_cast<const uint8_t*>(&val);
|
||||
for (int i = 0; i < sizeof(T); i++)
|
||||
buffer.push_back(data[sizeof(T)-1-i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Endian-correct appending of Parameter Data
|
||||
* @param val
|
||||
*/
|
||||
template<typename T>
|
||||
static void writeType(std::vector<uint8_t> &data, const T val)
|
||||
void appendParameterData(const T &val)
|
||||
{
|
||||
auto raw = reinterpret_cast<const uint8_t*>(&val);
|
||||
for (int i = sizeof(T); --i >= 0; )
|
||||
data.push_back(raw[i]);
|
||||
Message::writeType<T>(mdb.pd, val);
|
||||
}
|
||||
|
||||
private: // templates
|
||||
|
@ -133,22 +143,21 @@ private: // templates
|
|||
template<typename T>
|
||||
static void addSum_(uint16_t &sum, const T &val)
|
||||
{
|
||||
uint8_t byte;
|
||||
uint16_t carry;
|
||||
auto raw = reinterpret_cast<const uint8_t*>(val);
|
||||
auto data = reinterpret_cast<const uint8_t*>(&val);
|
||||
for (int i = sizeof(T); --i >= 0; )
|
||||
{
|
||||
auto num = raw[i];
|
||||
while (num != 0)
|
||||
byte = data[i];
|
||||
while (byte != 0)
|
||||
{
|
||||
carry = sum & num;
|
||||
sum = sum ^ num;
|
||||
num = carry << 1;
|
||||
carry = sum & byte;
|
||||
sum = sum ^ byte;
|
||||
byte = carry << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // struct Message
|
||||
|
||||
|
||||
} // namespace RDM
|
||||
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Property::Property
|
||||
* @brief Parameter::Parameter
|
||||
* @param id
|
||||
*/
|
||||
Parameter::Parameter()
|
||||
Parameter::Parameter(const PID id)
|
||||
: id(id)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
#include "rdm.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -42,9 +43,11 @@ using PidAction = std::function<void(const MsgPtr message, MsgPtr response)>;
|
|||
class Parameter
|
||||
{
|
||||
public:
|
||||
explicit Parameter();
|
||||
explicit Parameter(const PID id);
|
||||
virtual ~Parameter();
|
||||
|
||||
const PID id; //!< Parameter ID
|
||||
|
||||
void disc(const MsgPtr message, MsgPtr response) const;
|
||||
void get(const MsgPtr message, MsgPtr response) const;
|
||||
void set(const MsgPtr message, MsgPtr response) const;
|
||||
|
|
|
@ -41,72 +41,55 @@ Responder::Responder(UID id, Device* parent)
|
|||
deviceModelDescription = "Basic RDM Responder";
|
||||
subdevice_flag = true;
|
||||
|
||||
Parameter *pid;
|
||||
|
||||
/// \cite RDM 7.5 Discovery Unique Branch Message (DISC_UNIQUE_BRANCH)
|
||||
parameters_.try_emplace(DISC_UNIQUE_BRANCH, new Parameter());
|
||||
parameters_.at(DISC_UNIQUE_BRANCH)->discAction(std::bind(
|
||||
&Responder::actionDiscoverUniqueBranch,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DISC_UNIQUE_BRANCH);
|
||||
pid->discAction(std::bind(&Responder::actionDiscoverUniqueBranch, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 7.6.3 Discovery Mute Message (DISC_MUTE)
|
||||
/// A responder port shall set its Mute flag when it receives this message
|
||||
/// containing its UID, or a broadcast address.
|
||||
parameters_.try_emplace(DISC_MUTE, new Parameter());
|
||||
parameters_.at(DISC_MUTE)->discAction(std::bind(
|
||||
&Responder::actionDiscoveryMute,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DISC_MUTE);
|
||||
pid->discAction(std::bind(&Responder::actionDiscoveryMute, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 7.6.4 Discovery Un-Mute Message (DISC_UN_MUTE)
|
||||
/// A responder port shall clear its Mute flag when it receives this message
|
||||
/// containing its UID, or a broadcast address.
|
||||
parameters_.try_emplace(DISC_UN_MUTE, new Parameter());
|
||||
parameters_.at(DISC_UN_MUTE)->discAction(std::bind(
|
||||
&Responder::actionDiscoveryUnmute,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(DISC_UN_MUTE);
|
||||
pid->discAction(std::bind(&Responder::actionDiscoveryUnmute, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.2.1 Communication Status (COMMS_STATUS)
|
||||
/// The COMMS_STATUS parameter is used to collect information that may be
|
||||
/// useful in analyzing the integrity of the communication system.
|
||||
parameters_.try_emplace(COMMS_STATUS, new Parameter());
|
||||
parameters_.at(COMMS_STATUS)->getAction(std::bind(
|
||||
&Responder::actionGetCommsStatus,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
parameters_.at(COMMS_STATUS)->setAction(std::bind(
|
||||
&Responder::actionSetCommsStatus,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(COMMS_STATUS);
|
||||
pid->getAction(std::bind(&Responder::actionGetCommsStatus, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
pid->setAction(std::bind(&Responder::actionSetCommsStatus, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.3.1 Get Queued Message (QUEUED_MESSAGE)
|
||||
/// The QUEUED_MESSAGE parameter shall be used to retrieve a message from the
|
||||
/// responder’s message queue. The Message Count field of all response
|
||||
/// messages defines the number of messages that are queued in the responder.
|
||||
/// Each QUEUED_MESSAGE response shall be composed of a single message response.
|
||||
parameters_.try_emplace(QUEUED_MESSAGE, new Parameter());
|
||||
parameters_.at(QUEUED_MESSAGE)->getAction(std::bind(
|
||||
&Responder::actionGetQueuedMessage,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(QUEUED_MESSAGE);
|
||||
pid->getAction(std::bind(&Responder::actionGetQueuedMessage, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.3.2 Get Status Messages (STATUS_MESSAGES)
|
||||
/// This parameter is used to collect Status or Error information
|
||||
/// from a device.
|
||||
parameters_.try_emplace(STATUS_MESSAGES, new Parameter());
|
||||
parameters_.at(STATUS_MESSAGES)->getAction(std::bind(
|
||||
&Responder::actionGetStatusMessages,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(STATUS_MESSAGES);
|
||||
pid->getAction(std::bind(&Responder::actionGetStatusMessages, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
/// \cite RDM 10.3.3 Get Status ID Description (STATUS_ID_DESCRIPTION)
|
||||
/// This parameter is used to request an ASCII text description of a given
|
||||
/// Status ID. The description may be up to 32 characters.
|
||||
parameters_.try_emplace(STATUS_ID_DESCRIPTION, new Parameter());
|
||||
parameters_.at(STATUS_ID_DESCRIPTION)->getAction(std::bind(
|
||||
&Responder::actionGetStatusIdDescription,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
pid = addParameter(STATUS_ID_DESCRIPTION);
|
||||
pid->getAction(std::bind(&Responder::actionGetStatusIdDescription, this,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::~Responder
|
||||
*/
|
||||
Responder::~Responder()
|
||||
{
|
||||
}
|
||||
|
@ -127,13 +110,21 @@ void Responder::send(const std::vector<uint8_t> &data)
|
|||
* @brief Responder::send
|
||||
* @param response
|
||||
*/
|
||||
void Responder::send(MsgPtr response)
|
||||
void Responder::send(const MsgPtr response)
|
||||
{
|
||||
if (!response)
|
||||
return;
|
||||
|
||||
if (response->do_not_send)
|
||||
return;
|
||||
return;
|
||||
|
||||
/// \cite RDM 6.3.4 Negative Acknowledge (RESPONSE_TYPE_NACK_REASON)
|
||||
/// The response RESPONSE_TYPE_NACK_REASON shall only be used in conjunction with the
|
||||
/// Command Classes GET_COMMAND_RESPONSE & SET_COMMAND_RESPONSE.
|
||||
if (response->responseType == RESPONSE_TYPE_NACK_REASON
|
||||
&& !(response->mdb.cc == GET_COMMAND_RESPONSE
|
||||
|| response->mdb.cc == SET_COMMAND_RESPONSE))
|
||||
return;
|
||||
|
||||
/// \cite RDM 6.2.8.2 Message Count field for Responder Generated Messages
|
||||
/// If a responder has more than 255 messages queued, then the Message Count
|
||||
|
@ -141,6 +132,7 @@ void Responder::send(MsgPtr response)
|
|||
/// below that number.
|
||||
response->messageCount = std::min(queued_messages_.size(),
|
||||
(size_t)std::numeric_limits<uint8_t>::max());
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
response->write(data);
|
||||
send(data);
|
||||
|
@ -169,8 +161,9 @@ std::shared_ptr<void> Responder::setSender(std::function<void(const std::vector<
|
|||
*/
|
||||
void Responder::receive(const std::vector<uint8_t> &data)
|
||||
{
|
||||
auto message = MsgPtr(new Message(data));
|
||||
receive(message);
|
||||
auto msg = std::make_shared<Message>();
|
||||
msg->read(data);
|
||||
receive(msg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,79 +175,82 @@ void Responder::receive(const MsgPtr message)
|
|||
{
|
||||
if (message->short_message)
|
||||
{
|
||||
if (short_message_counter_ != std::numeric_limits<uint16_t>::max())
|
||||
short_message_counter_++;
|
||||
return;
|
||||
short_message_counter_ = short_message_counter_ == std::numeric_limits<uint16_t>::max()
|
||||
? short_message_counter_
|
||||
: short_message_counter_++;
|
||||
return; // ignore unreadable messages
|
||||
}
|
||||
|
||||
// RDM::UID::operator== also returns true for broadcast messages
|
||||
if (message->destination != id_ ||
|
||||
message->incorrect_sc ||
|
||||
message->incorrect_sub_sc)
|
||||
return;
|
||||
if (message->destination != id_ // not for me
|
||||
|| message->incorrect_sc // not RDM
|
||||
|| message->incorrect_sub_sc // not a supported RDM format
|
||||
)
|
||||
return; // ignore message
|
||||
|
||||
if (message->length_mismatch)
|
||||
{
|
||||
if (length_mismatch_counter_ != std::numeric_limits<uint16_t>::max())
|
||||
length_mismatch_counter_++;
|
||||
return;
|
||||
}
|
||||
length_mismatch_counter_ = length_mismatch_counter_ == std::numeric_limits<uint16_t>::max()
|
||||
? length_mismatch_counter_
|
||||
: length_mismatch_counter_++;
|
||||
|
||||
if (message->checksum_fail)
|
||||
{
|
||||
if (checksum_fail_counter_ != std::numeric_limits<uint16_t>::max())
|
||||
checksum_fail_counter_++;
|
||||
return;
|
||||
}
|
||||
checksum_fail_counter_ = checksum_fail_counter_ == std::numeric_limits<uint16_t>::max()
|
||||
? checksum_fail_counter_
|
||||
: checksum_fail_counter_++;
|
||||
|
||||
// all other uncaught errors
|
||||
if (message->failure_mode != 0)
|
||||
if (message->do_not_send) // read error that prevents NAK
|
||||
return;
|
||||
|
||||
// responder can ignore _COMMAND_RESPONSE class messages
|
||||
if (message->commandClass == DISCOVERY_COMMAND_RESPONSE ||
|
||||
message->commandClass == GET_COMMAND_RESPONSE ||
|
||||
message->commandClass == SET_COMMAND_RESPONSE)
|
||||
return;
|
||||
uint8_t response_cc;
|
||||
switch (message->mdb.cc) {
|
||||
case DISCOVERY_COMMAND:
|
||||
response_cc = DISCOVERY_COMMAND_RESPONSE;
|
||||
break;
|
||||
case GET_COMMAND:
|
||||
response_cc = GET_COMMAND_RESPONSE;
|
||||
break;
|
||||
case SET_COMMAND:
|
||||
response_cc = SET_COMMAND_RESPONSE;
|
||||
break;
|
||||
default:
|
||||
return; // responder can ignore _RESPONSE class messages
|
||||
}
|
||||
|
||||
auto response = MsgPtr(new Message());
|
||||
response->source = id_;
|
||||
response->destination = message->source;
|
||||
response->subDevice = message->subDevice;
|
||||
response->parameterId = message->parameterId;
|
||||
response->transaction = message->transaction;
|
||||
auto response = std::make_shared<Message>();
|
||||
response->source = id_; // response is from this device
|
||||
response->destination = message->source; // send response to sender of message
|
||||
response->subDevice = message->subDevice; // copy sub-device
|
||||
response->mdb.pid = message->mdb.pid; // copy PID
|
||||
response->tn = message->tn; // this reply is a response to the received message
|
||||
response->mdb.cc = response_cc; // appropriate command class
|
||||
|
||||
/// \cite RDM 5.3 Broadcast Message Addressing
|
||||
/// When Broadcast Addressing is used for non-Discovery messages, the
|
||||
/// responders shall not send a response.
|
||||
if (message->destination.isBroadcast() &&
|
||||
message->commandClass != DISCOVERY_COMMAND)
|
||||
response->mdb.cc != DISCOVERY_COMMAND_RESPONSE)
|
||||
response->do_not_send = true;
|
||||
|
||||
switch (message->commandClass) {
|
||||
if (message->failure_mode)
|
||||
response->nak(NR_FORMAT_ERROR); // nak on any failure modes
|
||||
else
|
||||
{
|
||||
switch (message->mdb.cc) { // dispatch valid messages
|
||||
case DISCOVERY_COMMAND:
|
||||
response->commandClass = DISCOVERY_COMMAND_RESPONSE;
|
||||
rxDiscovery(message, response);
|
||||
break;
|
||||
case GET_COMMAND:
|
||||
response->commandClass = GET_COMMAND_RESPONSE;
|
||||
rxGet(message, response);
|
||||
break;
|
||||
case SET_COMMAND:
|
||||
response->commandClass = SET_COMMAND_RESPONSE;
|
||||
rxSet(message, response);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
response->nak(NR_UNSUPPORTED_COMMAND_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!response)
|
||||
return;
|
||||
|
||||
if (response->do_not_send)
|
||||
return;
|
||||
|
||||
send(response);
|
||||
send(response); // send the reply
|
||||
}
|
||||
|
||||
|
||||
|
@ -288,7 +284,7 @@ void Responder::rxDiscovery(const MsgPtr message, MsgPtr response)
|
|||
if (!actionPrep_(message, response))
|
||||
return;
|
||||
|
||||
parameters_.at(message->parameterId)->disc(message, response);
|
||||
parameters_.at(message->mdb.pid)->disc(message, response);
|
||||
}
|
||||
|
||||
|
||||
|
@ -369,8 +365,8 @@ void Responder::rxSet(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionDiscoverUniqueBranch(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(12, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 12)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
if (discovery_mute_flag_)
|
||||
{
|
||||
|
@ -379,10 +375,10 @@ void Responder::actionDiscoverUniqueBranch(const MsgPtr message, MsgPtr response
|
|||
}
|
||||
|
||||
UID lower, upper;
|
||||
lower.manufacturer = Message::readType<uint16_t>(*message->data(), 0);
|
||||
lower.device = Message::readType<uint32_t>(*message->data(), 2);
|
||||
upper.manufacturer = Message::readType<uint16_t>(*message->data(), 6);
|
||||
upper.device = Message::readType<uint32_t>(*message->data(), 8);
|
||||
lower.manufacturer = Message::readType<uint16_t>(message->mdb.pd, 0);
|
||||
lower.device = Message::readType<uint32_t>(message->mdb.pd, 2);
|
||||
upper.manufacturer = Message::readType<uint16_t>(message->mdb.pd, 6);
|
||||
upper.device = Message::readType<uint32_t>(message->mdb.pd, 8);
|
||||
|
||||
if (id_.uid() < lower.uid())
|
||||
{
|
||||
|
@ -395,8 +391,8 @@ void Responder::actionDiscoverUniqueBranch(const MsgPtr message, MsgPtr response
|
|||
return;
|
||||
}
|
||||
|
||||
response->appendData(id_.manufacturer);
|
||||
response->appendData(id_.device);
|
||||
response->appendParameterData(id_.manufacturer);
|
||||
response->appendParameterData(id_.device);
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,14 +403,14 @@ void Responder::actionDiscoverUniqueBranch(const MsgPtr message, MsgPtr response
|
|||
*/
|
||||
void Responder::actionDiscoveryMute(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
discovery_mute_flag_ = true;
|
||||
controller_uid_ = message->source;
|
||||
response->appendParameterData(control_field);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(control_field);
|
||||
}
|
||||
|
||||
|
||||
|
@ -425,13 +421,13 @@ void Responder::actionDiscoveryMute(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionDiscoveryUnmute(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
discovery_mute_flag_ = false;
|
||||
response->appendParameterData(control_field);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(control_field);
|
||||
}
|
||||
|
||||
|
||||
|
@ -442,13 +438,14 @@ void Responder::actionDiscoveryUnmute(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionGetCommsStatus(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
response->appendParameterData(short_message_counter_);
|
||||
response->appendParameterData(length_mismatch_counter_);
|
||||
response->appendParameterData(checksum_fail_counter_);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(short_message_counter_);
|
||||
response->appendData(length_mismatch_counter_);
|
||||
response->appendData(checksum_fail_counter_);
|
||||
}
|
||||
|
||||
|
||||
|
@ -459,8 +456,8 @@ void Responder::actionGetCommsStatus(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionSetCommsStatus(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(0, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 0)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
short_message_counter_ = 0;
|
||||
length_mismatch_counter_ = 0;
|
||||
|
@ -477,12 +474,12 @@ void Responder::actionSetCommsStatus(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionGetQueuedMessage(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
if (queued_messages_.empty())
|
||||
{
|
||||
response->parameterId = STATUS_MESSAGES;
|
||||
response->mdb.pid = STATUS_MESSAGES;
|
||||
actionGetStatusMessages(message, response);
|
||||
return;
|
||||
}
|
||||
|
@ -502,10 +499,10 @@ void Responder::actionGetQueuedMessage(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionGetStatusMessages(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(1, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 1)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint8_t type = message->data()->front();
|
||||
uint8_t type = message->mdb.pd.front();
|
||||
|
||||
if (type != STATUS_GET_LAST_MESSAGE &&
|
||||
type != STATUS_ERROR &&
|
||||
|
@ -529,7 +526,7 @@ void Responder::actionGetStatusMessages(const MsgPtr message, MsgPtr response)
|
|||
while(!q.empty() && counter < 25)
|
||||
{
|
||||
for (uint8_t& b : q.front()->bytes)
|
||||
response->appendData(b);
|
||||
response->appendParameterData(b);
|
||||
counter++;
|
||||
q.pop();
|
||||
}
|
||||
|
@ -575,19 +572,20 @@ void Responder::actionGetStatusMessages(const MsgPtr message, MsgPtr response)
|
|||
*/
|
||||
void Responder::actionGetStatusIdDescription(const MsgPtr message, MsgPtr response)
|
||||
{
|
||||
if (!message->requiredLength(2, response))
|
||||
return;
|
||||
if (message->mdb.pdl() != 2)
|
||||
return response->nak(NR_FORMAT_ERROR);
|
||||
|
||||
uint16_t status = message->readType<uint16_t>(*message->data(), 0);
|
||||
uint16_t status = message->readType<uint16_t>(message->mdb.pd, 0);
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
std::string label = RDM::StatusMessageDescription(status);
|
||||
for (size_t i = 0; i < label.size(); i++)
|
||||
{
|
||||
if (i > 32)
|
||||
break;
|
||||
response->appendData(label.at(i));
|
||||
response->appendParameterData(label.at(i));
|
||||
}
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
}
|
||||
|
||||
} // namespace RDM
|
||||
|
|
|
@ -52,14 +52,13 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
void receive(const std::vector<uint8_t>& data);
|
||||
virtual void send(const std::vector<uint8_t> &data);
|
||||
virtual void send(const MsgPtr message);
|
||||
virtual void receive(const std::vector<uint8_t> &data);
|
||||
virtual void receive(const MsgPtr message);
|
||||
virtual void reset(bool hard) override;
|
||||
|
||||
protected:
|
||||
virtual void send(const std::vector<uint8_t>& data);
|
||||
virtual void send(MsgPtr message);
|
||||
virtual void receive(const MsgPtr message);
|
||||
|
||||
virtual void rxDiscovery(const MsgPtr message, MsgPtr response);
|
||||
virtual void rxGet(const MsgPtr message, MsgPtr response);
|
||||
virtual void rxSet(const MsgPtr message, MsgPtr response);
|
||||
|
|
|
@ -139,20 +139,20 @@ void Sensor::clearMemory()
|
|||
void Sensor::actionGetSensorDefinition(uint8_t index, MsgPtr response)
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(index);
|
||||
response->appendData(type);
|
||||
response->appendData(unit);
|
||||
response->appendData(unitPrefix);
|
||||
response->appendData(minLimit);
|
||||
response->appendData(maxLimit);
|
||||
response->appendData(minNominal);
|
||||
response->appendData(maxNominal);
|
||||
response->appendData(recordedValueSupport);
|
||||
response->appendParameterData(index);
|
||||
response->appendParameterData(type);
|
||||
response->appendParameterData(unit);
|
||||
response->appendParameterData(unitPrefix);
|
||||
response->appendParameterData(minLimit);
|
||||
response->appendParameterData(maxLimit);
|
||||
response->appendParameterData(minNominal);
|
||||
response->appendParameterData(maxNominal);
|
||||
response->appendParameterData(recordedValueSupport);
|
||||
for (size_t i = 0; i < description.size(); i++)
|
||||
{
|
||||
if (i > 32)
|
||||
break;
|
||||
response->appendData(description.at(i));
|
||||
response->appendParameterData(description.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,11 +165,11 @@ void Sensor::actionGetSensorDefinition(uint8_t index, MsgPtr response)
|
|||
void Sensor::actionGetSensorValue(uint8_t index, MsgPtr response)
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(index);
|
||||
response->appendData(value());
|
||||
response->appendData(minimum());
|
||||
response->appendData(maximum());
|
||||
response->appendData(saved());
|
||||
response->appendParameterData(index);
|
||||
response->appendParameterData(value());
|
||||
response->appendParameterData(minimum());
|
||||
response->appendParameterData(maximum());
|
||||
response->appendParameterData(saved());
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +182,7 @@ void Sensor::actionSetSensorValue(uint8_t index, MsgPtr response)
|
|||
{
|
||||
clearMemory();
|
||||
|
||||
if (response->length() != 0)
|
||||
if (response->mdb.pdl() != 0)
|
||||
return;
|
||||
|
||||
int16_t val=0, min=0, max=0, mem=0;
|
||||
|
@ -195,11 +195,11 @@ void Sensor::actionSetSensorValue(uint8_t index, MsgPtr response)
|
|||
}
|
||||
|
||||
response->responseType = RESPONSE_TYPE_ACK;
|
||||
response->appendData(index);
|
||||
response->appendData(val);
|
||||
response->appendData(min);
|
||||
response->appendData(max);
|
||||
response->appendData(mem);
|
||||
response->appendParameterData(index);
|
||||
response->appendParameterData(val);
|
||||
response->appendParameterData(min);
|
||||
response->appendParameterData(max);
|
||||
response->appendParameterData(mem);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,17 +36,17 @@ struct UID {
|
|||
* @brief UID
|
||||
* @param dev
|
||||
* @param man
|
||||
* @param flag
|
||||
* @param dynamic
|
||||
*/
|
||||
UID(uint32_t dev = 0, uint16_t man = 0, bool flag = false)
|
||||
UID(uint32_t dev = 0, uint16_t man = 0, bool dynamic = false)
|
||||
: device(dev)
|
||||
, manufacturer(man)
|
||||
, flag(flag)
|
||||
{ if (man >> 15) this->flag = true; };
|
||||
, dynamic(dynamic)
|
||||
{ if (man >> 15) this->dynamic = true; };
|
||||
|
||||
uint32_t device; //!< manufacturer assigned device ID
|
||||
uint16_t manufacturer; //!< ESTA assigned manufacturer ID
|
||||
bool flag; //!< dynamic flag
|
||||
bool dynamic; //!< dynamic flag
|
||||
|
||||
/**
|
||||
* @brief uid
|
||||
|
@ -54,7 +54,7 @@ struct UID {
|
|||
*/
|
||||
uint64_t uid() const {
|
||||
uint64_t uid = device | (manufacturer < 32);
|
||||
if (flag)
|
||||
if (dynamic)
|
||||
uid |= (0b1 < 47);
|
||||
else
|
||||
uid |= (0b0 < 47);
|
||||
|
|
|
@ -133,7 +133,7 @@ struct command_data
|
|||
{
|
||||
RDM::Message message; //!< RDM message
|
||||
|
||||
size_t streamSize() const override { return 23 + message.length(); }
|
||||
size_t streamSize() const override { return 23 + message.mdb.pdl(); }
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
void oStream(ACN::PDU::Stream) const override;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue