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.common.networktables; 019 020import com.fasterxml.jackson.core.JsonProcessingException; 021import com.fasterxml.jackson.databind.ObjectMapper; 022import edu.wpi.first.networktables.RawPublisher; 023import java.util.HashSet; 024import java.util.Set; 025import org.photonvision.common.dataflow.structures.Packet; 026import org.photonvision.common.dataflow.structures.PacketSerde; 027 028@SuppressWarnings("doclint") 029public class PacketPublisher<T> implements AutoCloseable { 030 public final RawPublisher publisher; 031 private final PacketSerde<T> photonStruct; 032 033 public PacketPublisher(RawPublisher publisher, PacketSerde<T> photonStruct) { 034 this.publisher = publisher; 035 this.photonStruct = photonStruct; 036 037 var mapper = new ObjectMapper(); 038 try { 039 this.publisher 040 .getTopic() 041 .setProperty("message_uuid", mapper.writeValueAsString(photonStruct.getInterfaceUUID())); 042 } catch (JsonProcessingException e) { 043 // TODO Auto-generated catch block 044 e.printStackTrace(); 045 throw new RuntimeException(e); 046 } 047 addSchemaImpl(photonStruct, new HashSet<>()); 048 } 049 050 public void set(T value, int byteSize) { 051 var packet = new Packet(byteSize); 052 photonStruct.pack(packet, value); 053 publisher.set(packet.getWrittenDataCopy()); 054 } 055 056 public void set(T value) { 057 set(value, photonStruct.getMaxByteSize()); 058 } 059 060 @Override 061 public void close() { 062 publisher.close(); 063 } 064 065 /** 066 * Publish the schema for our type (and all nested types under it) to NT. 067 * 068 * <p>Copyright (c) FIRST and other WPILib contributors. Open Source Software; you can modify 069 * and/or share it under the terms of the WPILib BSD license file in the root directory of this 070 * project. 071 * 072 * @param struct The struct to publish 073 * @param seen The set of types we've already published 074 */ 075 private void addSchemaImpl(PacketSerde<?> struct, Set<String> seen) { 076 var instance = this.publisher.getTopic().getInstance(); 077 078 String typeString = struct.getTypeString(); 079 080 if (instance.hasSchema(typeString)) { 081 return; 082 } 083 084 if (!seen.add(typeString)) { 085 throw new UnsupportedOperationException(typeString + ": circular reference with " + seen); 086 } 087 088 instance.addSchema(typeString, "photonstructschema", struct.getSchema()); 089 090 for (var inner : struct.getNestedPhotonMessages()) { 091 addSchemaImpl(inner, seen); 092 } 093 for (var inner : struct.getNestedWpilibMessages()) { 094 instance.addSchema(inner); 095 } 096 seen.remove(typeString); 097 } 098}