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.networktables; 006 007import edu.wpi.first.util.protobuf.Protobuf; 008import edu.wpi.first.util.protobuf.ProtobufBuffer; 009 010/** 011 * NetworkTables protobuf-encoded value topic. 012 * 013 * @param <T> value class 014 */ 015public final class ProtobufTopic<T> extends Topic { 016 private ProtobufTopic(Topic topic, Protobuf<T, ?> proto) { 017 super(topic.m_inst, topic.m_handle); 018 m_proto = proto; 019 } 020 021 private ProtobufTopic(NetworkTableInstance inst, int handle, Protobuf<T, ?> proto) { 022 super(inst, handle); 023 m_proto = proto; 024 } 025 026 /** 027 * Create a ProtobufTopic from a generic topic. 028 * 029 * @param <T> value class (inferred from proto) 030 * @param topic generic topic 031 * @param proto protobuf serialization implementation 032 * @return ProtobufTopic for value class 033 */ 034 public static <T> ProtobufTopic<T> wrap(Topic topic, Protobuf<T, ?> proto) { 035 return new ProtobufTopic<>(topic, proto); 036 } 037 038 /** 039 * Create a ProtobufTopic from a native handle; generally NetworkTableInstance.getProtobufTopic() 040 * should be used instead. 041 * 042 * @param <T> value class (inferred from proto) 043 * @param inst Instance 044 * @param handle Native handle 045 * @param proto protobuf serialization implementation 046 * @return ProtobufTopic for value class 047 */ 048 public static <T> ProtobufTopic<T> wrap( 049 NetworkTableInstance inst, int handle, Protobuf<T, ?> proto) { 050 return new ProtobufTopic<>(inst, handle, proto); 051 } 052 053 /** 054 * Create a new subscriber to the topic. 055 * 056 * <p>The subscriber is only active as long as the returned object is not closed. 057 * 058 * <p>Subscribers that do not match the published data type do not return any values. To determine 059 * if the data type matches, use the appropriate Topic functions. 060 * 061 * @param defaultValue default value used when a default is not provided to a getter function 062 * @param options subscribe options 063 * @return subscriber 064 */ 065 public ProtobufSubscriber<T> subscribe(T defaultValue, PubSubOption... options) { 066 return new ProtobufEntryImpl<>( 067 this, 068 ProtobufBuffer.create(m_proto), 069 NetworkTablesJNI.subscribe( 070 m_handle, NetworkTableType.kRaw.getValue(), m_proto.getTypeString(), options), 071 defaultValue, 072 false); 073 } 074 075 /** 076 * Create a new publisher to the topic. 077 * 078 * <p>The publisher is only active as long as the returned object is not closed. 079 * 080 * <p>It is not possible to publish two different data types to the same topic. Conflicts between 081 * publishers are typically resolved by the server on a first-come, first-served basis. Any 082 * published values that do not match the topic's data type are dropped (ignored). To determine if 083 * the data type matches, use the appropriate Topic functions. 084 * 085 * @param options publish options 086 * @return publisher 087 */ 088 public ProtobufPublisher<T> publish(PubSubOption... options) { 089 m_inst.addSchema(m_proto); 090 return new ProtobufEntryImpl<>( 091 this, 092 ProtobufBuffer.create(m_proto), 093 NetworkTablesJNI.publish( 094 m_handle, NetworkTableType.kRaw.getValue(), m_proto.getTypeString(), options), 095 null, 096 true); 097 } 098 099 /** 100 * Create a new publisher to the topic, with type string and initial properties. 101 * 102 * <p>The publisher is only active as long as the returned object is not closed. 103 * 104 * <p>It is not possible to publish two different data types to the same topic. Conflicts between 105 * publishers are typically resolved by the server on a first-come, first-served basis. Any 106 * published values that do not match the topic's data type are dropped (ignored). To determine if 107 * the data type matches, use the appropriate Topic functions. 108 * 109 * @param properties JSON properties 110 * @param options publish options 111 * @return publisher 112 * @throws IllegalArgumentException if properties is not a JSON object 113 */ 114 public ProtobufPublisher<T> publishEx(String properties, PubSubOption... options) { 115 m_inst.addSchema(m_proto); 116 return new ProtobufEntryImpl<>( 117 this, 118 ProtobufBuffer.create(m_proto), 119 NetworkTablesJNI.publishEx( 120 m_handle, 121 NetworkTableType.kRaw.getValue(), 122 m_proto.getTypeString(), 123 properties, 124 options), 125 null, 126 true); 127 } 128 129 /** 130 * Create a new entry for the topic. 131 * 132 * <p>Entries act as a combination of a subscriber and a weak publisher. The subscriber is active 133 * as long as the entry is not closed. The publisher is created when the entry is first written 134 * to, and remains active until either unpublish() is called or the entry is closed. 135 * 136 * <p>It is not possible to use two different data types with the same topic. Conflicts between 137 * publishers are typically resolved by the server on a first-come, first-served basis. Any 138 * published values that do not match the topic's data type are dropped (ignored), and the entry 139 * will show no new values if the data type does not match. To determine if the data type matches, 140 * use the appropriate Topic functions. 141 * 142 * @param defaultValue default value used when a default is not provided to a getter function 143 * @param options publish and/or subscribe options 144 * @return entry 145 */ 146 public ProtobufEntry<T> getEntry(T defaultValue, PubSubOption... options) { 147 return new ProtobufEntryImpl<>( 148 this, 149 ProtobufBuffer.create(m_proto), 150 NetworkTablesJNI.getEntry( 151 m_handle, NetworkTableType.kRaw.getValue(), m_proto.getTypeString(), options), 152 defaultValue, 153 false); 154 } 155 156 /** 157 * Returns the protobuf. 158 * 159 * @return The protobuf. 160 */ 161 public Protobuf<T, ?> getProto() { 162 return m_proto; 163 } 164 165 @Override 166 public boolean equals(Object other) { 167 if (other == this) { 168 return true; 169 } 170 if (!(other instanceof ProtobufTopic)) { 171 return false; 172 } 173 174 return super.equals(other) && m_proto == ((ProtobufTopic<?>) other).m_proto; 175 } 176 177 @Override 178 public int hashCode() { 179 return super.hashCode() ^ m_proto.hashCode(); 180 } 181 182 private final Protobuf<T, ?> m_proto; 183}