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