1052 lines
51 KiB
C++
1052 lines
51 KiB
C++
/*
|
||
packet.cpp
|
||
|
||
Copyright (c) 2022 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 "packet.h"
|
||
#include "dmx.h"
|
||
|
||
#include <cstring>
|
||
#include <sstream>
|
||
|
||
namespace ARTNET {
|
||
|
||
|
||
void poll_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
*stream >> talk_to_me._raw; // 5
|
||
diagnostic_level = static_cast<Priority>(stream->get()); // 6
|
||
}
|
||
|
||
|
||
void poll_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
*stream << talk_to_me._raw; // 5
|
||
*stream << diagnostic_level; // 6
|
||
}
|
||
|
||
/**
|
||
* @brief ArtPollReply::set_report
|
||
* @param code
|
||
* @param count
|
||
* @param text
|
||
*/
|
||
void pollreply_data::set_report(NodeReport code, uint count, std::string text)
|
||
{
|
||
std::ostringstream report;
|
||
std::ostringstream codestr;
|
||
|
||
codestr << "#";
|
||
codestr.width(4);
|
||
codestr.fill('0');
|
||
codestr << std::ios::hex << code;
|
||
|
||
report << codestr.str();
|
||
report << " ";
|
||
report << count;
|
||
report << " ";
|
||
report << text;
|
||
|
||
_node_report = report.str();
|
||
_node_report.resize(Node_Report_Length - 1);
|
||
};
|
||
|
||
|
||
void pollreply_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
*stream >> my_ip; // 3
|
||
*stream >> udp_port; // 4
|
||
version = stream->get() << 8 | // 5
|
||
stream->get(); // 6
|
||
net_sub_switch.value = stream->get() << 8 | // 7
|
||
stream->get() << 4; // 8
|
||
oem.word = stream->get() << 8 | // 9
|
||
stream->get(); // 10
|
||
*stream >> ubea_version; // 11
|
||
*stream >> status._raw1; // 12
|
||
esta_manufacturer = stream->get() | // 13
|
||
stream->get() << 8; // 14
|
||
stream->readString(short_name, Short_Name_Length); // 15
|
||
stream->readString(long_name, Long_Name_Length); // 16
|
||
stream->readString(_node_report, Node_Report_Length); // 17
|
||
num_ports = stream->get() << 8 | // 18
|
||
stream->get(); // 19
|
||
for( size_t i = 0; i < sizeof(port_types) / sizeof(PortTypes); i++)
|
||
*stream >> port_types[i]._raw; // 20
|
||
for( size_t i = 0; i < sizeof(good_input) / sizeof(GoodInput); i++)
|
||
*stream >> good_input[i]._raw; // 21
|
||
for( size_t i = 0; i < sizeof(good_output) / sizeof(GoodOutput); i++)
|
||
*stream >> good_output[i]._rawA; // 22
|
||
for( size_t i = 0; i < sizeof(SwIn); i++)
|
||
SwIn[i] = stream->get() & 0x0f; // 23
|
||
for( size_t i = 0; i < sizeof(SwOut); i++)
|
||
SwOut[i] = stream->get() & 0x0f; // 24
|
||
*stream >> SwVideo; // 25
|
||
*stream >> SwMacro._raw; // 26
|
||
*stream >> SwRemote._raw; // 27
|
||
stream->get(); // 28
|
||
stream->get(); // 29
|
||
stream->get(); // 30
|
||
style = static_cast<Style>(stream->get()); // 31
|
||
for( size_t i = sizeof(mac_address); i > 0; i--)
|
||
*stream >> mac_address[i-1]; // 32-37
|
||
*stream >> bind_ip; // 38
|
||
*stream >> bind_index; // 39
|
||
*stream >> status._raw2; // 40
|
||
*stream >> good_output->_rawB; // 41
|
||
*stream >> status._raw3; // 42
|
||
for( size_t i = 0; i < _filler_length; i++)
|
||
stream->get(); // 43
|
||
}
|
||
|
||
|
||
void pollreply_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
*stream << my_ip; // 3
|
||
*stream << udp_port; // 4
|
||
stream->put(version >> 8); // 5
|
||
stream->put(version & 0xff); // 6
|
||
stream->put(net_sub_switch.value >> 8); // 7
|
||
stream->put(net_sub_switch.value >> 4 & 0x0f); // 8
|
||
stream->put(oem.word >> 8); // 9
|
||
stream->put(oem.word & 0xff); // 10
|
||
*stream << ubea_version; // 11
|
||
*stream << status._raw1; // 12
|
||
stream->put(esta_manufacturer & 0xff); // 13
|
||
stream->put(esta_manufacturer >> 8); // 14
|
||
stream->writeString(short_name, Short_Name_Length, true); // 15
|
||
stream->writeString(long_name, Long_Name_Length, true); // 16
|
||
stream->writeString(_node_report, Node_Report_Length, true); // 17
|
||
stream->put(num_ports >> 8); // 18
|
||
stream->put(num_ports & 0xff); // 19
|
||
for( size_t i = 0; i < sizeof(port_types) / sizeof(PortTypes); i++)
|
||
*stream << port_types[i]._raw; // 20
|
||
for( size_t i = 0; i < sizeof(good_input) / sizeof(GoodInput); i++)
|
||
*stream << good_input[i]._raw; // 21
|
||
for( size_t i = 0; i < sizeof(good_output) / sizeof(GoodOutput); i++)
|
||
*stream << good_output[i]._rawA; // 22
|
||
for( size_t i = 0; i < sizeof(SwIn); i++)
|
||
stream->put(SwIn[i] &0x0f); // 23
|
||
for( size_t i = 0; i < sizeof(SwOut); i++)
|
||
stream->put(SwOut[i] &0x0f); // 24
|
||
*stream << SwVideo; // 25
|
||
*stream << SwMacro._raw; // 26
|
||
*stream << SwRemote._raw; // 27
|
||
stream->put(0); // 28
|
||
stream->put(0); // 29
|
||
stream->put(0); // 30
|
||
*stream << style; // 31
|
||
for( size_t i = sizeof(mac_address); i > 0; i--)
|
||
*stream << mac_address[i-1]; // 32-37
|
||
*stream << bind_ip; // 38
|
||
*stream << bind_index; // 39
|
||
*stream << status._raw2; // 40
|
||
*stream << good_output->_rawB; // 41
|
||
*stream << status._raw3; // 42
|
||
for( size_t i = 0; i < _filler_length; i++)
|
||
stream->put(0); // 43
|
||
}
|
||
|
||
|
||
void ipprog_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
*stream >> command._raw; // 7
|
||
stream->get(); // 8
|
||
*stream >> ip_address; // 9-12
|
||
*stream >> subnet_mask; // 13-16
|
||
*stream >> udp_port; // 17-18
|
||
stream->ignore(_spare_length); // 19
|
||
}
|
||
|
||
|
||
void ipprog_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
*stream << command._raw; // 7
|
||
stream->put(0); // 8
|
||
*stream << ip_address; // 9-12
|
||
*stream << subnet_mask; // 13-16
|
||
*stream << udp_port; // 17-18
|
||
for( size_t i = 0; i < _spare_length; i++)
|
||
stream->put(0); // 19
|
||
}
|
||
|
||
|
||
void ipprogreply_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
*stream >> ip_address; // 9-12
|
||
*stream >> subnet_mask; // 13-16
|
||
*stream >> udp_port; // 17-18
|
||
*stream >> status._raw; // 19
|
||
stream->ignore(_spare_length); // 20-26
|
||
}
|
||
|
||
|
||
void ipprogreply_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
*stream << ip_address; // 9-12
|
||
*stream << subnet_mask; // 13-16
|
||
*stream << udp_port; // 17-18
|
||
*stream << status._raw; // 19
|
||
for( size_t i = 0; i < _spare_length; i++)
|
||
stream->put(0); // 20-26
|
||
}
|
||
|
||
|
||
void address_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
net_sub_switch.value = stream->get() << 8; // 5
|
||
*stream >> bind_index; // 6
|
||
stream->readString(short_name, Short_Name_Length); // 7
|
||
stream->readString(long_name, Long_Name_Length); // 8
|
||
for( size_t i = 0; i < sizeof(SwIn); i++)
|
||
SwIn[i] = stream->get() & 0x0f; // 9
|
||
for( size_t i = 0; i < sizeof(SwOut); i++)
|
||
SwOut[i] = stream->get() & 0x0f; // 10
|
||
net_sub_switch.value |= stream->get() << 4; // 11
|
||
*stream >> SwVideo; // 12
|
||
command = static_cast<AddressCommand>(stream->get()); // 13
|
||
}
|
||
|
||
|
||
void address_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(net_sub_switch.value >> 8); // 5
|
||
*stream << bind_index; // 6
|
||
stream->writeString(short_name, Short_Name_Length, true); // 7
|
||
stream->writeString(long_name, Long_Name_Length, true); // 8
|
||
for( size_t i = 0; i < sizeof(SwIn); i++)
|
||
stream->put(SwIn[i] &0x0f); // 9
|
||
for( size_t i = 0; i < sizeof(SwOut); i++)
|
||
stream->put(SwOut[i] &0x0f); // 10
|
||
stream->put(net_sub_switch.value >> 4 & 0x0f); // 11
|
||
*stream << SwVideo; // 12
|
||
*stream << command; // 13
|
||
}
|
||
|
||
|
||
void diagdata_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
priority = static_cast<Priority>(stream->get()); // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
uint16_t length = stream->get() << 8 | // 9
|
||
stream->get(); // 10
|
||
stream->readString(data, length); // 11
|
||
}
|
||
|
||
|
||
void diagdata_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
*stream << priority; // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
uint16_t length = data.length() + 1; // include null terminator
|
||
if ( length > _max_data_length )
|
||
length = _max_data_length;
|
||
stream->put(length >> 8); // 9
|
||
stream->put(length & 0xff); // 10
|
||
stream->writeString(data, length, true); // 11
|
||
}
|
||
|
||
|
||
void timecode_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
*stream >> time.frame; // 7
|
||
*stream >> time.seconds; // 8
|
||
*stream >> time.minutes; // 9
|
||
*stream >> time.hours; // 10
|
||
time.type = static_cast<TimecodeType>(stream->get()); // 11
|
||
}
|
||
|
||
|
||
void timecode_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
*stream << time.frame; // 7
|
||
*stream << time.seconds; // 8
|
||
*stream << time.minutes; // 9
|
||
*stream << time.hours; // 10
|
||
*stream << time.type; // 11
|
||
}
|
||
|
||
|
||
void command_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->put(esta_manufacturer & 0xff); // 5
|
||
stream->put(esta_manufacturer >> 8); // 6
|
||
uint16_t length = stream->get() << 8 | // 7
|
||
stream->get(); // 8
|
||
stream->readString(data, length); // 9
|
||
}
|
||
|
||
|
||
void command_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(esta_manufacturer & 0xff); // 5
|
||
stream->put(esta_manufacturer >> 8); // 6
|
||
uint16_t length = data.length() + 1; // include null terminator
|
||
if ( length > _max_data_length )
|
||
length = _max_data_length;
|
||
stream->put(length >> 8); // 7
|
||
stream->put(length & 0xff); // 8
|
||
stream->writeString(data, length, true); // 9
|
||
}
|
||
|
||
|
||
|
||
void trigger_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
oem.word = stream->get() << 8 | // 7
|
||
stream->get(); // 8
|
||
*stream >> key; // 9
|
||
*stream >> subkey; // 10
|
||
stream->read(data, sizeof(data)); // 11
|
||
}
|
||
|
||
|
||
void trigger_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
stream->put(oem.word >> 8); // 7
|
||
stream->put(oem.word & 0xff); // 8
|
||
*stream << key; // 9
|
||
*stream << subkey; // 10
|
||
stream->write(data, sizeof(data)); // 11
|
||
}
|
||
|
||
|
||
void dmx_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
*stream >> sequence; // 5
|
||
*stream >> physical; // 6
|
||
*stream >> universe.subuni; // 7
|
||
universe.net = stream->readType<uint8_t>(); // 8
|
||
uint16_t length = stream->get() << 8 | // 9
|
||
stream->get(); // 10
|
||
// this value should be an even number in the range 2 – 512
|
||
if ( length % 2 != 0 ||
|
||
length < 2 ||
|
||
length > DMX::E111_LAST_SLOT )
|
||
return stream->setstate(std::ios_base::failbit);
|
||
data.reserve(length + 1);
|
||
for (int i = 1; i <= length; i++)
|
||
data.push_back(stream->get()); // 11
|
||
}
|
||
|
||
|
||
void dmx_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
*stream << sequence; // 5
|
||
*stream << physical; // 6
|
||
*stream << universe.subuni; // 7
|
||
*stream << universe.net; // 8
|
||
uint16_t length = data.size() - 1;
|
||
uint16_t datalength = length + (length % 2);
|
||
stream->put(datalength >> 8); // 9
|
||
stream->put(datalength & 0xff ); // 10
|
||
for (int i = 1; i <= length; i++)
|
||
stream->put(data.at(i)); // 11
|
||
for (int i = 0; i < length % 2; i++)
|
||
stream->put(0);
|
||
}
|
||
|
||
|
||
void sync_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
}
|
||
|
||
|
||
void sync_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
}
|
||
|
||
|
||
void nzs_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
*stream >> sequence; // 5
|
||
data.clear();
|
||
data.push_back(stream->get()); // 6
|
||
*stream >> universe.subuni; // 7
|
||
universe.net = stream->readType<uint8_t>(); // 8
|
||
uint16_t length = stream->get() << 8 | // 9
|
||
stream->get(); // 10
|
||
// this value should be an even number in the range 1 – 512
|
||
if (length < 1 ||
|
||
length > DMX::E111_LAST_SLOT )
|
||
return stream->setstate(std::ios_base::failbit);
|
||
data.reserve(length + 1);
|
||
for (int i = 1; i <= length; i++)
|
||
data.push_back(stream->get()); // 11
|
||
}
|
||
|
||
|
||
void nzs_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
*stream << sequence; // 5
|
||
*stream << data.at(0); // 6
|
||
*stream << universe.subuni; // 7
|
||
*stream << universe.net; // 8
|
||
uint16_t length = data.size() - 1;
|
||
stream->put(length >> 8); // 9
|
||
stream->put(length & 0xff ); // 10
|
||
for (int i = 1; i <= length; i++)
|
||
stream->put(data.at(i)); // 11
|
||
}
|
||
|
||
|
||
bool vlc_data::_from_nzs(const nzs_data * other)
|
||
{ // Field #
|
||
version = other->version;
|
||
sequence = other->sequence;
|
||
universe = other->universe;
|
||
if (other->data.size() < 11) // enough data to read the payload length
|
||
return false;
|
||
if (other->data[0] != VLC::START_CODE ||
|
||
other->data[1] != VLC::MagicNumber[0] || // 11
|
||
other->data[2] != VLC::MagicNumber[1] || // 12
|
||
other->data[3] != VLC::MagicNumber[2]) // 13
|
||
return false;
|
||
flags._raw = other->data[4]; // 14
|
||
transaction = other->data[5] << 8 | // 15
|
||
other->data[6]; // 16
|
||
address = other->data[7] << 8 | // 17
|
||
other->data[8]; // 18
|
||
size_t length = other->data[9] << 8 | // 19
|
||
other->data[10]; // 20
|
||
if (other->data.size() < 23 + length ||
|
||
length > _payload_max_length)
|
||
return false;
|
||
uint16_t cksm = other->data[11] << 8 | // 21
|
||
other->data[12]; // 22
|
||
// skip unlucky other->data[13] // 23
|
||
depth = other->data[14]; // 24
|
||
frequency = other->data[15] << 8 | // 25
|
||
other->data[16]; // 26
|
||
modulation = other->data[17] << 8 | // 27
|
||
other->data[18]; // 28
|
||
language = other->data[19] << 8 | // 29
|
||
other->data[20]; // 30
|
||
beacon_frequency = other->data[21] << 8 | // 31
|
||
other->data[22]; // 32
|
||
for (size_t i = 0; i < length; i++)
|
||
payload.push_back(other->data[23+i]); // 33
|
||
if (cksm != _checksum())
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
|
||
void vlc_data::compile()
|
||
{ // Field #
|
||
data.insert(data.end(), // 11-13
|
||
std::begin(VLC::MagicNumber), std::end(VLC::MagicNumber));
|
||
data.push_back(flags._raw); // 14
|
||
data.push_back(transaction >> 8); // 15
|
||
data.push_back(transaction & 0xff); // 16
|
||
data.push_back(address >> 8); // 17
|
||
data.push_back(address & 0xff); // 18
|
||
uint16_t length = payload.size();
|
||
data.push_back(length >> 8); // 19
|
||
data.push_back(length & 0xff); // 20
|
||
uint16_t chksum = _checksum();
|
||
data.push_back(chksum >> 8); // 21
|
||
data.push_back(chksum & 0xff); // 22
|
||
data.push_back(0); // 23
|
||
data.push_back(depth); // 24
|
||
data.push_back(frequency >> 8); // 25
|
||
data.push_back(frequency & 0xff); // 26
|
||
data.push_back(modulation >> 8); // 27
|
||
data.push_back(modulation & 0xff); // 28
|
||
data.push_back(language >> 8); // 29
|
||
data.push_back(language & 0xff); // 30
|
||
data.push_back(beacon_frequency >> 8); // 31
|
||
data.push_back(beacon_frequency & 0xff); // 32
|
||
data.insert(data.end(), payload.begin(), payload.end()); // 33
|
||
}
|
||
|
||
|
||
uint16_t vlc_data::_checksum() const
|
||
{
|
||
/// \todo impliment the real checksum!
|
||
return 0;
|
||
}
|
||
|
||
|
||
void input_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
*stream >> bind_index; // 6
|
||
num_ports = stream->get() << 8 | // 7
|
||
stream->get(); // 8
|
||
for (size_t i = 0; i < (sizeof(status) / sizeof(InputFlags)); i++)
|
||
*stream >> status[i]._raw; // 9
|
||
}
|
||
|
||
|
||
void input_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
*stream << bind_index; // 6
|
||
stream->put(num_ports >> 8); // 7
|
||
stream->put(num_ports & 0xff); // 8
|
||
for (size_t i = 0; i < (sizeof(status) / sizeof(InputFlags)); i++)
|
||
*stream << status[i]._raw; // 9
|
||
}
|
||
|
||
|
||
void firmwaremaster_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
type = static_cast<FIRMWARE::MasterType>(stream->get()); // 7
|
||
*stream >> block_id; // 8
|
||
length = stream->get() << 24 | // 9
|
||
stream->get() << 16 | // 10
|
||
stream->get() << 8 | // 11
|
||
stream->get(); // 12
|
||
stream->ignore(_spare_length); // 13
|
||
for (size_t i = 0; i < sizeof(block) / sizeof(block[0]); i++)
|
||
*stream >> block[i]; // 14
|
||
}
|
||
|
||
|
||
void firmwaremaster_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
*stream << type; // 7
|
||
*stream << block_id; // 8
|
||
stream->put((length >> 24) & 0xff); // 9
|
||
stream->put((length >> 16) & 0xff); // 10
|
||
stream->put((length >> 8) & 0xff); // 11
|
||
stream->put(length & 0xff); // 12
|
||
for (size_t i = 0; i < _spare_length; i++)
|
||
stream->put(0); // 13
|
||
for (size_t i = 0; i < sizeof(block); i++)
|
||
*stream << block[i]; // 14
|
||
}
|
||
|
||
|
||
void firmwarereply_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
type = static_cast<FIRMWARE::ResponseType>(stream->get()); // 7
|
||
stream->ignore(_spare_length); // 8
|
||
}
|
||
|
||
|
||
void firmwarereply_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
*stream << type; // 7
|
||
for (size_t i = 0; i < _spare_length; i++)
|
||
stream->put(0); // 8
|
||
}
|
||
|
||
|
||
void todrequest_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
stream->get(); // 9
|
||
stream->get(); // 10
|
||
stream->get(); // 11
|
||
stream->get(); // 12
|
||
stream->get(); // 13
|
||
uint8_t net = stream->get(); // 14
|
||
if ( stream->get() != RDM::TodFull) // 15
|
||
return stream->setstate(std::ios_base::failbit);
|
||
uint8_t count = stream->get(); // 16
|
||
for (int i = 0; i < count; i++)
|
||
universes.push_back(PortAddress{.net=net, .subuni=stream->readType<uint8_t>()}); // 17
|
||
}
|
||
|
||
|
||
void todrequest_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
stream->put(0); // 9
|
||
stream->put(0); // 10
|
||
stream->put(0); // 11
|
||
stream->put(0); // 12
|
||
stream->put(0); // 13
|
||
stream->put(universes.empty() ? 0 : universes[0].net); // 14
|
||
stream->put(RDM::TodFull); // 15
|
||
stream->put(universes.size() < _max_count ? universes.size() : _max_count); // 16
|
||
for (size_t i = 0; i < universes.size() && i < _max_count; i++ )
|
||
stream->put(universes[i].subuni); // 17
|
||
}
|
||
|
||
|
||
void toddata_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
rdm_version = static_cast<RDM::Version>(stream->get()); // 5
|
||
*stream >> port; // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
stream->get(); // 9
|
||
stream->get(); // 10
|
||
stream->get(); // 11
|
||
stream->get(); // 12
|
||
*stream >> bind_index; // 13
|
||
universe.net = stream->readType<uint8_t>(); // 14
|
||
type = static_cast<RDM::TodCommandResponse>(stream->get()); // 15
|
||
*stream >> universe.subuni; // 16
|
||
*stream >> total_count; // 17-18
|
||
*stream >> block_count; // 19
|
||
uint8_t count = stream->get(); // 20
|
||
uint16_t manufacturer;
|
||
uint32_t device;
|
||
for (int i = 0; i < count; i++) // 21
|
||
{
|
||
*stream >> manufacturer;
|
||
*stream >> device;
|
||
devices.emplace_back(std::make_shared<::RDM::UID>(device, manufacturer));
|
||
}
|
||
}
|
||
|
||
|
||
void toddata_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(rdm_version); // 5
|
||
*stream << port; // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
stream->put(0); // 9
|
||
stream->put(0); // 10
|
||
stream->put(0); // 11
|
||
stream->put(0); // 12
|
||
*stream << bind_index; // 13
|
||
*stream << universe.net; // 14
|
||
*stream << type; // 15
|
||
*stream << universe.subuni; // 16
|
||
*stream << total_count; // 17-18
|
||
*stream << block_count; // 19
|
||
stream->put(devices.size()); // 20
|
||
for (size_t i = 0; i < devices.size(); i++) { // 21
|
||
auto uid = devices.at(i)->uid();
|
||
stream->put((uid >> 40) & 0xff);
|
||
stream->put((uid >> 32) & 0xff);
|
||
stream->put((uid >> 24) & 0xff);
|
||
stream->put((uid >> 16) & 0xff);
|
||
stream->put((uid >> 8) & 0xff);
|
||
stream->put(uid & 0xff);
|
||
}
|
||
}
|
||
|
||
|
||
void todcontrol_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
stream->get(); // 5
|
||
stream->get(); // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
stream->get(); // 9
|
||
stream->get(); // 10
|
||
stream->get(); // 11
|
||
stream->get(); // 12
|
||
stream->get(); // 13
|
||
universe.net = stream->readType<uint8_t>(); // 14
|
||
command = static_cast<RDM::TodControlCommand>(stream->get()); // 15
|
||
*stream >> universe.subuni; // 16
|
||
|
||
}
|
||
|
||
|
||
void todcontrol_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
stream->put(0); // 5
|
||
stream->put(0); // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
stream->put(0); // 9
|
||
stream->put(0); // 10
|
||
stream->put(0); // 11
|
||
stream->put(0); // 12
|
||
stream->put(0); // 13
|
||
*stream << universe.net; // 14
|
||
*stream << command; // 15
|
||
*stream << universe.subuni; // 16
|
||
}
|
||
|
||
|
||
void rdm_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
rdm_version = static_cast<RDM::Version>(stream->get()); // 5
|
||
stream->get(); // 6
|
||
stream->get(); // 7
|
||
stream->get(); // 8
|
||
stream->get(); // 9
|
||
stream->get(); // 10
|
||
stream->get(); // 11
|
||
stream->get(); // 12
|
||
stream->get(); // 13
|
||
universe.net = stream->readType<uint8_t>(); // 14
|
||
command = static_cast<RDM::RdmCommand>(stream->get()); // 15
|
||
*stream >> universe.subuni; // 16
|
||
data.reserve(stream->available() + 1);
|
||
while (stream->available())
|
||
data.push_back(stream->get()); // 17
|
||
}
|
||
|
||
|
||
void rdm_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
*stream << rdm_version; // 5
|
||
stream->put(0); // 6
|
||
stream->put(0); // 7
|
||
stream->put(0); // 8
|
||
stream->put(0); // 9
|
||
stream->put(0); // 10
|
||
stream->put(0); // 11
|
||
stream->put(0); // 12
|
||
stream->put(0); // 13
|
||
*stream << universe.net; // 14
|
||
*stream << command; // 15
|
||
*stream << universe.subuni; // 16
|
||
for (size_t i = 1; i < data.size(); i++)
|
||
*stream << data[i]; // 17
|
||
}
|
||
|
||
|
||
void rdmsub_data::iStream(std::shared_ptr<bufferstream> stream)
|
||
{ // Field #
|
||
version = stream->get() << 8 | // 3
|
||
stream->get(); // 4
|
||
if (version < VERSION)
|
||
return stream->setstate(std::ios_base::failbit);
|
||
rdm_version = static_cast<RDM::Version>(stream->get()); // 5
|
||
stream->get(); // 6
|
||
auto manufacturer = stream->readType<uint16_t>(); // 7
|
||
auto device = stream->readType<uint32_t>(); // 7
|
||
uid = ::RDM::UID(device, manufacturer);
|
||
stream->get(); // 8
|
||
*stream >> command_class; // 9
|
||
*stream >> pid; // 10
|
||
*stream >> subdevice; // 11
|
||
auto count = stream->readType<uint16_t>(); // 12
|
||
stream->get(); // 13
|
||
stream->get(); // 14
|
||
stream->get(); // 15
|
||
stream->get(); // 16
|
||
if (command_class == ::RDM::SET_COMMAND ||
|
||
command_class == ::RDM::GET_COMMAND_RESPONSE)
|
||
for (uint i = 0; i < count; i++)
|
||
data.push_back(stream->readType<uint16_t>()); // 17
|
||
}
|
||
|
||
|
||
void rdmsub_data::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{ // Field #
|
||
stream->put(version >> 8); // 3
|
||
stream->put(version & 0xff); // 4
|
||
*stream << rdm_version; // 5
|
||
stream->put(0); // 6
|
||
auto uid_number = uid.uid();
|
||
stream->put((uid_number >> 40) & 0xff); // 7
|
||
stream->put((uid_number >> 32) & 0xff); // 7
|
||
stream->put((uid_number >> 24) & 0xff); // 7
|
||
stream->put((uid_number >> 16) & 0xff); // 7
|
||
stream->put((uid_number >> 8) & 0xff); // 7
|
||
stream->put(uid_number & 0xff); // 7
|
||
stream->put(0); // 8
|
||
*stream << command_class; // 9
|
||
*stream << pid; // 10
|
||
*stream << subdevice; // 11
|
||
if (command_class == ::RDM::GET_COMMAND ||
|
||
command_class == ::RDM::SET_COMMAND_RESPONSE ||
|
||
data.empty())
|
||
*stream << (uint16_t)1; // 12
|
||
else
|
||
*stream << (uint16_t)data.size(); // 12
|
||
stream->put(0); // 13
|
||
stream->put(0); // 14
|
||
stream->put(0); // 15
|
||
stream->put(0); // 16
|
||
if (command_class == ::RDM::SET_COMMAND ||
|
||
command_class == ::RDM::GET_COMMAND_RESPONSE)
|
||
for (uint i = 0; i < data.size(); i++)
|
||
*stream << data[i]; // 17
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief packet::streamSize
|
||
* @return
|
||
*/
|
||
size_t Packet::streamSize() const
|
||
{
|
||
return sizeof(PACKET_IDENTIFIER)
|
||
+ sizeof(OpCode)
|
||
+ _data->streamSize();
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief packet::iStream
|
||
*
|
||
* Read a packet from the network.
|
||
*
|
||
* @param stream
|
||
*/
|
||
void Packet::iStream(std::shared_ptr<bufferstream> stream)
|
||
{
|
||
uint8_t identifier[sizeof(PACKET_IDENTIFIER)]; //!< 'A''r''t''-''N''e''t'0x00
|
||
// Field #
|
||
stream->read(identifier, sizeof(identifier)); // 1
|
||
if (stream->gcount() != sizeof(identifier))
|
||
return stream->setstate(std::ios_base::badbit);
|
||
if (memcmp(identifier, PACKET_IDENTIFIER, sizeof(identifier))) // memcmp returns 0 if matched
|
||
return stream->setstate(std::ios_base::failbit);
|
||
|
||
OpCode opcode = static_cast<OpCode>(stream->readType<uint16_t>()); // 2
|
||
|
||
switch (opcode) { // 3-...
|
||
case OpPoll:
|
||
_data = std::make_shared<poll_data>();
|
||
break;
|
||
case OpPollReply:
|
||
_data = std::make_shared<pollreply_data>();
|
||
break;
|
||
case OpIpProg:
|
||
_data = std::make_shared<ipprog_data>();
|
||
break;
|
||
case OpIpProgReply:
|
||
_data = std::make_shared<ipprogreply_data>();
|
||
break;
|
||
case OpAddress:
|
||
_data = std::make_shared<address_data>();
|
||
break;
|
||
case OpDiagData:
|
||
_data = std::make_shared<diagdata_data>();
|
||
break;
|
||
case OpTimeCode:
|
||
_data = std::make_shared<timecode_data>();
|
||
break;
|
||
case OpCommand:
|
||
_data = std::make_shared<command_data>();
|
||
break;
|
||
case OpTrigger:
|
||
_data = std::make_shared<trigger_data>();
|
||
break;
|
||
case OpDmx:
|
||
_data = std::make_shared<dmx_data>();
|
||
break;
|
||
case OpSync:
|
||
_data = std::make_shared<sync_data>();
|
||
break;
|
||
case OpNzs:
|
||
_data = std::make_shared<nzs_data>();
|
||
break;
|
||
case OpInput:
|
||
_data = std::make_shared<input_data>();
|
||
break;
|
||
case OpFirmwareMaster:
|
||
_data = std::make_shared<firmwaremaster_data>();
|
||
break;
|
||
case OpFirmwareReply:
|
||
_data = std::make_shared<firmwarereply_data>();
|
||
break;
|
||
case OpTodRequest:
|
||
_data = std::make_shared<todrequest_data>();
|
||
break;
|
||
case OpTodData:
|
||
_data = std::make_shared<toddata_data>();
|
||
break;
|
||
case OpTodControl:
|
||
_data = std::make_shared<todcontrol_data>();
|
||
break;
|
||
case OpRdm:
|
||
_data = std::make_shared<rdm_data>();
|
||
break;
|
||
case OpRdmSub:
|
||
_data = std::make_shared<rdmsub_data>();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (_data)
|
||
_data->iStream(stream);
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief packet::oStream
|
||
*
|
||
* Write a packet to the network.
|
||
*
|
||
* @param stream
|
||
*/
|
||
void Packet::oStream(std::shared_ptr<bufferstream> stream) const
|
||
{
|
||
if ( _opcode == OpNull )
|
||
return stream->setstate(std::ios_base::failbit);
|
||
if ( _data == nullptr )
|
||
return stream->setstate(std::ios_base::failbit);
|
||
// Field #
|
||
stream->write(PACKET_IDENTIFIER, sizeof(PACKET_IDENTIFIER)); // 1
|
||
*stream << _opcode; // 2
|
||
*stream << _data; // 3-...
|
||
}
|
||
|
||
} // namespace ARTNET
|