prremote 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfce7ce99a7bd04bbfde40aad5c53640f14f1ad90da41998c7399e6366d25198
4
- data.tar.gz: d60e5701e6d42baf78a82a6d7d919d3bb5664cd34cb9cb02cdf7a2a749368121
3
+ metadata.gz: ddaba1909af7ae567dda45d75d78c240347062d0e00a5dab966190b22f0b28eb
4
+ data.tar.gz: e9f933d93ca77aa8324f2502958150370afe8f61b902c4420d06cfeb3edfcabd
5
5
  SHA512:
6
- metadata.gz: 5fd70f1266d67f8f41aef2018c102d4827c53cb103f304a16d40f78ee618c99556bc45fbc94447f66ff4e157f5318ff5b62956e8edf5dd1d1acda5a53ac1d94d
7
- data.tar.gz: 70372664611e75517b6ea974ff85b222ecb6b53944ffdc345f423e6c15720b4daeedc84cdba20e5338c3c754f6090ac1aeb605ef34f498f1a4a6849236b62c31
6
+ metadata.gz: d885014b3034e5bcbb02203f12c994544a147f5d2439af7fd2162f39591104ce220f697732e6a62a455374508f62fa8685eb2a2f4d9e67f8593d83b9ec4676db
7
+ data.tar.gz: dc99149a4481721d2347f73345684ff1dd780a9ce96e4f861376a3077e0cce5be11a3be6598e4728cf1659bab1403e9678248ab7ffbce2c17091db9e08fd2695
data/README.md CHANGED
@@ -176,8 +176,8 @@ Show the gem version, mrbc version, and the connected device's runtime version.
176
176
 
177
177
  ```bash
178
178
  prremote version
179
- # prremote: 0.3.0
180
- # runtime: 0.3.0 (/dev/tty.usbmodem101)
179
+ # prremote: 0.3.1
180
+ # runtime: 0.3.1 (/dev/tty.usbmodem101)
181
181
  # mrbc: mruby 4.0.0 (2026-04-20) (/opt/homebrew/bin/mrbc)
182
182
  ```
183
183
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
@@ -20,6 +20,7 @@ module Prremote
20
20
  FLASH_DATA = 0x03
21
21
  FLASH_END = 0x04
22
22
  SYNC = 0x08
23
+ READ_REG = 0x0A
23
24
  SPI_SET_PARAMS = 0x0B
24
25
  SPI_ATTACH = 0x0D
25
26
  CHANGE_BAUD = 0x0F
@@ -32,6 +33,16 @@ module Prremote
32
33
  # Boards with built-in USB Serial/JTAG — flashed via esptool subprocess.
33
34
  USB_JTAG_SERIAL_BOARDS = %w[esp32c6].freeze
34
35
 
36
+ # Classic ESP32 ROM only auto-attaches flash on modules with pads wired
37
+ # to the default HSPI pins. SiP packages with in-package flash (e.g.
38
+ # ESP32-PICO-D4, used on M5StickC/PLUS) route flash through pins burned
39
+ # into eFuse instead, and FLASH_BEGIN silently hangs forever (no error
40
+ # response) if SPI_ATTACH(0) is sent on those. Mirrors esptool's
41
+ # attach_flash()/get_chip_spi_pads() (cmds.py / targets/esp32.py).
42
+ EFUSE_RD_REG_BASE = 0x3FF5A000
43
+ EFUSE_BLK0_RDATA3_REG_OFFS = EFUSE_RD_REG_BASE + 0x00C
44
+ EFUSE_BLK0_RDATA5_REG_OFFS = EFUSE_RD_REG_BASE + 0x014
45
+
35
46
  # ROM status-byte count: classic ESP32 appends 4 bytes, RISC-V chips 2.
36
47
  STATUS_BYTES_BY_BOARD = Hash.new(4).freeze
37
48
 
@@ -47,14 +58,13 @@ module Prremote
47
58
  TIOCM_RTS = 0x0004
48
59
  DARWIN = RbConfig::CONFIG['host_os'] =~ /darwin/ ? true : false
49
60
  TIOCMGET = DARWIN ? 0x4004746A : 0x5415
50
- TIOCMBIS = DARWIN ? 0x8004746E : 0x5416
51
- TIOCMBIC = DARWIN ? 0x8004746F : 0x5417
61
+ TIOCMSET = DARWIN ? 0x8004746D : 0x5418
52
62
 
53
63
  class Error < RuntimeError; end
54
64
 
55
65
  # Entry point. Routes USB-JTAG/Serial boards through esptool; handles
56
66
  # classic ESP32 with the pure-Ruby protocol implementation.
57
- def self.flash(port:, image_path:, baud: 230_400, board: nil, verbose: false)
67
+ def self.flash(port:, image_path:, baud: ROM_BAUD, board: nil, verbose: false)
58
68
  if USB_JTAG_SERIAL_BOARDS.include?(board)
59
69
  return flash_via_esptool(port: port, image_path: image_path, board: board,
60
70
  verbose: verbose)
@@ -214,7 +224,8 @@ module Prremote
214
224
  end
215
225
 
216
226
  def write_flash(image, offset: 0)
217
- spi_attach_payload = SPI_ATTACH_LEGACY_BOARDS.include?(@board) ? [0, 0].pack('V2') : [0].pack('V')
227
+ hspi_arg = SPI_ATTACH_LEGACY_BOARDS.include?(@board) ? efuse_spi_attach_arg : 0
228
+ spi_attach_payload = SPI_ATTACH_LEGACY_BOARDS.include?(@board) ? [hspi_arg, 0].pack('V2') : [hspi_arg].pack('V')
218
229
  command(SPI_ATTACH, spi_attach_payload)
219
230
  # id, total_size, block_size, sector_size, page_size, status_mask
220
231
  command(SPI_SET_PARAMS, [0, 4 * 1024 * 1024, 64 * 1024, 4096, 256, 0xFFFF].pack('V6'))
@@ -247,6 +258,30 @@ module Prremote
247
258
  raise Error, "MD5 mismatch after flashing (device #{device_md5}, local #{local_md5})"
248
259
  end
249
260
 
261
+ # SPI_ATTACH(0) only works for modules with flash on the default HSPI
262
+ # pins. In-package flash (ESP32-PICO-D4/V3, e.g. M5StickC/PLUS) needs its
263
+ # actual pin numbers, burned into eFuse, packed into SPI_ATTACH's arg.
264
+ # Returns 0 (the "use default pins" value) when eFuse has nothing burned.
265
+ def efuse_spi_attach_arg
266
+ rdata5 = read_reg(EFUSE_BLK0_RDATA5_REG_OFFS)
267
+ clk = rdata5 & 0x1F
268
+ q = (rdata5 >> 5) & 0x1F
269
+ d = (rdata5 >> 10) & 0x1F
270
+ cs = (rdata5 >> 15) & 0x1F
271
+ hd = (read_reg(EFUSE_BLK0_RDATA3_REG_OFFS) >> 4) & 0x1F
272
+
273
+ return 0 if [clk, q, d, hd, cs].all?(&:zero?)
274
+
275
+ vlog format('in-package flash detected (CLK:%<clk>d Q:%<q>d D:%<d>d HD:%<hd>d CS:%<cs>d)',
276
+ clk: clk, q: q, d: d, hd: hd, cs: cs)
277
+ (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk
278
+ end
279
+
280
+ def read_reg(addr)
281
+ value, = command(READ_REG, [addr].pack('V'))
282
+ value
283
+ end
284
+
250
285
  # ── request/response plumbing ──────────────────────────────────────────
251
286
 
252
287
  def command(op, payload, checksum: 0, timeout: 3)
@@ -335,12 +370,21 @@ module Prremote
335
370
  loop { break if read_frame(deadline).nil? }
336
371
  end
337
372
 
373
+ # Sets DTR and RTS together via a single TIOCMSET, matching esptool's
374
+ # UnixTightReset. Two separate TIOCMBIS/TIOCMBIC calls (the classic-reset
375
+ # approach) send DTR and RTS as separate USB control-line-state requests;
376
+ # some USB-serial adapters (seen with CP2104 on M5StickC PLUS) glitch the
377
+ # boot ROM's auto-reset during that gap.
338
378
  def set_lines(dtr:, rts:)
339
379
  return if @fd.nil?
340
380
 
341
- io = IO.for_fd(@fd, autoclose: false)
342
- io.ioctl(dtr ? TIOCMBIS : TIOCMBIC, [TIOCM_DTR].pack('L'))
343
- io.ioctl(rts ? TIOCMBIS : TIOCMBIC, [TIOCM_RTS].pack('L'))
381
+ io = IO.for_fd(@fd, autoclose: false)
382
+ buf = [0].pack('L')
383
+ io.ioctl(TIOCMGET, buf)
384
+ status = buf.unpack1('L')
385
+ status = dtr ? (status | TIOCM_DTR) : (status & ~TIOCM_DTR)
386
+ status = rts ? (status | TIOCM_RTS) : (status & ~TIOCM_RTS)
387
+ io.ioctl(TIOCMSET, [status].pack('L'))
344
388
  rescue StandardError
345
389
  nil
346
390
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prremote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ITO Yosei
@@ -139,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0'
141
141
  requirements: []
142
- rubygems_version: 4.0.10
142
+ rubygems_version: 4.0.19
143
143
  specification_version: 4
144
144
  summary: CLI tool for deploying and running mruby/c scripts on a Raspberry Pi Pico
145
145
  W over USB serial