Class UnitPort

java.lang.Object
org.emrick.project.dev.UnitPort

public final class UnitPort extends Object
Serial helpers for talking to Emrick units (Heltec boards behind a CP210x USB-UART bridge) at 9600 baud. Opening a port normally does not reset the unit (DTR/RTS are cleared first). Receivers on current firmware answer runtime commands ("info", "debug on", "blink", "label ...") at any time. Older firmware and transmitters only answer the board-type query 'q' in the 1 second window after a reset, so probeType(com.fazecast.jSerialComm.SerialPort) falls back to resetting the unit. Ports are claimed by one Developer Mode feature at a time through claim(java.lang.String, java.lang.String) so, for example, the flasher never fights the terminal for a port.
  • Field Details

  • Constructor Details

    • UnitPort

      private UnitPort()
  • Method Details

    • emrickPorts

      public static List<com.fazecast.jSerialComm.SerialPort> emrickPorts()
      Returns:
      every connected Emrick unit (CP210x bridge), sorted by port name
    • find

      public static com.fazecast.jSerialComm.SerialPort find(String systemPortName)
      Returns:
      a fresh handle for the port with this system name (e.g. COM12), or null if it's gone
    • claim

      public static boolean claim(String systemPortName, String owner)
      Returns:
      true if the port was free and is now owned by owner
    • claim

      public static boolean claim(String systemPortName, String owner, Runnable letGo)
      Claims a port and registers how to give it back early, so a higher-priority feature (flashing) can take it over. letGo must eventually call release(java.lang.String, java.lang.String).
    • claimWhenFree

      public static boolean claimWhenFree(String systemPortName, String owner, Runnable letGo, long timeoutMs)
      Like claim(String, String, Runnable), but waits for short-lived users (e.g. a unit being read) to finish instead of failing right away. Never takes the port from anyone.
    • release

      public static void release(String systemPortName, String owner)
    • takeOver

      public static boolean takeOver(String systemPortName, String owner, long timeoutMs)
      Claims a port even if another feature has it: the holder is asked to let go (e.g. the terminal disconnects), and short-lived users (a unit being read) are waited for.
      Returns:
      true if owner now has the port
    • isAnyPortOwnedBy

      public static boolean isAnyPortOwnedBy(String... featureNames)
      Returns:
      true if any port is held by one of these features (e.g. "Terminal")
    • ownerOf

      public static String ownerOf(String systemPortName)
      Returns:
      the feature using the port (e.g. "Terminal"), or null if it's free
    • open

      public static boolean open(com.fazecast.jSerialComm.SerialPort sp)
      Opens the port without resetting the unit.
    • openWithRetry

      public static boolean openWithRetry(com.fazecast.jSerialComm.SerialPort sp, int attempts)
      Opens the port without a reset, retrying briefly in case something else just let go of it.
    • reset

      public static void reset(com.fazecast.jSerialComm.SerialPort sp)
      Resets the unit by pulsing the bridge's RTS line (wired to the ESP32 enable pin). Port must be open.
    • write

      public static boolean write(com.fazecast.jSerialComm.SerialPort sp, String text)
    • readFor

      public static byte[] readFor(com.fazecast.jSerialComm.SerialPort sp, int millis)
      Reads whatever arrives within millis.
    • sendRaw

      public static boolean sendRaw(com.fazecast.jSerialComm.SerialPort sp, String text)
      Opens the port (without a reset) if needed, writes a single short message, and closes it again if this call opened it. Used for transmitter commands such as identify.
    • sendCommand

      public static String sendCommand(com.fazecast.jSerialComm.SerialPort sp, String command, String replyPrefix, int timeoutMs)
      Sends a runtime command and waits for the reply line starting with replyPrefix. The command is re-sent every 2 seconds in case the unit was still booting.
      Returns:
      the reply line, or null on timeout (e.g. older firmware without runtime commands)
    • queryInfo

      public static UnitInfo queryInfo(com.fazecast.jSerialComm.SerialPort sp, int timeoutMs)
      Returns:
      the unit's details, or null if it didn't answer (not a receiver, or older firmware)
    • displayName

      public static String displayName(String systemPortName)
      Friendly name for a port, for dropdowns: the board label, else "Board 12", else the unit type, else the port itself if the unit hasn't been read yet.
    • blink

      public static boolean blink(com.fazecast.jSerialComm.SerialPort sp, boolean on)
      Starts or stops blinking the receiver's status LED red, to find it. @return true if confirmed
    • setDebug

      public static boolean setDebug(com.fazecast.jSerialComm.SerialPort sp, boolean on)
    • probeType

      public static String probeType(com.fazecast.jSerialComm.SerialPort sp)
      Works out whether a unit is a receiver or transmitter. Current receivers answer 'q' at any time; if that gets no answer the unit is reset and asked again during its boot window, which every receiver and transmitter firmware supports.
      Returns:
      RECEIVER, TRANSMITTER, or UNKNOWN
    • knownType

      public static String knownType(String systemPortName)
      Returns:
      the type last found on this port by probeType(com.fazecast.jSerialComm.SerialPort), or null if it hasn't been probed
    • probe

      private static String probe(com.fazecast.jSerialComm.SerialPort sp)
    • lettersIn

      private static String lettersIn(byte[] data)
    • sleep

      public static void sleep(long millis)