Skip to content

Commit

Permalink
First attempt at LLRP header and PDU
Browse files Browse the repository at this point in the history
All there apart from flags should always be 0xF0 rather than 0x70

(cherry picked from commit 23a00bb)
  • Loading branch information
peternewman committed Mar 2, 2024
1 parent ff8bf86 commit 3599bb0
Show file tree
Hide file tree
Showing 10 changed files with 673 additions and 1 deletion.
3 changes: 3 additions & 0 deletions include/ola/acn/ACNVectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ enum RootVector {
VECTOR_ROOT_E131 = 4, /**< E1.31 (sACN) */
VECTOR_ROOT_E133 = 5, /**< E1.33 (RDNNet) */
VECTOR_ROOT_NULL = 6, /**< NULL (empty) root */
VECTOR_ROOT_BROKER = 9, /**< E1.33 (Broker) */
VECTOR_ROOT_LLRP = 0x0A, /**< E1.33 (LLRP) */
VECTOR_ROOT_EPT = 0x0B, /**< E1.33 (EPT) */
};

/**
Expand Down
8 changes: 7 additions & 1 deletion libs/acn/HeaderSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "libs/acn/DMPHeader.h"
#include "libs/acn/E131Header.h"
#include "libs/acn/E133Header.h"
#include "libs/acn/LLRPHeader.h"
#include "libs/acn/RootHeader.h"
#include "libs/acn/TransportHeader.h"

Expand Down Expand Up @@ -56,13 +57,17 @@ class HeaderSet {
const DMPHeader &GetDMPHeader() const { return m_dmp_header; }
void SetDMPHeader(const DMPHeader &header) { m_dmp_header = header; }

const LLRPHeader &GetLLRPHeader() const { return m_llrp_header; }
void SetLLRPHeader(const LLRPHeader &header) { m_llrp_header = header; }

bool operator==(const HeaderSet &other) const {
return (
m_transport_header == other.m_transport_header &&
m_root_header == other.m_root_header &&
m_e131_header == other.m_e131_header &&
m_e133_header == other.m_e133_header &&
m_dmp_header == other.m_dmp_header);
m_dmp_header == other.m_dmp_header &&
m_llrp_header == other.m_llrp_header);
}

private:
Expand All @@ -71,6 +76,7 @@ class HeaderSet {
E131Header m_e131_header;
E133Header m_e133_header;
DMPHeader m_dmp_header;
LLRPHeader m_llrp_header;
};
} // namespace acn
} // namespace ola
Expand Down
69 changes: 69 additions & 0 deletions libs/acn/LLRPHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* LLRPHeader.h
* The E1.33 LLRP Header
* Copyright (C) 2020 Peter Newman
*/

#ifndef LIBS_ACN_LLRPHEADER_H_
#define LIBS_ACN_LLRPHEADER_H_

#include <ola/acn/CID.h>
#include <ola/base/Macro.h>

#include <stdint.h>

namespace ola {
namespace acn {

/*
* Header for the LLRP layer
*/
class LLRPHeader {
public:
LLRPHeader()
: m_transaction_number(0) {
}

LLRPHeader(const ola::acn::CID &destination_cid,
uint32_t transaction_number)
: m_destination_cid(destination_cid),
m_transaction_number(transaction_number) {
}
~LLRPHeader() {}

const ola::acn::CID DestinationCid() const { return m_destination_cid; }
uint32_t TransactionNumber() const { return m_transaction_number; }

bool operator==(const LLRPHeader &other) const {
return m_destination_cid == other.m_destination_cid &&
m_transaction_number == other.m_transaction_number;
}

PACK(
struct llrp_pdu_header_s {
uint8_t destination_cid[CID::CID_LENGTH];
uint32_t transaction_number;
});
typedef struct llrp_pdu_header_s llrp_pdu_header;

private:
ola::acn::CID m_destination_cid;
uint32_t m_transaction_number;
};
} // namespace acn
} // namespace ola
#endif // LIBS_ACN_LLRPHEADER_H_
70 changes: 70 additions & 0 deletions libs/acn/LLRPInflator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* LLRPInflator.cpp
* The Inflator for E1.33 LLRP
* Copyright (C) 2020 Peter Newman
*/

#include "ola/Logging.h"
#include "ola/network/NetworkUtils.h"
#include "libs/acn/LLRPInflator.h"

namespace ola {
namespace acn {

using ola::network::NetworkToHost;

/*
* Decode the E1.33 LLRP headers. If data is null we're expected to use the
* last header we got.
* @param headers the HeaderSet to add to
* @param data a pointer to the data
* @param length length of the data
* @returns true if successful, false otherwise
*/
bool LLRPInflator::DecodeHeader(HeaderSet *headers,
const uint8_t *data,
unsigned int length,
unsigned int *bytes_used) {
if (data) {
// the header bit was set, decode it
if (length >= sizeof(LLRPHeader::llrp_pdu_header)) {
LLRPHeader::llrp_pdu_header raw_header;
memcpy(&raw_header, data, sizeof(LLRPHeader::llrp_pdu_header));
LLRPHeader header(
ola::acn::CID::FromData(raw_header.destination_cid),
NetworkToHost(raw_header.transaction_number));
m_last_header = header;
m_last_header_valid = true;
headers->SetLLRPHeader(header);
*bytes_used = sizeof(LLRPHeader::llrp_pdu_header);
return true;
}
*bytes_used = 0;
return false;
}

// use the last header if it exists
*bytes_used = 0;
if (!m_last_header_valid) {
OLA_WARN << "Missing E1.33 LLRP Header data";
return false;
}
headers->SetLLRPHeader(m_last_header);
return true;
}
} // namespace acn
} // namespace ola
58 changes: 58 additions & 0 deletions libs/acn/LLRPInflator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* LLRPInflator.h
* Interface for the LLRPInflator class.
* Copyright (C) 2020 Peter Newman
*/

#ifndef LIBS_ACN_LLRPINFLATOR_H_
#define LIBS_ACN_LLRPINFLATOR_H_

#include "ola/acn/ACNVectors.h"
#include "libs/acn/BaseInflator.h"
#include "libs/acn/LLRPHeader.h"

namespace ola {
namespace acn {

class LLRPInflator: public BaseInflator {
friend class LLRPInflatorTest;

public:
LLRPInflator()
: BaseInflator(),
m_last_header_valid(false) {
}
~LLRPInflator() {}

uint32_t Id() const { return ola::acn::VECTOR_ROOT_LLRP; }

protected:
bool DecodeHeader(HeaderSet *headers,
const uint8_t *data,
unsigned int len,
unsigned int *bytes_used);

void ResetHeaderField() {
m_last_header_valid = false;
}
private:
LLRPHeader m_last_header;
bool m_last_header_valid;
};
} // namespace acn
} // namespace ola
#endif // LIBS_ACN_LLRPINFLATOR_H_
126 changes: 126 additions & 0 deletions libs/acn/LLRPInflatorTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* LLRPInflatorTest.cpp
* Test fixture for the LLRPInflator class
* Copyright (C) 2020 Peter Newman
*/

#include <cppunit/extensions/HelperMacros.h>

#include "ola/Logging.h"
#include "ola/network/NetworkUtils.h"
#include "libs/acn/HeaderSet.h"
#include "libs/acn/PDUTestCommon.h"
#include "libs/acn/LLRPInflator.h"
#include "libs/acn/LLRPPDU.h"
#include "ola/testing/TestUtils.h"


namespace ola {
namespace acn {

using ola::network::HostToNetwork;

class LLRPInflatorTest: public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(LLRPInflatorTest);
CPPUNIT_TEST(testDecodeHeader);
CPPUNIT_TEST(testInflatePDU);
CPPUNIT_TEST_SUITE_END();

public:
void testDecodeHeader();
void testInflatePDU();
private:
static const uint8_t TEST_DATA[];
static const uint8_t TEST_DATA2[];
};

const uint8_t LLRPInflatorTest::TEST_DATA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15};
const uint8_t LLRPInflatorTest::TEST_DATA2[] = {10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24,
25};
CPPUNIT_TEST_SUITE_REGISTRATION(LLRPInflatorTest);


/*
* Check that we can decode headers properly
*/
void LLRPInflatorTest::testDecodeHeader() {
LLRPHeader::llrp_pdu_header header;
memset(&header, 0, sizeof(header));
LLRPInflator inflator;
HeaderSet header_set, header_set2;
unsigned int bytes_used;
const ola::acn::CID destination_cid = CID::FromData(TEST_DATA);

destination_cid.Pack(header.destination_cid);
header.transaction_number = HostToNetwork(72650u);

OLA_ASSERT(inflator.DecodeHeader(&header_set,
reinterpret_cast<uint8_t*>(&header),
sizeof(header),
&bytes_used));
OLA_ASSERT_EQ((unsigned int) sizeof(header), bytes_used);
LLRPHeader decoded_header = header_set.GetLLRPHeader();
OLA_ASSERT(destination_cid == decoded_header.DestinationCid());
OLA_ASSERT_EQ((uint32_t) 72650, decoded_header.TransactionNumber());

// try an undersized header
OLA_ASSERT_FALSE(inflator.DecodeHeader(
&header_set,
reinterpret_cast<uint8_t*>(&header),
static_cast<unsigned int>(sizeof(header) - 1),
&bytes_used));
OLA_ASSERT_EQ((unsigned int) 0, bytes_used);

// test inheriting the header from the prev call
OLA_ASSERT(inflator.DecodeHeader(&header_set2, NULL, 0, &bytes_used));
OLA_ASSERT_EQ((unsigned int) 0, bytes_used);
decoded_header = header_set2.GetLLRPHeader();
OLA_ASSERT(destination_cid == decoded_header.DestinationCid());
OLA_ASSERT_EQ((uint32_t) 72650, decoded_header.TransactionNumber());

inflator.ResetHeaderField();
OLA_ASSERT_FALSE(inflator.DecodeHeader(&header_set2, NULL, 0, &bytes_used));
OLA_ASSERT_EQ((unsigned int) 0, bytes_used);
}


/*
* Check that we can inflate a LLRP PDU that contains other PDUs
*/
void LLRPInflatorTest::testInflatePDU() {
const ola::acn::CID destination_cid = CID::FromData(TEST_DATA2);
LLRPHeader header(destination_cid, 2370);
// TODO(Peter): pass a different type of msg here as well
LLRPPDU pdu(3, header, NULL);
OLA_ASSERT_EQ((unsigned int) 26, pdu.Size());

unsigned int size = pdu.Size();
uint8_t *data = new uint8_t[size];
unsigned int bytes_used = size;
OLA_ASSERT(pdu.Pack(data, &bytes_used));
OLA_ASSERT_EQ((unsigned int) size, bytes_used);

LLRPInflator inflator;
HeaderSet header_set;
OLA_ASSERT(inflator.InflatePDUBlock(&header_set, data, size));
OLA_ASSERT(header == header_set.GetLLRPHeader());
delete[] data;
}
} // namespace acn
} // namespace ola
Loading

0 comments on commit 3599bb0

Please sign in to comment.