Module: Prremote::Commands::SerialHelpers

Included in:
Deploy, Ls, Run
Defined in:
lib/prremote/commands/serial_helpers.rb

Instance Method Summary collapse

Instance Method Details

#normalize(str) ⇒ Object



33
34
35
# File 'lib/prremote/commands/serial_helpers.rb', line 33

def normalize(str)
  str.gsub("\r\n", "\n").gsub("\r", '')
end

#safe_read(serial, size) ⇒ Object

Wraps serial.read so that a device disconnect (e.g. ENXIO on macOS when the Pico resets) surfaces as a human-readable error instead of a bare errno name.



39
40
41
42
43
# File 'lib/prremote/commands/serial_helpers.rb', line 39

def safe_read(serial, size)
  serial.read(size) || ''
rescue RubySerial::Error => e
  raise "Device disconnected (#{e.message}). Run `prremote reset` if the device is unresponsive."
end

#wait_for_ready(serial) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/prremote/commands/serial_helpers.rb', line 4

def wait_for_ready(serial)
  # On macOS, USB CDC TX buffers can be dropped when the host reopens the port,
  # leaving the device stuck in getchar() without re-sending READY.
  # Sending Ctrl+C forces the device to restart its READY loop.
  # Resent every second: ESP32 boards reset when the port opens (DTR/RTS
  # auto-reset circuit) and a Ctrl+C sent while they are still booting
  # is lost. Harmless on Pico — 0x03 while idle just re-prints READY.
  sleep 0.1
  serial.write("\x03") rescue nil

  buf = +''
  deadline  = Time.now + 10
  next_ctrl = Time.now + 1
  loop do
    buf << normalize(safe_read(serial, 256))
    if buf.include?('READY ')
      warn_if_runtime_outdated(buf)
      return
    end
    raise 'Timeout waiting for device. Run `prremote reset` if a script is running.' if Time.now > deadline

    if Time.now > next_ctrl
      serial.write("\x03") rescue nil
      next_ctrl = Time.now + 1
    end
    sleep 0.05
  end
end