/*
  rdmnet.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/rdm.h"

namespace RDMnet {
  using RDM::PID;

  /// Appendix A: Defined Parameters (Normative)
// MDNS_IPV4_MULTICAST_ADDRESS 224.0.0.251 (Informative)
// MDNS_IPV6_MULTICAST_ADDRESS ff02::fb (Informative)
  static const uint16_t MDNS_PORT                   = 5353;   //!< (Informative)
  static const char*    E133_DNSSD_PRI_SRV_TYPE     = "_rdmnet._tcp";
  static const char*    E133_DEFAULT_SCOPE          = "default";
  static const char*    E133_DEFAULT_DOMAIN         = "local.";
  static const uint8_t  E133_DNSSD_TXTVERS          = 1;
  static const uint8_t  E133_TCP_HEARTBEAT_INTERVAL = 15;     //!< seconds
  static const uint8_t  E133_HEARTBEAT_TIMEOUT      = 45;     //!< seconds
  static const uint8_t  E133_VERSION                = 1;
  static const uint16_t NULL_ENDPOINT               = 0x0000;
  static const uint16_t BROADCAST_ENDPOINT          = 0xFFFF;

  /// A.1 Broadcast UID Defines
  static const uint64_t RPT_ALL_CONTROLLERS = 0xFFFCFFFFFFFF;
  static const uint64_t RPT_ALL_DEVICES     = 0xFFFDFFFFFFFF;
//  RPT_ALL_MID_DEVICES 0xFFFDmmmmFFFF Addresses all Devices with the specific
//                                     Manufacturer ID 0xmmmm

  /// A.2 LLRP Constants
//  LLRP_MULTICAST_IPV4_ADDRESS_REQUEST = 239.255.250.133;
//  LLRP_MULTICAST_IPV4_ADDRESS_RESPONSE = 239.255.250.134;
//  LLRP_MULTICAST_IPV6_ADDRESS_REQUEST = ff18::85:0:0:85;
//  LLRP_MULTICAST_IPV6_ADDRESS_RESPONSE = ff18::85:0:0:86;
  static const uint16_t   LLRP_PORT           = 5569;
  static const uint8_t    LLRP_TIMEOUT        = 2;    //!< seconds
  static const uint16_t   LLRP_TARGET_TIMEOUT = 500;  //!< milliseconds
  static const double     LLRP_MAX_BACKOFF    = 1.5;  //!< seconds
  static const uint8_t    LLRP_KNOWN_UID_SIZE = 200;
  static const char*      LLRP_BROADCAST_CID  = "FBAD822C-BD0C-4D4C-BDC8-7EABEBC85AFF";

  /// A.3 Root Layer PDU Vector
  static const uint32_t VECTOR_ROOT_LLRP    = 0x0000000A; //!< Section 5.4
  static const uint32_t VECTOR_ROOT_RPT     = 0x00000005; //!< Section 7.5
  static const uint32_t VECTOR_ROOT_BROKER  = 0x00000009; //!< Section 6.3.1
  static const uint32_t VECTOR_ROOT_EPT     = 0x0000000B; //!< Section 8.3

  /// A.4 LLRP PDU Vector
  static const uint32_t VECTOR_LLRP_PROBE_REQUEST = 0x00000001; //!< Section 5.4.2.1
  static const uint32_t VECTOR_LLRP_PROBE_REPLY   = 0x00000002; //!< Section 5.4.2.2
  static const uint32_t VECTOR_LLRP_RDM_CMD       = 0x00000003; //!< Section 5.4.2.3

  /// A.5 LLRP Probe Request PDU Vector
  static const uint8_t VECTOR_PROBE_REQUEST_DATA = 0x01; //!< Section 5.4.2.1

  /// A.6 LLRP Probe Reply PDU Vector
  static const uint8_t VECTOR_PROBE_REPLY_DATA   = 0x01; //!< Section 5.4.2.2

  /// A.7 Broker PDU Vector
  static const uint16_t VECTOR_BROKER_CONNECT                = 0x0001; //!< Section 6.3.1.2
  static const uint16_t VECTOR_BROKER_CONNECT_REPLY          = 0x0002; //!< Section 6.3.1.3
  static const uint16_t VECTOR_BROKER_CLIENT_ENTRY_UPDATE    = 0x0003; //!< Section 6.3.1.4
  static const uint16_t VECTOR_BROKER_REDIRECT_V4            = 0x0004; //!< Section 6.3.1.5
  static const uint16_t VECTOR_BROKER_REDIRECT_V6            = 0x0005; //!< Section 6.3.1.6
  static const uint16_t VECTOR_BROKER_FETCH_CLIENT_LIST      = 0x0006; //!< Section 6.3.1.7
  static const uint16_t VECTOR_BROKER_CONNECTED_CLIENT_LIST  = 0x0007; //!< Section 6.3.1.8
  static const uint16_t VECTOR_BROKER_CLIENT_ADD             = 0x0008; //!< Section 6.3.1.9
  static const uint16_t VECTOR_BROKER_CLIENT_REMOVE          = 0x0009; //!< Section 6.3.1.10
  static const uint16_t VECTOR_BROKER_CLIENT_ENTRY_CHANGE    = 0x000A; //!< Section 6.3.1.11
  static const uint16_t VECTOR_BROKER_REQUEST_DYNAMIC_UIDS   = 0x000B; //!< Section 6.3.1.12
  static const uint16_t VECTOR_BROKER_ASSIGNED_DYNAMIC_UIDS  = 0x000C; //!< Section 6.3.1.13
  static const uint16_t VECTOR_BROKER_FETCH_DYNAMIC_UID_LIST = 0x000D; //!< Section 6.3.1.14
  static const uint16_t VECTOR_BROKER_DISCONNECT             = 0x000E; //!< Section 6.3.1.15
  static const uint16_t VECTOR_BROKER_NULL                   = 0x000F; //!< Section 6.3.1.16

  /// A.8 RPT PDU Vector
  static const uint32_t VECTOR_RPT_REQUEST      = 0x00000001; //!< Section 7.5.2
  static const uint32_t VECTOR_RPT_STATUS       = 0x00000002; //!< Section 7.5.3
  static const uint32_t VECTOR_RPT_NOTIFICATION = 0x00000003; //!< Section 7.5.4

  /// A.9 RPT Request Vector
  static const uint8_t  VECTOR_REQUEST_RDM_CMD = 0x01; //!< Section 7.5.2

  /// A.10 RPT Status PDU Vector
  static const uint16_t VECTOR_RPT_STATUS_UNKNOWN_RPT_UID       = 0x0001; //!< Section 7.5.3.2
  static const uint16_t VECTOR_RPT_STATUS_RDM_TIMEOUT           = 0x0002; //!< Section 7.5.3.3
  static const uint16_t VECTOR_RPT_STATUS_RDM_INVALID_RESPONSE  = 0x0003; //!< Section 7.5.3.4
  static const uint16_t VECTOR_RPT_STATUS_UNKNOWN_RDM_UID       = 0x0004; //!< Section 7.5.3.5
  static const uint16_t VECTOR_RPT_STATUS_UNKNOWN_ENDPOINT      = 0x0005; //!< Section 7.5.3.6
  static const uint16_t VECTOR_RPT_STATUS_BROADCAST_COMPLETE    = 0x0006; //!< Section 7.5.3.7
  static const uint16_t VECTOR_RPT_STATUS_UNKNOWN_VECTOR        = 0x0007; //!< Section 7.5.3.8
  static const uint16_t VECTOR_RPT_STATUS_INVALID_MESSAGE       = 0x0008; //!< Section 7.5.3.9
  static const uint16_t VECTOR_RPT_STATUS_INVALID_COMMAND_CLASS = 0x0009; //!< Section 7.5.3.10

  /// A.11 Notification PDU Vector
  static const uint8_t  VECTOR_NOTIFICATION_RDM_CMD = 0x01; //!< Section 7.5.4

  /// A.12 RDM Command PDU Vector
  static const uint8_t  VECTOR_RDM_CMD_RDM_DATA     = 0xCC; //!< Section 7.5.5

  /// A.13 EPT PDU Vector
  static const uint32_t VECTOR_EPT_DATA       = 0x00000001; //!< Section 8.3.3
  static const uint32_t VECTOR_EPT_STATUS     = 0x00000002; //!< Section 8.3.4

  /// A.14 EPT Status PDU Vector
  static const uint16_t VECTOR_EPT_STATUS_UNKNOWN_CID    = 0x0001; //!< Section 8.3.4.2
  static const uint16_t VECTOR_EPT_STATUS_UNKNOWN_VECTOR = 0x0002; //!< Section 8.3.4.3

  /// A.15 RDM Parameter ID
  static const PID COMPONENT_SCOPE   = 0x0800; //!<  B/C/D
  static const PID SEARCH_DOMAIN     = 0x0801; //!<  C/D
  static const PID TCP_COMMS_STATUS  = 0x0802; //!<  C/D
  static const PID BROKER_STATUS     = 0x0803; //!<  B

  /// A.16 Additional Response NACK Reason Codes
  static const uint16_t NR_ACTION_NOT_SUPPORTED       = 0x000B; //!< The specified action is not supported.
  static const uint16_t NR_UNKNOWN_SCOPE              = 0x000F; //!< The Component is not participating in the given Scope.
  static const uint16_t NR_INVALID_STATIC_CONFIG_TYPE = 0x0010; //!< The Static Config Type provided is invalid.
  static const uint16_t NR_INVALID_IPV4_ADDRESS       = 0x0011; //!< The IPv4 Address provided is invalid.
  static const uint16_t NR_INVALID_IPV6_ADDRESS       = 0x0012; //!< The IPv6 Address provided is invalid.
  static const uint16_t NR_INVALID_PORT               = 0x0013; //!< The transport layer port provided is invalid.

  /// A.17 Static Config Type for COMPONENT_SCOPE Parameter Message
  static const uint8_t NO_STATIC_CONFIG   = 0x00; //!< No Broker Static Configuration is present; the Client shall locate a Broker via DNS-SD.
  static const uint8_t STATIC_CONFIG_IPV4 = 0x01; //!< A Static Configuration exists for locating a Broker via IPv4.
  static const uint8_t STATIC_CONFIG_IPV6 = 0x02; //!< A Static Configuration exists for locating a Broker via IPv6.

  /// A.18 Broker State Definitions for BROKER_STATUS Parameter Message
  static const uint8_t BROKER_DISABLED = 0x00; //!< The Broker has been disabled through either a SET: BROKER_STATUS command or some implementation-defined method.
  static const uint8_t BROKER_ACTIVE   = 0x01; //!< The Broker is running normally and has successfully registered its DNS-SD subtype.
  static const uint8_t BROKER_STANDBY  = 0x02; //!< The Broker has detected another Broker registered with its scope and is waiting for this condition to be resolved before continuing operation.

  /// A.19 Connection Status Codes for Broker Connect
  static const uint16_t CONNECT_OK                   = 0x0000; //!< Section 9.1.5
  static const uint16_t CONNECT_SCOPE_MISMATCH       = 0x0001; //!< Section 9.1.5
  static const uint16_t CONNECT_CAPACITY_EXCEEDED    = 0x0002; //!< Section 9.1.5
  static const uint16_t CONNECT_DUPLICATE_UID        = 0x0003; //!< Section 9.1.5
  static const uint16_t CONNECT_INVALID_CLIENT_ENTRY = 0x0004; //!< Section 9.1.5
  static const uint16_t CONNECT_INVALID_UID          = 0x0005; //!< Section 9.1.5

  /// A.20 Status Codes for Dynamic UID Mapping
  static const uint16_t DYNAMIC_UID_STATUS_OK                 = 0x0000; //!< The Dynamic UID Mapping was fetched or assigned successfully.
  static const uint16_t DYNAMIC_UID_STATUS_INVALID_REQUEST    = 0x0001; //!< The corresponding request contained a malformed UID value.
  static const uint16_t DYNAMIC_UID_STATUS_UID_NOT_FOUND      = 0x0002; //!< The requested Dynamic UID was not found in the Broker's Dynamic UID mapping table.
  static const uint16_t DYNAMIC_UID_STATUS_DUPLICATE_RID      = 0x0003; //!< This RID has already been assigned a Dynamic UID by this Broker.
  static const uint16_t DYNAMIC_UID_STATUS_CAPACITY_EXHAUSTED = 0x0004; //!< The Broker has exhausted its capacity to generate Dynamic UIDs.

  /// A.21 Client Protocol Codes
  static const uint32_t CLIENT_PROTOCOL_RPT = 0x00000005; //!< Section 6.3.2
  static const uint32_t CLIENT_PROTOCOL_EPT = 0x0000000B; //!< Section 6.3.2

  /// A.22 RPT Client Type Codes
  static const uint8_t RPT_CLIENT_TYPE_DEVICE     = 0x00; //!< Section 6.3.2.2
  static const uint8_t RPT_CLIENT_TYPE_CONTROLLER = 0x01; //!< Section 6.3.2.2

  /// A.23 LLRP Component Type Codes
  static const uint8_t LLRP_COMPONENT_TYPE_RPT_DEVICE     = 0x00; //!< The LLRP Target is a Device
  static const uint8_t LLRP_COMPONENT_TYPE_RPT_CONTROLLER = 0x01; //!< The LLRP Target is a Controller
  static const uint8_t LLRP_COMPONENT_TYPE_BROKER         = 0x02; //!< The LLRP Target is a Broker
  static const uint8_t LLRP_COMPONENT_TYPE_NON_RDMNET     = 0xFF; //!< The LLRP Target does not implement any RDMnet protocol other than LLRP

  /// A.24 Client Disconnect Reason Codes
  static const uint16_t DISCONNECT_SHUTDOWN           = 0x0000; //!< Comment Sent by Components to indicate that they are about to shut down.
  static const uint16_t DISCONNECT_CAPACITY_EXHAUSTED = 0x0001; //!< Sent by Components when they do not have the ability to support this connection. Note that a Component must reserve certain resources to be able to send this message when it is in such a state.
  static const uint16_t DISCONNECT_HARDWARE_FAULT     = 0x0002; //!< Sent by Components which must terminate a connection due to an internal hardware fault.
  static const uint16_t DISCONNECT_SOFTWARE_FAULT     = 0x0003; //!< Sent by Components which must terminate a connection due to a software fault.
  static const uint16_t DISCONNECT_SOFTWARE_RESET     = 0x0004; //!< Sent by Components which must terminate a connection because of a software reset. This message should not be sent in the case of a reboot, as the Shutdown message is preferred.
  static const uint16_t DISCONNECT_INCORRECT_SCOPE    = 0x0005; //!< Sent by Brokers that are not on the desired Scope.
  static const uint16_t DISCONNECT_RPT_RECONFIGURE    = 0x0006; //!< Sent by Components which must terminate a connection because they were reconfigured using RPT.
  static const uint16_t DISCONNECT_LLRP_RECONFIGURE   = 0x0007; //!< Sent by Components which must terminate a connection because they were reconfigured using LLRP.
  static const uint16_t DISCONNECT_USER_RECONFIGURE   = 0x0008; //!< Sent by Components which must terminate a connection because they were reconfigured through some means outside the scope of this standard (i.e. front panel configuration)

} // namespace RDMnet
