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.util.datalog; 006 007import java.nio.ByteBuffer; 008import java.util.Arrays; 009 010/** Log raw byte array values. */ 011public class RawLogEntry extends DataLogEntry { 012 /** The data type for raw values. */ 013 public static final String kDataType = "raw"; 014 015 /** 016 * Constructs a raw log entry. 017 * 018 * @param log datalog 019 * @param name name of the entry 020 * @param metadata metadata 021 * @param type Data type 022 * @param timestamp entry creation timestamp (0=now) 023 */ 024 public RawLogEntry(DataLog log, String name, String metadata, String type, long timestamp) { 025 super(log, name, type, metadata, timestamp); 026 } 027 028 /** 029 * Constructs a raw log entry. 030 * 031 * @param log datalog 032 * @param name name of the entry 033 * @param metadata metadata 034 * @param type Data type 035 */ 036 public RawLogEntry(DataLog log, String name, String metadata, String type) { 037 this(log, name, metadata, type, 0); 038 } 039 040 /** 041 * Constructs a raw log entry. 042 * 043 * @param log datalog 044 * @param name name of the entry 045 * @param metadata metadata 046 * @param timestamp entry creation timestamp (0=now) 047 */ 048 public RawLogEntry(DataLog log, String name, String metadata, long timestamp) { 049 this(log, name, metadata, kDataType, timestamp); 050 } 051 052 /** 053 * Constructs a raw log entry. 054 * 055 * @param log datalog 056 * @param name name of the entry 057 * @param metadata metadata 058 */ 059 public RawLogEntry(DataLog log, String name, String metadata) { 060 this(log, name, metadata, 0); 061 } 062 063 /** 064 * Constructs a raw log entry. 065 * 066 * @param log datalog 067 * @param name name of the entry 068 * @param timestamp entry creation timestamp (0=now) 069 */ 070 public RawLogEntry(DataLog log, String name, long timestamp) { 071 this(log, name, "", timestamp); 072 } 073 074 /** 075 * Constructs a raw log entry. 076 * 077 * @param log datalog 078 * @param name name of the entry 079 */ 080 public RawLogEntry(DataLog log, String name) { 081 this(log, name, 0); 082 } 083 084 /** 085 * Appends a record to the log. 086 * 087 * @param value Value to record; will send entire array contents 088 * @param timestamp Time stamp (0 to indicate now) 089 */ 090 public void append(byte[] value, long timestamp) { 091 m_log.appendRaw(m_entry, value, timestamp); 092 } 093 094 /** 095 * Appends a record to the log. 096 * 097 * @param value Value to record; will send entire array contents 098 */ 099 public void append(byte[] value) { 100 append(value, 0); 101 } 102 103 /** 104 * Appends a record to the log. 105 * 106 * @param value Data to record 107 * @param start Start position of data (in byte array) 108 * @param len Length of data (must be less than or equal to value.length - offset) 109 * @param timestamp Time stamp (0 to indicate now) 110 */ 111 public void append(byte[] value, int start, int len, long timestamp) { 112 m_log.appendRaw(m_entry, value, start, len, timestamp); 113 } 114 115 /** 116 * Appends a record to the log. 117 * 118 * @param value Data to record 119 * @param start Start position of data (in byte array) 120 * @param len Length of data (must be less than or equal to value.length - offset) 121 */ 122 public void append(byte[] value, int start, int len) { 123 append(value, start, len, 0); 124 } 125 126 /** 127 * Appends a record to the log. 128 * 129 * @param value Data to record; will send from value.position() to value.limit() 130 * @param timestamp Time stamp (0 to indicate now) 131 */ 132 public void append(ByteBuffer value, long timestamp) { 133 m_log.appendRaw(m_entry, value, timestamp); 134 } 135 136 /** 137 * Appends a record to the log. 138 * 139 * @param value Data to record; will send from value.position() to value.limit() 140 */ 141 public void append(ByteBuffer value) { 142 append(value, 0); 143 } 144 145 /** 146 * Appends a record to the log. 147 * 148 * @param value Data to record 149 * @param start Start position of data (in value buffer) 150 * @param len Length of data (must be less than or equal to value.length - offset) 151 * @param timestamp Time stamp (0 to indicate now) 152 */ 153 public void append(ByteBuffer value, int start, int len, long timestamp) { 154 m_log.appendRaw(m_entry, value, start, len, timestamp); 155 } 156 157 /** 158 * Appends a record to the log. 159 * 160 * @param value Data to record 161 * @param start Start position of data (in value buffer) 162 * @param len Length of data (must be less than or equal to value.length - offset) 163 */ 164 public void append(ByteBuffer value, int start, int len) { 165 append(value, start, len, 0); 166 } 167 168 /** 169 * Updates the last value and appends a record to the log if it has changed. 170 * 171 * <p>Note: the last value is local to this class instance; using update() with two instances 172 * pointing to the same underlying log entry name will likely result in unexpected results. 173 * 174 * @param value Value to record; will send entire array contents 175 * @param timestamp Time stamp (0 to indicate now) 176 */ 177 public synchronized void update(byte[] value, long timestamp) { 178 if (!equalsLast(value, 0, value.length)) { 179 copyToLast(value, 0, value.length); 180 append(value, timestamp); 181 } 182 } 183 184 /** 185 * Updates the last value and appends a record to the log if it has changed. 186 * 187 * <p>Note: the last value is local to this class instance; using update() with two instances 188 * pointing to the same underlying log entry name will likely result in unexpected results. 189 * 190 * @param value Value to record; will send entire array contents 191 */ 192 public void update(byte[] value) { 193 update(value, 0); 194 } 195 196 /** 197 * Updates the last value and appends a record to the log if it has changed. 198 * 199 * <p>Note: the last value is local to this class instance; using update() with two instances 200 * pointing to the same underlying log entry name will likely result in unexpected results. 201 * 202 * @param value Data to record 203 * @param start Start position of data (in byte array) 204 * @param len Length of data (must be less than or equal to value.length - offset) 205 * @param timestamp Time stamp (0 to indicate now) 206 */ 207 public synchronized void update(byte[] value, int start, int len, long timestamp) { 208 if (!equalsLast(value, start, len)) { 209 copyToLast(value, start, len); 210 append(value, start, len, timestamp); 211 } 212 } 213 214 /** 215 * Updates the last value and appends a record to the log if it has changed. 216 * 217 * <p>Note: the last value is local to this class instance; using update() with two instances 218 * pointing to the same underlying log entry name will likely result in unexpected results. 219 * 220 * @param value Data to record 221 * @param start Start position of data (in byte array) 222 * @param len Length of data (must be less than or equal to value.length - offset) 223 */ 224 public void update(byte[] value, int start, int len) { 225 update(value, start, len, 0); 226 } 227 228 /** 229 * Updates the last value and appends a record to the log if it has changed. 230 * 231 * <p>Note: the last value is local to this class instance; using update() with two instances 232 * pointing to the same underlying log entry name will likely result in unexpected results. 233 * 234 * @param value Data to record; will send from value.position() to value.limit() 235 * @param timestamp Time stamp (0 to indicate now) 236 */ 237 public synchronized void update(ByteBuffer value, long timestamp) { 238 if (!equalsLast(value)) { 239 int start = value.position(); 240 int len = value.limit() - start; 241 copyToLast(value, start, len); 242 append(value, start, len, timestamp); 243 } 244 } 245 246 /** 247 * Updates the last value and appends a record to the log if it has changed. 248 * 249 * <p>Note: the last value is local to this class instance; using update() with two instances 250 * pointing to the same underlying log entry name will likely result in unexpected results. 251 * 252 * @param value Data to record; will send from value.position() to value.limit() 253 */ 254 public void update(ByteBuffer value) { 255 update(value, 0); 256 } 257 258 /** 259 * Updates the last value and appends a record to the log if it has changed. 260 * 261 * <p>Note: the last value is local to this class instance; using update() with two instances 262 * pointing to the same underlying log entry name will likely result in unexpected results. 263 * 264 * @param value Data to record 265 * @param start Start position of data (in value buffer) 266 * @param len Length of data (must be less than or equal to value.length - offset) 267 * @param timestamp Time stamp (0 to indicate now) 268 */ 269 public synchronized void update(ByteBuffer value, int start, int len, long timestamp) { 270 if (!equalsLast(value, start, len)) { 271 copyToLast(value, start, len); 272 append(value, start, len, timestamp); 273 } 274 } 275 276 /** 277 * Updates the last value and appends a record to the log if it has changed. 278 * 279 * <p>Note: the last value is local to this class instance; using update() with two instances 280 * pointing to the same underlying log entry name will likely result in unexpected results. 281 * 282 * @param value Data to record 283 * @param start Start position of data (in value buffer) 284 * @param len Length of data (must be less than or equal to value.length - offset) 285 */ 286 public void update(ByteBuffer value, int start, int len) { 287 update(value, start, len, 0); 288 } 289 290 /** 291 * Gets whether there is a last value. 292 * 293 * <p>Note: the last value is local to this class instance and updated only with update(), not 294 * append(). 295 * 296 * @return True if last value exists, false otherwise. 297 */ 298 public synchronized boolean hasLastValue() { 299 return m_lastValue != null; 300 } 301 302 /** 303 * Gets the last value. 304 * 305 * <p>Note: the last value is local to this class instance and updated only with update(), not 306 * append(). 307 * 308 * @return Last value, or null if none. 309 */ 310 @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") 311 public synchronized byte[] getLastValue() { 312 if (m_lastValue == null) { 313 return null; 314 } 315 return Arrays.copyOf(m_lastValue.array(), m_lastValue.limit()); 316 } 317 318 private boolean equalsLast(byte[] value, int start, int len) { 319 if (m_lastValue == null || m_lastValue.limit() != len) { 320 return false; 321 } 322 return Arrays.equals(m_lastValue.array(), 0, len, value, start, start + len); 323 } 324 325 @SuppressWarnings("PMD.SimplifyBooleanReturns") 326 private boolean equalsLast(ByteBuffer value) { 327 if (m_lastValue == null) { 328 return false; 329 } 330 return value.equals(m_lastValue); 331 } 332 333 private boolean equalsLast(ByteBuffer value, int start, int len) { 334 if (m_lastValue == null || m_lastValue.limit() != len) { 335 return false; 336 } 337 int origpos = value.position(); 338 value.position(start); 339 int origlimit = value.limit(); 340 value.limit(start + len); 341 boolean eq = value.equals(m_lastValue); 342 value.position(origpos); 343 value.limit(origlimit); 344 return eq; 345 } 346 347 private void copyToLast(byte[] value, int start, int len) { 348 if (m_lastValue == null || m_lastValue.limit() < len) { 349 m_lastValue = ByteBuffer.allocate(len); 350 } 351 System.arraycopy(value, start, m_lastValue.array(), 0, len); 352 m_lastValue.limit(len); 353 } 354 355 private void copyToLast(ByteBuffer value, int start, int len) { 356 if (m_lastValue == null || m_lastValue.limit() < len) { 357 m_lastValue = ByteBuffer.allocate(len); 358 } 359 int origpos = value.position(); 360 value.position(start); 361 value.get(m_lastValue.array(), 0, len); 362 value.position(origpos); 363 m_lastValue.limit(len); 364 } 365 366 private ByteBuffer m_lastValue; 367}