gRPC Interface

Note

In order to use the API, you may have to enable it in the GRX1090’s web interface first. If you are developing an application that will run on the device itself, the API is always available internally, even if it is not explicitely enabled in the configuration. This allows running embedded applications without exposing the API to the network.

The GRX’s API is based on gRPC and Protocol Buffers. Both frameworks are widely used (e.g., by Google, Netflix, Docker, …) to provide language- and platform-indepdent APIs. As a consequence, tooling and support are extremely mature and developed with plenty of documentation and community support. Over 20 languages are supported by the two frameworks (and therefore by the GRX API), including Java, Python, C++, Ruby, Go, Node.js, and C#.

The GRX API is split into three sub-APIs providing different kinds of information:

  • Receiver API: This sub-API provides all data and information related to signal reception, including the received signals themselves. More details are provided in Receiver API.

  • Monitoring API: This sub-API provides all information on the device itself, including GNSS synchronization status, its location, or system health information. More details are provided in Monitoring API.

  • Spectrum API: This sub-API provides all data and information related to the radio frequency band that is observed by the GRX. More details are provided in Spectrum API.

The API is defined in Protocol Buffer schema (.proto) files. These files contain definitions for the data and services provided by the GRX API. There are three of such files for the GRX API, one for each sub-API. If you are interested in which information is provided by the three APIs, this is where you want to look. The files are shown below under Protocol Buffers Definitions. You can also download the files here:

Receiver API

Note

The receiver API is provided on TCP port 5303.

The Receiverd.proto file defines the following service methods:

GetStateVectors()
GetStateVectorHistory(GetStateVectorHistoryRequest)
GetRangeChart()
ResetRangeChart()
GetStatistics()
GetSamplesStatistics()
GetRadioFrontEndStatus()
RecalibrateDCOffset()
GetModeSDownlinkFrames(GetModeSDownlinkFramesRequest)
GetModeSUplinkFrames(GetModeSUplinkFramesRequest)
GetModeACDownlinkFrames(GetModeACDownlinkFramesRequest)

Their names pretty much suggest which kind of information and functionality they provide. GetStateVectors provides a list of all Mode S aircraft that are currently tracked by the device. For each aircraft, basic tracking information is provided such as its ICAO 24-bit transponder address, signal level, frame rate, and some decoded information such as its ADS-B position, callsign, heading, and speed. GetRangeChart returns the sensor’s coverage, estimated based on all received ADS-B signals. Use ResetRangeChart to reset the chart. GetStatistics returns statistics on received signals, whereas GetSamplesStatistics returns internals of the I/Q sample processing. The device’s gain settings and much more information about the radio hardware can be retrieved with the GetRadioFrontEndStatus method. In case the response of this call indicates that the DC offset calibration has not finished successfully, you can use RecalibrateDCOffset to trigger a new calibration. If you are interested in some historical information about an aircraft that is currently tracked, use GetStateVectorHistory to retrieve a sequence of information such as the aircraft’s recent locations, frame rates, signal levels, and so on.

Finally, the method most people are usually interested in is GetModeSDownlinkFrames, GetModeACDownlinkFrames and GetModeSUplinkFrames. These methods can be used to access the stream of signals received by the device in real-time. Their parameters let you specify a set of filters that control the streams, including the raw signal (I/Q) data that can be provided along with the received signals (see also Retrieving I/Q Samples).

Note

Which data your GRX provides depends on which radio front-ends are available. For example, the GRX1090 has a 1090 MHz radio front-end. Consequently, only methods are available on a GRX1090 for retrieving data that was received on 1090 MHz, that is, GetModeSDownlinkFrames and GetModeACDownlinkFrames.

How exactly each of these methods is called and how the data of the returned messages is accessed depends on the target language. Examples for common language such as Python and Java are provided separately in this documentation.

Retrieving I/Q Samples

I/Q samples are only provided by the device if an explicit subscription was requested by the application when it retrieves Mode S frames. I/Q sample subscriptions can be managed with the GetModeSDownlinkFramesRequest sent to the device when calling the GetModeSDownlinkFrames method. Subscriptions are based on target addresses (usually ICAO 24-bit address) and Mode S downlink formats. This allows you to retrieve I/Q samples for specific downlink formats and transponder addresses only. You can have multiple subscriptions at the same time.

If you want to subscribe to all I/Q samples use the address qualifier MATCH_ANY_ADDRESS. This will tell the receiver to not apply any address-based filter at all. For instance, if you want to retrieve I/Q samples for all downlink format 17 signals of all aircraft, add a SampleEnableRule with the address set to a QualifiedAddressModeS with qualifier MATCH_ANY_ADDRESS and the downlink_formats array to [17]. Note that if you set the address qualifier to MATCH_ANY_ADDRESS, the address part of the qualified address will be ignored and can therefore be left with the standard value of 0.

Note

Subscribing to the respective downlink formats via the request’s downlink_formats field is a prerequisite for receiving I/Q samples. If multiple filters are specified in the GetModeSDownlinkFramesRequest, samples are provided if any of the filters matches.

Warning

Retrieving I/Q samples is very network bandwidth intensive. Make sure to stay below the bandwidth limits of the link between your application and the device by using filters on specific downlink formats and/or aircraft. If the bandwidth limit is exceeded, the device starts dropping frames. You can detect this by monitoring the frames_dropped field in the ModeSFrameWithStreamInfo messages. If this value increases, frames are being dropped.

You can reduce drops/losses by reducing your I/Q sample subscriptions or setting stricter downlink format filters.

Monitoring API

Note

The monitoring API is provided on TCP port 5305.

The Monitord.proto file defines the following service methods:

GetCPUUsage()
GetCPUUsageHistory()
GetMemoryUsage()
GetMemoryUsageHistory()
GetSwapUsage()
GetSwapUsageHistory()
GetMountedFilesystemUsage()
GetProcessList()
GetSystemPackages()
GetLogMessages(GetLogMessagesRequest)
GetUnitList()
GetNetworkUsage()
GetNetworkUsageHistory()
GetNetworkCounters()
GetSystemHealth()
GetSystemHealthHistory()
GetSystemLoad()
GetSystemLoadHistory()
GetSystemInformation()
ClearResetReasons()
GetGNSSInformation()
GetFullSystemStatus()

These methods generally allow applications to retrieve extensive information about the system’s current state, load, available resources and system health in general. This can be used for remote monitoring and retrieval of the device’s location. As before, the names suggest which information will be provided in the reply message. For further details on each of the methods and the return messages, refer to the comments in the Protocol Buffer definitions in Monitoring API. We will just cover the most important methods here.

Retrieving the GPS Position

Note

To ensure a good GPS synchronization, we recommend using a dedicated GNSS antenna with a good 360° view around the sky. The synchronization quality depends on the number and geometry of the satellites that are in a line of sight with the device’s GNSS antenna. Also make sure that the signal quality is high enough. The latter depends on parameters such as the GNSS antenna gain and cable length.

If GPS synchronization is available, the GRX1090’s exact location can be accessed via the GetGNSSInformation method. It returns a GNSSInformation message which contains the device’s GPS hardware and synchronization status, accuracy indicators, and the GPS position itself. Before using the information, we recommend checking the fix_type attribute of the provided position first. It can have the following values:

  • None (0): GPS synchronization is currently not available. This means that the device’s GNSS antenna is not connected or not properly configured. Note that reception of GPS signals indoors is usually not possible.

  • Pos2D (2): Latitude and longitude of the device have been estimated. This fix type is rare as the device usually sees enough satellites to estimate its three-dimensional location.

  • Pos3D (3): This is the desired synchronization state. The three-dimensional position (latitude, longitude, height) has been determined and is available in this message.

  • TimeOnly (5): This is a special state where the device’s location has been entered by the user or determined in survey in mode and stored on the device. Signals from the GPS satellites are then only used for time synchronization. This mode provides advantages in terms of accuracy in fixed setups where the device’s location does not change. For more information on how to use this mode, please contact support.

If the fix_type indicates that location information is available (i.e., fix_type >= 2) the device’s exact location can be accessed via the latitude, longitude, and height attributes. The accuracy of these values is indicated in the respective horizontal_accuracy and vertical_accuracy attributes.

Note

Values provided by the GRX1090 are generally in metric units. In this specific case, the height field and the accuracy indicators are in meters and latitude and longitude in decimal degrees. The units of the specific fields are also indicated in the .proto files.

Spectrum API

Note

The spectrum API is provided on TCP port 5306.

The Spectrumd.proto file defines the following service methods:

GetAggregatedFFTProperties()
GetAggregatedFFTBlockStream()
GetWaterfallJPEG(GetWaterfallJPEGRequest)
GetWaterfallJPEGStream(GetWaterfallJPEGRequest)
GetChannelPowerStream(ChannelPowerRequest)

This part of the API provides access to the extended frequency spectrum monitoring capabilities of the device. It allows measuring the occupancy or interference levels on the frequency band around 1090 MHz. More specifically, the device is constantly executing a Fourier transform on the raw I/Q data and provides a stream of aggregated FFT results (average or peak). This stream can be used to measure the average or peak power on the observed frequency band or sub-bands. It can also be used, e.g., to generate visual representations such as waterfall charts.

An example of the output of the GetWaterfallJPEG call is provided here:

Example output of GetWaterfallJPEG call

It shows a waterfall chart generated over 10 seconds of aggregated FFT data. It shows a lot of activity around the center frequency (1090 MHz) and some DME activity around 1085 MHz. The internal sample frequency of the GRX1090 is 12 MHz, so the frequency range shown in the chart is 1084 to 1096 MHz.

Other Languages

In case there is no specific documentation on your choice of language, please refer to the original documentation on gRPC and Protocol Buffers. The basic workflow for using gRPC and Protocol Buffers is the same across all languages and consists of the following two steps:

  1. Download the Protocol Buffers definition for the GRX1090’s gRPC interface (links above)

  2. Use the Protocol Buffer compiler protoc to generate gRPC bindings for your language

Executing these steps produces language bindings for the GRX1090’s API. Use these bindings to access the methods and data mentioned above.

Protocol Buffers Definitions

The files listed below can also be downloaded here:

Receiver API

syntax = "proto3";

import "google/protobuf/empty.proto";

package serosystems.proto.v3.grx.receiverd;
option java_package = "de.serosystems.proto.v3.grx.receiverd";
option java_outer_classname = "ReceiverDProto";
// Go package is relative to the web-ui package
// This will result in "golang.sero-systems.de/grx/web-ui/proto/.../v3
option go_package = "proto/receiverd/v3";

/* 2D Position. */
message Position2D {
	/* Latitude [degrees], WGS-84. */
	double latitude = 1;
	/* Longitude [degrees], WGS-84. */
	double longitude = 2;
}

/* List of state vectors. */
message StateVectorList {
	/*
	 * State vector.
	 * Note: all fields having a timestamp (i.e. a ..._last_updated) field should
	 *  be checked for their validity: if the timestamp is 0, the value of the
	 *  field is not valid.
	*/
	message StateVector {
		/*
		 * Qualified address: an address with a qualifier (e.g. ICAO24).
		 */
		message QualifiedAddress {
			/* Address qualifiers. */
			enum AddressQualifier {
				/*
				 * ICAO24, directly or rebroadcast, all map to the same qualified
				 * address.
				 * Consult the data_sources for a list of actual sources.
				 */
				ICAO24 = 0;

				/*
				 * The following are all non-ICAO24 addresses received via UAT.
				 * They all map to qualified addresses that describe them further.
				 */

				/* UAT ADS-B with temporary address. */
				UAT_ADS_B_WITH_TEMPORARY = 1;
				/* UAT TIS-B target with track file identifier. */
				UAT_TIS_B_TARGET_WITH_TRACK_FILE_IDENTIFIER = 2;
				/* UAT surface vehicle. */
				UAT_SURFACE_VEHICLE = 3;
				/* UAT fixed ADS-B beacon. */
				UAT_FIXED_ADS_B_BEACON = 4;
				/* UAT ADS-R target with non-icao address. */
				UAT_ADS_R_TARGET_WITH_NON_ICAO = 5;
				/* UAT reserved. */
				UAT_RESERVED = 6;

				/*
				 * The following are all non-ICAO24 addresses received via Mode-S.
				 * They map to distinct qualified addresses; including their sources.
				 */

				/* Mode-S / ADS-B anonymous or ground vehicle or fixed obstacle. */
				MODE_S_ADS_B_ANONYMOUS_OR_GROUND_VEHICLE_OR_FIXED_OBSTACLE = 7;
				/* Mode-S / ADS-R anonymous or ground vehicle or fixed obstacle. */
				MODE_S_ADS_R_ANONYMOUS_OR_GROUND_VEHICLE_OR_FIXED_OBSTACLE = 8;
				/* Mode-S / TIS-B Mode-A and track file identifier. */
				MODE_S_TIS_B_MODE_AC_CODE_AND_TRACK_FILE_IDENTIFIER = 9;
				/* Mode-S / TIS-B non-icao address. */
				MODE_S_TIS_B_NON_ICAO24 = 10;

				/*
				 * Mode S message with reserved content or in general:
				 * when the address cannot be determined from the message.
				 */
				MODE_S_INVALID = 11;
			}

			/* Address qualifier. */
			AddressQualifier aq = 1;

			/* Address part of the qualified address, 24 bits. */
			uint32 address = 2;
		}

		/* Qualified address. */
		QualifiedAddress qualified_address = 1;

		/*
		 * Data source.
		 */
		enum DataSource {
			/*
			 * Mode S Downlink message, including DF 17 (ADS-B), excluding certain
			 *  DF 18 message that do not carry data originating from the transmitter
			 *  themselves.
			 */
			MODE_S_DL = 0;

			/*
			 * Mode S Uplink message. Set when
			 *  1. ACAS broadcast or resolutionmessage (UF 16) is received
			 *  2. target is selectively interrogated by another transmitter
			 */
			MODE_S_UL = 1;

			/*
			 * Mode S Downlink message having DF 18, with CF 2, 3, 5 or 6 (see
			 *  DO-260B, Table 2-13).
			 * Those are all messages where the transmitter itself does not carry the
			 *  address, but re-broadcasts the message in some way.
			 * Note: there is no distinction between TIS-B and ADS-R.
			 * If the address is not an ICAO 24-bit address, the address qualifier
			 *  may contain further information to distinguish between TIS-B and
			 *  ADS-R.
			 */
			MODE_S_DL_ADS_R_TIS_B = 2;

			/*
			 * UAT ADS-B message with address qualifier 0, 1, 4 or 5.
			 * Those contain data originating from the transmitter themselves.
			 */
			UAT_ADS_B = 3;

			/*
			 * UAT ADS-B message with address qualifier 2, 3 or 6.
			 * Note: there is no distinction between TIS-B and ADS-R.
			 * If the address is not an ICAO 24-bit address, the address qualifier
			 *  may contain further information to distinguish between TIS-B and
			 *  ADS-R.
			 */
			UAT_ADS_R_TIS_B = 4;
		}

		/*
		 * List of data sources from which the state vector has been composed.
		 */
		repeated DataSource data_sources = 3;

		/* Average rate of directly received (i.e. non-rebroadcasted) messages
		 *   [1/s]. */
		float average_message_rate_directly_received = 4;

		/*
		 * Average signal level of directly received (i.e. non-rebroadcasted)
		 *  messages [dBm].
		 */
		float average_signal_level_directly_received = 5;

		/* Time [s since epoch UTC] of last received arbitrary message. */
		uint64 last_seen = 6;

		/*
		 * Decoded identification of the target, aka. call sign. Empty if not valid.
		 */
		string identification = 7;

		/*
		 * Time [s since epoch UTC] of last updating the identification.
		 * Is 0 if too old/not received yet.
		 */
		uint64 identification_last_update = 8;

		/* Whether target is on ground. */
		bool ground_flag = 9;

		/*
		 * Time [s since epoch UTC] of last updating the ground flag.
		 * Is 0 if too old/not received yet.
		 */
		uint64 ground_flag_last_update = 10;

		/*
		 * Position of the target.
		 * Only available if position is recent.
		 */
		Position2D position = 11;

		/*
		 * Time [s since epoch UTC] of last updating the position.
		 * Is 0 if too old/not received yet.
		 */
		uint64 position_last_update = 12;

		/* Track angle [degrees] of the target. */
		uint32 track_angle = 13;

		/*
		 * Time [s since epoch UTC] of last updating the track angle.
		 * Is 0 if too old/not received yet.
		 */
		uint64 track_angle_last_update = 14;

		/* Speed over ground [knots] of the target. */
		uint32 speed_over_ground = 15;

		/*
		 * Time [s since epoch UTC] of last updating the speed over ground.
		 * Is 0 if too old/not received yet.
		 */
		uint64 speed_over_ground_last_update = 16;

		/* Barometric altitude [feet] of the target. */
		int32 barometric_altitude = 17;

		/*
		 * Time [s since epoch UTC] of last updating the barometric altitude.
		 * Is 0 if too old/not received yet.
		 */
		uint64 barometric_altitude_last_update = 18;

		/* Geometric height [feet] of the target. */
		int32 geometric_height = 19;

		/*
		 * Time [s since epoch UTC] of last updating the geometric height.
		 * Is 0 if too old/not received yet.
		 */
		uint64 geometric_height_last_update = 20;

		/* Vertical rate [feet/min] of the target. */
		int32 vertical_rate = 21;

		/*
		 * Time [s since epoch UTC] of last updating the vertical rate.
		 * Is 0 if too old/not received yet.
		 */
		uint64 vertical_rate_last_update = 22;

		/*
		 * Country, as determined by the ICAO address.
		 * Is either the full country name (e.g. "Germany") or "unknown".
		 */
		string country = 23;

		/* The "4096 identification code", aka. squawk. */
		uint32 identification_code = 24;

		/*
		 * Time [s since epoch UTC] of last updating the identification code.
		 * Is 0 if too old/not received yet.
		 */
		uint64 identification_code_last_update = 25;
	}

	/*
	 * Current timestamp [s since epoch UTC], can be used to check if fields
	 *  are up-to-date.
	 */
	uint64 current_timestamp = 1;

	/* List of state vectors. */
	repeated StateVector state_vectors = 2;
}

/* History (time series) of StateVectors for a single target. */
message StateVectorHistory {
	/*
	 * Single data point in the time-series.
	 * Overlaps with StateVectorList.StateVector message, but is shorter.
	 * Note: all fields having a valid flag (i.e. a ..._valid field) should
	 *  be checked for their validity: if the valid flag is false, the value of
	 *  the field should not be interpreted.
	 */
	message DataPoint {
		/* Time [s since epoch UTC] of this data point. */
		uint64 timestamp = 1;

		/* Average rate of directly received (i.e. non-rebroadcasted) messages
		 *   [1/s]. */
		float average_message_rate_directly_received = 2;

		/*
		 * Average signal level of directly received (i.e. non-rebroadcasted)
		 *  messages [dBm].
		 */
		float average_signal_level_directly_received = 3;

		/* Whether target is on ground. */
		bool on_ground = 4;

		/*
		 * Whether the on_ground flag is considered valid.
		 */
		bool on_ground_valid = 5;

		/*
		 * Decoded identification, aka. call sign. Empty if not valid (i.e. if
		 *  identification_valid is false).
		 */
		string identification = 6;

		/*
		 * Whether the identification is considered valid.
		 */
		bool identification_valid = 7;

		/*
		 * Track angle [degrees] of the target.
		 */
		uint32 track_angle = 8;

		/*
		 * Whether the track angle is considered valid.
		 */
		bool track_angle_valid = 9;

		/* Speed over ground [knots] of the target. */
		uint32 speed_over_ground = 10;

		/* Whether speed over ground is considered valid. */
		bool speed_over_ground_valid = 11;

		/* Barometric altitude [feet] of the target. */
		int32 barometric_altitude = 12;

		/* Whether barometric altitude is considered valid. */
		bool barometric_altitude_valid = 13;

		/* Geometric height [feet] of the target. */
		int32 geometric_height = 14;

		/* Whether geometric height is considered valid. */
		bool geometric_height_valid = 15;

		/*
		 * Position of the target.
		 * Only available if position is considered valid.
		 */
		Position2D position = 16;

		/* Vertical rate [feet/min] of the target. */
		int32 vertical_rate = 17;

		/* Whether vertical rate is considered valid. */
		bool vertical_rate_valid = 18;

		/* The "4096 identification code", a.k.a. squawk. */
		uint32 identification_code = 19;

		/* Whether identification_code is considered valid. */
		bool identification_code_valid = 20;
	}

	/*
	 * List of data points describing different points of time.
	 * Empty if there are no such data points, e.g. if target is not tracked.
	 */
	repeated DataPoint data_point = 1;

	/*
	 * Current time [s since epoch UTC]. Can be used to represent the
	 *  DataPoints' timestamps relative to the current time.
	 */
	uint64 current_timestamp = 2;
}

/* Range chart, computed by directly received (non-rebroadcasted) position
 *  messages. */
message RangeChart {
	/*
	 * Center of the chart, i.e. sensor position.
	 * Note: not included if position is not available.
	 */
	Position2D center = 1;

	/*
	 * Reception range [m] from the center for each degree.
	 * Exactly 360 items.
	 */
	repeated float ranges = 2;
}

/* Reception capabilities */
message ReceptionCapabilities {
	/* Capabilities. */
	enum Capability {
		/* Mode-S frame on downlink. */
		DOWNLINK_MODE_S_FRAME = 0;
		/* Mode-AC reply on downlink. */
		DOWNLINK_MODE_AC_REPLY = 1;
		/* Mode-4 reply on downlink. */
		DOWNLINK_MODE_4_REPLY = 2;
		/* Mode-5 reply on downlink. */
		DOWNLINK_Mode_5_REPLY = 3;
		/* DME/TACAN pulse pair on downlink. */
		DOWNLINK_DME_TACAN_PULSE_PAIR = 4;
		/* Isolated pulse on downlink. */
		DOWNLINK_ISOLATED_PULSE = 5;
		/* Mode-S frame on uplink. */
		UPLINK_Mode_S_FRAME = 8;
		/* Mode-1, Mode-2, Mode-A, Mode-C interrogation on uplink. */
		UPLINK_Basic_INTERROGATION = 9;
		/* Mode-4 interrogation on uplink. */
		UPLINK_Mode_4_INTERROGATION = 10;
		/* Mode-5 interrogation on uplink. */
		UPLINK_Mode_5_INTERROGATION = 11;
		/* DME/TACAN pulse pair on uplink. */
		UPLINK_DME_TACAN_PULSE_PAIR = 12;
		/* Isolated pulse on uplink. */
		UPLINK_ISOLATED_PULSE = 13;
		/* UAT ADS-B message. */
		UAT_ADS_B_MESSAGE = 16;
		/* UAT ground uplink message. */
		UAT_GROUND_UPLINK_MESSAGE = 17;
	}

	/* Capabilities. */
	repeated Capability capabilities = 1;
}

/* Received signal statistics. */
message Statistics {
	/* Absolute message counter. */
	message Counters {
		/* Mode S downlink, split by DF (0-24). */
		repeated uint64 dl_mode_s_by_df = 1;

		/* Mode 1/2/A/C downlink. */
		uint64 dl_mode_1_2_a_c_reply = 2;

		/* Mode 4 downlink. */
		uint64 dl_mode_4_reply = 3;

		/* Mode 5 downlink. */
		uint64 dl_mode_5_reply = 4;

		/* Isolated pulses on 1090MHz. */
		uint64 dl_isolated_pulse = 5;

		/* DME/TACAN pulse pair on 1090MHz. */
		uint64 dl_dme_tacan_pulse_pair = 6;

		/* Mode S uplink, split by UF (0-24). */
		repeated uint64 ul_mode_s_by_uf = 7;

		/* Mode 1 uplink. */
		uint64 ul_mode_1_interrogation = 8;

		/* Mode 2 uplink. */
		uint64 ul_mode_2_interrogation = 9;

		/* Mode 4 uplink. */
		uint64 ul_mode_4_interrogation = 10;

		/* Mode 5 uplink. */
		uint64 ul_mode_5_interrogation = 11;

		/* Mode A uplink. */
		uint64 ul_mode_a_interrogation = 12;

		/* Mode C uplink. */
		uint64 ul_mode_c_interrogation = 13;

		/* Isolated pulses on 1030MHz.. */
		uint64 ul_isolated_pulse = 14;

		/* DME/TACAN pulse pair on 1030MHz. */
		uint64 ul_dme_tacan_pulse_pair = 15;

		/* UAT ADS-B by payload type (0-31). */
		repeated uint64 uat_adsb_message_by_payload_type = 16;

		/* UAT ground uplink. */
		uint64 uat_ground_uplink_message = 17;

		/* UAT ground uplink information by frame type (0..15). */
		repeated uint64 uat_ground_uplink_information_frame_by_type = 18;
	}

	/* Message rates. */
	message Rates {
		/* Mode S downlink, split by DF (0-24). */
		repeated float dl_mode_s_by_df = 1;

		/* Mode 1/2/A/C downlink. */
		float dl_mode_1_2_a_c_reply = 2;

		/* Mode 4 downlink. */
		float dl_mode_4_reply = 3;

		/* Mode 5 downlink. */
		float dl_mode_5_reply = 4;

		/* Isolated pulses on 1090MHz. */
		float dl_isolated_pulse = 5;

		/* DME/TECAN pulse pair on 1090MHz. */
		float dl_dme_tacan_pulse_pair = 6;

		/* Mode S uplink, split by UF (0-24). */
		repeated float ul_mode_s_by_uf = 7;

		/* Mode 1 uplink. */
		float ul_mode_1_interrogation = 8;

		/* Mode 2 uplink. */
		float ul_mode_2_interrogation = 9;

		/* Mode 4 uplink. */
		float ul_mode_4_interrogation = 10;

		/* Mode 5 uplink. */
		float ul_mode_5_interrogation = 11;

		/* Mode A uplink. */
		float ul_mode_a_interrogation = 12;

		/* Mode C uplink. */
		float ul_mode_c_interrogation = 13;

		/* Isolated pulses on 1030MHz.. */
		float ul_isolated_pulse = 14;

		/* DME/TECAN pulse pair on 1030MHz. */
		float ul_dme_tacan_pulse_pair = 15;

		/* UAT ADS-B by payload type (0-31). */
		repeated float uat_adsb_message_by_payload_type = 16;

		/* UAT ground uplink. */
		float uat_ground_uplink_message = 17;

		/* UAT ground uplink information by frame type (0..15). */
		repeated float uat_ground_uplink_information_frame_by_type = 18;
	}

	/* Message counters. */
	Counters counters = 1;

	/* Message rate [1/s] over last 10 seconds. */
	Rates rates_10s = 2;

	/* Message rate [1/s] over last 60 seconds. */
	Rates rates_60s = 3;

	/* Device reception capabilities. */
	ReceptionCapabilities reception_capabilities = 4;
}

/* Samples statistics, may indicate system overloads. */
message SamplesStatistics {
	/*
	 * Number of sample read attempts.
	 * Subtract the errors below to get successful attempts.
	 */
	uint64 read_attempts = 1;

	/*
	 * Number of attempts which failed due to deadline passed.
	 * Signifies too high load.
	 */
	uint64 stale = 2;

	/*
	 * Number of other errors.
	 * Might signify hardware/software incompatibilities.
	 */
	uint64 other_error = 3;
}

/* Band/Frequency a front end operates on. */
enum Band {
	/* Unspecified, used if unknown. */
	BAND_UNSPECIFIED = 0;
	/* 978 MHz band. */
	BAND_987_MHZ = 1;
	/* 1030 MHz band. */
	BAND_1030_MHZ = 2;
	/* 1090 MHz band. */
	BAND_1090_MHZ = 3;
}

/*
 * Antenna status.
 */
message AntennaStatus {
	/* Unique identification of the antenna. */
	string id = 1;

	/* Human-readable label describing the antenna. */
	string label = 2;

	/* Whether power supply of the antenna can be enabled/disabled. */
	bool has_supply_enable = 3;

	/* Whether power supply should be enabled. */
	bool supply_enable = 4;

	/* Power supply faults. */
	enum SupplyFault {
		/* No power supply fault detection supported. */
		NOT_SUPPORTED = 0;
		/* No power supply fault detected. */
		NO_FAULT_DETECTED = 1;
		/* Power supply fault detected. */
		FAULT_DETECTED = 2;
	}

	/* Power fault. Note: power faults can only be detected if
	 * power_supply_enabled is true.
	 */
	SupplyFault supply_fault = 5;
}

/*
 * Antenna switch status.
 */
message AntennaSwitchStatus {
	/* Unique identification of the antenna switch. */
	string id = 1;

	/* Human-readable label describing the antenna switch. */
	string label = 2;

	/*
	 * Map from state id (e.g. "combined") to label (e.g. "Combined GNSS and
	 * Mode-S")
	 */
	map<string,string> state_id_to_label = 3;

	/* Current state id, referenced an id in state_id_to_label. */
	string state_id = 4;
}

/*
 * Radio frontend status.
 * This includes mostly low-level data, such as current gain and noise level.
 * Different frontends can be distinguished via fields 'band' and
 * 'per_band_index'.
 */
message RadioFrontEndStatus {
	/*
	 * Fixed external gain (before entering the receiver) [dB].
	 * This can be used to represent the losses in the cable or the gain of
	 *  the (active) antenna.
	 */
	float external_fixed_gain = 1;

	/*
	 * Fixed gain of the RX chain (beginning at the antenna input) [dB].
	 * This excludes the rx_chain_variable_gain.
	 */
	float rx_chain_fixed_gain = 2;

	/*
	 * Variable gain of the RX chain [dB].
	 * Can be used as a measure to see how the receiver did adapt to the current
	 *  situation.
	 */
	float rx_chain_variable_gain = 3;

	/*
	 * Noise level [dBm].
	 * Estimated by analyzing "zero power" positions in the preamble of Mode S
	 *  frames.
	 * Note that this only gets updated if valid frames are received.
	 */
	float noise_level = 4;

	/* DC offset applied on-chip for channel I. */
	int32 dc_offset_on_chip_i = 5;

	/* DC offset applied on-chip for channel Q. */
	int32 dc_offset_on_chip_q = 6;

	/* DC offset applied in PL for channel I. */
	int32 dc_offset_pl_i = 7;

	/* DC offset applied in PL for channel Q. */
	int32 dc_offset_pl_q = 8;

	/*
	 * Most recent averaged, DC corrected residual value for channel I.
	 */
	int32 dc_offset_last_i_residual_avg = 9;

	/*
	 * Most recent averaged, DC corrected residual value for channel Q.
	 */
	int32 dc_offset_last_q_residual_avg = 10;

	/* Whether a DC offset calibration is performed right now. */
	bool dc_offset_calibration_ongoing = 11;

	/*
	 * Whether a DC offset calibration has been performed.
	 * Note: if neither this nor dc_offset_calibration_ongoing is set,
	 *  no calibration has been done since the device is running.
	 */
	bool dc_offset_calibration_done = 12;

	/* Whether DC offset calibration failed: did not converge. */
	bool dc_offset_calibration_no_convergence = 13;

	/* Whether DC offset recalibration should be done. */
	bool dc_offset_calibration_recalibration_advised = 14;

	/* Whether DC offset recalibration must be done. */
	bool dc_offset_calibration_recalibration_required = 15;

	/* Band this radio front end operates on. */
	Band band = 16;

	/* Distinguishes front ends operating on same band/frequency. */
	int32 per_band_index = 17;

	/* Antenna id. May be empty for "unknown". */
	string antenna_id = 18;

	/*
	 * Antenna status. May be unavailable.
	 * Note: response GetRadioFrontEndStatusReply contains map antenna_status.
	 *  The antenna_id above maps to the same info as this field, this is just a
	 *  shortcut.
	 */
	AntennaStatus antenna_status = 19;
}

/* Parameter for GetStateVectorRequest request. */
message GetStateVectorHistoryRequest {
	/* The qualified address of the requested target. */
	StateVectorList.StateVector.QualifiedAddress address = 1;
}

/*
 * The Mode S specific address qualifier.
 * Mainly for use with DF 18.
 * See DO-260B, Table 2-11.
 */
message QualifiedAddressModeS {
	/* Address qualifier. */
	enum AddressQualifier {
		/* Mode S (or ADS-B) Target with ICAO 24 bit address. */
		ICAO24 = 0;
		/* TIS-B target with ICAO 24 bit address. */
		TIS_B_ICAO24 = 1;
		/* ADS-R target with ICAO 24 bit address. */
		ADS_R_ICAO24 = 2;
		/* ADS-B target with anonymous, ground vehicle or fixed obstacle address. */
		ADS_B_ANONYMOUS_OR_GROUND_VEHICLE_OR_FIXED_OBSTACLE = 3;
		/* ADS-R target with anonymous, ground vehicle or fixed obstacle address. */
		ADS_R_ANONYMOUS_OR_GROUND_VEHICLE_OR_FIXED_OBSTACLE = 4;
		/* TIS-B target with Mode A code and track file identifier. */
		TIS_B_MODE_A_CODE_AND_TRACK_FILE_IDENTIFIER = 5;
		/* TIS-B target with non-ICAO 24 bit address. */
		TIS_B_NON_ICAO24 = 6;
		/*
		 * Invalid or reserved address; will also be used to indicated that the
		 * address could not be determined
		 */
		INVALID = 7;

		/*
		 * Begin Special address qualifiers that may be used to when matching
		 * addresses/qualifiers.
		 */

		/*
		 * Matches addresses with any qualifier (including invalid ones) that
		 * additionally have a matching address part.
		 * Use this if you want to match an address, but do not care about the
		 * exact qualifier.
		 */
		MATCH_ANY_QUALIFIER = 254;

		/*
		 * Matches any addresses with any qualifier (including invalid ones).
		 * Use this to disable any filtering.
		 */
		MATCH_ANY_ADDRESS = 255;
	}

	/* Address qualifier. */
	AddressQualifier aq = 1;

	/* Address part of the qualified address, 24 bits */
	uint32 address = 2;
}

/* Parameter for GetModeSDownlinkFrames request. */
message GetModeSDownlinkFramesRequest {

	/*
	 * Single rule that enables samples for decoded frames.
	 * Both, Address and DF, must match in order for the rule to apply
	 *  (logic AND).
	 */
	message SampleEnableRule {
		/* Qualified address to be matched */
		QualifiedAddressModeS address = 1;

		/*
		 * Set of downlink formats to be matched.
		 * If e.g. only 1 and 17 are put into this array, only samples of a
		 *  frame with downlink format 1 and 17 from the specified AA will be
		 *  relayed.
		 * If this array is empty, this rule is not effective.
		 * It is an error to specify downlink formats > 24.
		 * Note also, that all given downlink formats should also be
		 *  specified in the df_enable array of the
		 *  GetModeSDownlinkFramesRequest, otherwise the frame (and thus the
		 *  samples) won't be relayed at all.
		 */
		repeated uint32 downlink_formats = 2;
	}

	/*
	 * Set of downlink formats to be relayed.
	 * If e.g. only 1 and 17 are put into this array, only frames with df 1 and
	 *  17 will be relayed.
	 * It is an error to leave this array empty.
	 * It is an error to specify downlink formats > 24.
	 */
	repeated uint32 downlink_formats = 1;

	/*
	 * List of rules that describe for which of the decoded frames the samples
	 *  should be included.
	 */
	repeated SampleEnableRule sample_enable_rules = 2;
}

/* Parameter for GetModeSUplinkFrames request. */
message GetModeSUplinkFramesRequest {
	/*
	 * Single rule that enables samples for decoded frames.
	 * Both, Address and UF, must match in order for the rule to apply
	 *  (logic AND).
	 */
	message SampleEnableRule {
		/* Qualified address to be matched */
		QualifiedAddressModeS address = 1;

		/*
		 * Set of uplink formats to be matched.
		 * If e.g. only 0 and 16 are put into this array, only samples of a
		 *  frame with uplink format 0 and 16 from the specified AA will be
		 *  relayed.
		 * If this array is empty, this rule is not effective.
		 * It is an error to specify uplink formats > 24.
		 * Note also, that all given uplink formats should also be
		 *  specified in the uf_enable array of the GetModeSUplinkFramesRequest,
		 *  otherwise the frame (and thus the samples) won't be relayed at all.
		 */
		repeated uint32 uplink_formats = 2;
	}

	/*
	 * Set of uplink formats to be relayed.
	 * If e.g. only 1 and 16 are put into this array, only frames with uf 0 and
	 *  16 will be relayed.
	 * It is an error to leave this array empty.
	 * It is an error to specify uplink formats > 24.
	 */
	repeated uint32 uplink_formats = 1;

	/*
	 * List of rules that describe for which of the decoded frames the samples
	 *  should be included.
	 */
	repeated SampleEnableRule sample_enable_rules = 2;
}

/*
 * Time base (from where timestamp was taken).
 * Also implies epoch for the timestamp.
 */
enum TimingBase {
	/* Not based on any time base */
	NO_BASE = 0;
	/*
	 * Clock advances with system clock, and is based on the system's uptime,
	 *  i.e. advances monotonic. It only has 51 bit, thus resets each 2^51 ns,
	 *  which is about 13 days.
	 */
	SYSTEM_TIME = 1;
	/* Based on GPS Time of Week (ToW) */
	GPS_TOW = 2;
}

/*
 * Synchronization source.
 */
enum TimingSyncSource {
	/* No valid synchronization source or not within allowed bounds */
	NO_SOURCE = 0;
	/* Synchronized to a Global Navigation Satellite System (GNSS) clock */
	GNSS = 1;
	/* Synchronized to a (local) atomic clock */
	ATOMIC_CLOCK = 2;
}

/* Signal samples. */
message SignalSamples {
	/* Sample formats. */
	enum SampleFormat {
		/* Unspecified sample format, should not happen. */
		Unspecified = 0x00;

		/* I (12 bit signed) and Q (12 bit signed) packed into 32 bits. */
		S12I_S12Q = 0x01;

		/* I (16 bit signed) and Q (16 bit signed) packed into 32 bits */
		S16I_S16Q = 0x02;

		/* I (8 bit signed) and Q (8 bit signed) packed into 16 bits */
		S8I_S8Q = 0x03;

		/* I (8 bit signed) and Q (8 bit signed), squelch compressed.
         * Not used at the moment. */
		S8I_S8Q_SQUELCH_COMPRESSED = 0x04;
	}

	/* Samples bytes, must be interpreted as specified by sample_format. */
	bytes samples = 1;

	/* Sample rate [Hz]. */
	fixed32 sample_rate = 2;

	/* Sample format. */
	SampleFormat sample_format = 3;

	/* Start of data index (index into decoded samples). */
	uint32 start_of_data = 4;
}

/* Mode S Downlink Frame. */
message ModeSDownlinkFrame {
	/*
	 * Timestamp [ns] of the frame.
	 * Also look at timing_base and timing_sync_source to know how to interpret
	 *  the timestamp.
	 */
	fixed64 timestamp = 1;

	/* Time base. */
	TimingBase timing_base = 2;

	/* Synchronization source. */
	TimingSyncSource timing_sync_source = 3;

	/* Number of bits that have been corrected. */
	uint32 number_corrected_bits = 4;

	/* Noise level of this frame [dBm]. */
	float level_noise = 5;

	/* Signal level of this frame [dBm]. */
	float level_signal = 6;

	/* Whether received carrier frequency was computed. */
	bool carrier_frequency_offset_computed = 7;

	/*
	 * Offset of received carrier frequency from nominal carrier frequency [Hz].
	 * Only valid if carrier_frequency_offset_computed is true.
	 */
	float carrier_frequency_offset = 8;

	/*
	 * Error indicator of received carrier frequency offset computation.
	 * Only valid if carrier_frequency_offset_computed is true.
	 * Smaller values signify a better estimation of the offset.
	 * Should be a sufficiently small value (<= 0.16) to assert a meaningful
	 *  estimation.
	 */
	float carrier_frequency_estimation_error = 9;

	/* 14 (or 7, in case of a short frame) bytes of payload. */
	bytes payload = 10;

	/* Raw samples of the signal (only set if explicitly enabled). */
	SignalSamples samples = 11;
}

/* Mode S Uplink Frame. */
message ModeSUplinkFrame {
	/*
	 * Timestamp [ns] of the frame.
	 * Also look at timing_base and timing_sync_source to know how to interpret
	 *  the timestamp.
	 */
	fixed64 timestamp = 1;

	/* Time base. */
	TimingBase timing_base = 2;

	/* Synchronization source. */
	TimingSyncSource timing_sync_source = 3;

	/* Number of bits that have been corrected. */
	uint32 number_corrected_bits = 4;

	/* Noise level of this frame [dBm]. */
	float level_noise = 5;

	/* Signal level of this frame [dBm]. */
	float level_signal = 6;

	/* Whether received carrier frequency was computed. */
	bool carrier_frequency_offset_computed = 7;

	/*
	 * Offset of received carrier frequency from nominal carrier frequency [Hz].
	 * Only valid if carrier_frequency_offset_computed is true.
	 */
	float carrier_frequency_offset = 8;

	/*
	 * Error indicator of received carrier frequency offset computation.
	 * Only valid if carrier_frequency_offset_computed is true.
	 * Smaller values signify a better estimation of the offset.
	 * Should be a sufficiently small value (<= 0.16) to assert a meaningful
	 *  estimation.
	 */
	float carrier_frequency_estimation_error = 9;

	/* 14 (or 7, in case of a short frame) bytes of payload. */
	bytes payload = 10;

	/* Raw samples of the signal (only set if explicitly enabled). */
	SignalSamples samples = 11;
}

/* Mode S Downlink Frame with stream info. */
message ModeSDownlinkFrameWithStreamInfo {
	/* Mode S Downlink frame. */
	ModeSDownlinkFrame frame = 1;

	/*
	 * Number of dropped frames for this stream.
	 * Dropped frames indicate high network and/or system utilization.
	 */
	fixed32 frames_dropped = 2;
}

/* Mode S Uplink Frame with stream info. */
message ModeSUplinkFrameWithStreamInfo {
	/* Mode S Uplink frame. */
	ModeSUplinkFrame frame = 1;

	/*
	 * Number of dropped frames for this stream.
	 * Dropped frames indicate high network and/or system utilization.
	 */
	fixed32 frames_dropped = 2;
}

/* Parameter for GetModeACDownlinkFrames request. */
message GetModeACDownlinkFramesRequest {
	/*
	 * Binning mode for Mode AC frames.
	 * As Mode AC frames are sent in bursts (and the amount of frames is very
	 *  high), forwarding each frame on its own would generate a high load.
	 * Because of this, Mode AC frames with the same code are grouped into bins
	 *  of 100ms and transferred in those bins.
	 * It is not common, that there is only a single reception of a code within
	 *  100ms, so these binning modes act like a filter on those bins.
	 */
	enum BinningMode {
		/* Forward all bins, even those containing only single receptions. */
		ALL = 0;
		/*
		 * Forward only those bins which contain at least two receptions.
		 */
		AT_LEAST_2RECEPTIONS = 1;
		/*
		 * Forward only those bins which contain at least two receptions
		 *  or (in case the is only one reception) whose code has been seen
		 *  recently (with exponential decay).
		 */
		AT_LEAST_2RECEPTIONS_OR_RECENT = 2;
	}

	/* Binning mode. */
	BinningMode binning_mode = 1;
}

/*
 * Mode AC Downlink receptions.
 * Message contains a burst of receptions of the same code.
 */
message ModeACDownlinkBinnedFrame {
	/*
	 * Timestamp [ns] of the primary reception, i.e. the same as the timestamp
	 *  of the first reception within this message.
	 * Also look at timing_base and timing_sync_source to know how to interpret
	 *  the timestamp.
	 */
	fixed64 timestamp = 1;

	/* Time base for all receptions within this message. */
	TimingBase timing_base = 2;

	/* Synchronization source for all receptions within this message. */
	TimingSyncSource timing_sync_source = 3;

	/* Mode A/C code without X bit (number between 0 and 4095). */
	fixed32 code = 4;

	/* Single reception of the code. */
	message Reception {
		/*
		 * Timestamp [ns] of the reception.
		 * Also look at timing_base and timing_sync_source of outer message to
		 *  know how to interpret the timestamp.
		 */
		fixed64 timestamp = 1;

		/* Signal level of this reception [dBm]. */
		float signal_level = 2;
	}

	/* Array of receptions, at least one. */
	repeated Reception receptions = 5;
}

/* Mode AC Downlink Binned Frame with stream info. */
message ModeACDownlinkBinnedFrameWithStreamInfo {
	/* Mode AC Downlink binned frame. */
	ModeACDownlinkBinnedFrame frame = 1;

	/*
	 * Number of dropped frames for this stream.
	 * Dropped frames indicate high network and/or system utilization.
	 */
	fixed32 frames_dropped = 2;
}

/*
 * Reply for GetRadioFrontEndStatus() call.
 */
message GetRadioFrontEndStatusReply {
	/* Array of radio front end status: one for each front end. */
	repeated RadioFrontEndStatus radio_front_end_status = 1;

	/* Map from antenna id to antenna status. */
	map<string, AntennaStatus> antenna_status = 2;

	/* Map from antenna switch id to antenna switch status. */
	map<string, AntennaSwitchStatus> antenna_switch_status = 3;
}

/* Receiver daemon service definition. Port 5303. */
service Receiverd {
	/*
	 * Get a list of state vectors.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetStateVectors (google.protobuf.Empty) returns (StateVectorList);

	/*
	 * Get a history of state vectors for some target.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetStateVectorHistory (GetStateVectorHistoryRequest) returns (StateVectorHistory);

	/*
	 * Get a range chart.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetRangeChart (google.protobuf.Empty) returns (RangeChart);

	/*
	 * Reset range chart.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 */
	rpc ResetRangeChart (google.protobuf.Empty) returns (google.protobuf.Empty);

	/*
	 * Get received signal counters and rates.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetStatistics (google.protobuf.Empty) returns (Statistics);

	/*
	 * Get samples statistics.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetSamplesStatistics (google.protobuf.Empty) returns (SamplesStatistics);

	/*
	 * Get radio frontend status.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 * Returns DEADLINE_UNAVAILABLE if receiverd did not reply in time.
	 */
	rpc GetRadioFrontEndStatus (google.protobuf.Empty) returns (GetRadioFrontEndStatusReply);

	/*
	 * Recalibrate DC offset.
	 * Should be done if
	 *  rf.dc_offset_calibration_recalibration_advised or
	 *  rf.dc_offset_calibration_recalibration_required
	 *  for some rf as returned by GetRadioFrontEndStatus() is set.
	 * Ongoing calibration can be monitored by
	 *  rf.dc_offset_calibration_ongoing, see also
	 *  documentation on the fields in RadioFrontEndStatus.
	 * Returns UNAVAILABLE if receiverd could not be reached.
	 */
	rpc RecalibrateDCOffset (google.protobuf.Empty) returns (google.protobuf.Empty);

	/*
	 * Request a stream of Mode S downlink frames (matching the request) from
	 *  the server.
	 * For reconfiguration, the call has to be cancelled.
	 * Returns UNAVAILABLE if the service is shutting down.
	 * Returns INVALID_ARGUMENT if request was invalid, see GetModeSDownlinkFramesRequest
	 */
	rpc GetModeSDownlinkFrames (GetModeSDownlinkFramesRequest) returns (stream ModeSDownlinkFrameWithStreamInfo);

	/*
	 * Request a stream of Mode S uplink frames (matching the request) from
	 *  the server.
	 * For reconfiguration, the call has to be cancelled.
	 * Returns UNAVAILABLE if the service is shutting down.
	 * Returns INVALID_ARGUMENT if request was invalid, see GetModeSUplinkFramesRequest
	 */
	rpc GetModeSUplinkFrames (GetModeSUplinkFramesRequest) returns (stream ModeSUplinkFrameWithStreamInfo);

	/*
	 * Request a stream of Mode AC downlink frames (matching the request) from
	 *  the server.
	 * For reconfiguration, the call has to be cancelled.
	 * Returns UNAVAILABLE if the service is shutting down.
	 * Returns INVALID_ARGUMENT if request was invalid, see GetModeACDownlinkFramesRequest
	 */
	rpc GetModeACDownlinkFrames (GetModeACDownlinkFramesRequest) returns (stream ModeACDownlinkBinnedFrameWithStreamInfo);
}

Monitoring API

syntax = "proto3";

import "google/protobuf/empty.proto";

package serosystems.proto.v3.grx.monitord;
option java_package = "de.serosystems.proto.v3.grx.monitord";
option java_outer_classname = "MonitorDProto";
// Go package is relative to the web-ui package
// This will result in "golang.sero-systems.de/grx/web-ui/proto/.../v3
option go_package = "proto/monitord/v3";

/* CPU Usage */
message CPUUsage {
	/*
	 * CPU Usage information for a single CPU/core (or aggregated over all).
	 * All values are percent of time spent in the given states within the last
	 *  measurement period.
	 */
	message SingleCPUUsage {
		float total = 1;
		float user = 2;
		float nice = 3;
		float sys = 4;
		float idle = 5;
		float iowait = 6;
		float irq = 7;
		float softirq = 8;
	}

	/* Total CPU usage (of all CPUs/cores) as average. */
	SingleCPUUsage total = 1;

	/* CPU Usage broken down for each CPU/core. */
	repeated SingleCPUUsage per_cpu = 2;
}

/* Memory usage. All values are in bytes. */
message MemoryUsage {
	uint64 total = 1;
	uint64 used = 2;
	uint64 free = 3;
	uint64 shared = 4;
	uint64 buffer = 5;
	uint64 cached = 6;
	uint64 user = 7;
	uint64 locked = 8;
}

/* Swap memory usage. All values are in bytes. */
message SwapUsage {
	uint64 total = 1;
	uint64 used = 2;
	uint64 free = 3;
}

/* File system usage. */
message FileSystemUsage {
	/* Mount point. */
	message MountEntry {
		/* Probably not needed, what is it anyways? */
		//uint64 dev = 1;
		reserved 1;

		/* Device name. */
		string devname = 2;

		/* Mount point. */
		string mountdir = 3;

		/* Filesystem type. */
		string type = 4;
	}

	/* Mount point for this usage info. */
	MountEntry mount = 1;

	/* Total number of blocks. */
	uint64 blocks = 2;

	/* Free blocks available to non-superuser. */
	uint64 bavail = 3;

	/* Size of a block [b]. */
	uint32 block_size = 4;
}

/* Process info. */
message ProcessInfo {
	/* Process ID. */
	uint64 pid = 1;

	/* User name. */
	string user = 2;

	/* Kernel scheduling priority. */
	int32 priority = 3;

	/* Standard unix nice level of process. */
	int32 nice = 4;

	/* The state, as defined by the GLIBTOP_PROCESS_* macros. */
	int32 state = 5;

	/* Command name. */
	string command = 6;

	/* Command Arguments. */
	repeated string argument = 7;

	/* Parent process ID. */
	uint64 ppid = 8;

	/* Total number of pages of virtual memory. */
	uint64 mem_virt = 9;

	/* Number of resident set (non-swapped) pages. */
	uint64 mem_res = 10;

	/* Number of pages of shared memory. */
	uint64 mem_shared = 11;

	/* Start time of the process [s since epoch UTC]. */
	uint64 start_time = 12;

	/* User-mode CPU time [s]. */
	float utime = 13;

	/* Kernel-mode CPU time [s]. */
	float stime = 14;

	/* TODO: possibly missing: %cpu, %mem */
}

/* Representation of a Debian Package. */
message SystemPackage {
	/* Debian package states. */
	enum Status {
		NOTINSTALLED = 0;
		CONFIGFILES = 1;
		HALFINSTALLED = 2;
		UNPACKED = 3;
		HALFCONFIGURED = 4;
		TRIGGERSAWAITED = 5;
		TRIGGERSPENDING = 6;
		INSTALLED = 7;
	};

	/* Debian package state. */
	Status status = 1;

	/* Package name. */
	string name = 2;

	/* Package version. */
	string version = 3;

	/* Package architecture. */
	string architecture = 4;
}

/*
 * Representation of of a single log message.
 * See also SYSTEMD.JOURNAL-FIELDS(7) for details.
 */
message LogMessage {
	/* TODO: there can be many, many fields, which are usually organized in
	 * key-value pairs, we only extract some here. */

	/* Log message. */
	string message = 1;

	/* Value between 0 (emergency) and 7 (debug). */
	uint32 priority = 2;

	/* File of the code where the messages originates (if known). */
	string code_file = 3;

	/* Line of the code where the messages originates (if known). */
	string code_line = 4;

	/* Function of the code where the messages originates (if known). */
	string code_func = 5;

	/* Value of errno (if available). */
	uint32 causing_errno = 6;

	/* Syslog facility, see RFC 3164. */
	uint32 syslog_facility = 7;

	/*
	 * Systemd SyslogIdentifier, defaulting to process name.
	 * See also systemd.exec(5).
	 */
	string syslog_identifier = 8;

	/* Syslog PID. */
	uint32 syslog_pid = 9;

	/* Time [ms since epoch UTC] this entry was received in the journal. */
	uint64 realtime_timestamp = 10;
}

/* Representation of a systemd unit. */
message Unit {
	/* ID/name of the unit. */
	string id = 1;

	/* Description of the unit. */
	string description = 2;

	/* Load state, e.g. "loaded", "not-found",etc. */
	string load_state = 3;

	/* Active state, e.g. "active", "inactive", etc. */
	string active_state = 4;

	/* Sub-state, e.g. "running", "exited", etc. */
	string sub_state = 5;

	string following = 6;

	/* SD-Bus path of the unit. */
	string unit_path = 7;

	uint32 job_id = 8;
	string job_type = 9;
	string job_path = 10;
}

/*
 * Network device usage: rates for the measurement period, i.e.
 * packets/s, bytes/s, errors/s and collisions/s.
 */
message NetworkDeviceUsage {
	/* Name of the device. */
	string device = 1;

	uint32 packets_in = 2;
	uint32 packets_out = 3;
	uint32 packets_total = 4;
	uint32 bytes_in = 5;
	uint32 bytes_out = 6;
	uint32 bytes_total = 7;
	uint32 errors_in = 8;
	uint32 errors_out = 9;
	uint32 errors_total = 10;
	uint32 collisions = 11;
}

/*
 * Network device counters.
 * Very similar to NetworkDeviceUsage, but gives absolute counter values instead
 *  of rates.
 * Make sure to take care of overflows. Currently, Linux uses 32 bit counters
 *  for (probably most of) these values.
 */
message NetworkDeviceCounters {
	/* Name of the device */
	string device = 1;

	uint32 packets_in = 2;
	uint32 packets_out = 3;
	uint32 packets_total = 4;
	uint32 bytes_in = 5;
	uint32 bytes_out = 6;
	uint32 bytes_total = 7;
	uint32 errors_in = 8;
	uint32 errors_out = 9;
	uint32 errors_total = 10;
	uint32 collisions = 11;

}

/* System health information. */
message SystemHealth {
	/* CPU temperature [Deg. Celcius]. */
	float temperature_cpu = 1;

	/* Voltage at the DC input [V]. */
	float voltage_dc_in = 2;
}

/* Overall system information. */
message SystemInformation {
	/* Current system time [s since epoch UTC]. */
	uint64 system_time = 1;

	/* Uptime of the system [s]. */
	uint32 uptime = 2;

	/* Reset reasons. */
	enum ResetReason {
		/*
		 * Power on Reset, i.e. device has been connected to power. Does not
		 *  indicate a problem.
		 */
		PowerOnReset = 0;

		/*
		 * System level controller reset. Happens e.g. if the device is
		 *  rebooted manually. Usually does not indicate a problem.
		 */
		SystemLevelControllerReset = 1;

		/*
		 * System watchdog reset. Happens if the device is reset by the
		 * internal watchdog timer. Indicates a problem.
		 */
		SystemWatchdogReset = 2;

		/*
		 * External system reset. Can happen on development device which have a
		 *  mounted reset switch and if the Zynq is reset by the CPLD. Usually
		 *  indicates a problem.
		 */
		ExternalSystemReset = 3;

		/*
		 * Debug reset. Should only happen during debugging with JTAG
		 *  hardware.
		 */
		DebugReset = 4;

		/* CPU0 APU watchdog timer reset, should never happen. */
		APUWatchdogTimerReset0 = 5;

		/* CPU1 APU watchdog timer reset, should never happen. */
		APUWatchdogTimerReset1 = 6;
	}

	/*
	 * The reset reasons. There can be multiple, as they need to be manually
	 *  cleared.
	 */
	repeated ResetReason reset_reasons = 3;

	/* The serial number of the device. */
	string serial_number = 4;

	/* System version fields. */
	map<string, string> version_information = 5;
}

/*
 * System Load: Number of jobs in run queue or waiting for IO over time.
 * See /proc/loadavg under proc(5) for details.
 */
message SystemLoad {
	/* Load average over last minute. */
	float load_avg_1m = 1;

	/* Load average over last 5 minutes. */
	float load_avg_5m = 2;

	/* Load average over last 15 minutes. */
	float load_avg_15m = 3;
}

/* GNSS Information. */
message GNSSInformation {
	/* Position information. */
	message Position {
		/* Fix type of GNSS receiver. */
		enum FixType {
			/* No fix established. */
			None = 0;
			/* 2D position fix. */
			Pos2D = 2;
			/* 3D position fix. */
			Pos3D = 3;
			/*
			 * Time only fix. Used in "stationary" mode, when the position is
			 *  assumed to be static.
			 */
			TimeOnly = 5;
		}

		/* Type of fix. */
		FixType fix_type = 1;

		/* Number of satellites used in the solution. Actually uint8. */
		uint32 sats_used = 2;

		/* Latitude [degrees]. */
		double latitude = 3;

		/* Longitude [degrees]. */
		double longitude = 4;

		/* Height above WGS-84 ellipsoid [m]. */
		double height = 5;

		/* Estimated horizontal accuracy [m]. */
		double horizontal_accuracy = 6;

		/* Estimated vertical accuracy [m]. */
		double vertical_accuracy = 7;
	}

	/* Further timing-related information. */
	message Timing {
		/* UTC Timing information. */
		message UTC {
			/* UTC standard of GNSS receiver. */
			enum Standard {
				/* Unknown. */
				Unknown = 0;
				/* UTC as operated by the U.S. Naval Observatory (USNO). */
				USNO = 3;
				/* UTC as operated by the former Soviet Union. */
				SU = 6;
				/*
				 * UTC as operated by the National Time Service Center, China.
				 */
				China = 7;
			};

			/* Whether all UTC fields are valid. */
			bool valid = 1;

			/* Used UTC standard. */
			Standard standard = 2;

			/* UTC year. Actually uint16. */
			uint32 year = 3;

			/* UTC month. Actually uint8. */
			uint32 month = 4;

			/* UTC day. Actually uint8. */
			uint32 day = 5;

			/* UTC hour. Actually uint8. */
			uint32 hour = 6;

			/* UTC minute. actually uint8. */
			uint32 min = 7;

			/*
			 * UTC second (may also be 60, if a leap second is present).
			 * Actually uint8.
			 */
			uint32 sec = 8;
		}

		/* Disciplining sources of GNSS receiver. */
		enum DiscipliningSource {
			/* Internal oscillator. */
			Internal = 0;
			/* GNSS. */
			GNSS = 1;
			EXTINT0 = 2;
			EXTINT1 = 3;
			/* Internal oscillator measured by the host. */
			InternalMeasuredByHost = 4;
			/* External oscillator measured by the host. */
			ExternalMeasuredByHost = 5;
		};

		/* UTC timing information. */
		UTC utc = 1;

		/* Whether time pulse is within tolerance limits. */
		bool time_pulse_within_tolerance = 2;

		/* Whether the internal oscillator is within tolerance limits. */
		bool internal_oscillator_within_tolerance = 3;

		/* Disciplining source of the oscillator. */
		DiscipliningSource disciplining_source = 4;

		/*
		 * Whether the Receiver Autonomous Integrity Monitoring Algorithm
		 * (RAIM) system is active.
		 */
		bool raim_active = 5;

		/* Whether coherent pulse generation is in operation. */
		bool coherent_pulse_generation = 6;

		/* Whether the time pulse is locked.
		 * Note: even when locked, it may still be out of tolerance.
		 */
		bool time_pulse_locked = 7;

		/* Offset between preceding pulse and UTC top of second [ns]. */
		int32 preceding_pulse_utc_offset = 8;

		/* Estimated GNSS time accuracy [ns]. If 0, value is invalid.
		 * During holdover, this will usually grow large.
		 * Was previously only named `time_accuracy`, which was inaccurate.
		 */
		uint32 gnss_time_accuracy = 9;

		/* Internal oscillator frequency offset [ppb]. */
		float internal_oscillator_frequency_offset = 10;

		/* Internal oscillator frequency uncertainty [ppb]. */
		float internal_oscillator_frequency_uncertainty = 11;

		/* Estimated overall time accuracy [ns] as reported by the module. If 0, value is invalid.
		 * It is important to note that this may not include external holdover
		 * oscillator uncertainties, but can only represent a module-internal
		 * state.
		 * During non-holdover, this will be similar as the `gnss_time_accuracy`, but
		 * during holdover, this value should NOT be consulted. Instead, use the
		 * field `time_accuracy_estimation` of `holdover_oscillator`.
		 */
		uint32 module_utc_accuracy = 12;

		/* Estimated overall time accuracy [ns]. If 0, value is invalid.
		 * During non-holdover, this will be similar as the `gnss_time_accuracy`, but
		 * during holdover, this value will represent the accuracy of the (external)
		 * holdover oscillator (see also `HoldoverOscillator::time_accuracy_estimation`).
		 */
		uint32 overall_time_accuracy = 13;
	}


	message HoldoverOscillator {

	  /* Describes what kind of holdover oscillator schema is used. */
	  enum Schema {
	    /* Only the built-in oscillator (in most cases, this will be the VCTCXO of the GNSS module) is used */
	    BUILT_IN_ONLY = 0;
	    /* The built-in oscillator is main clock source, but during hold-over
	       it is disciplined by a more stable external oscillator */
	    BUILT_IN_DISCIPLINED_BY_EXTERNAL = 1;
	    /* The external oscillator is main clock source. During non-holdover,
	       it is disciplined by the built-in GNSS module. */
	    EXTERNAL_DISCIPLINED_BY_BUILT_IN = 2;
	    /* The external oscillator is main clock source. It is self-contained, i.e.
	       it does not need to be disciplined by the built-in GNSS module. */
	    EXTERNAL_SELF_CONTAINED = 3;
	  };

	  Schema schema = 1;
	  /* A string describing the model of the external oscillator, e.g. "CSAC SA.45s" */
	  string model = 2;

	  /* For how many seconds the holdover state is active. Holdover is active iff value > 0 */
	  uint32 holdover_active_seconds = 3;

	  /* True iff the external oscillator is considered "ready" to holdover.
	     This usually requires some internal locks to be acquired, device to be sufficiently
	     warmed up and more.
	   */
	  bool is_ready_for_holdover = 4;

	  /* True iff the external oscillator issues a warning.
	     A warning is considered to describe a non-fatal, but possibly degraded state.
	     This could e.g. be the case if the internal temperature cannot be properly maintained.
	   */
	  bool warning_present = 5;

	  /* True iff the external oscillator issues a failure.
	     A failure is considered to describe a fatal state where no operation is possible.
	     This could e.g. be hardware failure.
	   */
	  bool failure_present = 6;

	  /* Estimated accuracy of the time [ns]. If 0, value is invalid. */
	  uint32 time_accuracy_estimation = 7;

	  /* Detailed health information about external oscillator.
	     As this is highly device-specific, we only provide key-value string-pairs here. */
	  //message HealthDetails {
	  // string key;
	  // string value;
	  //};
	  //repeated HealthDetails health_details;

	};


	/* GNSS hardware monitoring related information. */
	message HardwareMonitoring {
		/* Jamming state of GNSS receiver. */
		enum JammingState {
			/* Unknown or feature disabled. */
			UnknownOrDisabled = 0;
			/* OK, no significant jamming. */
			OK = 1;
			/* Warning, interference visible, but fix OK. */
			Warning = 2;
			/* Critical, interference visible and no fix. */
			Critical = 3;
		}

		/* Noise level (as measured by the GPS core), actually uint8. */
		uint32 noise_level = 1;

		/* AGC Monitor (range 0 to 8191). */
		uint32 agc_monitor = 2;

		/* Output of the interference monitor. */
		JammingState jamming_state = 3;

		/*
		 * Continuous wave (CW) jamming indicator: 0 (no CW jamming) to 255
		 *  (strong CW jamming).
		 */
		uint32 jamming_indicator = 4;

		/* Magnitude of the I-part of the complex signal (0..255). */
		uint32 signal_magnitude_i = 5;

		/* Magnitude of the Q-part of the complex signal (0..255). */
		uint32 signal_magnitude_q = 6;

		/* Imbalance of the I-part of the complex signal (-128..127). */
		int32 signal_imbalance_i = 7;

		/* Imbalance of the Q-part of the complex signal (-128..127). */
		int32 signal_imbalance_q = 8;

		/* Number of 100ms timeslots with parity errors. */
		uint32 timeslots_parity_errors = 9;

		/* Number of 100ms timeslots with framing errors. */
		uint32 timeslots_framing_errors = 10;

		/* Number of 100ms timeslots with overrun errors. */
		uint32 timeslots_overrun_errors = 11;

		/* Number of 100ms timeslots with break conditions. */
		uint32 timeslots_break_conditions = 12;

		/* Maximum usage of transmitter buffer during the last sysmon period for all targets [%]. */
		uint32 tx_buffers_usage = 13;

		/* Maximum usage of transmitter buffer for all targets (overall) [%]. */
		uint32 tx_buffers_peak_usage = 14;
	}

	/* Version information. */
	message Versions {
		/* Hardware version of the GNSS module. */
		string module_hw = 1;

		/* Software version of the GNSS module. */
		string module_sw = 2;
	}

	/* GNSS Survey-In (timing mode) related information. */
	message SurveyIn {
		/* Duration of the survey-in process [s]. */
		uint32 duration = 1;

		/* Current mean position in ECEF coordinates (X component) [cm]. */
		int32 mean_ecef_x = 2;

		/* Current mean position in ECEF coordinates (Y component) [cm]. */
		int32 mean_ecef_y = 3;

		/* Current mean position in ECEF coordinates (Z component) [cm]. */
		int32 mean_ecef_z = 4;

		/* Mean variance of the position [mm^2]. */
		uint32 mean_variance = 5;

		/* Number of observations until now. */
		uint32 num_observations = 6;

		/* Whether a valid position has been found. */
		bool valid = 7;

		/* Whether the survey in progress is still active. */
		bool active = 8;
	}

	/* Position information. */
	Position position = 1;

	/* Timing-related information, such as UTC time. */
	Timing timing = 2;

	/* GNSS hardware monitoring related information. */
	HardwareMonitoring hardware = 3;

	/* Version information. */
	Versions versions = 4;

	/* GNSS Survey-In (timing mode) related information. */
	SurveyIn survey_in = 5;

	/* Holdover oscillator related information */
	// TODO: this might need to move out of GNSS ...
	HoldoverOscillator holdover_oscillator = 6;
}

/* Reply for GetCPUUsageHistory() call. */
message GetCPUUsageHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and cpu usage. */
	message Pair {
		uint64 timestamp = 1;
		CPUUsage cpu_usage = 2;
	}

	/* CPU usage history. */
	repeated Pair history = 1;
}

/* Reply for GetMemoryUsageHistory() call. */
message GetMemoryUsageHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and memory usage. */
	message Pair {
		uint64 timestamp = 1;
		MemoryUsage memory_usage = 2;
	}

	/* Memory usage history. */
	repeated Pair history = 1;
}

/* Reply for GetSwapUsageHistory() call. */
message GetSwapUsageHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and swap usage. */
	message Pair {
		uint64 timestamp = 1;
		SwapUsage swap_usage = 2;
	}

	/* Swap usage history. */
	repeated Pair history = 1;
}

/* Request for GetLogMessages() call. */
message GetLogMessagesRequest {
	/* List of matches, same semantics as specified for journalctl(1). */
	repeated string match = 1;

	/* Maximum number of (most recent) entries to fetch. Set to 0 for all. */
	uint32 max_lines = 2;

	/* If set, only show entries after the specified cursor. */
	string after_cursor = 3;

	/*
	 * If set, only show entries since the specified timestamp [ms since epoch
	 *  UTC].
	 */
	uint64 since = 4;

	/*
	 * If set, only show entries until the specified timestamp [ms since epoch]
	.*/
	uint64 until = 5;
}

/* Reply for GetMountedFilesystemUsage() call. */
message GetMountedFilesystemUsageReply {
	/* List of mounted file systems with their usage. */
	repeated FileSystemUsage file_system = 1;
}

/* Reply for GetProcessList() call. */
message GetProcessListReply {
	/* List of processes. */
	repeated ProcessInfo processes = 1;
}

/* Reply for GetSystemPackages() call. */
message GetSystemPackagesReply {
	/* List of (installed) packages */
	repeated SystemPackage package = 1;
}

/* Reply for GetLogMessages() call. */
message GetLogMessagesReply {
	/*
	 * Current cursor in the journal, can be used to only fetch new messages in
	 * the next request.
	 */
	string cursor = 1;

	/* Messages. */
	repeated LogMessage message = 2;
}

/* Reply for GetUnitList() call. */
message GetUnitListReply {
	/* List of systemd units */
	repeated Unit unit = 1;
}

/* Reply for GetNetworkUsage() call. */
message GetNetworkUsageReply {
	/* List of network devices with their usage. */
	repeated NetworkDeviceUsage device_usage = 1;
}

/* Reply for GetNetworkUsageHistory() call. */
message GetNetworkUsageHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and network device usage. */
	message Pair {
		uint64 timestamp = 1;
		repeated NetworkDeviceUsage network_usage = 2;
	}

	/* Network device usage history. */
	repeated Pair history = 1;
}

/* Reply for GetNetworkCounters() call. */
message GetNetworkCountersReply {
	/* List of network devices with their counters. */
	repeated NetworkDeviceCounters device_counters = 1;
}

/* Reply for GetSystemHealthHistory() call. */
message GetSystemHealthHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and system health values. */
	message Pair {
		uint64 timestamp = 1;
		SystemHealth values = 2;
	}
	/* System health value history. */
	repeated Pair history = 1;
}

/* Reply for GetSystemLoadHistory() call. */
message GetSystemLoadHistoryReply {
	/* Pair of timestamp [s since epoch UTC] and system load. */
	message Pair {
		uint64 timestamp = 1;
		SystemLoad load = 2;
	}
	/* System load history. */
	repeated Pair history = 1;
}

/* Reply for GetFullSystemStatus() call. **/
message GetFullSystemStatusReply {
	GNSSInformation gnss_information = 1;
	SystemLoad system_load = 2;
	SystemHealth system_health = 3;
	MemoryUsage memory_usage = 4;
	repeated FileSystemUsage file_system_usage = 5;
	repeated NetworkDeviceUsage network_usage = 6;
	SystemInformation system_information = 7;
}

/* Monitor daemon service definition. Port 5305. */
service Monitord {
	/* Get current CPU usage. */
	rpc GetCPUUsage (google.protobuf.Empty) returns (CPUUsage);

	/* Get history of CPU usage. */
	rpc GetCPUUsageHistory (google.protobuf.Empty) returns (GetCPUUsageHistoryReply);

	/* Get current memory usage. */
	rpc GetMemoryUsage (google.protobuf.Empty) returns (MemoryUsage);

	/* Get history of memory usage. */
	rpc GetMemoryUsageHistory (google.protobuf.Empty) returns (GetMemoryUsageHistoryReply);

	/* Get current swap usage. */
	rpc GetSwapUsage (google.protobuf.Empty) returns (SwapUsage);

	/* Get history of swap usage. */
	rpc GetSwapUsageHistory (google.protobuf.Empty) returns (GetSwapUsageHistoryReply);

	/* Get current file system usage. */
	rpc GetMountedFilesystemUsage (google.protobuf.Empty) returns (GetMountedFilesystemUsageReply);

	/* Get a list of processes. */
	rpc GetProcessList (google.protobuf.Empty) returns (GetProcessListReply);

	/* Get a list of (installed) system packages. */
	rpc GetSystemPackages (google.protobuf.Empty) returns (GetSystemPackagesReply);

	/* Get log messages (without streaming/waiting for new ones). */
	rpc GetLogMessages (GetLogMessagesRequest) returns (GetLogMessagesReply);

	/* Get a list (with states) of systemd units. */
	rpc GetUnitList (google.protobuf.Empty) returns (GetUnitListReply);

	/* Get current network usage. */
	rpc GetNetworkUsage (google.protobuf.Empty) returns (GetNetworkUsageReply);

	/* Get history of network usage. */
	rpc GetNetworkUsageHistory (google.protobuf.Empty) returns (GetNetworkUsageHistoryReply);

	/* Get counters (in contrast to the rates) of the network usage. */
	rpc GetNetworkCounters (google.protobuf.Empty) returns (GetNetworkCountersReply);

	/* Get current system health. */
	rpc GetSystemHealth (google.protobuf.Empty) returns (SystemHealth);

	/* Get history of system health. */
	rpc GetSystemHealthHistory (google.protobuf.Empty) returns (GetSystemHealthHistoryReply);

	/* Get current system load. */
	rpc GetSystemLoad (google.protobuf.Empty) returns (SystemLoad);

	/* Get history of system load. */
	rpc GetSystemLoadHistory (google.protobuf.Empty) returns (GetSystemLoadHistoryReply);

	/*
	 * Get (lower level) information about the system, like e.g. uptime, reset
	 *  reasons or low-level version information.
	 */
	rpc GetSystemInformation (google.protobuf.Empty) returns (SystemInformation);


	/*
	 * Clear all reset resons (see SystemInformation message).
	 *  This can be used to "acknowledge" certain events, such as a watchdog reset
	 *  (or also a simple "power on reset").
	 */
	rpc ClearResetReasons (google.protobuf.Empty) returns (google.protobuf.Empty);

	/*
	 * Get information related to the Global Navigation Satellite System
	 *  (GNSS).
	 *  Note: if the information is not available or outdated, the gRPC
	 *  call will fail with status code ABORTED.
	 */
	rpc GetGNSSInformation (google.protobuf.Empty) returns (GNSSInformation);

	/* Get full system status (single call for 7 most used calls).
	 *  Note: submessages may be omitted if the "sub calls" fail, e.g.
	 *  if GNSS information are invalid, the `gnss_information` submessage
	 *  will not be included.
	 */
	rpc GetFullSystemStatus (google.protobuf.Empty) returns (GetFullSystemStatusReply);
}

Spectrum API

syntax = "proto3";

import "google/protobuf/empty.proto";

package serosystems.proto.v3.grx.spectrumd;
option java_package = "de.serosystems.proto.v3.grx.spectrumd";
option java_outer_classname = "SpectrumDProto";

/*
 * This is a service for measuring spectrum occupancy.
 * For that, (fft_size) samples are taken and transformed into frequency domain.
 * We call this an FFT block. Then (aggregation_factor) of those blocks are
 * aggregated (avg and peak=max). We call this an aggregated FFT block.
 * Regarding those aggregated FFT blocks, different services are derived:
 *  - GetAggregatedFFTProperties() returns the fixed parameters used for
 *    transformation and aggregation,
 *  - GetAggregatedFFTBlockStream() returns a stream of aggregated FFT blocks,
 *  - GetWaterfallJPEG() gathers multiple FFT blocks into an waterfall plot,
 *    returning the plot rendered in a JPEG,
 *  - GetWaterfallJPEGStream() returns a stream of such rendered plots,
 *  - GetChannelPowerStream() re-aggregates aggregated FFT blocks over a longer
 *    period and for a frequency range (we call that a channel).
 */

/*
 * Aggregated FFT properties.
 * Response of GetAggregatedFFTProperties() call.
 */
message AggregatedFFTProperties {
	/* Center Frequency [Hz]. */
	uint32 center_frequency = 1;

	/*
	 * Sample rate [Hz].
	 * Observed band is [-sample_rate/2,+sample_rate/2),
	 *  centered at (center_frequency).
	 */
	uint32 sample_rate = 2;

	/*
	 * FFT size, i.e. number of samples used in a single FFT block.
	 * This translates directly into the number of frequency bins of the FFT
	 *  result. Each bin has bandwidth (sample_rate / fft_size).
	 * Thinking of a waterfall plot, this is the number of steps of the x axis
	 *  (frequency).
	 */
	uint32 fft_size = 3;

	/*
	 * Number of FFT blocks aggregated into an aggregated FFT block.
	 * The duration observed for a single FFT block is
	 *  (fft_size / sample_rate). Accordingly, the duration observed for an
	 *  aggregated FFT block is (aggregation_factor * fft_size / sample_rate).
	 */
	uint32 aggregation_factor = 4;
}

/*
 * Aggregated (avg/peak) FFT block, basically one line of a waterfall plot.
 * Has observation duration (aggregation_factor * fft_size / sample_rate).
 * Response of GetAggregatedFFTBlock() call.
 */
message AggregatedFFTBlock {
	/*
	 * Averaged FFT bins [dBm].
	 * Each bin has bandwidth (sample_rate / fft_size) and is averaged over
	 *  a duration of (aggregation_factor * fft_size / sample_rate).
	 * The FFT bins are centered around center_frequency, i.e.
	 *  first element corresponds to (center_frequency - 0.5 * sample_rate),
	 *  last element corresponds to
	 *   (center_frequency + (0.5 - 1/fft_size) * sample_rate),
	 *  and the center frequency is found at index (fft_size/2).
	 * The number of FFT bins is fixed to (fft_size).
	 */
	repeated float bins_avg = 1;

	/*
	 * Aggregated (peak=max) FFT bins [dBm].
	 * Each bin has bandwidth (sample_rate / fft_size) and is the maximum
	 *  observed over a duration of
	 *  (aggregation_factor * fft_size / sample_rate).
	 * The FFT bins are centered around center_frequency, i.e.
	 *  first element corresponds to center_frequency - 0.5 * sample_rate,
	 *  last element corresponds to
	 *   (center_frequency + (0.5 - 1/fft_size) * sample_rate),
	 *  and the center frequency is found at index (fft_size/2).
	 * The number of FFT bins is fixed to fft_size.
	 *
	 * Important note: intermediate peak results are highly compressed (using a
	 *  logarithmic representation), thus you will almost certainly note
	 *  "steps" in the data. Small values might be smaller than the average
	 *  values or they might even be -inf, due to a low resolution for low
	 *  values.
	 *  In such cases, the average value represents a "better" peak.
	 *  This should not be an issue for strong signals, though.
	 */
	repeated float bins_peak = 2;
}

/*
 * Request of GetWaterfallJPEG() and GetWaterfallJPEGStream() calls.
 */
message GetWaterfallJPEGRequest {
	/*
	 * Number of lines of the rendered image, defining the JPEG height [px].
	 * The service records num_lines aggregated FFT block messages and renders
	 *  them as JPEG. Each line corresponds to one aggregated FFT block.
	 * The duration shown in the waterfall plot corresponds to
	 *  (lines * aggregation_factor * fft_size / sample_rate)
	 *  which is also the duration needed for the call to return.
	 */
	uint32 num_lines = 1;

	/* Lower limit of the color scale [dBm]. */
	float min_level = 2;

	/* Upper limit of the color scale [dBm]. */
	float max_level = 3;

	/* JPEG quality [%]. */
	uint32 jpeg_quality = 4;

	/* Aggregation type for aggregated FFT blocks. */
	enum AggregationType {
		/* Aggregate blocks by average. */
		AVERAGE = 0;
		/* Aggregate blocks by peak. */
		PEAK = 1;
	}

	/* Aggregation type for aggregated FFT blocks. */
	AggregationType aggregation_type = 5;
}

/*
 * Waterfall plot rendered as a JPEG image.
 * Response of GetWaterfallJPEG() and GetWaterfallJPEGStream() calls.
 */
message WaterfallJPEGImage {
	/*
	 * Timestamp [s since epoch UTC] for the bottom line in the JPEG.
	 */
	uint64 timestamp = 1;

	/*
	 * JPEG image for waterfall plot, rendered from top (first block) to bottom
	 *  (last block).
	 */
	bytes image = 2;
}

/* Request of GetChannelPowerStream() call. */
message ChannelPowerRequest {
	/*
	 * Additional aggregation factor for channel power measurements.
	 * The total aggregation factor will be this factor multiplied by
	 *  (aggregation_factor).
	 * The response is measured over a period of
	 *  (channel_aggregation_factor * aggregation_factor * fft_size
	 *   / sample_rate). This is also the time needed for the call to return.
	 */
	uint32 channel_aggregation_factor = 1;

	/*
	 * Lower bin index of the FFT to be included in the result.
	 * See also documentation of AggregatedFFTBlock.bins_avg.
	 */
	uint32 lower_bin = 2;

	/*
	 * Upper bin index of the FFT to be included in the result.
	 * See also documentation of AggregatedFFTBlock.bins_avg.
	 */
	uint32 upper_bin = 3;
}

/* Response of GetChannelPowerStream() call. */
message ChannelPower {
	/*
	 * Timestamp [s since epoch UTC] when the measurement was finished.
	 */
	uint64 timestamp = 1;

	/*
	 * Average channel power [dBm].
	 * Average over all
	 *  (channel_aggregation_factor * aggregation_factor) FFT blocks,
	 * averaged over the channel.
	 */
	float average_channel_power = 2;

	/*
	 * Peak average channel power [dBm], peak over averages:
	 * Peak over AggregatedFFTBlock.bins_avg averaged over the channel.
	 */
	float peak_average_channel_power = 3;

	/*
	 * Peak power [dBm].
	 * Peak over all
	 *  (channel_aggregation_factor * aggregation_factor) FFTs,
	 * averaged over the channel.
	 * Please observe the notes on AggregatedFFTBlock.bins_peak when
	 *  interpreting the data.
	 */
	float peak_channel_power = 4;
}

/* Spectrum daemon service definition. Port 5306. */
service Spectrumd {
	/* Request the aggregated FFT properties, they do not change over time. */
	rpc GetAggregatedFFTProperties (google.protobuf.Empty) returns (AggregatedFFTProperties);

	/* Request a stream of aggregated (avg/peak) FFT blocks. */
	rpc GetAggregatedFFTBlockStream (google.protobuf.Empty) returns (stream AggregatedFFTBlock);

	/* Request a single waterfall plot as JPEG image. */
	rpc GetWaterfallJPEG (GetWaterfallJPEGRequest) returns (WaterfallJPEGImage);

	/* Request a stream of waterfall plots as JPEG images. */
	rpc GetWaterfallJPEGStream (GetWaterfallJPEGRequest) returns (stream WaterfallJPEGImage);

	/* Request a stream of channel occupancy measurements. */
	rpc GetChannelPowerStream (ChannelPowerRequest) returns (stream ChannelPower);
}