syntax = "proto3";

package gw;

option go_package = "github.com/chirpstack/chirpstack-api/go/v4/gw";
option java_package = "io.chirpstack.api.gw";
option java_multiple_files = true;
option java_outer_classname = "GatewayProto";

import "chirpstack-api/common/common.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";


enum DownlinkTiming {
    // Send the downlink immediately.
    IMMEDIATELY = 0;

    // Send downlink at the given delay (based on provided context).
    DELAY = 1;

    // Send at given GPS epoch value.
    GPS_EPOCH = 2;
}


enum FineTimestampType {
    // No fine-timestamp available.
    NONE = 0;

    // Encrypted fine-timestamp.
    ENCRYPTED = 1;

    // Plain fine-timestamp.
    PLAIN = 2;
}

enum CRCStatus {
    // No CRC.
    NO_CRC = 0;

    // Bad CRC.
    BAD_CRC = 1;

    // CRC OK.
    CRC_OK = 2;
}

enum TxAckStatus {
    // Ignored (when a previous item was already emitted).
    IGNORED = 0;

    // Packet has been programmed for downlink.
    OK = 1;

    // Rejected because it was already too late to program this packet for downlink.
    TOO_LATE = 2;

    // Rejected because downlink packet timestamp is too much in advance.
    TOO_EARLY = 3;

    // Rejected because there was already a packet programmed in requested timeframe.
    COLLISION_PACKET = 4;

    // Rejected because there was already a beacon planned in requested timeframe.
    COLLISION_BEACON = 5;

    // Rejected because requested frequency is not supported by TX RF chain.
    TX_FREQ = 6;

    // Rejected because requested power is not supported by gateway.
    TX_POWER = 7;

    // Rejected because GPS is unlocked, so GPS timestamp cannot be used.
    GPS_UNLOCKED = 8;

    // Downlink queue is full.
    QUEUE_FULL = 9;

    // Internal error.
    INTERNAL_ERROR = 10;
}

message Modulation {
    oneof parameters {
        // LoRa modulation information.
        LoRaModulationInfo lora = 3 [json_name = "loRa"];

        // FSK modulation information.
        FSKModulationInfo fsk = 4;

        // LR-FHSS modulation information.
        LRFHSSModulationInfo lr_fhss = 5 [json_name = "lrFHSS"];
    }
}

message UplinkTXInfo {
    // Frequency (Hz).
    uint32 frequency = 1;

    // Modulation.
    common.Modulation modulation = 2;

    oneof modulation_info {
        // LoRa modulation information.
        LoRaModulationInfo lora_modulation_info = 3 [json_name = "loRaModulationInfo"];

        // FSK modulation information.
        FSKModulationInfo fsk_modulation_info = 4;

        // LR-FHSS modulation information.
        LRFHSSModulationInfo lr_fhss_modulation_info = 5 [json_name = "lrFHSSModulationInfo"];
    }
}

message LoRaModulationInfo {
    // Bandwidth.
    uint32 bandwidth = 1;

    // Speading-factor.
    uint32 spreading_factor = 2;

    // Code-rate.
    string code_rate = 3;

    // Polarization inversion.
    bool polarization_inversion = 4;
}

message FSKModulationInfo {
    // Frequency deviation.
    uint32 frequency_deviation = 1;

    // FSK datarate (bits / sec).
    uint32 datarate = 2;
}

message LRFHSSModulationInfo {
    // Operating channel width (OCW) in Hz.
    uint32 operating_channel_width = 1;

    // Code-rate.
    string code_rate = 2;

    // Hopping grid number of steps.
    uint32 grid_steps = 3;
}

message EncryptedFineTimestamp {
    // AES key index used for encrypting the fine timestamp.
    uint32 aes_key_index = 1;

    // Encrypted 'main' fine-timestamp (ns precision part of the timestamp).
    bytes encrypted_ns = 2 [json_name = "encryptedNS"];

    // FPGA ID.
    bytes fpga_id = 3 [json_name = "fpgaID"];
}

message PlainFineTimestamp {
    // Full timestamp.
    google.protobuf.Timestamp time = 1;
}

message GatewayStats {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Gateway IP.
    string ip = 9;

    // Gateway time.
    google.protobuf.Timestamp time = 2;

    // Gateway location.
    common.Location location = 3;

    // Gateway configuration version (this maps to the config_version sent
    // by LoRa Server to the gateway).
    string config_version = 4;

    // Number of radio packets received.
    uint32 rx_packets_received = 5;

    // Number of radio packets received with valid PHY CRC.
    uint32 rx_packets_received_ok = 6 [json_name = "rxPacketsReceivedOK"];

    // Number of downlink packets received for transmission.
    uint32 tx_packets_received = 7;

    // Number of downlink packets emitted.
    uint32 tx_packets_emitted = 8;

    // Additional gateway meta-data.
    map<string, string> meta_data = 10;

    // Stats ID (UUID).
    // Unique identifier for the gateway stats.
    bytes stats_id = 11 [json_name = "statsID"];

    // Tx packets per frequency.
    map<uint32, uint32> tx_packets_per_frequency = 12;

    // Rx packets per frequency.
    map<uint32, uint32> rx_packets_per_frequency = 13;

    // Tx packets per modulation parameters.
    repeated PerModulationCount tx_packets_per_modulation = 14;

    // Rx packets per modulation parameters.
    repeated PerModulationCount rx_packets_per_modulation = 15;

    // Tx packets per status.
    map<string, uint32> tx_packets_per_status = 16;
}

message PerModulationCount {
    // Modulation.
    Modulation modulation = 1;

    // Count.
    uint32 count = 2;
}

message UplinkRXInfo {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // RX time (only set when the gateway has a GPS module).
    google.protobuf.Timestamp time = 2;

    // RX time since GPS epoch (only set when the gateway has a GPS module).
    google.protobuf.Duration time_since_gps_epoch = 3 [json_name = "timeSinceGPSEpoch"];

    // RSSI.
    int32 rssi = 5;

    // LoRa SNR.
    double lora_snr = 6 [json_name = "loRaSNR"];

    // Channel.
    uint32 channel = 7;

    // RF Chain.
    uint32 rf_chain = 8;

    // Board.
    uint32 board = 9;

    // Antenna.
    uint32 antenna = 10;

    // Location.
    common.Location location = 11;

    // Fine-timestamp type.
    FineTimestampType fine_timestamp_type = 12;

    // Fine-timestamp data.
    oneof fine_timestamp {
        // Encrypted fine-timestamp data.
        EncryptedFineTimestamp encrypted_fine_timestamp = 13;

        // Plain fine-timestamp data.
        PlainFineTimestamp plain_fine_timestamp = 14;
    }

    // Gateway specific context.
    bytes context = 15;

    // Uplink ID (UUID bytes).
    // Unique and random ID which can be used to correlate the uplink across multiple logs.
    bytes uplink_id = 16 [json_name = "uplinkID"];

    // CRC status.
    CRCStatus crc_status = 17 [json_name = "crcStatus"];

    // Optional meta-data map.
    map<string, string> metadata = 18;
}

message DownlinkTXInfo {
    // Gateway ID.
    // Deprecated: replaced by gateway_id in DownlinkFrame.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // TX frequency (in Hz).
    uint32 frequency = 5;

    // TX power (in dBm).
    int32 power = 6;

    // Modulation.
    common.Modulation modulation = 7;

    oneof modulation_info {
        // LoRa modulation information.
        LoRaModulationInfo lora_modulation_info = 8 [json_name = "loRaModulationInfo"];

        // FSK modulation information.
        FSKModulationInfo fsk_modulation_info = 9;
    }

    // The board identifier for emitting the frame.
    uint32 board = 10;

    // The antenna identifier for emitting the frame.
    uint32 antenna = 11;

    // Timing defines the downlink timing to use.
    DownlinkTiming timing = 12;

    oneof timing_info {
        // Immediately timing information.
        ImmediatelyTimingInfo immediately_timing_info = 13;

        // Context based delay timing information.
        DelayTimingInfo delay_timing_info = 14;

        // GPS Epoch timing information.
        GPSEpochTimingInfo gps_epoch_timing_info = 15;
    }

    // Gateway specific context.
    // In case of a Class-A downlink, this contains a copy of the uplink context.
    bytes context = 16;
}

message ImmediatelyTimingInfo {
    // Not implemented yet.
}


message DelayTimingInfo {
    // Delay (duration).
    // The delay will be added to the gateway internal timing, provided by the context object.
    google.protobuf.Duration delay = 1;
}

message GPSEpochTimingInfo {
    // Duration since GPS Epoch.
    google.protobuf.Duration time_since_gps_epoch = 1 [json_name = "timeSinceGPSEpoch"];
}

message UplinkFrame {
    // PHYPayload.
    bytes phy_payload = 1;

    // TX meta-data.
    UplinkTXInfo tx_info = 2;

    // RX meta-data.
    UplinkRXInfo rx_info = 3;
}

message UplinkFrameSet {
    // PHYPayload.
    bytes phy_payload = 1;

    // TX meta-data.
    UplinkTXInfo tx_info = 2;

    // RX meta-data set.
    repeated UplinkRXInfo rx_info = 3;
}

message DownlinkFrame {
    // PHYPayload.
    // Deprecated: replaced by items.
    bytes phy_payload = 1;

    // TX meta-data.
    // Deprecated: replaced by items.
    DownlinkTXInfo tx_info = 2;

    // Token (uint16 value).
    // Deprecated: replaced by downlink_id.
    uint32 token = 3;

    // Downlink ID (UUID).
    bytes downlink_id = 4 [json_name = "downlinkID"];

    // Downlink frame items.
    // This makes it possible to send multiple downlink opportunities to the
    // gateway at once (e.g. RX1 and RX2 in LoRaWAN). The first item has the
    // highest priority, the last the lowest. The gateway will emit at most
    // one item.
    repeated DownlinkFrameItem items = 5;

    // Gateway ID.
    bytes gateway_id = 6 [json_name = "gatewayID"];
}

message DownlinkFrameItem {
    // PHYPayload.
    bytes phy_payload = 1;

    // TX meta-data.
    DownlinkTXInfo tx_info = 2;
}

message DownlinkTXAck {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Token (uint16 value).
    // Deprecated: replaced by downlink_id.
    uint32 token = 2;

    // Error.
    // Deprecated: replaced by items.
    string error = 3;

    // Downlink ID (UUID).
    bytes downlink_id = 4 [json_name = "downlinkID"];

    // Downlink frame items.
    // This list has the same length as the request and indicates which
    // downlink frame has been emitted of the requested list (or why it failed).
    // Note that at most one item has a positive acknowledgement.
    repeated DownlinkTXAckItem items = 5;
}

message DownlinkTXAckItem {
    // The Ack status of this item.
    TxAckStatus status = 1;
}

message GatewayConfiguration {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Configuration version.
    string version = 2;

    // Channels.
    repeated ChannelConfiguration channels = 3;

    // Stats interval.
    google.protobuf.Duration stats_interval = 4;
}

message ChannelConfiguration {
    // Frequency (Hz).
    uint32 frequency = 1;

    // Channel modulation.
    common.Modulation modulation = 2;

    oneof modulation_config {
        // LoRa modulation config.
        LoRaModulationConfig lora_modulation_config = 3 [json_name = "loRaModulationConfig"];

        // FSK modulation config.
        FSKModulationConfig fsk_modulation_config = 4;
    }

    // Board index.
    uint32 board = 5;

    // Demodulator index (of the given board).
    uint32 demodulator = 6;
}

message LoRaModulationConfig {
    // Bandwidth.
    uint32 bandwidth = 1;

    // Spreading-factors.
    repeated uint32 spreading_factors = 2;
}

message FSKModulationConfig {
    // Bandwidth.
    uint32 bandwidth = 1;

    // Bitrate.
    uint32 bitrate = 2;
}

message GatewayCommandExecRequest {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Command to execute.
    // This command must be pre-configured in the LoRa Gateway Bridge configuration.
    string command = 2;

    // Execution request ID (UUID).
    // The same token will be returned when the execution of the command has
    // completed.
    bytes ExecId = 3 [json_name = "execID"];

    // Standard input.
    bytes stdin = 4;

    // Environment variables.
    map<string, string> environment = 5;
}

message GatewayCommandExecResponse {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Execution request ID (UUID).
    bytes exec_id = 2 [json_name = "execID"];

    // Standard output.
    bytes stdout = 3;

    // Standard error.
    bytes stderr = 4;

    // Error message.
    string error = 5;
}

// RawPacketForwarderEvent contains a raw packet-forwarder event.
// It can be used to access packet-forwarder features that are not (fully)
// integrated with the ChirpStack Gateway Bridge.
message RawPacketForwarderEvent {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Raw ID (UUID).
    bytes raw_id = 2 [json_name = "rawID"];

    // Payload contains the raw payload.
    bytes payload = 3;
}

// RawPacketForwarderEvent contains a raw packet-forwarder command.
// It can be used to access packet-forwarder features that are not (fully)
// integrated with the ChirpStack Gateway Bridge.
message RawPacketForwarderCommand {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    // Raw ID (UUID).
    bytes raw_id = 2 [json_name = "rawID"];

    // Payload contains the raw payload.
    bytes payload = 3;
}

// ConnState contains the connection state of a gateway.
message ConnState {
    // Gateway ID.
    bytes gateway_id = 1 [json_name = "gatewayID"];

    enum State {
        OFFLINE = 0;
        ONLINE = 1;
    }

    State state = 2;
}
