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}