Class ProxyServerThread

java.lang.Object
java.lang.Thread
com.marswars.proxy_server.ProxyServerThread
All Implemented Interfaces:
Runnable

public class ProxyServerThread extends Thread
Proxy server thread for handling UDP communication with external systems. Receives and processes various packet types including odometry, module states, AprilTag solutions, piece detections, and timesync requests. Provides bidirectional communication capabilities on a single UDP port.

Multi-Client Support

The proxy server can handle multiple simultaneous clients (e.g., multiple vision coprocessors). Each client is tracked independently with its own connection monitoring and alerts. Data from all clients is merged into shared queues, accessible via the getter methods.

Use broadcastData(byte[]) to send data to all connected clients, or sendDataToClient(byte[], SocketAddress) to send to a specific client. The legacy sendData(byte[]) method sends to the most recent client for backward compatibility.

Connection Monitoring

The proxy server automatically monitors the connection to each client and publishes individual WPILib Alerts when connections are lost. Connection is considered lost if no packets are received within the timeout period (1 second by default). A debouncer is used to prevent alert flapping during intermittent connectivity issues.

Use isConnected() to check if any client is connected, getConnectedClientCount() to get the number of active clients, and getTimeSinceLastPacket() to get time since last received packet from any client.

Camera Tracking

The proxy server tracks individual cameras by their serial number (extracted from vision packets). Each camera gets its own connection monitoring and alert that includes both the camera serial and the client it's connected to for easy debugging. Cameras are considered disconnected if no vision packets (tag solutions or piece detections) are received within 2 seconds.

Use getConnectedCameraCount() to get the number of active cameras, getCameraSerials() to list all tracked cameras, and isCameraConnected(String) to check if a specific camera is connected.

PhotonVision Simulation Support

In simulation mode, this class can use PhotonVision simulation to generate simulated vision data that populates the tagSolutions queue, allowing you to test vision-based robot code without a physical robot or vision coprocessor.

Usage Example:


 // In your robot initialization (Robot.java or subsystem)
 ProxyServerThread proxyServer = ProxyServerThread.getInstance();
 
 // Check connection status for multiple clients
 int connectedClients = proxyServer.getConnectedClientCount();
 System.out.println("Connected clients: " + connectedClients);
 
 // Get all client addresses
 List<SocketAddress> clients = proxyServer.getClientAddresses();
 
 // Broadcast data to all connected clients
 byte[] customData = new byte[]{1, 2, 3};
 int sentCount = proxyServer.broadcastData(customData);
 System.out.println("Sent to " + sentCount + " clients");
 
 // Initialize vision simulation (only in simulation mode)
 if (RobotBase.isSimulation()) {
     // Load the field layout
     AprilTagFieldLayout fieldLayout = AprilTagFieldLayout.loadField(
         AprilTagFields.k2025Reefscape
     );
     MwVisionSimulation visionSim = proxyServer.initializeVisionSimulation(fieldLayout);
     
     // Add default cameras (front, left, right, back)
     visionSim.addDefaultCameras();
     
     // Or add a custom camera
     // Camera mounted 0.5m forward, 0.3m up, angled 15 degrees down
     Transform3d robotToCamera = new Transform3d(
         new Translation3d(0.5, 0, 0.3),
         new Rotation3d(0, Math.toRadians(-15), 0)
     );
     visionSim.addCamera("simCamera", robotToCamera);
 }
 
 // In your periodic method, update with current robot pose
 if (RobotBase.isSimulation()) {
     Pose2d currentPose = drivetrain.getPose(); // Get from your drivetrain
     proxyServer.updateVisionSimulation(currentPose);
 }
 
 // Vision data will now be available via getLatestTagSolutions()
 List<TagSolutionData> solutions = proxyServer.getLatestTagSolutions();
 
See Also:
  • Constructor Details

    • ProxyServerThread

      public ProxyServerThread()
  • Method Details

    • getInstance

      public static ProxyServerThread getInstance()
      Gets the singleton instance of the ProxyServerThread.
      Returns:
      the ProxyServerThread instance
    • start

      public void start()
      Overrides:
      start in class Thread
    • run

      public void run()
      Specified by:
      run in interface Runnable
      Overrides:
      run in class Thread
    • configureServer

      public boolean configureServer()
      Binds the server socket to the set port to begin communication. This must be called once before you can attempt to updateData().
      Returns:
      true: server configured successfully | false: configuration error occurred.
      Throws:
      SocketException - if the socket could not be opened, or the socket could not bind to the specified local port.
    • isConnected

      public boolean isConnected()
      Checks if the proxy server currently has an active connection to any client.
      Returns:
      true if at least one client is connected, false if all connections lost
    • getConnectedClientCount

      public int getConnectedClientCount()
      Gets the number of currently connected clients.
      Returns:
      number of clients with active connections
    • getClientAddresses

      public List<SocketAddress> getClientAddresses()
      Gets a list of all tracked client addresses (both connected and disconnected).
      Returns:
      list of client socket addresses
    • getTimeSinceLastPacket

      public double getTimeSinceLastPacket()
      Gets the time elapsed since the last packet was received from any client.
      Returns:
      seconds since last packet from any client, or Double.MAX_VALUE if no clients
    • getConnectedCameraCount

      public int getConnectedCameraCount()
      Gets the number of currently connected cameras.
      Returns:
      number of cameras with active connections
    • getCameraSerials

      public List<String> getCameraSerials()
      Gets a list of all tracked camera serial numbers (both connected and disconnected).
      Returns:
      list of camera serial numbers
    • isCameraConnected

      public boolean isCameraConnected(String cameraSerial)
      Checks if a specific camera is currently connected.
      Parameters:
      cameraSerial - the camera serial number to check
      Returns:
      true if the camera is connected, false otherwise
    • getTimeSinceLastCameraPacket

      public double getTimeSinceLastCameraPacket(String cameraSerial)
      Gets the time elapsed since the last packet was received from a specific camera.
      Parameters:
      cameraSerial - the camera serial number
      Returns:
      seconds since last packet from the camera, or Double.MAX_VALUE if camera not found
    • sendData

      public boolean sendData(byte[] buffer)
      Sends data back to the last connected client on the same port. For multi-client support, use sendDataToClient(byte[], SocketAddress) instead.
      Parameters:
      buffer - the byte array to send
      Returns:
      true if data was sent successfully, false if there was an error
    • sendDataToClient

      public boolean sendDataToClient(byte[] buffer, SocketAddress client_address)
      Sends data to a specific client address.
      Parameters:
      buffer - the byte array to send
      clientAddress - the destination client address
      Returns:
      true if data was sent successfully, false if there was an error
    • broadcastData

      public int broadcastData(byte[] buffer)
      Broadcasts data to all currently connected clients.
      Parameters:
      buffer - the byte array to send
      Returns:
      number of clients successfully sent to
    • getLatestOdometryReadings

      public List<OdomPacket.OdometryData> getLatestOdometryReadings()
      Gets the current robot pose, velocity, and variance data from odometry readings. Data is updated by calling updateData() periodically.
      Returns:
      list of recent OdomPacket.OdometryData from chassis proxy
    • getLatestModuleStatesReadings

      public List<StatesPacket.ModuleStatesData> getLatestModuleStatesReadings()
      Gets the current robot module states information. States are updated by calling updateData() periodically.
      Returns:
      list of recent StatesPacket.ModuleStatesData containing swerve module information
    • getLatestModuleStatesArrays

      public List<SwerveModuleState[]> getLatestModuleStatesArrays()
      Gets the current robot module states as individual SwerveModuleState arrays. This is a convenience method that extracts the module states arrays from the data objects.
      Returns:
      list of SwerveModuleState arrays (for backward compatibility)
    • getLatestTagSolutions

      public List<TagSolutionPacket.TagSolutionData> getLatestTagSolutions()
      Gets the current AprilTag solution information. Solutions are updated by calling updateData() periodically.
      Returns:
      list of recent TagSolutionPacket.TagSolutionData with pose estimates and detected tag IDs
    • getLatestPieceDetections

      public List<PieceDetectionPacket.PieceDetectionData> getLatestPieceDetections()
      Gets the current detected game pieces information. Detections are updated by calling updateData() periodically.
      Returns:
      list of recent PieceDetectionPacket.PieceDetectionData with piece detection information
    • snapshot

      public boolean snapshot(String tag_name)
      Sends snapshot trigger packet for log location flagging
      Parameters:
      tag_name - flag name to record in log
      Returns:
      true if packet was sent successfully, false otherwise
    • syncMatchData

      public boolean syncMatchData()
      Sends match data packet for log name syncing
      Returns:
      true if packet was sent successfully, false otherwise
    • sendCustomPacket

      public boolean sendCustomPacket(byte message_id, byte[] payload)
      Sends a custom packet with specified message ID and payload data
      Parameters:
      message_id - the message type identifier
      payload - the data payload (can be null for header-only packets)
      Returns:
      true if packet was sent successfully, false otherwise
    • getClientAddress

      public SocketAddress getClientAddress()
      Gets the last client address that sent data to the server. For multi-client tracking, use getClientAddresses() instead.
      Returns:
      SocketAddress of the last client that sent data, null if no client has connected
    • hasClientConnection

      public boolean hasClientConnection()
      Checks if the server has any active client connections.
      Returns:
      true if at least one client is connected
    • initializeVisionSimulation

      public MwVisionSim initializeVisionSimulation(AprilTagFieldLayout field_layout)
      Initializes vision simulation for generating simulated vision data. This should be called in simulation mode to enable PhotonVision simulation. Only works in simulation mode - does nothing on real robot.
      Parameters:
      fieldLayout - the AprilTag field layout to use
      Returns:
      the created MwVisionSimulation instance, or null if not in simulation
    • updateVisionSimulation

      public void updateVisionSimulation(Pose2d robot_pose)
      Updates the vision simulation with the current robot pose and generates vision data. This should be called periodically with the simulated robot pose. The generated vision data is automatically added to the tagSolutions queue. Only works in simulation mode - does nothing on real robot.
      Parameters:
      robotPose - the current simulated robot pose