Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for serial UART and local domain socket protocolInterfaces #150

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ option(BUILD_AVDECC_INTERFACE_PCAP_DYNAMIC_LINKING "Pcap protocol interface uses
option(BUILD_AVDECC_INTERFACE_MAC "Build the macOS native protocol interface (macOS only)." TRUE)
option(BUILD_AVDECC_INTERFACE_PROXY "Build the proxy protocol interface." FALSE)
option(BUILD_AVDECC_INTERFACE_VIRTUAL "Build the virtual protocol interface (for unit tests)." TRUE)
option(BUILD_AVDECC_INTERFACE_SERIAL "Build the serial protocol interface." !${WIN32})
option(BUILD_AVDECC_INTERFACE_LOCAL "Build the local domain socket protocol interface." !${WIN32})
# Install options
option(INSTALL_AVDECC_EXAMPLES "Install examples." FALSE)
option(INSTALL_AVDECC_TESTS "Install unit tests." FALSE)
Expand Down
2 changes: 2 additions & 0 deletions include/la/avdecc/internals/protocolInterface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class ProtocolInterface : public la::avdecc::utils::Subject<ProtocolInterface, s
MacOSNative = 1u << 1, /**< macOS native API protocol interface - Only usable on macOS. */
Proxy = 1u << 2, /**< IEEE Std 1722.1 Proxy protocol interface. */
Virtual = 1u << 3, /**< Virtual protocol interface. */
Serial = 1u << 4, /**< Serial port protocol interface. */
Local = 1u << 5, /**< Local domain socket protocol interface. */
};

/** Possible Error status returned (or thrown) by a ProtocolInterface */
Expand Down
2 changes: 2 additions & 0 deletions include/la/avdecc/internals/typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ enum avdecc_protocol_interface_type_e
avdecc_protocol_interface_type_macos_native = 1u << 1, /**< macOS native API protocol interface - Only usable on macOS. */
avdecc_protocol_interface_type_proxy = 1u << 2, /**< IEEE Std 1722.1 Proxy protocol interface. */
avdecc_protocol_interface_type_virtual = 1u << 3, /**< Virtual protocol interface. */
avdecc_protocol_interface_type_serial = 1u << 4, /**< Serial port protocol interface. */
avdecc_protocol_interface_type_local = 1u << 5, /**< Local domain socket protocol interface. */
};

/** Valid values for avdecc_protocol_interface_error_t */
Expand Down
24 changes: 24 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,30 @@ if(BUILD_AVDECC_INTERFACE_VIRTUAL)
list(APPEND ADD_PRIVATE_COMPILE_OPTIONS "-DHAVE_PROTOCOL_INTERFACE_VIRTUAL")
endif()

# Serial Protocol interface
if(BUILD_AVDECC_INTERFACE_SERIAL)
list(APPEND SOURCE_FILES_PROTOCOL_INTERFACE
protocolInterface/protocolInterface_serial.cpp
protocolInterface/cobsSerialization.cpp
)
list(APPEND HEADER_FILES_PROTOCOL_INTERFACE
protocolInterface/protocolInterface_serial.hpp
protocolInterface/cobsSerialization.hpp
)
list(APPEND ADD_PRIVATE_COMPILE_OPTIONS "-DHAVE_PROTOCOL_INTERFACE_SERIAL")
endif()

# Local Domain Socket Protocol interface
if(BUILD_AVDECC_INTERFACE_LOCAL)
list(APPEND SOURCE_FILES_PROTOCOL_INTERFACE
protocolInterface/protocolInterface_local.cpp
)
list(APPEND HEADER_FILES_PROTOCOL_INTERFACE
protocolInterface/protocolInterface_local.hpp
)
list(APPEND ADD_PRIVATE_COMPILE_OPTIONS "-DHAVE_PROTOCOL_INTERFACE_LOCAL")
lhoward marked this conversation as resolved.
Show resolved Hide resolved
endif()

# Features
if(ENABLE_AVDECC_FEATURE_REDUNDANCY)
list(APPEND ADD_PUBLIC_COMPILE_OPTIONS "-DENABLE_AVDECC_FEATURE_REDUNDANCY")
Expand Down
125 changes: 125 additions & 0 deletions src/protocolInterface/cobsSerialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2011, Jacques Fortier
*
* 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 <stdexcept>

#include "cobsSerialization.hpp"

namespace la
{
namespace avdecc
{
namespace protocol
{
namespace cobs
{

/**
* COBS encodes a message
* @param input [in] pointer to the raw message
* @param input_length [in] the length of the raw message
* @param output [out] pointer to the output encode buffer
* @return the number of bytes written to "output".
*/
std::size_t encode(const std::uint8_t* input, std::size_t input_length, std::uint8_t* output) noexcept
{
std::size_t read_index = 0, write_index = 1;
std::size_t code_index = 0;
std::uint8_t code = 1;

while (read_index < input_length)
{
if (input[read_index] == 0)
{
output[code_index] = code;
code = 1;
code_index = write_index++;
read_index++;
}
else
{
output[write_index++] = input[read_index++];
code++;
if (code == 0xFF)
{
output[code_index] = code;
code = 1;
code_index = write_index++;
}
}
}

output[code_index] = code;

return write_index;
}

/**
* Decodes a COBS encoded message
* @param input [in] pointer to the COBS encoded message
* @param input_length [in] the length of the COBS encoded message
* @param output [in] pointer to the decode buffer
* @param output_length [in] length of the decode buffer
* @return the number of bytes written to "output" if "input" was successfully
* unstuffed, and 0 if there was an error unstuffing "input".
*/
std::size_t decode(const std::uint8_t* input, std::size_t input_length, std::uint8_t* output, std::size_t output_length)
{
std::size_t read_index = 0, write_index = 0;
std::uint8_t code, i;

while (read_index < input_length)
{
code = input[read_index];

if (read_index + code > input_length && code != 1)
{
return 0;
}

read_index++;

for (i = 1; i < code; i++)
{
if (write_index == output_length)
{
throw std::invalid_argument("Not enough room to decode");
}
output[write_index++] = input[read_index++];
}
if (code != 0xFF && read_index != input_length)
{
if (write_index == output_length)
{
throw std::invalid_argument("Not enough room to decode");
}
output[write_index++] = '\0';
}
}

return write_index;
}

} // namespace cobs
} // namespace protocol
} // namespace avdecc
} // namespace la
70 changes: 70 additions & 0 deletions src/protocolInterface/cobsSerialization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2011, Jacques Fortier
*
* 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 <cstddef>

namespace la
{
namespace avdecc
{
namespace protocol
{
namespace cobs
{
/**
* Delimiter byte to frame COBS encoded data
*/
static constexpr std::uint8_t DelimiterByte = 0;

/**
* Macro to calculate the maximum number of COBS pad bytes with a given payload size 'n'
* @note Do not use this macro to determine the overhead resulting from a COBS encoding. Use the return value from \ref cobs_encode instead
*/
#define COBS_BUFFER_PAD(n) ((((n) + 254 - 1) & ~(254 - 1)) / 254)

/**
* COBS encodes a message
* @param input [in] pointer to the raw message
* @param input_length [in] the length of the raw message
* @param output [out] pointer to the output encode buffer
* @return the number of bytes written to "output".
*/
std::size_t encode(const std::uint8_t* input, std::size_t input_length, std::uint8_t* output) noexcept;

/**
* Decodes a COBS encoded message
* @param input [in] pointer to the COBS encoded message
* @param input_length [in] the length of the COBS encoded message
* @param output [in] pointer to the decode buffer
* @param output_length [in] length of the decode buffer
* @return the number of bytes written to "output" if "input" was successfully
* unstuffed, and 0 if there was an error unstuffing "input".
*/
std::size_t decode(const std::uint8_t* input, std::size_t input_length, std::uint8_t* output, std::size_t output_length);

} // namespace cobs
} // namespace protocol
} // namespace avdecc
} // namespace la
34 changes: 34 additions & 0 deletions src/protocolInterface/protocolInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
#ifdef HAVE_PROTOCOL_INTERFACE_VIRTUAL
# include "protocolInterface/protocolInterface_virtual.hpp"
#endif // HAVE_PROTOCOL_INTERFACE_VIRTUAL
#ifdef HAVE_PROTOCOL_INTERFACE_SERIAL
# include "protocolInterface/protocolInterface_serial.hpp"
#endif // HAVE_PROTOCOL_INTERFACE_SERIAL
#ifdef HAVE_PROTOCOL_INTERFACE_LOCAL
# include "protocolInterface/protocolInterface_local.hpp"
#endif // HAVE_PROTOCOL_INTERFACE_LOCAL

namespace la
{
Expand Down Expand Up @@ -196,6 +202,14 @@ ProtocolInterface* LA_AVDECC_CALL_CONVENTION ProtocolInterface::createRawProtoco
case Type::Virtual:
return ProtocolInterfaceVirtual::createRawProtocolInterfaceVirtual(networkInterfaceName, { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 } }, executorName);
#endif // HAVE_PROTOCOL_INTERFACE_VIRTUAL
#if defined(HAVE_PROTOCOL_INTERFACE_SERIAL)
case Type::Serial:
return ProtocolInterfaceSerial::createRawProtocolInterfaceSerial(networkInterfaceName, executorName);
#endif // HAVE_PROTOCOL_INTERFACE_SERIAL
#if defined(HAVE_PROTOCOL_INTERFACE_LOCAL)
case Type::Local:
return ProtocolInterfaceLocal::createRawProtocolInterfaceLocal(networkInterfaceName, executorName);
#endif // HAVE_PROTOCOL_INTERFACE_LOCAL
default:
break;
}
Expand All @@ -222,6 +236,10 @@ std::string LA_AVDECC_CALL_CONVENTION ProtocolInterface::typeToString(Type const
return "IEEE Std 1722.1 proxy";
case Type::Virtual:
return "Virtual interface";
case Type::Serial:
return "Serial port interface";
case Type::Local:
return "Local domain socket interface";
default:
return "Unknown protocol interface type";
}
Expand Down Expand Up @@ -264,6 +282,22 @@ ProtocolInterface::SupportedProtocolInterfaceTypes LA_AVDECC_CALL_CONVENTION Pro
s_supportedProtocolInterfaceTypes.set(Type::Virtual);
}
#endif // HAVE_PROTOCOL_INTERFACE_VIRTUAL

// Serial
#if defined(HAVE_PROTOCOL_INTERFACE_SERIAL)
if (protocol::ProtocolInterfaceSerial::isSupported())
{
s_supportedProtocolInterfaceTypes.set(Type::Serial);
}
#endif // HAVE_PROTOCOL_INTERFACE_SERIAL

// Local domain socket
#if defined(HAVE_PROTOCOL_INTERFACE_LOCAL)
if (protocol::ProtocolInterfaceLocal::isSupported())
{
s_supportedProtocolInterfaceTypes.set(Type::Local);
}
#endif // HAVE_PROTOCOL_INTERFACE_LOCAL
}

return s_supportedProtocolInterfaceTypes;
Expand Down
Loading