2021-08-08 17:25:41 -04:00
|
|
|
|
/*
|
|
|
|
|
device.cpp
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-08-09 15:04:49 -04:00
|
|
|
|
#include "config.h"
|
2021-08-08 17:25:41 -04:00
|
|
|
|
#include "device.h"
|
|
|
|
|
|
|
|
|
|
namespace RDM {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::Device
|
|
|
|
|
*/
|
2021-08-09 15:04:49 -04:00
|
|
|
|
Device::Device(Device* parent)
|
|
|
|
|
: DMX::Device()
|
|
|
|
|
, deviceModelID(0)
|
|
|
|
|
, deviceModelDescription("Basic RDM Device")
|
|
|
|
|
, deviceProductCategory(PRODUCT_CATEGORY_NOT_DECLARED)
|
|
|
|
|
, parent_(parent)
|
2021-08-08 17:25:41 -04:00
|
|
|
|
{
|
2021-08-09 15:04:49 -04:00
|
|
|
|
id.manufacturer = MY_ESTA_MANUFACTURER_ID;
|
|
|
|
|
|
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
2021-08-09 17:50:36 -04:00
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
2021-08-09 15:04:49 -04:00
|
|
|
|
/// 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));
|
2021-08-09 17:50:36 -04:00
|
|
|
|
///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));
|
|
|
|
|
/// 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));
|
|
|
|
|
/// 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));
|
2021-08-10 00:56:43 -04:00
|
|
|
|
/// 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::actionGetSensorDefinition,
|
|
|
|
|
this, std::placeholders::_1,
|
|
|
|
|
std::placeholders::_2));
|
|
|
|
|
/// 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::actionGetSensorValue,
|
|
|
|
|
this, std::placeholders::_1,
|
|
|
|
|
std::placeholders::_2));
|
|
|
|
|
parameters_.at(SENSOR_VALUE)->setAction(std::bind(
|
|
|
|
|
&Device::actionSetSensorValue,
|
|
|
|
|
this, std::placeholders::_1,
|
|
|
|
|
std::placeholders::_2));
|
|
|
|
|
/// 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::actionSetRecordSensors,
|
|
|
|
|
this, std::placeholders::_1,
|
|
|
|
|
std::placeholders::_2));
|
2021-08-09 15:04:49 -04:00
|
|
|
|
/// 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));
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::~Device
|
|
|
|
|
*/
|
|
|
|
|
Device::~Device()
|
|
|
|
|
{
|
2021-08-09 15:04:49 -04:00
|
|
|
|
for( auto& [_, device] : sub_devices_)
|
|
|
|
|
delete device;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
for (auto& [_, parameter] : parameters_)
|
|
|
|
|
delete parameter;
|
2021-08-09 15:04:49 -04:00
|
|
|
|
for (auto sensor : sensors_)
|
|
|
|
|
delete sensor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::addSubDevice
|
|
|
|
|
* @param number
|
|
|
|
|
* @param dev
|
|
|
|
|
*
|
|
|
|
|
* Root devices (ie. Respoders) shall override with a meaningful implimentation
|
|
|
|
|
*/
|
|
|
|
|
void Device::addSubDevice(uint16_t number, Device *dev)
|
|
|
|
|
{
|
|
|
|
|
if (parent_)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (sub_devices_.count(number))
|
|
|
|
|
delete sub_devices_.at(number);
|
|
|
|
|
sub_devices_[number] = dev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::subDevice
|
|
|
|
|
* @param number
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
Device* Device::subDevice(uint16_t number)
|
|
|
|
|
{
|
|
|
|
|
if (parent_)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
if (sub_devices_.count(number))
|
|
|
|
|
return sub_devices_.at(number);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::subDeviceCount
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
uint16_t Device::subDeviceCount() const
|
|
|
|
|
{
|
|
|
|
|
if (parent_)
|
|
|
|
|
return parent_->subDeviceCount();
|
|
|
|
|
return sub_devices_.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::addProductDetailId
|
|
|
|
|
* @param id
|
|
|
|
|
*/
|
|
|
|
|
void Device::addProductDetailId(uint16_t id)
|
|
|
|
|
{
|
|
|
|
|
product_detail_list_.push_back(id);
|
|
|
|
|
while (product_detail_list_.size() > 6)
|
|
|
|
|
product_detail_list_.pop_front();
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::get
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::get(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->commandClass = GET_COMMAND_RESPONSE;
|
2021-08-09 15:04:49 -04:00
|
|
|
|
if (!actionPrep_(message, response))
|
|
|
|
|
return;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
parameters_.at(message->propertyID)->get(message, response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::set
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::set(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->commandClass = SET_COMMAND_RESPONSE;
|
2021-08-09 15:04:49 -04:00
|
|
|
|
if (!actionPrep_(message, response))
|
|
|
|
|
return;
|
|
|
|
|
parameters_.at(message->propertyID)->set(message, response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionPrep
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
bool Device::actionPrep_(const Message *message, Message *response)
|
|
|
|
|
{
|
2021-08-08 17:25:41 -04:00
|
|
|
|
if (!parameters_.count(message->propertyID))
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_UNKNOWN_PID);
|
2021-08-09 15:04:49 -04:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (message->propertyID == last_rx_pid_)
|
|
|
|
|
++ack_overflow_page;
|
|
|
|
|
else {
|
|
|
|
|
ack_overflow_page = 0;
|
|
|
|
|
last_rx_pid_ = message->propertyID;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetSupportedParameters
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetSupportedParameters(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
uint count = parameters_.size();
|
|
|
|
|
uint length = count * sizeof(PID);
|
|
|
|
|
uint lastPage = length / 0xfe;
|
|
|
|
|
uint first = ack_overflow_page * ( 0xfe / sizeof(PID) );
|
|
|
|
|
if (first >= count) {
|
|
|
|
|
ack_overflow_page = 0;
|
|
|
|
|
first = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>(pid->first);
|
|
|
|
|
pid++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetDeviceInfo
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetDeviceInfo(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint16_t>(RDM_PROTOCOL_VERSION);
|
|
|
|
|
response->appendData<uint16_t>(deviceModelID);
|
|
|
|
|
response->appendData<uint16_t>(deviceProductCategory);
|
|
|
|
|
response->appendData<uint32_t>(LIB_VERSION);
|
|
|
|
|
response->appendData<uint16_t>(DMX::Device::footprint());
|
|
|
|
|
response->appendData<uint8_t> (DMX::Device::personality());
|
|
|
|
|
response->appendData<uint8_t> (DMX::Device::personalityCount());
|
|
|
|
|
response->appendData<uint16_t>(DMX::Device::address());
|
|
|
|
|
response->appendData<uint16_t>(subDeviceCount());
|
|
|
|
|
response->appendData<uint8_t> (sensors_.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetProductDetailIdList
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetProductDetailIdList(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
if (product_detail_list_.empty())
|
|
|
|
|
{
|
|
|
|
|
response->appendData<uint16_t>(PRODUCT_DETAIL_NOT_DECLARED);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
2021-08-09 15:04:49 -04:00
|
|
|
|
for ( uint16_t id : product_detail_list_ )
|
|
|
|
|
response->appendData<uint16_t>(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetDevModelDescription
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetDevModelDescription(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
for (size_t i = 0; i < deviceModelDescription.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 32)
|
|
|
|
|
break;
|
|
|
|
|
response->appendData<char>(deviceModelDescription.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetManufacturerLabel
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetManufacturerLabel(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
std::string label = std::string(MY_ESTA_MANUFACTURER_LABEL);
|
|
|
|
|
for (size_t i = 0; i < label.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 32)
|
|
|
|
|
break;
|
|
|
|
|
response->appendData<char>(label.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-09 17:50:36 -04:00
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetLanguage
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetLanguage(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
std::string label = std::string("en");
|
|
|
|
|
for (char& c : label)
|
|
|
|
|
response->appendData<char>(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetLanguage
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetLanguage(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 2)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::string s;
|
|
|
|
|
for ( char c : *message->data())
|
|
|
|
|
s += c;
|
|
|
|
|
|
|
|
|
|
if (s != "en")
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-09 15:04:49 -04:00
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetSoftwareVersionLabel
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetSoftwareVersionLabel(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
std::string label = std::string(LIB_VERSION_LABEL);
|
|
|
|
|
for (size_t i = 0; i < label.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 32)
|
|
|
|
|
break;
|
|
|
|
|
response->appendData<char>(label.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-09 17:50:36 -04:00
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetDmxPersonality
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetDmxPersonality(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(DMX::Device::personality());
|
|
|
|
|
response->appendData<uint8_t>(DMX::Device::personalityCount());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetDmxPersonality
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetDmxPersonality(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t mode = message->data()->front();
|
|
|
|
|
if ( mode == 0 || mode > DMX::Device::personalityCount())
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
setPersonality(mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetDmxPersonalityDesc
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetDmxPersonalityDesc(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t mode = message->data()->front();
|
|
|
|
|
if ( mode == 0 || mode > DMX::Device::personalityCount())
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(mode);
|
|
|
|
|
response->appendData<uint16_t>(personalities_.at(mode)->footprint());
|
|
|
|
|
for (size_t i = 0; i < personalities_.at(mode)->description.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 32)
|
|
|
|
|
break;
|
|
|
|
|
response->appendData<char>(personalities_.at(mode)->description.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetDmxStartAddress
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetDmxStartAddress(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
if (footprint() == 0)
|
|
|
|
|
response->appendData<uint16_t>(0xFFFF);
|
|
|
|
|
else
|
|
|
|
|
response->appendData<uint16_t>(address());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetDmxStartAddress
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetDmxStartAddress(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 2)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint16_t addr = Message::readType<uint16_t>(*message->data(), 0);
|
|
|
|
|
if (!setAddress(addr))
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-10 00:56:43 -04:00
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetSensorDefinition
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetSensorDefinition(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t index = message->data()->front();
|
|
|
|
|
if (index == 0xFF || index >= sensors_.size())
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto sensor = sensors_.at(index);
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(index);
|
|
|
|
|
response->appendData<uint8_t>(sensor->type);
|
|
|
|
|
response->appendData<uint8_t>(sensor->unit);
|
|
|
|
|
response->appendData<uint8_t>(sensor->unitPrefix);
|
|
|
|
|
response->appendData<int16_t>(sensor->minLimit);
|
|
|
|
|
response->appendData<int16_t>(sensor->maxLimit);
|
|
|
|
|
response->appendData<int16_t>(sensor->minNominal);
|
|
|
|
|
response->appendData<int16_t>(sensor->maxNominal);
|
|
|
|
|
response->appendData<uint8_t>(sensor->recordedValueSupport);
|
|
|
|
|
for (size_t i = 0; i < sensor->description.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > 32)
|
|
|
|
|
break;
|
|
|
|
|
response->appendData<char>(sensor->description.at(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetSensorValue
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetSensorValue(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t index = message->data()->front();
|
|
|
|
|
if (index == 0xFF || index >= sensors_.size())
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto sensor = sensors_.at(index);
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(index);
|
|
|
|
|
response->appendData<int16_t>(sensor->value());
|
|
|
|
|
response->appendData<int16_t>(sensor->minimum());
|
|
|
|
|
response->appendData<int16_t>(sensor->maximum());
|
|
|
|
|
response->appendData<int16_t>(sensor->saved());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetSensorValue
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetSensorValue(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t index = message->data()->front();
|
|
|
|
|
if (index >= sensors_.size() && index != 0xFF)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int16_t val = 0, min = 0, max = 0, mem = 0;
|
|
|
|
|
if (index == 0xFF)
|
|
|
|
|
for ( Sensor * s : sensors_ )
|
|
|
|
|
s->clearMemory();
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto sensor = sensors_.at(index);
|
|
|
|
|
sensor->clearMemory();
|
|
|
|
|
val = sensor->value();
|
|
|
|
|
min = sensor->minimum();
|
|
|
|
|
max = sensor->maximum();
|
|
|
|
|
mem = sensor->saved();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(index);
|
|
|
|
|
response->appendData<int16_t>(val);
|
|
|
|
|
response->appendData<int16_t>(min);
|
|
|
|
|
response->appendData<int16_t>(max);
|
|
|
|
|
response->appendData<int16_t>(mem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetRecordSensors
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetRecordSensors(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint8_t index = message->data()->front();
|
|
|
|
|
if (index >= sensors_.size() && index != 0xFF)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_DATA_OUT_OF_RANGE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (index == 0xFF)
|
|
|
|
|
for ( Sensor* s : sensors_ )
|
|
|
|
|
s->save();
|
|
|
|
|
else
|
|
|
|
|
sensors_.at(index)->save();
|
|
|
|
|
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-08-09 15:04:49 -04:00
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionGetIdentifyDevice
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionGetIdentifyDevice(
|
|
|
|
|
__attribute__((unused)) const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
response->appendData<uint8_t>(identifying_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Device::actionSetIdentifyDevice
|
|
|
|
|
* @param message
|
|
|
|
|
* @param response
|
|
|
|
|
*/
|
|
|
|
|
void Device::actionSetIdentifyDevice(const Message *message, Message *response)
|
|
|
|
|
{
|
|
|
|
|
if (message->data()->size() != 1)
|
|
|
|
|
{
|
|
|
|
|
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
|
|
|
|
response->appendData<uint16_t>(NR_FORMAT_ERROR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
response->responseType = RESPONSE_TYPE_ACK;
|
|
|
|
|
identify(message->data()->front());
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace RDM
|