/**
* This file contains the protobuf message definitions for RedVox API 1000 (M) data and network communications.
*
* Standards and related documentation for API M is available at:
*   - https://github.com/RedVoxInc/redvox-api-1000
*/

syntax = "proto3";
package redvox_api_m;
option java_package = "io.redvox.apis";

message RedvoxPacketM {
    // Top level packet fields

    // The API version, should always be 1000
    float api = 1;

    // The sub-api version.
    float sub_api = 2;

    // Station metadata/metrics
    StationInformation station_information = 3;

    // Timing information, synch exchanges
    TimingInformation timing_information = 4;

    // Sensors, payloads, etc
    Sensors sensors = 5;

    // Derived event streams
    repeated EventStream event_streams = 6;

    // A map from string to string for including untyped metadata
    map<string, string> metadata = 7;

    // --------- The rest of this message contains embedded message types

    // This message contains station metadata and related station state metrics
    message StationInformation {
        // The user selectable station id
        string id = 1;

        // The software provided UUID
        string uuid = 2;

        // Human friendly description of station (i.e. ISLA_0)
        string description = 3;

        // Authentication ID (user's email)
        string auth_id = 4;

        // Make of the station
        string make = 5;

        // Model of the station
        string model = 6;

        // OS of the station
        OsType os = 7;

        // OS version of the station
        string os_version = 8;

        // App version on the station
        string app_version = 9;

        // If the station was set to record privately when this packet was recorded
        bool is_private = 10;

        // A copy of the App's settings
        AppSettings app_settings = 11;

        // Detail station performance metrics
        StationMetrics station_metrics = 12;

        // URLs of remote services utilized by this station
        ServiceUrls service_urls = 13;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 14;

        // An enumeration specifying the available operating system types
        enum OsType {
            UNKNOWN_OS = 0;
            ANDROID = 1;
            IOS = 2;
            OSX = 3;
            LINUX = 4;
            WINDOWS = 5;
        }

        // Backend service URLs used in the creation of this packet
        message ServiceUrls {
            // The URL of the authentication server
            string auth_server = 1;

            // The URL of the synch server
            string synch_server = 2;

            // The URL of the acquisition server
            string acquisition_server = 3;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 4;
        }

        // Collection of station state and performance metrics
        message StationMetrics {
            // Timestamps associated with following sensor state metrics
            TimingPayload timestamps = 1;

            // Type of network connection
            repeated NetworkType network_type = 2;

            // State of the cellular service
            repeated CellServiceState cell_service_state = 3;

            // A value representing the strength of the network connection in decibels
            SamplePayload network_strength = 4;

            // Internal temperature of station in degrees Celsius
            SamplePayload temperature = 5;

            // Remaining percentage of station's battery
            SamplePayload battery = 6;

            // Current in microamperes
            SamplePayload battery_current = 7;

            // Available ram in bytes
            SamplePayload available_ram = 8;

            // Available disk space in bytes
            SamplePayload available_disk = 9;

            // CPU utilization as a percentage
            SamplePayload cpu_utilization = 10;

            // Power state enumeration
            repeated PowerState power_state = 11;

            // If a wifi wake lock is being utilized
            repeated WifiWakeLock wifi_wake_lock = 12;

            // The screen state (if available)
            repeated ScreenState screen_state = 13;

            // Screen brightness as a percentage
            SamplePayload screen_brightness = 14;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 15;

            // An enumeration specifying the available network types
            enum NetworkType {
                UNKNOWN_NETWORK = 0;
                NO_NETWORK = 1;
                WIFI = 2;
                CELLULAR = 3;
                WIRED = 4;
            }

            // Type of WiFi wake lock un use
            enum WifiWakeLock {
                NONE = 0;
                HIGH_PERF = 1;
                LOW_LATENCY = 2;
                OTHER = 3;
            }

            // State of the cellular service
            enum CellServiceState {
                // State is unknown
                UNKNOWN = 0;

                // Only emergency calls
                EMERGENCY = 1;

                // Everything is working fine
                NOMINAL = 2;

                // Cell is searching for service, no available networks
                OUT_OF_SERVICE = 3;

                // Cellular radio is powered off
                POWER_OFF = 4;
            }

            // The state of power supply to station
            enum PowerState {
                // Station is in an unknown power state
                UNKNOWN_POWER_STATE = 0;

                // Station is unplugged
                UNPLUGGED = 1;

                // Station is charging
                CHARGING = 2;

                // Station is charged
                CHARGED = 3;
            }

            // State of the station's screen
            enum ScreenState {
                // Unknown screen state
                UNKNOWN_SCREEN_STATE = 0;

                // Screen is turned on
                ON = 1;

                // Screen is turned off
                OFF = 2;

                // Station is running in headless mode and does not utilize a screen
                HEADLESS = 3;
            }
        }

        // A message that encapsulates the state of the app settings
        message AppSettings {
            // The selected audio sampling rate
            AudioSamplingRate audio_sampling_rate = 1;

            float samples_per_window = 2;

            // The selected audio source tuning
            AudioSourceTuning audio_source_tuning = 3;

            // Additional input sensors
            repeated InputSensor additional_input_sensors = 4;

            // Station automatically records on start
            bool automatically_record = 5;

            // App automatically starts on station
            bool launch_at_power_up = 6;

            // User selectable station id
            string station_id = 7;

            // User selectable station description
            string station_description = 8;

            // Is station data pushed to server?
            bool push_to_server = 9;

            // Is station data published as private?
            bool publish_data_as_private = 10;

            // Is station audio data scrambled?
            bool scramble_audio_data = 11;

            // Should station backfill unsent data?
            bool provide_backfill = 12;

            // Does station remove DC offset?
            bool remove_sensor_dc_offset = 13;

            // Station FFT overlap
            FftOverlap fft_overlap = 14;

            // Should station use custom time synch server?
            bool use_custom_time_sync_server = 15;

            // URL of custom time synch server
            string time_sync_server_url = 16;

            // Should station use custom data server?
            bool use_custom_data_server = 17;

            // URL of custom data server
            string data_server_url = 18;

            // Should station use custom auth server
            bool use_custom_auth_server = 19;

            // URL of custom auth server
            string auth_server_url = 20;

            // Should station auto delete data?
            bool auto_delete_data_files = 21;

            // Station data allowance in bytes
            float storage_space_allowance = 22;

            // Should station use SD card for storage?
            bool use_sd_card_for_data_storage = 23;

            // Should station use location services?
            bool use_location_services = 24;

            // User set latitude decimal degrees
            double use_latitude = 25;

            // User set longitude decimal degrees
            double use_longitude = 26;

            // User set altitude meters
            float use_altitude = 27;

            // User defined setting for how often metrics should be collected
            MetricsRate metrics_rate = 28;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 29;

            // Configured FFT overlap
            enum FftOverlap {
                UNKNOWN = 0;
                PERCENT_25 = 1;
                PERCENT_50 = 2;
                PERCENT_75 = 3;
            }

            // Configured sampling rate
            enum AudioSamplingRate {
                UNKNOWN_SAMPLING_RATE = 0;
                HZ_80 = 1;
                HZ_800 = 2;
                HZ_8000 = 3;
                HZ_16000 = 4;
                HZ_48000 = 5;
            }

            // Configured audio source tuning
            enum AudioSourceTuning {
                UNKNOWN_TUNING = 0;
                INFRASOUND_TUNING = 1;
                LOW_AUDIO_TUNING = 2;
                AUDIO_TUNING = 3;
            }

            // Configured input sensors
            enum InputSensor {
                UNKNOWN_SENSOR = 0;
                ACCELEROMETER = 1;
                ACCELEROMETER_FAST = 2;
                AMBIENT_TEMPERATURE = 3;
                AUDIO = 4;
                COMPRESSED_AUDIO = 5;
                GRAVITY = 6;
                GYROSCOPE = 7;
                GYROSCOPE_FAST = 8;
                IMAGE_PER_SECOND = 9;
                IMAGE_PER_PACKET = 10;
                LIGHT = 11;
                LINEAR_ACCELERATION = 12;
                LOCATION = 13;
                MAGNETOMETER = 14;
                MAGNETOMETER_FAST = 15;
                ORIENTATION = 16;
                PRESSURE = 17;
                PROXIMITY = 18;
                RELATIVE_HUMIDITY = 19;
                ROTATION_VECTOR = 20;
                VELOCITY = 21;
            }
        }

        // Defines how often metrics are collected
        enum MetricsRate {
            UNKNOWN = 0;
            ONCE_PER_SECOND = 1;
            ONCE_PER_PACKET = 2;
        }
    }

    // Stores timing information and related metrics
    // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/keeping_time.md
    message TimingInformation {
        // Start timestamp of the packet using the os clock (corresponding to first audio sample)
        double packet_start_os_timestamp = 1;

        // Start timestamp of the packet using machine time (corresponding to the first audio sample)
        double packet_start_mach_timestamp = 2;

        // End timestamp of the packet using the os clock (corresponding to the last audio sample)
        double packet_end_os_timestamp = 3;

        // End timestamp of the packet using machine time (corresponding to the last audio sample)
        double packet_end_mach_timestamp = 4;

        // Timestamp that the packet arrived at the acquisition server
        double server_acquisition_arrival_timestamp = 5;

        // The start of the app as machine time
        double app_start_mach_timestamp = 6;

        // An array of synchronization params from the synch server
        repeated SynchExchange synch_exchanges = 7;

        // The best latency as determined from the synch params in microseconds
        float best_latency = 8;

        // The best offset as determined from the synch params in microseconds
        float best_offset = 9;

        // The overall timing score
        float score = 10;

        // Method used to provide score
        TimingScoreMethod score_method = 11;

        // A unit describing the time (should always be MICROSECONDS_SINCE_UNIX_EPOCH)
        Unit unit = 12;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 13;

        // Type-safe synchronization exchange values
        message SynchExchange {
            double a1 = 1;
            double a2 = 2;
            double a3 = 3;
            double b1 = 4;
            double b2 = 5;
            double b3 = 6;

            // Unit of parameters a1-b3
            Unit unit = 7;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 8;
        }

        // Method used to score timing metrics
        enum TimingScoreMethod {
            UNKNOWN = 0;
        }
    }

    // Collection of available sensor types
    // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/standard_sensor_units.md
    message Sensors {
        // meters/second^2
        Xyz accelerometer = 1;

        // degrees Celsius
        Single ambient_temperature = 2;

        // normalized counts
        Audio audio = 3;

        // bytes (codec specific)
        CompressedAudio compressed_audio = 4;

        // meters/second^2
        Xyz gravity = 5;

        // radians/second
        Xyz gyroscope = 6;

        // bytes (codec specific)
        Image image = 7;

        // lux
        Single light = 8;

        // meters/second^2
        Xyz linear_acceleration = 9;

        // See standard
        Location location = 10;

        // microtesla
        Xyz magnetometer = 11;

        // radians
        Xyz orientation = 12;

        // kilopascal
        Single pressure = 13;

        // on, off, cm
        Single proximity =14;

        // percentage
        Single relative_humidity = 15;

        // Unitless
        Xyz rotation_vector = 16;

        // m/s
        Xyz velocity = 17;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 18;

        // This message describes a stable audio channel
        // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/storing_audio_data.md
        message Audio {
            // The name or description of the audio sensor
            string sensor_description = 1;

            // Timestamp of the first audio sample
            double first_sample_timestamp = 2;

            // Microphone sample rate in Hz
            float sample_rate = 3;

            // Bits of precision for normalized audio samples
            float bits_of_precision = 4;

            // If audio data has been scrambled to remove voice
            bool is_scrambled = 5;

            // The audio encoding used... TODO: Turn this into an enum!
            string encoding = 6;

            // List of audio samples
            SamplePayload samples = 7;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 8;
        }

        message CompressedAudio {
            // The name or description of the audio sensor
            string sensor_description = 1;

            // Mach timestamp of the first audio sample
            double first_sample_timestamp = 2;

            // Microphone sample rate in Hz
            float sample_rate = 3;

            // If audio data has been scrambled to remove voice
            bool is_scrambled = 4;

            // Bytes that make up audio payload
            bytes audio_bytes = 5;

            // Codec used to compress audio
            AudioCodec audio_codec = 6;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 7;

            // Available audio codecs
            enum AudioCodec {
                UNKNOWN = 0;
                FLAC = 1;
            }
        }

        // A single channel of data
        // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/storing_single_channel_data.md
        message Single {
            // The name or description of the sensor
            string sensor_description = 1;

            // List of timestamps per sample and associated stats
            TimingPayload timestamps = 2;

            // List of samples and associated stats
            SamplePayload samples = 3;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 4;
        }

        // Location channels
        // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/storing_location_data.md
        message Location {
            // The name or description of the sensor
            string sensor_description = 1;

            // Timestamps and stats
            TimingPayload timestamps = 2;

            TimingPayload timestamps_gps = 3;

            // A list of latitude samples
            DoubleSamplePayload latitude_samples = 4;

            // A list of longitude samples
            DoubleSamplePayload longitude_samples = 5;

            // A list of altitude samples
            SamplePayload altitude_samples = 6;

            // A list of speed samples
            SamplePayload speed_samples = 7;

            // A list of bearing samples
            SamplePayload bearing_samples = 8;

            // A list of horizontal accuracy samples
            SamplePayload horizontal_accuracy_samples = 9;

            // A list of vertical accuracy samples
            SamplePayload vertical_accuracy_samples = 10;

            // A list of speed accuracy samples
            SamplePayload speed_accuracy_samples = 11;

            // A list of bearing accuracy samples
            SamplePayload bearing_accuracy_samples = 12;

            // Most recent best location
            BestLocation last_best_location = 13;

            // Best last location
            BestLocation overall_best_location = 14;

            // Have location permissions been granted by the user?
            bool location_permissions_granted = 15;

            // Has location services been requested by the user?
            bool location_services_requested = 16;

            // Are location services enabled and working?
            bool location_services_enabled = 17;

            // Location provider enumeration
            repeated LocationProvider location_providers = 18;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 19;

            message BestLocation {
                // Timestamp of best lat/lng measurement
                BestTimestamp latitude_longitude_timestamp = 1;

                // Timestamp of best altitude measurement
                BestTimestamp altitude_timestamp = 2;

                // Timestamp of best speed measurement
                BestTimestamp speed_timestamp = 3;

                // Timestamp of best bearing estimate
                BestTimestamp bearing_timestamp = 4;

                // Unit used for latitude/longitude (should be decimal degrees)
                Unit latitude_longitude_unit = 5;

                // Unit used for altitude (should be meters)
                Unit altitude_unit = 6;

                // Unit used for speed (should be m/s)
                Unit speed_unit = 7;

                // Unit used for bearing (should be radians)
                Unit bearing_unit = 8;

                // Unit used for vertical accuracy
                Unit vertical_accuracy_unit = 9;

                // Unit used for horizontal accuracy
                Unit horizontal_accuracy_unit = 10;

                // Unit used for speed accuracy
                Unit speed_accuracy_unit = 11;

                // Unit used for bearing accuracy
                Unit bearing_accuracy_unit = 12;

                // The best latitude
                double latitude = 13;

                // The best longitude
                double longitude = 14;

                // The best altitude
                float altitude = 15;

                // The best speed
                float speed = 16;

                // The best bearing
                float bearing = 17;

                // Vertical accuracy
                float vertical_accuracy = 18;

                // Horizontal accuracy
                float horizontal_accuracy = 19;

                // Speed accuracy
                float speed_accuracy = 20;

                // Bearing accuracy
                float bearing_accuracy = 21;

                // The best location score
                float score = 22;

                // Method used to derive the location score
                LocationScoreMethod method = 23;

                LocationProvider location_provider = 24;

                // A map from string to string for including untyped metadata
                map<string, string> metadata = 25;

                // A message that encapsulates both a mach and GPS timestamp
                message BestTimestamp {
                    // Unit of timestamps (should be microseconds since unix epoch UTC)
                    Unit unit = 1;

                    // Best mach timestamp
                    double mach = 2;

                    // Best gps timestamp
                    double gps = 3;

                    // A map from string to string for including untyped metadata
                    map<string, string> metadata = 4;
                }

                // An enumeration for the various scoring methods for the "best of" metrics
                enum LocationScoreMethod {
                    UNKNOWN_METHOD = 0;
                }
            }

            // An enumeration of location providers
            enum LocationProvider {
                UNKNOWN = 0;
                NONE = 1;
                USER = 2;
                GPS = 3;
                NETWORK = 4;
            }
        }

        // Message representing data channels with X, Y, and Z components
        // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/storing_xyz_channel_data.md
        message Xyz {
            // The name or description of the sensor
            string sensor_description = 1;

            // List of timestamps per sample
            TimingPayload timestamps = 2;

            // A list of samples for the X-channel
            SamplePayload x_samples = 3;

            // A list of samples for the Y-channel
            SamplePayload y_samples = 4;

            // A list of samples for the Z-channel
            SamplePayload z_samples = 5;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 6;
        }

        // Image/video channel
        // See: https://github.com/RedVoxInc/redvox-api-1000/src/master/docs/standards/storing_image_data.md
        message Image {
            // The name or description of the sensor
            string sensor_description = 1;

            // Timestamps per sample
            TimingPayload timestamps = 2;

            // A list of bytes each representing a single image
            repeated bytes samples = 3;

            // The image codec being used
            ImageCodec image_codec = 4;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 5;

            // Codec used to encode the image
            enum ImageCodec {
                UNKNOWN = 0;
                PNG = 1;
                JPG = 2;
                BMP = 3;
            }
        }
    }

    // Provides a mechanism for storing various generic derived events
    message EventStream {
        // The name of this stream
        string name = 1;

        // List of timestamps, each associated with one Event
        TimingPayload timestamps = 2;

        // List of events that belong to this stream
        repeated Event events = 3;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 4;

        message Event {
            // Textual description of the event
            string description = 1;

            // Key-pairs of type string to string
            map<string, string> string_payload = 2;

            // Key-pairs of type string to double
            map<string, double> numeric_payload = 3;

            // Key-pairs of type string to boolean
            map<string, bool> boolean_payload = 4;

            // Key-pairs of type string to bytes.
            // This one is mainly for transmitting binary or data that doesn't fit well into one of the other payloads.
            map<string, bytes> byte_payload = 5;

            // A map from string to string for including untyped metadata
            map<string, string> metadata = 6;
        }
    }

    // Combines a unit, sample values, and value statistics
    // Used to store collections of samples, their unit, and the statistics for those samples.
    message SamplePayload {
        // Unit of payload values
        Unit unit = 1;

        // Values in payload
        repeated float values = 2;

        // Statistics of stored values
        SummaryStatistics value_statistics = 3;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 4;
    }

    // Exactly like a SamplePayload, but payload values are 64-bit floats rather than 32-bit floats.
    message DoubleSamplePayload {
        // Unit of payload values
        Unit unit = 1;

        // Values in payload
        repeated double values = 2;

        // Statistics of stored values
        SummaryStatistics value_statistics = 3;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 4;
    }

    // Combines a unit, sample values, and value statistics
    // Used to store collections of samples, their unit, and the statistics for those samples.
    message TimingPayload {
        // Unit of payload values
        Unit unit = 1;

        // Values in payload
        repeated double timestamps = 2;

        // Statistics of stored values
        SummaryStatistics timestamp_statistics = 3;

        // Mean sample rate in Hz
        float mean_sample_rate = 4;

        // Standard deviation of sample rate in Hz
        float stdev_sample_rate = 5;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 6;
    }

    // Enumeration of API M supported units
    enum Unit {
        UNKNOWN = 0;
        METERS_PER_SECOND_SQUARED = 1;
        KILOPASCAL = 2;
        RADIANS_PER_SECOND = 3;
        DECIMAL_DEGREES = 4;
        METERS = 5;
        METERS_PER_SECOND = 6;
        MICROTESLA = 7;
        LSB_PLUS_MINUS_COUNTS = 8;
        MICROSECONDS_SINCE_UNIX_EPOCH = 9;
        DECIBEL = 10;
        DEGREES_CELSIUS = 11;
        BYTE = 12;
        PERCENTAGE = 13;
        RADIANS = 14;
        MICROAMPERES = 15;
        CENTIMETERS = 16;
        NORMALIZED_COUNTS = 17;
        LUX = 18;
        UNITLESS = 19;
        PCM = 20;
    }

    // Common statistics stored with payloads
    message SummaryStatistics {
        // The total count of values included in the statistics
        double count = 1;

        // The mean of the values
        double mean = 2;

        // The standard deviation of the values
        double standard_deviation = 3;

        // The minimum value
        double min = 4;

        // The maximum value
        double max = 5;

        // The range of the values
        double range = 6;

        // A map from string to string for including untyped metadata
        map<string, string> metadata = 7;
    }
}

// --------- E2E Encryption

// Message type for providing E2E encryption.
// The header is encrypted via RedVox keys.
// The body is encrypted via user keys.
// Each payload consists of bytes from the following transformations
//   Serialization: Object -> serialize to bytes -> LZ4 frame compress -> encrypt -> payload bytes
//   Deserialization: Payload bytes -> decrypt -> LZ4 frame decompress -> deserialize from bytes -> object
message EncryptedRedvoxPacketM {
    // redvox encrypt(compress(EncryptedRedvoxPacket1000.Header))
    bytes header = 1;

    // user encrypt(compress(RedvoxPacketApi1000))
    bytes packet = 2;

    message Header {
        // The station id
        string station_id = 1;

        // The station uuid
        string station_uuid = 2;

        // The station's authorization token
        string auth_token = 3;

        // The station's firebase token
        string firebase_token = 4;

        // The station's auth email
        string auth_email = 5;
    }
}

// --------- Message types for communicating with RedVox data acquisition servers
// Message for sending RedVox data to a redvox.io data acquisition service.
message AcquisitionRequest {
    // The server provided authentication token
    string auth_token = 1;

    // The API provided firebase token
    string firebase_token = 2;

    // A checksum of the payload bytes
    int64 checksum = 3;

    // If set, then the payload contains
    bool is_encrypted = 4;

    // The compressed packet to send
    bytes payload = 5;

    // A variable that starts at 0 when the data stream starts and increments by one for each transmission
    int64 seq_id = 6;
}

// Response from data acquisition services.
message AcquisitionResponse {
    // Response type (as above)
    ResponseType response_type = 1;

    // Checksum computed by server
    int64 checksum = 2;

    // Any other error details
    string details = 3;

    // If set, client to should attempt to resend the file
    // otherwise, don't resend the file.
    bool resend = 4;

    // A copy of the seq_id provided in the AcquisitionRequest
    int64 seq_id = 5;

    enum ResponseType {
        // Unknown (default) response type
        UNKNOWN = 0;

        // No issues with packet
        OK = 1;

        // An authentication error has occurred
        AUTH_ERROR = 2;

        // An error with the data decoding or data quality
        DATA_ERROR = 3;

        // Any other errors
        OTHER_ERROR = 4;
    }
}

// --------- Message types for communicating with RedVox v3 time synchronization service
message SynchRequest {
    // Id of the station
    string station_id = 1;

    // Uuid of the station
    string station_uuid = 2;

    // The overall number of synch requests made. Starts at 0 on recording start.
    uint32 seq_id = 3;

    // The seq id within a single exchange
    uint32 sub_seq_id = 4;
}

message SynchResponse {
    // Should match same field from request
    string station_id = 1;

    // Should match same field from request
    string station_uuid = 2;

    // Should match same field from request
    uint32 seq_id = 3;

    // Should be req field + 1
    uint32 sub_seq_id = 4;

    // Time synch server received request
    uint64 recv_ts_us = 5;

    // Time synch server sent response
    uint64 send_ts_us = 6;
}

// --------- Message types for custom logging
// TODO

// --------- Message types for command, control, and communication
// TODO
