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

GVCP support #1357

Draft
wants to merge 79 commits into
base: dev
Choose a base branch
from
Draft

GVCP support #1357

wants to merge 79 commits into from

Conversation

tigercosmos
Copy link
Collaborator

@tigercosmos tigercosmos commented Apr 12, 2024

Per #1321

This PR supported the GVCP protocol, including the GVCP request and GVCP acknowledgment.

Also, the PR added the most common commands of GVCP: Discovery command, ForceIP command, Read register Command, and Write register command.

@tigercosmos tigercosmos requested a review from seladb as a code owner April 12, 2024 09:31
@tigercosmos tigercosmos marked this pull request as draft April 12, 2024 09:31
@egecetin egecetin added this to the Augest 2024 Release milestone Jun 5, 2024
Packet++/header/GvcpLayer.h Show resolved Hide resolved
Packet++/header/GvcpLayer.h Outdated Show resolved Hide resolved

GvcpCommand getCommand() const
{
return static_cast<GvcpCommand>(netToHost16(command));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a good practice to put this in the header file, I vote we don't forward declare and move the implementation to the cpp file

Comment on lines 118 to 123
GvcpRequestHeader() = default;

GvcpRequestHeader(GvcpFlag flag, GvcpCommand command, uint16_t dataSize, uint16_t requestId)
: flag(flag), command(hostToNet16(static_cast<uint16_t>(command))), dataSize(hostToNet16(dataSize)),
requestId(hostToNet16(requestId))
{}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need c'tors for a struct? 🤔

What we usually do is declare all properties as public and then we don't need c'tors.
These structs are internal to the GVCP layers classes and shouldn't be exposed outside, so it doesn't matter if their properties are public.

If you want you can move these structs as protected inside of the GVCP layer classes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a constructor for it because the byte order will change, and it's better to handle it by the constructor. In addition, GvcpRequestHeader is public in purpose here. Users are free to get the raw header if they want, so there is also a public function getGvcpHeader() in the layers. I don't think we should stop users from getting the header.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I mentioned it in some comments, but I'm not sure.... In my opinion there is no need to expose both getGvcpHeader() and getters/setters for each property, that will create a somewhat confusing API.

In older protocols we used to only expose the "raw header" (like getGvcpHeader()), but in newer protocols we usually expose getters and setters which I think provides a cleaner API. We also got feedback from users that they prefer the getters/setters over the "raw header"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let me not expose it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are under internal now

Packet++/header/GvcpLayer.h Outdated Show resolved Hide resolved
*/
GvcpCommand getCommand() const
{
return static_cast<GvcpCommand>(netToHost16(getGvcpHeader()->command));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do:

return getGvcpHeader()->getCommand();

* @param[in] data A pointer to the data including the header and the payload
* @param[in] dataSize The size of the data in bytes
*/
GvcpAcknowledgeLayer(const uint8_t* data, size_t dataSize);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: why do we need this c'tor if we have the c'tor below?

Comment on lines 426 to 429
GvcpAckHeader* getGvcpHeader() const
{
return reinterpret_cast<GvcpAckHeader*>(m_Data); // the header is at the beginning of the data
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: this method can be private/protected

*/
GvcpResponseStatus getStatus() const
{
return static_cast<GvcpResponseStatus>((netToHost16(getGvcpHeader()->status)));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should handle cases where getGvcpHeader()->status is an unexpected value and return GvcpResponseStatus::Unknown

*/
GvcpCommand getCommand() const
{
return static_cast<GvcpCommand>(netToHost16(getGvcpHeader()->command));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: we can do:

return getGvcpHeader()->getCommand();

@seladb
Copy link
Owner

seladb commented Oct 23, 2024

@tigercosmos a gentle reminder to address the PR comments ☝️

@tigercosmos
Copy link
Collaborator Author

@tigercosmos a gentle reminder to address the PR comments ☝️

Thanks. I will continue on this after October. Quite busy these days.


using GvcpFlag = uint8_t; // flag bits are specified by each command

/// @brief Gvcp command defines the command values and the corresponding acknowledge values
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. nit: let's use GVCP (capital letters) instead of Gvcp in the doxygen documentation (not in class names etc).
    Please search and replace other instances of Gvcp in this file and replace them too
  2. In order to keep the convention we have everywhere else, maybe use this format for doxygen comments?
    /**
     * comment...
     */

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure fixed.

Comment on lines 119 to 133
uint8_t magicNumber = internal::kGvcpMagicNumber; // always fixed
uint8_t flag = 0; // 0-3 bits are specified by each command, 4-6 bits are reserved, 7 bit is acknowledge
uint16_t command = 0;
uint16_t dataSize = 0;
uint16_t requestId = 0;

// ------------- methods --------------
gvcp_request_header() = default;

gvcp_request_header(GvcpFlag flag, GvcpCommand command, uint16_t dataSize, uint16_t requestId)
: flag(flag), command(hostToNet16(static_cast<uint16_t>(command))), dataSize(hostToNet16(dataSize)),
requestId(hostToNet16(requestId))
{}

GvcpCommand getCommand() const
Copy link
Owner

@seladb seladb Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to keep this struct and the other structs public, we should add doxygen documentation for each public member and public method.

If we move them to be private/protected then no doxygen documentation is needed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the struct is now under internal.


/// @brief GVCP response status can be returned in an acknowledge message or a GVSP header.
/// See more in the spec "Table 19-1: List of Standard Status Codes"
enum class GvcpResponseStatus : uint16_t
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enum has doxygen documentation for its values but GvcpCommand doesn't. I think we should be consistent - either we add doxygen to all values in all enums, or we don't...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some enums in the spec have explanations but some don't. I will add the comments for the enum values as long as the spec has the sentences for the values.

Comment on lines 88 to 91
LocalProblem = 0x8008, // deprecated
MsgMismatch = 0x8009, // deprecated
InvalidProtocol = 0x800A, // deprecated
NoMsg = 0x800B, // deprecated
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These // deprecated comments are not in the doxygen format so these values won't appear in the API documentation. We should change them to ///< deprecated.

Same for other // deprecated comments below

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Comment on lines 118 to 123
GvcpRequestHeader() = default;

GvcpRequestHeader(GvcpFlag flag, GvcpCommand command, uint16_t dataSize, uint16_t requestId)
: flag(flag), command(hostToNet16(static_cast<uint16_t>(command))), dataSize(hostToNet16(dataSize)),
requestId(hostToNet16(requestId))
{}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I mentioned it in some comments, but I'm not sure.... In my opinion there is no need to expose both getGvcpHeader() and getters/setters for each property, that will create a somewhat confusing API.

In older protocols we used to only expose the "raw header" (like getGvcpHeader()), but in newer protocols we usually expose getters and setters which I think provides a cleaner API. We also got feedback from users that they prefer the getters/setters over the "raw header"

@tigercosmos
Copy link
Collaborator Author

Still WIP, not ready yet.

@seladb
Copy link
Owner

seladb commented Nov 26, 2024

Still WIP, not ready yet.

@tigercosmos maybe you can move the PR to draft until it's ready?

@tigercosmos tigercosmos marked this pull request as draft November 26, 2024 08:31
@tigercosmos
Copy link
Collaborator Author

Ops, I didn't notice this. Changed.

/*
* GVCP protocol
*/
const ProtocolType GVCP = 57;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Protocol number 57 is already taken by GTPv2.

{
namespace internal
{
std::unordered_set<GvcpCommand> gvcpCommandSet = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I could see, gvcpCommandSet is only used in the current file.
It would be better to change the symbol to use internal linkage, rather than external, as it is not declared in GvcpLayer.h.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Also maybe have the set as const?

pcpp::MacAddress getMacAddress() const
{
auto body = this->getGvcpDiscoveryBody();
return pcpp::MacAddress(body->macAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do we need the pcpp namespace qualification here?

pcpp::IPv4Address getIpAddress() const
{
auto body = this->getGvcpDiscoveryBody();
return pcpp::IPv4Address(body->ipAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::IPv4Address getSubnetMask() const
{
auto body = this->getGvcpDiscoveryBody();
return pcpp::IPv4Address(body->subnetMask);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::IPv4Address getGatewayIpAddress() const
{
auto body = this->getGvcpDiscoveryBody();
return pcpp::IPv4Address(body->defaultGateway);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::MacAddress getMacAddress() const
{
auto body = this->getGvcpForceIpBody();
return pcpp::MacAddress(reinterpret_cast<const uint8_t*>(body->macAddress));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::IPv4Address getIpAddress() const
{
auto body = this->getGvcpForceIpBody();
return pcpp::IPv4Address(body->ipAddress);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::IPv4Address getSubnetMask() const
{
auto body = this->getGvcpForceIpBody();
return pcpp::IPv4Address(body->subnetMask);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

pcpp::IPv4Address getGatewayIpAddress() const
{
auto body = this->getGvcpForceIpBody();
return pcpp::IPv4Address(body->gateway);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, ditto: namespace qualification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce GigE Vision Control Protocol (GVCP) protocol
4 participants