// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
Measurements represent recordings from sensors at regular intervals, or
algorithm outputs derived from such sensor data.

The structure works a bit like a csv. There is a header which describes the
type and order of the values stored in the data field.

When dealing with measurements it is important to consider if the signal you
are measuring is a sample an integral signal. Samples and integrals are
treated very different mathematically.

Samples only make sense to talk about at instants in time, while integrals
only make sense to talk about  time windows. Heart rate and acceleration are
good examples of sample measurements, while steps and  are good examples of
integral measurements.

For sequential integral measurements, one time window ends an instant before
the next measurement begins, therefore one only need to add an explicit end
to the last measurement (see time_end_utc)

Because of these assumptions, non-sequential integral measurements should
be broken into separate messages.
*/

syntax = "proto2";

package pebble.pipeline;

option java_package = "com.getpebble.pipeline";

import "common.proto";

message Measurement {
  required uint32 offset_sec = 1; /// offset since timestamp (in seconds)
  repeated uint32 data = 2 [packed=true];
}

message MeasurementSet {
  enum HeartRateQuality {
      NoAccel = 0;
      OffWrist = 1;
      NoSignal = 2;
      Worst = 3;
      Poor = 4;
      Acceptable = 5;
      Good = 6;
      Excellent = 7;
  }
  enum Type { /// types of measurement samples we can take. minor changes to SI units to encode efficiently
    UnknownEvent = 0; /// Protocol Buffers uses the first enum as the default
    TimeMS = 1; /// more precise time, in milliseconds
    VMC = 2; /// Vector Magnitude Counts. Rough measure of total activity. Unitless
    Steps = 3; /// Accumulated steps. Unitless
    DistanceCM = 4; /// Distance traveled. In centimeters
    RestingGCalories = 5; /// Calories burned due to resting metabolic rate. In gram calories
    ActiveGCalories = 6; /// Calories burned due to activity. In gram calories
    BPM = 7; /// Heart rate. Beats per minutes
    RR = 8; /// Heart rate variability. Peak to peak time in ms
    Orientation = 9; /// Orientation of the watch. Some weird units
    Light = 10; ///  Ambient light. 
    Temperature = 11; /// Temperature of watch. Kelvin
    HRQuality = 12; /// Quality of heart rate signal, a HeartRateQuality enum
  }
  required bytes uuid = 1; /// 16-byte uuid for efficient message size
  optional User user = 2;
  required uint32 time_utc = 3; /// time since epoch (in seconds)
  required sint32 utc_to_local = 4; /// sint32 stores neg number efficiently. need to recast before adding to time_utc, but saves storage
  optional bytes sensor_settings = 5; /// sensors might have all sorts of different modes or config that might be best represented as a byte blob
  repeated Type types = 7; /// denotes types and order of packed data in each Sample
  repeated Measurement measurements = 8;
  optional uint32 time_end_utc = 9; /// end of last time window if data contains any integral signals
}
