001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.epilogue.logging;
006
007import edu.wpi.first.units.Measure;
008import edu.wpi.first.units.Unit;
009import edu.wpi.first.util.protobuf.Protobuf;
010import edu.wpi.first.util.struct.Struct;
011import java.util.Collection;
012import us.hebi.quickbuf.ProtoMessage;
013
014/** A backend is a generic interface for Epilogue to log discrete data points. */
015public interface EpilogueBackend {
016  /**
017   * Creates a backend that logs to multiple backends at once. Data reads will still only occur
018   * once; data is passed to all composed backends at once.
019   *
020   * @param backends the backends to compose together
021   * @return the multi backend
022   */
023  static EpilogueBackend multi(EpilogueBackend... backends) {
024    return new MultiBackend(backends);
025  }
026
027  /**
028   * Creates a lazy version of this backend. A lazy backend will only log data to a field when its
029   * value changes, which can help keep file size and bandwidth usage in check. However, there is an
030   * additional CPU and memory overhead associated with tracking the current value of every logged
031   * entry. The most surefire way to reduce CPU and memory usage associated with logging is to log
032   * fewer things - which can be done by opting out of logging unnecessary data or increasing the
033   * minimum logged importance level in the Epilogue configuration.
034   *
035   * @return the lazy backend
036   */
037  default EpilogueBackend lazy() {
038    return new LazyBackend(this);
039  }
040
041  /**
042   * Gets a backend that can be used to log nested data underneath a specific path.
043   *
044   * @param path the path to use for logging nested data under
045   * @return the nested backend
046   */
047  EpilogueBackend getNested(String path);
048
049  /**
050   * Logs a 32-bit integer data point.
051   *
052   * @param identifier the identifier of the data point
053   * @param value the value of the data point
054   */
055  void log(String identifier, int value);
056
057  /**
058   * Logs a 64-bit integer data point.
059   *
060   * @param identifier the identifier of the data point
061   * @param value the value of the data point
062   */
063  void log(String identifier, long value);
064
065  /**
066   * Logs a 32-bit floating point data point.
067   *
068   * @param identifier the identifier of the data point
069   * @param value the value of the data point
070   */
071  void log(String identifier, float value);
072
073  /**
074   * Logs a 64-bit floating point data point.
075   *
076   * @param identifier the identifier of the data point
077   * @param value the value of the data point
078   */
079  void log(String identifier, double value);
080
081  /**
082   * Logs a boolean data point.
083   *
084   * @param identifier the identifier of the data point
085   * @param value the value of the data point
086   */
087  void log(String identifier, boolean value);
088
089  /**
090   * Logs a raw byte array data point. <strong>NOTE:</strong> serializable data should be logged
091   * using {@link #log(String, Object, Struct)}.
092   *
093   * @param identifier the identifier of the data point
094   * @param value the value of the data point
095   */
096  void log(String identifier, byte[] value);
097
098  /**
099   * Logs a 32-bit integer array data point.
100   *
101   * @param identifier the identifier of the data point
102   * @param value the value of the data point
103   */
104  void log(String identifier, int[] value);
105
106  /**
107   * Logs a 64-bit integer array data point.
108   *
109   * @param identifier the identifier of the data point
110   * @param value the value of the data point
111   */
112  void log(String identifier, long[] value);
113
114  /**
115   * Logs a 32-bit floating point array data point.
116   *
117   * @param identifier the identifier of the data point
118   * @param value the value of the data point
119   */
120  void log(String identifier, float[] value);
121
122  /**
123   * Logs a 64-bit floating point array data point.
124   *
125   * @param identifier the identifier of the data point
126   * @param value the value of the data point
127   */
128  void log(String identifier, double[] value);
129
130  /**
131   * Logs a boolean array data point.
132   *
133   * @param identifier the identifier of the data point
134   * @param value the value of the data point
135   */
136  void log(String identifier, boolean[] value);
137
138  /**
139   * Logs a text data point.
140   *
141   * @param identifier the identifier of the data point
142   * @param value the value of the data point
143   */
144  void log(String identifier, String value);
145
146  /**
147   * Logs a string array data point.
148   *
149   * @param identifier the identifier of the data point
150   * @param value the value of the data point
151   */
152  void log(String identifier, String[] value);
153
154  /**
155   * Logs a collection of strings data point.
156   *
157   * @param identifier the identifier of the data point
158   * @param value the value of the data point
159   */
160  default void log(String identifier, Collection<String> value) {
161    log(identifier, value.toArray(String[]::new));
162  }
163
164  /**
165   * Logs a struct-serializable object.
166   *
167   * @param identifier the identifier of the data point
168   * @param value the value of the data point
169   * @param struct the struct to use to serialize the data
170   * @param <S> the serializable type
171   */
172  <S> void log(String identifier, S value, Struct<S> struct);
173
174  /**
175   * Logs an array of struct-serializable objects.
176   *
177   * @param identifier the identifier of the data point
178   * @param value the value of the data point
179   * @param struct the struct to use to serialize the objects
180   * @param <S> the serializable type
181   */
182  <S> void log(String identifier, S[] value, Struct<S> struct);
183
184  /**
185   * Logs a collection of struct-serializable objects.
186   *
187   * @param identifier the identifier of the data
188   * @param value the collection of objects to log
189   * @param struct the struct to use to serialize the objects
190   * @param <S> the serializable type
191   */
192  default <S> void log(String identifier, Collection<S> value, Struct<S> struct) {
193    @SuppressWarnings("unchecked")
194    S[] array = (S[]) value.toArray(Object[]::new);
195    log(identifier, array, struct);
196  }
197
198  /**
199   * Logs a protobuf-serializable object.
200   *
201   * @param identifier the identifier of the data point
202   * @param value the value of the data point
203   * @param proto the protobuf to use to serialize the data
204   * @param <P> the protobuf-serializable type
205   * @param <M> the protobuf message type
206   */
207  <P, M extends ProtoMessage<M>> void log(String identifier, P value, Protobuf<P, M> proto);
208
209  /**
210   * Logs a measurement's value in terms of its base unit.
211   *
212   * @param identifier the identifier of the data field
213   * @param value the new value of the data field
214   */
215  default void log(String identifier, Measure<?> value) {
216    log(identifier, value.baseUnitMagnitude());
217  }
218
219  /**
220   * Logs a measurement's value in terms of another unit.
221   *
222   * @param identifier the identifier of the data field
223   * @param value the new value of the data field
224   * @param unit the unit to log the measurement in
225   * @param <U> the dimension of the unit
226   */
227  default <U extends Unit> void log(String identifier, Measure<U> value, U unit) {
228    log(identifier, value.in(unit));
229  }
230
231  /**
232   * Logs an enum value. The value will appear as a string entry using the name of the enum.
233   *
234   * @param identifier the identifier of the data field
235   * @param value the new value of the data field
236   */
237  default void log(String identifier, Enum<?> value) {
238    log(identifier, value.name());
239  }
240
241  // TODO: Add default methods to support common no-struct no-sendable types like joysticks?
242}