more rdm support
This commit is contained in:
parent
970617b9cd
commit
1d996f46a4
|
@ -41,8 +41,22 @@ set(SOURCE_FILES
|
|||
dmx/universe.cpp
|
||||
dmx/universe.h
|
||||
otp/opt.h
|
||||
rdm/controller.h
|
||||
rdm/controller.cpp
|
||||
rdm/device.h
|
||||
rdm/device.cpp
|
||||
rdm/E1.37-1.h
|
||||
rdm/E1.37-2.h
|
||||
rdm/E1.37-7.h
|
||||
rdm/message.h
|
||||
rdm/message.cpp
|
||||
rdm/parameter.h
|
||||
rdm/parameter.cpp
|
||||
rdm/rdm.h
|
||||
rdm/rdm.cpp
|
||||
rdm/responder.h
|
||||
rdm/responder.cpp
|
||||
rdm/uid.h
|
||||
rdmnet/rdmnet.h
|
||||
sacn/data.cpp
|
||||
sacn/data.h
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
E1.37-1.h.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief ANSI E1.37-1 – 2012 (R2017)
|
||||
* Additional Message Sets for ANSI E1.20 (RDM) – Part 1,
|
||||
* Dimmer Message Sets
|
||||
*/
|
||||
namespace RDM {
|
||||
|
||||
using PID = uint16_t;
|
||||
|
||||
/// Appendix A: Defined Parameters (Normative)
|
||||
|
||||
/// Table A-1: RDM Parameter ID Defines
|
||||
/// Category – DMX512 Setup
|
||||
static const PID DMX_BLOCK_ADDRESS = 0x0140;
|
||||
static const PID DMX_FAIL_MODE = 0x0141;
|
||||
static const PID DMX_STARTUP_MODE = 0x0142;
|
||||
/// Category – Dimmer Settings
|
||||
static const PID DIMMER_INFO = 0x0340;
|
||||
static const PID MINIMUM_LEVEL = 0x0341;
|
||||
static const PID MAXIMUM_LEVEL = 0x0342;
|
||||
static const PID CURVE = 0x0343;
|
||||
static const PID CURVE_DESCRIPTION = 0x0344;
|
||||
static const PID OUTPUT_RESPONSE_TIME = 0x0345;
|
||||
static const PID OUTPUT_RESPONSE_TIME_DESCRIPTION = 0x0346;
|
||||
static const PID MODULATION_FREQUENCY = 0x0347;
|
||||
static const PID MODULATION_FREQUENCY_DESCRIPTION = 0x0348;
|
||||
/// Category – Power/Lamp Settings
|
||||
static const PID BURN_IN = 0x0440;
|
||||
/// Category – Configuration
|
||||
static const PID LOCK_PIN = 0x0640;
|
||||
static const PID LOCK_STATE = 0x0641;
|
||||
static const PID LOCK_STATE_DESCRIPTION = 0x0642;
|
||||
/// Category – Control
|
||||
static const PID IDENTIFY_MODE = 0x1040;
|
||||
static const PID PRESET_INFO = 0x1041;
|
||||
static const PID PRESET_STATUS = 0x1042;
|
||||
static const PID PRESET_MERGEMODE = 0x1043;
|
||||
static const PID POWER_ON_SELF_TEST = 0x1044;
|
||||
|
||||
/// Preset Programmed Defines
|
||||
static const uint8_t PRESET_NOT_PROGRAMMED = 0x00;
|
||||
static const uint8_t PRESET_PROGRAMMED = 0x01;
|
||||
static const uint8_t PRESET_PROGRAMMED_READ_ONLY = 0x02;
|
||||
|
||||
/// Merge Mode Defines
|
||||
static const uint8_t MERGEMODE_DEFAULT = 0x00;
|
||||
static const uint8_t MERGEMODE_HTP = 0x01;
|
||||
static const uint8_t MERGEMODE_LTP = 0x02;
|
||||
static const uint8_t MERGEMODE_DMX_ONLY = 0x03;
|
||||
static const uint8_t MERGEMODE_OTHER = 0xFF;
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
E1.37-2.h.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief ANSI E1.37-2 – 2015 Entertainment Technology
|
||||
* Additional Message Sets for ANSI E1.20 (RDM) – Part 2,
|
||||
* IPv4 & DNS Configuration Messages
|
||||
*/
|
||||
namespace RDM {
|
||||
|
||||
using PID = uint16_t;
|
||||
|
||||
/// Appendix A: Defined Parameters (Normative)
|
||||
static const uint32_t IPV4_UNCONFIGURED = 0x00000000;
|
||||
static const uint32_t NO_DEFAULT_ROUTE = 0x00000000;
|
||||
|
||||
/// Table A-1: RDM Parameter ID
|
||||
static const PID LIST_INTERFACES = 0x0700;
|
||||
static const PID INTERFACE_LABEL = 0x0701;
|
||||
static const PID INTERFACE_HARDWARE_ADDRESS_TYPE1 = 0x0702;
|
||||
static const PID IPV4_DHCP_MODE = 0x0703;
|
||||
static const PID IPV4_ZEROCONF_MODE = 0x0704;
|
||||
static const PID IPV4_CURRENT_ADDRESS = 0x0705;
|
||||
static const PID IPV4_STATIC_ADDRESS = 0x0706;
|
||||
static const PID INTERFACE_RENEW_DHCP = 0x0707;
|
||||
static const PID INTERFACE_RELEASE_DHCP = 0x0708;
|
||||
static const PID INTERFACE_APPLY_CONFIGURATION = 0x0709;
|
||||
static const PID IPV4_DEFAULT_ROUTE = 0x070A;
|
||||
static const PID DNS_IPV4_NAME_SERVER = 0x070B;
|
||||
static const PID DNS_HOSTNAME = 0x070C;
|
||||
static const PID DNS_DOMAIN_NAME = 0x070D;
|
||||
|
||||
/// Table A-2: Additional NACK Reason Codes
|
||||
// superseded in E1.37-7
|
||||
// static const uint16_t NR_ACTION_NOT_SUPPORTED = 0x000B; //!< The parameter data is valid but the SET operation cannot be performed with the current configuration.
|
||||
|
||||
/// Table A-3: DHCP Mode
|
||||
static const uint8_t DHCP_STATUS_INACTIVE = 0x00;
|
||||
static const uint8_t DHCP_STATUS_ACTIVE = 0x01; //!< The IP address was not obtained via DHCP.
|
||||
static const uint8_t DHCP_STATUS_UNKNOWN = 0x02; //!< The IP address was obtained via DHCP.
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
E1.37-7.h.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief ANSI E1.37-7
|
||||
* Additional Message Sets for ANSI E1.20 (RDM) -
|
||||
* Gateway & Splitter Configuration Messages
|
||||
*/
|
||||
namespace RDM {
|
||||
using PID = uint16_t;
|
||||
|
||||
/// Appendix A: Defined Parameters (Normative)
|
||||
|
||||
/// Table A-1: RDM Parameter ID
|
||||
static const PID ENDPOINT_LIST = 0x0900;
|
||||
static const PID ENDPOINT_LIST_CHANGE = 0x0901;
|
||||
static const PID IDENTIFY_ENDPOINT = 0x0902;
|
||||
static const PID ENDPOINT_TO_UNIVERSE = 0x0903;
|
||||
static const PID ENDPOINT_MODE = 0x0904;
|
||||
static const PID ENDPOINT_LABEL = 0x0905;
|
||||
static const PID RDM_TRAFFIC_ENABLE = 0x0906;
|
||||
static const PID DISCOVERY_STATE = 0x0907;
|
||||
static const PID BACKGROUND_DISCOVERY = 0x0908;
|
||||
static const PID ENDPOINT_TIMING = 0x0909;
|
||||
static const PID ENDPOINT_TIMING_DESCRIPTION = 0x090A;
|
||||
static const PID ENDPOINT_RESPONDERS = 0x090B;
|
||||
static const PID ENDPOINT_RESPONDER_LIST_CHANGE = 0x090C;
|
||||
static const PID BINDING_CONTROL_FIELDS = 0x090D;
|
||||
static const PID BACKGROUND_QUEUED_STATUS_POLICY = 0x090E;
|
||||
static const PID BACKGROUND_QUEUED_STATUS_POLICY_DESCRIPTION = 0x090F;
|
||||
|
||||
/// Table A-2: Discovery State
|
||||
static const uint8_t DISCOVERY_INCOMPLETE = 0x00;
|
||||
static const uint8_t DISCOVERY_INCREMENTAL = 0x01;
|
||||
static const uint8_t DISCOVERY_FULL = 0x02;
|
||||
static const uint8_t DISCOVERY_NOT_ACTIVE = 0x04;
|
||||
|
||||
/// Table A-3: Discovery Status
|
||||
static const uint16_t DISCOVERY_COUNT_INCOMPLETE = 0x0000;
|
||||
static const uint16_t DISCOVERY_COUNT_UNKNOWN = 0xFFFF;
|
||||
|
||||
/// Table A-4: Endpoint Mode
|
||||
static const uint8_t ENDPOINT_MODE_DISABLED = 0x00;
|
||||
static const uint8_t ENDPOINT_MODE_INPUT = 0x01;
|
||||
static const uint8_t ENDPOINT_MODE_OUTPUT = 0x02;
|
||||
|
||||
/// Table A-5: Endpoint Types
|
||||
static const uint8_t ENDPOINT_TYPE_VIRTUAL = 0x00;
|
||||
static const uint8_t ENDPOINT_TYPE_PHYSICAL = 0x01;
|
||||
|
||||
/// Table A-6: Additional Response NACK Reason Codes
|
||||
static const uint16_t NR_ACTION_NOT_SUPPORTED = 0x000B; // also defined in E1.37-2
|
||||
static const uint16_t NR_ENDPOINT_NUMBER_INVALID = 0x000C;
|
||||
static const uint16_t NR_INVALID_ENDPOINT_MODE = 0x000D;
|
||||
static const uint16_t NR_UNKNOWN_UID = 0x000E;
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
controller.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 "controller.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Controller::Controller
|
||||
*/
|
||||
Controller::Controller()
|
||||
: Responder()
|
||||
, next_transaction_(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Controller::~Controller
|
||||
*/
|
||||
Controller::~Controller()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Controller::rxDiscoveryResponse
|
||||
* @param message
|
||||
*/
|
||||
void Controller::rxDiscoveryResponse(__attribute__((unused)) const Message* message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Controller::rxGetResponse
|
||||
* @param message
|
||||
*/
|
||||
void Controller::rxGetResponse(__attribute__((unused)) const Message* message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Controller::rxSetResponse
|
||||
* @param message
|
||||
*/
|
||||
void Controller::rxSetResponse(__attribute__((unused)) const Message* message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
controller.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "responder.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief The Controller class
|
||||
*/
|
||||
class Controller
|
||||
: public Responder
|
||||
{
|
||||
public:
|
||||
Controller();
|
||||
~Controller();
|
||||
|
||||
protected:
|
||||
virtual void rxDiscoveryResponse(const Message* message) override;
|
||||
virtual void rxGetResponse(const Message* message) override;
|
||||
virtual void rxSetResponse(const Message* message) override;
|
||||
|
||||
private:
|
||||
uint8_t next_transaction_;
|
||||
};
|
||||
|
||||
} // namespace RDM
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "device.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Device::Device
|
||||
*/
|
||||
Device::Device()
|
||||
{
|
||||
// 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_[SUPPORTED_PARAMETERS] = new Parameter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Device::~Device
|
||||
*/
|
||||
Device::~Device()
|
||||
{
|
||||
for (auto& [_, parameter] : parameters_)
|
||||
delete parameter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Device::get
|
||||
* @param message
|
||||
* @param response
|
||||
*/
|
||||
void Device::get(const Message *message, Message *response)
|
||||
{
|
||||
response->commandClass = GET_COMMAND_RESPONSE;
|
||||
if (!parameters_.count(message->propertyID))
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_UNKNOWN_PID);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
if (!parameters_.count(message->propertyID))
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_UNKNOWN_PID);
|
||||
return;
|
||||
}
|
||||
parameters_.at(message->propertyID)->set(message, response);
|
||||
}
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
device.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "parameter.h"
|
||||
#include "rdm.h"
|
||||
#include "uid.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace RDM {
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
Device();
|
||||
virtual ~Device();
|
||||
|
||||
const UID id() const { return id_; }
|
||||
|
||||
virtual void get(const Message* message, Message* response);
|
||||
virtual void set(const Message* message, Message* response);
|
||||
|
||||
void setManufacturerId(uint16_t man) { id_.manufacturer = man; }
|
||||
void setDeviceId(uint32_t dev) { id_.device = dev; }
|
||||
|
||||
protected:
|
||||
std::unordered_map<PID, Parameter*> parameters_;
|
||||
|
||||
private:
|
||||
UID id_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace RDM
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
message.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 "message.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Message::Message
|
||||
*/
|
||||
Message::Message()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::Message
|
||||
* @param obj
|
||||
*/
|
||||
Message::Message(const Message &obj)
|
||||
: source(obj.source)
|
||||
, destination(obj.destination)
|
||||
, transaction(obj.transaction)
|
||||
, portID(obj.portID)
|
||||
, messageCount(obj.messageCount)
|
||||
, subDevice(obj.subDevice)
|
||||
, propertyID(obj.propertyID)
|
||||
{
|
||||
data_.insert(data_.end(), obj.data()->begin(), obj.data()->end());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::~Message
|
||||
*/
|
||||
Message::~Message()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Message::checksum
|
||||
* @return
|
||||
*/
|
||||
uint16_t Message::checksum()
|
||||
{
|
||||
uint16_t sum = 0;
|
||||
|
||||
sum = addSum_<uint8_t> (sum, SC_RDM);
|
||||
sum = addSum_<uint8_t> (sum, SC_SUB_MESSAGE);
|
||||
sum = addSum_<uint8_t> (sum, 24 + length());
|
||||
sum = addSum_<uint16_t>(sum, source.manufacturer);
|
||||
sum = addSum_<uint32_t>(sum, source.device);
|
||||
sum = addSum_<uint16_t>(sum, destination.manufacturer);
|
||||
sum = addSum_<uint32_t>(sum, destination.device);
|
||||
sum = addSum_<uint8_t> (sum, transaction);
|
||||
sum = addSum_<uint8_t> (sum, portID);
|
||||
sum = addSum_<uint8_t> (sum, messageCount);
|
||||
sum = addSum_<uint16_t>(sum, subDevice);
|
||||
sum = addSum_<uint8_t> (sum, commandClass);
|
||||
sum = addSum_<uint16_t>(sum, propertyID);
|
||||
sum = addSum_<uint8_t> (sum, length());
|
||||
for (uint8_t val : data_)
|
||||
sum = addSum_<uint8_t>(sum, val);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
message.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "rdm.h"
|
||||
#include "uid.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
struct Message
|
||||
{
|
||||
UID source;
|
||||
UID destination;
|
||||
uint8_t transaction;
|
||||
union {
|
||||
uint8_t portID;
|
||||
uint8_t responseType;
|
||||
};
|
||||
uint8_t messageCount;
|
||||
uint16_t subDevice;
|
||||
uint8_t commandClass;
|
||||
PID propertyID;
|
||||
|
||||
Message();
|
||||
Message(const Message &obj);
|
||||
~Message();
|
||||
|
||||
const std::vector<uint8_t>* data() const { return &data_; }
|
||||
uint8_t length() const { return data_.size(); }
|
||||
uint16_t checksum();
|
||||
|
||||
template<typename T>
|
||||
void appendData(const T & val)
|
||||
{
|
||||
Message::writeType<T>(data_, val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T readType(const std::vector<uint8_t>& vect, size_t start)
|
||||
{
|
||||
if (vect.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;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void writeType(std::vector<uint8_t>& data, T val)
|
||||
{
|
||||
auto raw = reinterpret_cast<uint8_t*>(val);
|
||||
for (int i = sizeof(T); --i >= 0; )
|
||||
data.push_back(raw[i]);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
template<typename T>
|
||||
uint16_t addSum_(uint16_t sum, T val) const
|
||||
{
|
||||
uint16_t carry;
|
||||
auto raw = reinterpret_cast<uint8_t*>(val);
|
||||
for (int i = sizeof(T); --i >= 0; )
|
||||
{
|
||||
uint8_t num = raw[i];
|
||||
while (num != 0)
|
||||
{
|
||||
carry = sum & num;
|
||||
sum = sum ^ num;
|
||||
num = carry << 1;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace RDM
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
property.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 "parameter.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Property::Property
|
||||
*/
|
||||
Parameter::Parameter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Property::get
|
||||
* @param message
|
||||
* @param ack
|
||||
* @param nak
|
||||
*/
|
||||
void Parameter::get(__attribute__((unused)) const Message* message,
|
||||
Message* response) const
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_UNSUPPORTED_COMMAND_CLASS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Property::set
|
||||
* @param message
|
||||
* @param ack
|
||||
* @param nak
|
||||
*/
|
||||
void Parameter::set(__attribute__((unused)) const Message* message,
|
||||
Message* response)
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_UNSUPPORTED_COMMAND_CLASS);
|
||||
}
|
||||
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
property.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "rdm.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
class Parameter
|
||||
{
|
||||
public:
|
||||
Parameter();
|
||||
virtual ~Parameter();
|
||||
|
||||
virtual void get(const Message* message, Message* response) const;
|
||||
virtual void set(const Message* message, Message* response);
|
||||
};
|
||||
|
||||
|
||||
} // namespace RDM
|
44
rdm/rdm.cpp
44
rdm/rdm.cpp
|
@ -355,11 +355,53 @@ std::string ProductDetailDescription(const u_int16_t PRODUCT_DETAIL)
|
|||
/// for where the Manufacturer believes that none of the defined details apply.
|
||||
case PRODUCT_DETAIL_OTHER:
|
||||
return std::string("Other");
|
||||
|
||||
default:
|
||||
return std::string("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief NackReasonDescription
|
||||
* @param NR
|
||||
* @return
|
||||
*/
|
||||
std::string NackReasonDescription(const uint16_t NR)
|
||||
{
|
||||
switch (NR) {
|
||||
case NR_UNKNOWN_PID:
|
||||
return std::string("The responder cannot comply with request because the message is not implemented in responder.");
|
||||
case NR_FORMAT_ERROR:
|
||||
return std::string("The responder cannot interpret request as controller data was not formatted correctly.");
|
||||
case NR_HARDWARE_FAULT:
|
||||
return std::string("The responder cannot comply due to an internal hardware fault.");
|
||||
case NR_PROXY_REJECT:
|
||||
return std::string("Proxy is not the RDM line master and cannot comply with message.");
|
||||
case NR_WRITE_PROTECT:
|
||||
return std::string("SET Command normally allowed but being blocked currently.");
|
||||
case NR_UNSUPPORTED_COMMAND_CLASS:
|
||||
return std::string("Not valid for Command Class attempted.");
|
||||
case NR_DATA_OUT_OF_RANGE:
|
||||
return std::string("Value for given Parameter out of allowable range or not supported.");
|
||||
case NR_BUFFER_FULL:
|
||||
return std::string("Buffer or Queue space currently has no free space to store data.");
|
||||
case NR_PACKET_SIZE_UNSUPPORTED:
|
||||
return std::string("Incoming message exceeds buffer capacity.");
|
||||
case NR_SUB_DEVICE_OUT_OF_RANGE:
|
||||
return std::string("Sub-Device is out of range or unknown.");
|
||||
case NR_PROXY_BUFFER_FULL:
|
||||
return std::string("The proxy buffer is full and can not store any more Queued Message or Status Message responses.");
|
||||
case NR_ACTION_NOT_SUPPORTED: //!< from E1.37-7
|
||||
return std::string("The specified action is not supported.");
|
||||
case NR_ENDPOINT_NUMBER_INVALID: //!< from E1.37-7
|
||||
return std::string("The specified endpoint is invalid.");
|
||||
case NR_INVALID_ENDPOINT_MODE: //!< from E1.37-7
|
||||
return std::string("The specified endpoint is in an invalid Endpoint Mode for the requested action.");
|
||||
case NR_UNKNOWN_UID: //!< from E1.37-7
|
||||
return std::string("The specified UID is not recognized.");
|
||||
default:
|
||||
return std::string("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RDM
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "dmx/dmx.h"
|
||||
#include "E1.37-1.h"
|
||||
#include "E1.37-2.h"
|
||||
#include "E1.37-7.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace RDM {
|
||||
|
@ -438,6 +442,7 @@ using namespace DMX;
|
|||
static const uint8_t CC_SET = 0x02; //!< PID supports SET only
|
||||
static const uint8_t CC_GET_SET = 0x03;
|
||||
|
||||
std::string NackReasonDescription(const uint16_t NR);
|
||||
/// Table A-17: Response NACK Reason Code
|
||||
static const uint16_t NR_UNKNOWN_PID = 0x0000;
|
||||
static const uint16_t NR_FORMAT_ERROR = 0x0001;
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
namespace RDM {
|
||||
|
||||
/**
|
||||
* @brief Responder::Responder
|
||||
*/
|
||||
Responder::Responder()
|
||||
: Device()
|
||||
{
|
||||
// E1.20 required parameters
|
||||
parameters_[DISC_UNIQUE_BRANCH] = new Parameter;
|
||||
parameters_[DISC_MUTE] = new Parameter;
|
||||
parameters_[DISC_UN_MUTE] = new Parameter;
|
||||
parameters_[DEVICE_INFO] = new Parameter;
|
||||
parameters_[SOFTWARE_VERSION_LABEL] = new Parameter;
|
||||
parameters_[IDENTIFY_DEVICE] = new Parameter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::~Responder
|
||||
*/
|
||||
Responder::~Responder()
|
||||
{
|
||||
for( auto& [_, dev] : sub_devices_)
|
||||
delete dev;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::addSubDevice
|
||||
* @param number
|
||||
* @param dev
|
||||
*/
|
||||
void Responder::addSubDevice(uint16_t number, Device *dev)
|
||||
{
|
||||
if (sub_devices_.count(number))
|
||||
delete sub_devices_.at(number);
|
||||
sub_devices_[number] = dev;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::subDevice
|
||||
* @param number
|
||||
* @return
|
||||
*/
|
||||
Device* Responder::subDevice(uint16_t number)
|
||||
{
|
||||
if (sub_devices_.count(number))
|
||||
return sub_devices_.at(number);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::receive
|
||||
* @param data
|
||||
*/
|
||||
void Responder::receive(const std::vector<uint8_t> &data)
|
||||
{
|
||||
if (data.size() < 3) // SC + SC_SUB + LENGTH
|
||||
return;
|
||||
|
||||
Message message;
|
||||
|
||||
// 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)
|
||||
return;
|
||||
|
||||
// 6.2.2 Sub START Code
|
||||
// This field shall contain the Sub-START Code within RDM that defines this
|
||||
// packet structure (SC_SUB_MESSAGE). Future versions of this standard which
|
||||
// may have additional or different packet structures would use this field to
|
||||
// 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)
|
||||
return;
|
||||
|
||||
// 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 != data.size() - 2)
|
||||
return;
|
||||
|
||||
// 6.2.4 Destination UID
|
||||
// The Destination UID is the UID of the target device(s).
|
||||
message.destination.manufacturer = Message::readType<uint16_t>(data, 3);
|
||||
message.destination.device = Message::readType<uint32_t>(data, 5);
|
||||
|
||||
// 6.2.5 Source UID
|
||||
// The Source UID is the UID of the device originating this packet.
|
||||
message.source.manufacturer = Message::readType<uint16_t>(data, 9);
|
||||
message.source.device = Message::readType<uint32_t>(data, 11);
|
||||
|
||||
// 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.
|
||||
message.transaction = data[15];
|
||||
|
||||
// 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.
|
||||
message.portID = data[16];
|
||||
|
||||
// 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.
|
||||
message.messageCount = data[17];
|
||||
|
||||
// 6.2.9 Sub-Device Field
|
||||
// Sub-devices should be used in devices containing a repetitive number of
|
||||
// similar modules, such as a dimmer rack. The Sub-Device field allows
|
||||
// Parameter messages to be addressed to a specific module within the device
|
||||
// to set or get properties of that module.
|
||||
// The 16-bit sub-device field provides a range of 512 valid sub-devices,
|
||||
// addressed from 1 - 512.
|
||||
// The value of 0xFFFF is reserved as a SUB_DEVICE_ALL_CALL. A value of 0x0000
|
||||
// shall be used to address the root or base properties of the device that do
|
||||
// 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.
|
||||
message.subDevice = Message::readType<uint16_t>(data, 18);
|
||||
|
||||
// 6.2.10.1 Command Class (CC)
|
||||
message.commandClass = data[20];
|
||||
|
||||
// 6.2.10.2 Parameter ID (PID)
|
||||
// The Parameter ID is a 16-bit number that identifies a specific type of
|
||||
// Parameter Data. The Parameter ID (PID) may represent either a well known
|
||||
// Parameter such as those defined in this document, or a
|
||||
// Manufacturer-specific parameter whose details are either published by the
|
||||
// Manufacturer for third-party support or proprietary for the Manufacturer’s
|
||||
// own use.
|
||||
message.propertyID = Message::readType<uint16_t>(data, 21);
|
||||
|
||||
// 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];
|
||||
|
||||
// 6.2.10.4 Parameter Data (PD)
|
||||
// The Parameter Data is of variable length. The content format is PID dependent.
|
||||
if (pdl > 0)
|
||||
for (int i = 0; i < pdl; i++)
|
||||
message.appendData(data[24+i]);
|
||||
if (message.length() != pdl)
|
||||
return;
|
||||
|
||||
// 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 checksum = Message::readType<uint16_t>(data, length);
|
||||
if (checksum != message.checksum())
|
||||
return;
|
||||
|
||||
receive(&message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::send
|
||||
*/
|
||||
void Responder::send()
|
||||
{
|
||||
if (queued_messages_.empty())
|
||||
return;
|
||||
|
||||
auto message = queued_messages_.front();
|
||||
queued_messages_.pop();
|
||||
send(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::send
|
||||
* @param data
|
||||
*/
|
||||
void Responder::send(__attribute__((unused)) const std::vector<uint8_t> &data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::send
|
||||
* @param message
|
||||
*/
|
||||
void Responder::send(Message *message)
|
||||
{
|
||||
// 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.
|
||||
if (queued_messages_.size() > 255)
|
||||
message->messageCount = 255;
|
||||
else
|
||||
message->messageCount = queued_messages_.size();
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
data.push_back(SC_RDM);
|
||||
data.push_back(SC_SUB_MESSAGE);
|
||||
data.push_back(24 + message->length());
|
||||
Message::writeType<uint16_t>(data, message->destination.manufacturer);
|
||||
Message::writeType<uint32_t>(data, message->destination.device);
|
||||
Message::writeType<uint16_t>(data, message->source.manufacturer);
|
||||
Message::writeType<uint32_t>(data, message->source.device);
|
||||
data.push_back(message->transaction);
|
||||
data.push_back(message->portID);
|
||||
data.push_back(message->messageCount);
|
||||
Message::writeType<uint16_t>(data, message->subDevice);
|
||||
data.push_back(message->commandClass);
|
||||
Message::writeType<uint16_t>(data, message->propertyID);
|
||||
data.push_back(message->length());
|
||||
data.insert(data.end(), message->data()->begin(), message->data()->end());
|
||||
Message::writeType<uint16_t>(data, message->checksum());
|
||||
|
||||
send(data);
|
||||
delete message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::receive
|
||||
* @param message
|
||||
*/
|
||||
void Responder::receive(const Message *message)
|
||||
{
|
||||
Message * response = nullptr;
|
||||
if (message->commandClass == DISCOVERY_COMMAND ||
|
||||
message->commandClass == GET_COMMAND ||
|
||||
message->commandClass == SET_COMMAND)
|
||||
{
|
||||
// 6.2.8.1 Message Count field for Controller Generated Messages
|
||||
// The Message Count shall be set to 0x00 in all controller generated requests.
|
||||
if (message->messageCount != 0)
|
||||
return;
|
||||
|
||||
response = new Message();
|
||||
response->source = id();
|
||||
response->destination = message->source;
|
||||
response->subDevice = message->subDevice;
|
||||
response->propertyID = message->propertyID;
|
||||
response->transaction = message->transaction;
|
||||
}
|
||||
|
||||
switch (message->commandClass) {
|
||||
case DISCOVERY_COMMAND:
|
||||
rxDiscovery(message, response);
|
||||
return;
|
||||
case DISCOVERY_COMMAND_RESPONSE:
|
||||
rxDiscoveryResponse(message);
|
||||
return;
|
||||
case GET_COMMAND:
|
||||
rxGet(message, response);
|
||||
return;
|
||||
case GET_COMMAND_RESPONSE:
|
||||
rxGetResponse(message);
|
||||
return;
|
||||
case SET_COMMAND:
|
||||
rxSet(message, response);
|
||||
return;
|
||||
case SET_COMMAND_RESPONSE:
|
||||
rxSetResponse(message);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxDiscovery
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxDiscovery(__attribute__((unused)) const Message *message,
|
||||
Message* response)
|
||||
{
|
||||
response->commandClass = DISCOVERY_COMMAND_RESPONSE;
|
||||
send(response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxDiscoveryResponse
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxDiscoveryResponse(__attribute__((unused)) const Message *message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxGet
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxGet(const Message *message,
|
||||
__attribute__((unused)) Message* response)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_SUB_DEVICE_OUT_OF_RANGE);
|
||||
send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->subDevice == 0)
|
||||
{
|
||||
get(message, response);
|
||||
send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sub_devices_.count(message->subDevice))
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_SUB_DEVICE_OUT_OF_RANGE);
|
||||
send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
sub_devices_.at(message->subDevice)->get(message, response);
|
||||
send(response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxGetResponse
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxGetResponse(__attribute__((unused)) const Message *message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxSet
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxSet(const Message *message,
|
||||
__attribute__((unused)) Message* response)
|
||||
{
|
||||
if (message->subDevice == 0)
|
||||
{
|
||||
set(message, response);
|
||||
send(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;
|
||||
send();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sub_devices_.count(message->subDevice))
|
||||
{
|
||||
response->responseType = RESPONSE_TYPE_NACK_REASON;
|
||||
response->appendData<uint16_t>(NR_SUB_DEVICE_OUT_OF_RANGE);
|
||||
send(response);
|
||||
return;
|
||||
}
|
||||
|
||||
sub_devices_.at(message->subDevice)->set(message, response);
|
||||
send(response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Responder::rxSetResponse
|
||||
* @param message
|
||||
*/
|
||||
void Responder::rxSetResponse(__attribute__((unused)) const Message *message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
responder.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "device.h"
|
||||
#include "message.h"
|
||||
#include "uid.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
namespace RDM {
|
||||
|
||||
class Responder
|
||||
: public Device
|
||||
{
|
||||
public:
|
||||
Responder();
|
||||
virtual ~Responder();
|
||||
|
||||
void receive(const std::vector<uint8_t>& data);
|
||||
void addSubDevice(uint16_t number, Device* dev);
|
||||
Device* subDevice(uint16_t number);
|
||||
|
||||
protected:
|
||||
virtual void send();
|
||||
virtual void send(const std::vector<uint8_t>& data);
|
||||
virtual void send(Message* message);
|
||||
virtual void receive(const Message* message);
|
||||
|
||||
virtual void rxDiscovery(const Message* message, Message* response);
|
||||
virtual void rxDiscoveryResponse(const Message* message);
|
||||
virtual void rxGet(const Message* message, Message* response);
|
||||
virtual void rxGetResponse(const Message* message);
|
||||
virtual void rxSet(const Message* message, Message* response);
|
||||
virtual void rxSetResponse(const Message* message);
|
||||
|
||||
std::queue<Message*> queued_messages_;
|
||||
|
||||
private:
|
||||
std::unordered_map<uint16_t, Device*> sub_devices_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace RDM
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
uid.h
|
||||
|
||||
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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace RDM {
|
||||
|
||||
struct UID {
|
||||
union {
|
||||
uint64_t uid : 48;
|
||||
struct {
|
||||
uint16_t manufacturer;
|
||||
uint32_t device;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace RDM
|
Loading…
Reference in New Issue