001/*
002 * Copyright (C) Photon Vision.
003 *
004 * This program is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package org.photonvision.targeting;
019
020import org.photonvision.common.dataflow.structures.PacketSerde;
021import org.photonvision.struct.PhotonPipelineMetadataSerde;
022import org.photonvision.targeting.serde.PhotonStructSerializable;
023
024public class PhotonPipelineMetadata implements PhotonStructSerializable<PhotonPipelineMetadata> {
025    // Image capture and NT publish timestamp, in microseconds
026    // The timebase is nt::Now on the time sync server
027    public long captureTimestampMicros;
028    public long publishTimestampMicros;
029
030    // Mirror of the heartbeat entry -- monotonically increasing
031    public long sequenceID;
032
033    // Time from last Time Sync Pong received and the construction of this metadata, in uS
034    public long timeSinceLastPong;
035
036    public PhotonPipelineMetadata(
037            long captureTimestampMicros,
038            long publishTimestampMicros,
039            long sequenceID,
040            long timeSinceLastPong) {
041        this.captureTimestampMicros = captureTimestampMicros;
042        this.publishTimestampMicros = publishTimestampMicros;
043        this.sequenceID = sequenceID;
044        this.timeSinceLastPong = timeSinceLastPong;
045    }
046
047    public PhotonPipelineMetadata() {
048        this(-1, -1, -1, Long.MAX_VALUE);
049    }
050
051    /** Returns the time between image capture and publish to NT */
052    public double getLatencyMillis() {
053        return (publishTimestampMicros - captureTimestampMicros) / 1e3;
054    }
055
056    /** The time that this image was captured, in the coprocessor's time base. */
057    public long getCaptureTimestampMicros() {
058        return captureTimestampMicros;
059    }
060
061    /** The time that this result was published to NT, in the coprocessor's time base. */
062    public long getPublishTimestampMicros() {
063        return publishTimestampMicros;
064    }
065
066    /**
067     * The number of non-empty frames processed by this camera since boot. Useful to checking if a
068     * camera is alive.
069     */
070    public long getSequenceID() {
071        return sequenceID;
072    }
073
074    @Override
075    public String toString() {
076        return "PhotonPipelineMetadata [captureTimestampMicros="
077                + captureTimestampMicros
078                + ", publishTimestampMicros="
079                + publishTimestampMicros
080                + ", sequenceID="
081                + sequenceID
082                + ", timeSinceLastPong="
083                + timeSinceLastPong
084                + "]";
085    }
086
087    @Override
088    public int hashCode() {
089        final int prime = 31;
090        int result = 1;
091        result = prime * result + (int) (captureTimestampMicros ^ (captureTimestampMicros >>> 32));
092        result = prime * result + (int) (publishTimestampMicros ^ (publishTimestampMicros >>> 32));
093        result = prime * result + (int) (sequenceID ^ (sequenceID >>> 32));
094        result = prime * result + (int) (timeSinceLastPong ^ (timeSinceLastPong >>> 32));
095        return result;
096    }
097
098    @Override
099    public boolean equals(Object obj) {
100        if (this == obj) return true;
101        if (obj == null) return false;
102        if (getClass() != obj.getClass()) return false;
103        PhotonPipelineMetadata other = (PhotonPipelineMetadata) obj;
104        if (captureTimestampMicros != other.captureTimestampMicros) return false;
105        if (publishTimestampMicros != other.publishTimestampMicros) return false;
106        if (sequenceID != other.sequenceID) return false;
107        if (timeSinceLastPong != other.timeSinceLastPong) return false;
108        return true;
109    }
110
111    public static final PhotonPipelineMetadataSerde photonStruct = new PhotonPipelineMetadataSerde();
112
113    @Override
114    public PacketSerde<PhotonPipelineMetadata> getSerde() {
115        return photonStruct;
116    }
117}