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}