2021-08-08 17:25:41 -04:00
|
|
|
|
/*
|
|
|
|
|
responder.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.
|
|
|
|
|
*/
|
|
|
|
|
#include "responder.h"
|
|
|
|
|
|
2021-08-10 15:35:27 -04:00
|
|
|
|
#include <limits>
|
|
|
|
|
|
2021-08-08 17:25:41 -04:00
|
|
|
|
namespace RDM {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::Responder
|
|
|
|
|
*/
|
|
|
|
|
Responder::Responder()
|
|
|
|
|
: Device()
|
|
|
|
|
{
|
2021-08-09 15:04:49 -04:00
|
|
|
|
deviceModelID = 1;
|
|
|
|
|
deviceModelDescription = "Basic RDM Responder";
|
|
|
|
|
|
2021-08-10 15:35:27 -04:00
|
|
|
|
// /// Category – Network Management
|
|
|
|
|
// static const PID DISC_UNIQUE_BRANCH = 0x0001;
|
|
|
|
|
// static const PID DISC_MUTE = 0x0002;
|
|
|
|
|
// static const PID DISC_UN_MUTE = 0x0003;
|
|
|
|
|
// static const PID PROXIED_DEVICES = 0x0010;
|
|
|
|
|
// static const PID PROXIED_DEVICE_COUNT = 0x0011;
|
|
|
|
|
// static const PID COMMS_STATUS = 0x0015;
|
|
|
|
|
// /// Category - Status Collection
|
|
|
|
|
// static const PID QUEUED_MESSAGE = 0x0020; // See Table A-4
|
|
|
|
|
// static const PID STATUS_MESSAGES = 0x0030; // See Table A-4
|
|
|
|
|
// static const PID STATUS_ID_DESCRIPTION = 0x0031;
|
|
|
|
|
// static const PID CLEAR_STATUS_ID = 0x0032;
|
|
|
|
|
// static const PID SUB_DEVICE_STATUS_REPORT_THRESHOLD = 0x0033; // See Table A-4
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::~Responder
|
|
|
|
|
*/
|
|
|
|
|
Responder::~Responder()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::send
|
|
|
|
|
* @param data
|
|
|
|
|
*/
|
|
|
|
|
void Responder::send(__attribute__((unused)) const std::vector<uint8_t> &data)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::send
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
2021-08-10 13:33:24 -04:00
|
|
|
|
void Responder::send(Message *response)
|
2021-08-08 17:25:41 -04:00
|
|
|
|
{
|
2021-08-10 13:33:24 -04:00
|
|
|
|
if (!response)
|
|
|
|
|
return;
|
2021-08-10 00:57:09 -04:00
|
|
|
|
|
2021-08-08 17:25:41 -04:00
|
|
|
|
// 6.2.8.2 Message Count field for Responder Generated Messages
|
|
|
|
|
// If a responder has more than 255 messages queued, then the Message Count
|
|
|
|
|
// field shall remain at 255 until the number of queued messages is reduced
|
|
|
|
|
// below that number.
|
2021-08-10 16:08:09 -04:00
|
|
|
|
if (queued_messages_.size() > std::numeric_limits<uint8_t>::max())
|
|
|
|
|
response->messageCount = std::numeric_limits<uint8_t>::max();
|
2021-08-08 17:25:41 -04:00
|
|
|
|
else
|
2021-08-10 13:33:24 -04:00
|
|
|
|
response->messageCount = queued_messages_.size();
|
2021-08-08 17:25:41 -04:00
|
|
|
|
|
|
|
|
|
std::vector<uint8_t> data;
|
2021-08-10 13:33:24 -04:00
|
|
|
|
response->write(data);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
send(data);
|
2021-08-10 13:33:24 -04:00
|
|
|
|
delete response;
|
|
|
|
|
response = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::receive
|
|
|
|
|
* @param data
|
|
|
|
|
*/
|
|
|
|
|
void Responder::receive(const std::vector<uint8_t> &data)
|
|
|
|
|
{
|
|
|
|
|
auto message = new Message(data);
|
|
|
|
|
receive(message);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
delete message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::receive
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
|
|
|
|
void Responder::receive(const Message *message)
|
|
|
|
|
{
|
2021-08-10 15:35:27 -04:00
|
|
|
|
if (message->short_message)
|
|
|
|
|
{
|
|
|
|
|
if (short_message_counter_ != std::numeric_limits<uint16_t>::max())
|
|
|
|
|
short_message_counter_++;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-08-08 17:25:41 -04:00
|
|
|
|
|
2021-08-10 13:33:24 -04:00
|
|
|
|
// RDM::UID::operator== also returns true for broadcast messages
|
2021-08-10 15:35:27 -04:00
|
|
|
|
if (message->destination != id ||
|
|
|
|
|
message->incorrect_sc ||
|
|
|
|
|
message->incorrect_sub_sc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (message->length_mismatch)
|
|
|
|
|
{
|
|
|
|
|
if (length_mismatch_counter_ != std::numeric_limits<uint16_t>::max())
|
|
|
|
|
length_mismatch_counter_++;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (message->checksum_fail)
|
|
|
|
|
{
|
|
|
|
|
if (checksum_fail_counter_ != std::numeric_limits<uint16_t>::max())
|
|
|
|
|
checksum_fail_counter_++;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// all other uncaught errors
|
|
|
|
|
if (message->failure_mode != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// responder can ignore _COMMAND_RESPONSE class messages
|
|
|
|
|
if (message->commandClass == DISCOVERY_COMMAND_RESPONSE ||
|
|
|
|
|
message->commandClass == GET_COMMAND_RESPONSE ||
|
|
|
|
|
message->commandClass == SET_COMMAND_RESPONSE)
|
2021-08-10 13:02:58 -04:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
auto response = new Message();
|
|
|
|
|
response->source = id;
|
|
|
|
|
response->destination = message->source;
|
|
|
|
|
response->subDevice = message->subDevice;
|
|
|
|
|
response->propertyID = message->propertyID;
|
|
|
|
|
response->transaction = message->transaction;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
|
|
|
|
|
switch (message->commandClass) {
|
|
|
|
|
case DISCOVERY_COMMAND:
|
|
|
|
|
rxDiscovery(message, response);
|
2021-08-10 13:02:58 -04:00
|
|
|
|
break;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
case GET_COMMAND:
|
|
|
|
|
rxGet(message, response);
|
2021-08-10 13:02:58 -04:00
|
|
|
|
break;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
case SET_COMMAND:
|
|
|
|
|
rxSet(message, response);
|
2021-08-10 13:02:58 -04:00
|
|
|
|
break;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
default:
|
2021-08-10 15:35:27 -04:00
|
|
|
|
delete response;
|
2021-08-10 16:08:09 -04:00
|
|
|
|
response = nullptr;
|
|
|
|
|
break;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
2021-08-10 15:35:27 -04:00
|
|
|
|
|
|
|
|
|
if (response)
|
|
|
|
|
queued_messages_.push(response);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::rxDiscovery
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
|
|
|
|
void Responder::rxDiscovery(__attribute__((unused)) const Message *message,
|
|
|
|
|
Message* response)
|
|
|
|
|
{
|
|
|
|
|
response->commandClass = DISCOVERY_COMMAND_RESPONSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::rxGet
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
2021-08-10 16:08:09 -04:00
|
|
|
|
void Responder::rxGet(const Message *message, Message* response)
|
2021-08-08 17:25:41 -04:00
|
|
|
|
{
|
|
|
|
|
// 9.2.2 Using Sub-Devices
|
|
|
|
|
// Broadcast GET commands sent to the SUB_DEVICE_ALL_CALL Sub-Device ID are
|
|
|
|
|
// not allowed. Any responder receiving a GET command sent to this Sub-Device
|
|
|
|
|
// ID shall respond with a NACK with a NACK Reason Code of
|
|
|
|
|
// NR_SUB_DEVICE_OUT_OF_RANGE.
|
|
|
|
|
if (message->subDevice == SUB_DEVICE_ALL_CALL)
|
|
|
|
|
{
|
2021-08-10 16:08:09 -04:00
|
|
|
|
response->nak(NR_SUB_DEVICE_OUT_OF_RANGE);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (message->subDevice == 0)
|
|
|
|
|
{
|
|
|
|
|
get(message, response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sub_devices_.count(message->subDevice))
|
|
|
|
|
{
|
2021-08-10 16:08:09 -04:00
|
|
|
|
response->nak(NR_SUB_DEVICE_OUT_OF_RANGE);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub_devices_.at(message->subDevice)->get(message, response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Responder::rxSet
|
|
|
|
|
* @param message
|
|
|
|
|
*/
|
2021-08-10 16:08:09 -04:00
|
|
|
|
void Responder::rxSet(const Message *message, Message* response)
|
2021-08-08 17:25:41 -04:00
|
|
|
|
{
|
|
|
|
|
if (message->subDevice == 0)
|
|
|
|
|
{
|
|
|
|
|
set(message, response);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (message->subDevice == SUB_DEVICE_ALL_CALL)
|
|
|
|
|
{
|
|
|
|
|
for (auto& [num, dev] : sub_devices_)
|
|
|
|
|
{
|
|
|
|
|
Message * rsp = new Message(*response);
|
|
|
|
|
rsp->subDevice = num;
|
|
|
|
|
dev->set(message, rsp);
|
|
|
|
|
queued_messages_.push(rsp);
|
|
|
|
|
}
|
|
|
|
|
delete response;
|
2021-08-10 15:35:27 -04:00
|
|
|
|
response = nullptr;
|
2021-08-08 17:25:41 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sub_devices_.count(message->subDevice))
|
|
|
|
|
{
|
2021-08-10 16:08:09 -04:00
|
|
|
|
response->nak(NR_SUB_DEVICE_OUT_OF_RANGE);
|
2021-08-08 17:25:41 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub_devices_.at(message->subDevice)->set(message, response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace RDM
|