001package edu.wpi.first.wpilibj.networktables2.connection; 002 003import java.io.*; 004 005import edu.wpi.first.wpilibj.networktables2.*; 006import edu.wpi.first.wpilibj.networktables2.stream.*; 007import edu.wpi.first.wpilibj.networktables2.type.*; 008 009 010/** 011 * An abstraction for the NetworkTable protocol 012 * 013 * @author mwills 014 * 015 */ 016public class NetworkTableConnection { 017 public static final char PROTOCOL_REVISION = 0x0200; 018 019 private final Object WRITE_LOCK = new Object(); 020 021 private final DataInputStream is; 022 private final DataOutputStream os; 023 /** 024 * the raw stream that is used in this connection 025 */ 026 public final IOStream stream; 027 private final NetworkTableEntryTypeManager typeManager; 028 private boolean isValid; 029 030 031 public NetworkTableConnection(IOStream stream, NetworkTableEntryTypeManager typeManager){ 032 this.stream = stream; 033 this.typeManager = typeManager; 034 this.is = new DataInputStream(new BufferedInputStream(stream.getInputStream())); 035 this.os = new DataOutputStream(new BufferedOutputStream(stream.getOutputStream())); 036 isValid = true; 037 } 038 039 public void close() { 040 if(isValid){ 041 isValid = false; 042 stream.close(); 043 } 044 } 045 046 047 private void sendMessageHeader(int messageType) throws IOException{ 048 synchronized(WRITE_LOCK){ 049 os.writeByte(messageType); 050 } 051 } 052 public void flush() throws IOException{ 053 synchronized(WRITE_LOCK){ 054 os.flush(); 055 } 056 } 057 058 059 060 public void sendKeepAlive() throws IOException { 061 synchronized(WRITE_LOCK){ 062 sendMessageHeader(NetworkTableMessageType.KEEP_ALIVE); 063 flush(); 064 } 065 } 066 067 public void sendClientHello() throws IOException { 068 synchronized(WRITE_LOCK){ 069 sendMessageHeader(NetworkTableMessageType.CLIENT_HELLO); 070 os.writeChar(PROTOCOL_REVISION); 071 flush(); 072 } 073 } 074 075 public void sendServerHelloComplete() throws IOException { 076 synchronized(WRITE_LOCK){ 077 sendMessageHeader(NetworkTableMessageType.SERVER_HELLO_COMPLETE); 078 flush(); 079 } 080 } 081 082 public void sendProtocolVersionUnsupported() throws IOException { 083 synchronized(WRITE_LOCK){ 084 sendMessageHeader(NetworkTableMessageType.PROTOCOL_VERSION_UNSUPPORTED); 085 os.writeChar(PROTOCOL_REVISION); 086 flush(); 087 } 088 } 089 090 091 092 public void sendEntryAssignment(NetworkTableEntry entry) throws IOException { 093 synchronized(WRITE_LOCK){ 094 sendMessageHeader(NetworkTableMessageType.ENTRY_ASSIGNMENT); 095 os.writeUTF(entry.name); 096 os.writeByte(entry.getType().id); 097 os.writeChar(entry.getId()); 098 os.writeChar(entry.getSequenceNumber()); 099 entry.sendValue(os); 100 } 101 } 102 public void sendEntryUpdate(NetworkTableEntry entry) throws IOException { 103 synchronized(WRITE_LOCK){ 104 sendMessageHeader(NetworkTableMessageType.FIELD_UPDATE); 105 os.writeChar(entry.getId()); 106 os.writeChar(entry.getSequenceNumber()); 107 entry.sendValue(os); 108 } 109 } 110 111 112 113 public void read(ConnectionAdapter adapter) throws IOException { 114 try{ 115 int messageType = is.readByte(); 116 switch(messageType){ 117 case NetworkTableMessageType.KEEP_ALIVE: 118 adapter.keepAlive(); 119 return; 120 case NetworkTableMessageType.CLIENT_HELLO: 121 { 122 char protocolRevision = is.readChar(); 123 adapter.clientHello(protocolRevision); 124 return; 125 } 126 case NetworkTableMessageType.SERVER_HELLO_COMPLETE: 127 { 128 adapter.serverHelloComplete(); 129 return; 130 } 131 case NetworkTableMessageType.PROTOCOL_VERSION_UNSUPPORTED: 132 { 133 char protocolRevision = is.readChar(); 134 adapter.protocolVersionUnsupported(protocolRevision); 135 return; 136 } 137 case NetworkTableMessageType.ENTRY_ASSIGNMENT: 138 { 139 String entryName = is.readUTF(); 140 byte typeId = is.readByte(); 141 NetworkTableEntryType entryType = typeManager.getType(typeId); 142 if(entryType==null) 143 throw new BadMessageException("Unknown data type: 0x"+Integer.toHexString((int)typeId)); 144 char entryId = is.readChar(); 145 char entrySequenceNumber = is.readChar(); 146 Object value = entryType.readValue(is); 147 adapter.offerIncomingAssignment(new NetworkTableEntry(entryId, entryName, entrySequenceNumber, entryType, value)); 148 return; 149 } 150 case NetworkTableMessageType.FIELD_UPDATE: 151 { 152 char entryId = is.readChar(); 153 char entrySequenceNumber = is.readChar(); 154 NetworkTableEntry entry = adapter.getEntry(entryId); 155 if(entry==null) 156 throw new BadMessageException("Received update for unknown entry id: "+(int)entryId); 157 Object value = entry.getType().readValue(is); 158 159 adapter.offerIncomingUpdate(entry, entrySequenceNumber, value); 160 return; 161 } 162 default: 163 throw new BadMessageException("Unknown Network Table Message Type: "+messageType); 164 } 165 } catch(IOException e){ 166 throw e; 167 } 168 } 169 170}