/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * Ola.proto
 * Defines the protocol buffers used to talk to olad
 * Copyright (C) 2005 Simon Newton
 */

package ola.proto;

option cc_generic_services = false;
option py_generic_services = true;
option java_generic_services = true;

enum RegisterAction {
  REGISTER = 1;
  UNREGISTER = 2;
}

enum PatchAction {
  PATCH = 1;
  UNPATCH = 2;
}

enum MergeMode {
  HTP = 1;
  LTP = 2;
}

/**
 * Please see the note below about getting a new Plugin ID.
 */
enum PluginIds {
  OLA_PLUGIN_ALL = 0;
  OLA_PLUGIN_DUMMY = 1;
  OLA_PLUGIN_ARTNET = 2;
  OLA_PLUGIN_SHOWNET = 3;
  OLA_PLUGIN_ESPNET = 4;
  OLA_PLUGIN_USBPRO = 5;
  OLA_PLUGIN_OPENDMX = 6;
  OLA_PLUGIN_SANDNET = 7;
  OLA_PLUGIN_STAGEPROFI = 8;
  OLA_PLUGIN_PATHPORT = 9;
  OLA_PLUGIN_DMX4LINUX = 10;
  OLA_PLUGIN_E131 = 11;
  OLA_PLUGIN_USBDMX = 12;
  OLA_PLUGIN_FTDIDMX = 13;
  OLA_PLUGIN_OSC = 14;
  OLA_PLUGIN_SPI = 15;
  OLA_PLUGIN_KINET = 16;
  OLA_PLUGIN_KARATE = 17;
  OLA_PLUGIN_MILINST = 18;
  OLA_PLUGIN_RENARD = 19;
  OLA_PLUGIN_UARTDMX = 20;
  OLA_PLUGIN_OPENPIXELCONTROL = 21;
  OLA_PLUGIN_GPIO = 22;

  /*
   * To obtain a new plugin ID, open a ticket at
   * https://github.com/OpenLightingProject/ola/issues/new
   * Plugin IDs are usually assigned just prior to merging the code into the
   * mainline. For development of plugins please use the value of
   * OLA_PLUGIN_EXPERIMENTAL in a plugin ID you define above.
   */
  OLA_PLUGIN_EXPERIMENTAL = 10000;
}

/**
 * If you add more here be sure to update ResponseCodeToString in RDMHelper.cpp
 */
enum RDMResponseCode {
  // The request/response completed correctly
  RDM_COMPLETED_OK = 0;
  // The request was broadcast, no response expected
  RDM_WAS_BROADCAST = 1;
  // We failed to send this request
  RDM_FAILED_TO_SEND = 2;
  // The response timed out
  RDM_TIMEOUT = 3;
  // The response was invalid
  RDM_INVALID_RESPONSE = 4;
  // The UID could not be located (may have been removed)
  RDM_UNKNOWN_UID = 5;
  // The response checksum was wrong
  RDM_CHECKSUM_INCORRECT = 6;
  // Invalid transaction number
  RDM_TRANSACTION_MISMATCH = 7;
  // Wrong sub device
  RDM_SUB_DEVICE_MISMATCH = 8;
  //Source UID in response doesn't match
  RDM_SRC_UID_MISMATCH = 9;
  //Destination UID in response doesn't match
  RDM_DEST_UID_MISMATCH = 10;
  //Incorrect sub start code
  RDM_WRONG_SUB_START_CODE = 11;
  //RDM response was smaller than the minimum size
  RDM_PACKET_TOO_SHORT = 12;
  //The length field of packet didn't match length received
  RDM_PACKET_LENGTH_MISMATCH = 13;
  //The parameter length exceeds the remaining packet size
  RDM_PARAM_LENGTH_MISMATCH = 14;
  //The command class was not one of GET_RESPONSE or SET_RESPONSE
  RDM_INVALID_COMMAND_CLASS = 15;
  //The command class didn't match the request
  RDM_COMMAND_CLASS_MISMATCH = 16;
  //The response type was not ACK, ACK_OVERFLOW, ACK_TIMER or NACK
  RDM_INVALID_RESPONSE_TYPE = 17;
  // The discovery command class is not supported by this device. This
  // typically means the hardware doesn't support discovery commands.
  RDM_PLUGIN_DISCOVERY_NOT_SUPPORTED = 18;
  // Responses to DUB commands, these responses won't have a defined RDM
  // message, but rather just a string of bytes from the wire.
  RDM_DUB_RESPONSE = 19;
}


/**
 * The valid Response Types when the response_code is RDM_COMPLETED_OK.
 * ACK_OVERFLOW isn't in this list because overflows are handed by the plugins,
 * not the clients.
 */
enum RDMResponseType {
  RDM_ACK = 0;
  RDM_ACK_TIMER = 1;
  RDM_NACK_REASON = 2;
  // OVERFLOW can never be returned
}


/**
 * The RDM command class
 */
enum RDMCommandClass {
  RDM_GET_RESPONSE = 0;
  RDM_SET_RESPONSE = 1;
  RDM_DISCOVERY_RESPONSE = 2;
}


// This is a special string which indicates that no response will be received
// for an RPC.
message STREAMING_NO_RESPONSE {}

// Generic Ack Message
message Ack {}

// request the list of available plugins
message PluginListRequest {}

// Trigger a plugin reload.
message PluginReloadRequest {}

message PluginInfo {
  required int32 plugin_id = 1;
  required string name = 2;
  required bool active = 3;
  optional bool enabled = 4;
}

message PluginListReply {
  repeated PluginInfo plugin = 1;
}

// request the description for a plugin
message PluginDescriptionRequest {
  required int32 plugin_id = 1;
}

message PluginDescriptionReply {
  required string name = 1;
  required string description = 2;
}

// request the state for a plugin
message PluginStateRequest {
  required int32 plugin_id = 1;
}

message PluginStateReply {
  required string name = 1;
  required bool enabled = 2;
  required bool active = 3;
  required string preferences_source = 4;
  repeated PluginInfo conflicts_with = 5;
}

message PluginStateChangeRequest {
  required int32 plugin_id = 1;
  required bool enabled = 2;
}

// request info on a device
message DeviceInfoRequest {
  optional int32 plugin_id = 1;
}

message PortInfo {
  required int32 port_id = 1;
  required int32 priority_capability = 2;
  required string description = 5;
  optional int32 universe = 3;
  optional bool active = 4;
  optional int32 priority_mode = 6;
  optional int32 priority = 7;
  optional bool supports_rdm = 8 [default = false];
}

message DeviceInfo {
  required int32 device_alias = 1;
  required int32 plugin_id = 2;
  required string device_name = 3;
  repeated PortInfo input_port = 4;
  repeated PortInfo output_port = 5;
  required string device_id = 6;
}

message DeviceInfoReply {
  repeated DeviceInfo device = 1;
}

message DmxData {
  required int32 universe = 1;
  required bytes data = 2;
  optional int32 priority = 3;
}

message RegisterDmxRequest {
  required int32 universe = 1;
  required RegisterAction action = 2;
}

message PatchPortRequest {
  required int32 universe = 1;
  required int32 device_alias = 2;
  required int32 port_id = 3;
  required PatchAction action = 4;
  required bool is_output = 5;
}

message UniverseNameRequest {
  required int32 universe = 1;
  required string name = 2;
}

message MergeModeRequest {
  required int32 universe = 1;
  required MergeMode merge_mode = 2;
}

// request info about a universe
message OptionalUniverseRequest {
  optional int32 universe = 1;
}

message UniverseInfo {
  required int32 universe = 1;
  required string name = 2;
  required MergeMode merge_mode = 3;
  required int32 input_port_count = 4;
  required int32 output_port_count = 5;
  required int32 rdm_devices = 6;
  repeated PortInfo input_ports = 7;
  repeated PortInfo output_ports = 8;
}

message UniverseInfoReply {
  repeated UniverseInfo universe = 1;
}

message PortPriorityRequest {
  required int32 device_alias = 1;
  required bool is_output = 2;
  required int32 port_id = 3;
  required int32 priority_mode = 4;
  optional int32 priority = 5;
}

// a device config request
message DeviceConfigRequest {
  required int32 device_alias = 1;
  required bytes data = 2;
}

message DeviceConfigReply {
  required bytes data = 1;
}

// RDM Messages
// This represents a UID
message UID {
  required int32 esta_id = 1;  // only lower 2 bytes are used
  required fixed32 device_id = 2;
}

// Request the UID list for a universe
message UniverseRequest {
  required int32 universe = 1;
}

message DiscoveryRequest {
  required int32 universe = 1;
  required bool full = 2;
}

message UIDListReply {
  required int32 universe = 1;
  repeated UID uid = 2;
}

message RDMRequestOverrideOptions {
  optional uint32 sub_start_code = 1;
  optional uint32 message_length = 2;
  optional uint32 message_count = 3;
  optional uint32 checksum = 4;
}

message RDMRequest {
  required int32 universe = 1;
  required UID uid = 2;
  required int32 sub_device = 3;
  required int32 param_id = 4;
  required bytes data = 5; // 0 - 231 bytes
  required bool is_set = 6;
  optional bool include_raw_response = 7 [default = false];
  optional RDMRequestOverrideOptions options = 8;
}

message RDMDiscoveryRequest {
  required int32 universe = 1;
  required UID uid = 2;
  required int32 sub_device = 3;
  required int32 param_id = 4;
  required bytes data = 5; // 0 - 231 bytes
  optional bool include_raw_response = 6 [default = false];
  optional RDMRequestOverrideOptions options = 8;
}

message RDMFrameTiming {
  optional int32 response_delay = 1;
  optional int32 break_time = 2;
  optional int32 mark_time = 3;
  optional int32 data_time = 4;
}

message RDMFrame {
  optional bytes raw_response = 1;
  optional RDMFrameTiming timing = 2;
}

message RDMResponse {
  required RDMResponseCode response_code = 1;
  optional UID source_uid = 9;
  optional UID dest_uid = 10;
  optional int32 transaction_number = 11;

  // ACK, NACK or TIMER
  optional RDMResponseType response_type = 2;
  optional uint32 message_count = 3 [default = 0];
  optional uint32 sub_device = 7; // the sub device
  optional RDMCommandClass command_class = 6; // the command class
  optional uint32 param_id = 5;  // the param id, required for queued messages
  optional bytes data = 4 [default = ""]; // 0 - 231 bytes
  repeated bytes raw_response = 8;  // deprecated
  repeated RDMFrame raw_frame = 12;
}


// timecode

enum TimeCodeType {
  TIMECODE_FILM = 0;   // 24fps
  TIMECODE_EBU = 1;    // 25fps
  TIMECODE_DF = 2;     // 29.97fps
  TIMECODE_SMPTE = 3;  // 30fps
};

message TimeCode {
  required uint32 hours = 1;
  required uint32 minutes = 2;
  required uint32 seconds = 3;
  required uint32 frames = 4;
  required TimeCodeType type = 5;
}

// Services

// RPCs handled by the OLA Server
service OlaServerService {
  rpc GetPlugins (PluginListRequest) returns (PluginListReply);
  rpc ReloadPlugins (PluginReloadRequest) returns (Ack);
  rpc GetPluginDescription (PluginDescriptionRequest) returns
    (PluginDescriptionReply);
  rpc GetPluginState (PluginStateRequest) returns (PluginStateReply);
  rpc GetDeviceInfo (DeviceInfoRequest) returns (DeviceInfoReply);
  rpc GetCandidatePorts (OptionalUniverseRequest) returns (DeviceInfoReply);
  rpc ConfigureDevice (DeviceConfigRequest) returns (DeviceConfigReply);
  rpc SetPluginState (PluginStateChangeRequest) returns (Ack);
  rpc SetPortPriority (PortPriorityRequest) returns (Ack);
  rpc GetUniverseInfo (OptionalUniverseRequest) returns (UniverseInfoReply);
  rpc SetUniverseName (UniverseNameRequest) returns (Ack);
  rpc SetMergeMode (MergeModeRequest) returns (Ack);
  rpc PatchPort (PatchPortRequest) returns (Ack);
  rpc RegisterForDmx (RegisterDmxRequest) returns (Ack);
  rpc UpdateDmxData (DmxData) returns (Ack);
  rpc GetDmx (UniverseRequest) returns (DmxData);
  rpc GetUIDs (UniverseRequest) returns (UIDListReply);
  rpc ForceDiscovery (DiscoveryRequest) returns (UIDListReply);
  rpc SetSourceUID (UID) returns (Ack);

  rpc RDMCommand (RDMRequest) returns (RDMResponse);
  rpc RDMDiscoveryCommand (RDMDiscoveryRequest) returns (RDMResponse);
  rpc StreamDmxData (DmxData) returns (STREAMING_NO_RESPONSE);

  // timecode
  rpc SendTimeCode(TimeCode) returns (Ack);
}

// RPCs handled by the OLA Client
service OlaClientService {
  rpc UpdateDmxData (DmxData) returns (Ack);
}
