prremote 0.1.0 → 0.1.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 +4 -4
- data/README.md +12 -7
- data/lib/prremote/cli.rb +50 -14
- data/lib/prremote/commands/install.rb +5 -3
- data/lib/prremote/commands/undeploy.rb +52 -3
- data/lib/prremote/commands/watch.rb +1 -1
- data/lib/prremote/runtime_manager.rb +11 -12
- data/lib/prremote/version.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d080a70a00d10af1e419cae964da017bbc6650f85f54f3a18223b81bb204fe7
|
|
4
|
+
data.tar.gz: 158c193d72d4d414726f79183f6016017132077f37f0adc2f3238cd843e5672b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47d36cf128e0106b732273bad92aeb3af77c97a4e93f167e77d3ea34999578976a75f7babe8e3e910c6cf364422821cca6e5886cc7c7e5fa327a032a7d3bafb9
|
|
7
|
+
data.tar.gz: a63fae436f971e92d97386933706f99396dfcfc1ecf105c4ded5215aa1410d3ba3fadeb49805a9735a7285c1b6202da51dad325438d9b13d444756d48d88906e
|
data/README.md
CHANGED
|
@@ -12,7 +12,9 @@ Inspired by [mpremote](https://docs.micropython.org/en/latest/reference/mpremote
|
|
|
12
12
|
|
|
13
13
|
- Ruby 3.x or later
|
|
14
14
|
- Raspberry Pi Pico W
|
|
15
|
-
- `mrbc` in your PATH (for `run`, `deploy`, and `eval`)
|
|
15
|
+
- `mrbc` in your PATH (for `run`, `deploy`, and `eval`)
|
|
16
|
+
- macOS: `brew install mruby`
|
|
17
|
+
- Ubuntu / Raspberry Pi OS: `sudo apt install mruby`
|
|
16
18
|
|
|
17
19
|
---
|
|
18
20
|
|
|
@@ -43,16 +45,18 @@ prremote run app.rb
|
|
|
43
45
|
|
|
44
46
|
### `install`
|
|
45
47
|
|
|
46
|
-
Flash the prremote runtime firmware to a Pico W.
|
|
48
|
+
Flash the prremote runtime firmware to a Pico W or Pico.
|
|
47
49
|
|
|
48
50
|
```bash
|
|
49
|
-
prremote install
|
|
50
|
-
prremote install --
|
|
51
|
+
prremote install # Pico W (default)
|
|
52
|
+
prremote install --board pico # Pico (no wireless)
|
|
53
|
+
prremote install --version 0.1.1 # specify a runtime version
|
|
54
|
+
prremote install --board pico --version 0.1.1
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
The firmware is downloaded from GitHub Releases on first use and cached in `~/.prremote/runtime/`. Subsequent installs use the cache.
|
|
54
58
|
|
|
55
|
-
Put the
|
|
59
|
+
Put the device into BOOTSEL mode (hold BOOTSEL, connect USB, release) when prompted.
|
|
56
60
|
|
|
57
61
|
---
|
|
58
62
|
|
|
@@ -140,9 +144,9 @@ Show the gem version, mrbc version, and the connected device's runtime version.
|
|
|
140
144
|
|
|
141
145
|
```bash
|
|
142
146
|
prremote version
|
|
143
|
-
# prremote: 0.1.
|
|
147
|
+
# prremote: 0.1.1
|
|
144
148
|
# mrbc: 3.3.0 (/usr/local/bin/mrbc)
|
|
145
|
-
# runtime: 0.1.
|
|
149
|
+
# runtime: 0.1.3
|
|
146
150
|
```
|
|
147
151
|
|
|
148
152
|
---
|
|
@@ -199,4 +203,5 @@ Scripts saved via `deploy` are stored in flash and run automatically on every bo
|
|
|
199
203
|
## Related Projects
|
|
200
204
|
|
|
201
205
|
- [mruby/c](https://github.com/mrubyc/mrubyc) — Lightweight mruby implementation used in the runtime
|
|
206
|
+
- [picotool](https://github.com/raspberrypi/picotool) — Official Raspberry Pi tool for inspecting and managing Pico devices; useful for checking what's on flash or force-rebooting outside of prremote
|
|
202
207
|
- [mpremote](https://docs.micropython.org/en/latest/reference/mpremote.html) — MicroPython equivalent (inspiration)
|
data/lib/prremote/cli.rb
CHANGED
|
@@ -20,12 +20,18 @@ module Prremote
|
|
|
20
20
|
true
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
desc 'install', 'Flash prremote runtime firmware to Pico W'
|
|
23
|
+
desc 'install', 'Flash prremote runtime firmware to Pico W or Pico'
|
|
24
24
|
option :version, type: :string, desc: "Firmware version to install (default: #{RUNTIME_VERSION})"
|
|
25
|
+
option :board, type: :string, desc: 'Board type: pico or picow (default: picow)'
|
|
25
26
|
def install
|
|
26
27
|
version = options[:version] || RUNTIME_VERSION
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
board = options[:board] || 'picow'
|
|
29
|
+
unless RuntimeManager::BOARDS.include?(board)
|
|
30
|
+
raise Thor::Error, "Unknown board '#{board}'. Valid values: #{RuntimeManager::BOARDS.join(', ')}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Commands::Install.new(version: version, board: board).call
|
|
34
|
+
rescue StandardError => e
|
|
29
35
|
raise Thor::Error, e.message
|
|
30
36
|
end
|
|
31
37
|
|
|
@@ -33,7 +39,7 @@ module Prremote
|
|
|
33
39
|
def run_script(file)
|
|
34
40
|
port = resolve_port
|
|
35
41
|
Commands::Run.new(port: port, baud: options[:baud]).call(file)
|
|
36
|
-
rescue
|
|
42
|
+
rescue StandardError => e
|
|
37
43
|
raise Thor::Error, e.message
|
|
38
44
|
end
|
|
39
45
|
map 'run' => :run_script
|
|
@@ -42,7 +48,7 @@ module Prremote
|
|
|
42
48
|
def deploy(file)
|
|
43
49
|
port = resolve_port
|
|
44
50
|
Commands::Deploy.new(port: port, baud: options[:baud]).call(file)
|
|
45
|
-
rescue
|
|
51
|
+
rescue StandardError => e
|
|
46
52
|
raise Thor::Error, e.message
|
|
47
53
|
end
|
|
48
54
|
|
|
@@ -50,7 +56,7 @@ module Prremote
|
|
|
50
56
|
def undeploy
|
|
51
57
|
port = resolve_port
|
|
52
58
|
Commands::Undeploy.new(port: port, baud: options[:baud]).call
|
|
53
|
-
rescue
|
|
59
|
+
rescue StandardError => e
|
|
54
60
|
raise Thor::Error, e.message
|
|
55
61
|
end
|
|
56
62
|
|
|
@@ -58,7 +64,7 @@ module Prremote
|
|
|
58
64
|
def eval(expr)
|
|
59
65
|
port = resolve_port
|
|
60
66
|
Commands::EvalCmd.new(port: port, baud: options[:baud]).call(expr)
|
|
61
|
-
rescue
|
|
67
|
+
rescue StandardError => e
|
|
62
68
|
raise Thor::Error, e.message
|
|
63
69
|
end
|
|
64
70
|
|
|
@@ -66,7 +72,7 @@ module Prremote
|
|
|
66
72
|
def watch(file)
|
|
67
73
|
port = resolve_port
|
|
68
74
|
Commands::Watch.new(port: port, baud: options[:baud]).call(file)
|
|
69
|
-
rescue
|
|
75
|
+
rescue StandardError => e
|
|
70
76
|
raise Thor::Error, e.message
|
|
71
77
|
end
|
|
72
78
|
|
|
@@ -87,7 +93,7 @@ module Prremote
|
|
|
87
93
|
serial.write("\x03")
|
|
88
94
|
sleep 0.1
|
|
89
95
|
puts 'Reset signal sent.'
|
|
90
|
-
rescue
|
|
96
|
+
rescue StandardError => e
|
|
91
97
|
raise Thor::Error, e.message
|
|
92
98
|
ensure
|
|
93
99
|
serial&.close
|
|
@@ -99,7 +105,7 @@ module Prremote
|
|
|
99
105
|
|
|
100
106
|
begin
|
|
101
107
|
puts "mrbc: #{Mrbc.version} (#{Mrbc.bin})"
|
|
102
|
-
rescue
|
|
108
|
+
rescue StandardError => e
|
|
103
109
|
puts "mrbc: (#{e.message})"
|
|
104
110
|
end
|
|
105
111
|
|
|
@@ -108,7 +114,7 @@ module Prremote
|
|
|
108
114
|
|
|
109
115
|
private
|
|
110
116
|
|
|
111
|
-
def fetch_runtime_version
|
|
117
|
+
def fetch_runtime_version # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
112
118
|
port = options[:port] || Detector.find_device
|
|
113
119
|
return '(no device connected)' unless port
|
|
114
120
|
|
|
@@ -116,14 +122,44 @@ module Prremote
|
|
|
116
122
|
serial.write("\x03")
|
|
117
123
|
buf = +''
|
|
118
124
|
deadline = Time.now + 5
|
|
125
|
+
|
|
119
126
|
loop do
|
|
120
|
-
|
|
127
|
+
begin
|
|
128
|
+
buf << (serial.read(256) || '').gsub("\r\n", "\n").gsub("\r", '')
|
|
129
|
+
rescue StandardError
|
|
130
|
+
# Watchdog reboot dropped USB; wait for re-enumeration then reopen.
|
|
131
|
+
begin
|
|
132
|
+
serial.close
|
|
133
|
+
rescue StandardError
|
|
134
|
+
nil
|
|
135
|
+
end
|
|
136
|
+
serial = nil
|
|
137
|
+
reopen_deadline = [deadline, Time.now + 8].min
|
|
138
|
+
loop do
|
|
139
|
+
return '(not responding)' if Time.now > reopen_deadline
|
|
140
|
+
|
|
141
|
+
p = options[:port] || Detector.find_device
|
|
142
|
+
if p && File.exist?(p)
|
|
143
|
+
serial = begin
|
|
144
|
+
Serial.new(p, options[:baud])
|
|
145
|
+
rescue StandardError
|
|
146
|
+
nil
|
|
147
|
+
end
|
|
148
|
+
break if serial
|
|
149
|
+
end
|
|
150
|
+
sleep 0.3
|
|
151
|
+
end
|
|
152
|
+
buf = +''
|
|
153
|
+
next
|
|
154
|
+
end
|
|
155
|
+
|
|
121
156
|
return ::Regexp.last_match(1) if buf =~ %r{READY prremote-runtime/([\d.]+)}
|
|
122
|
-
|
|
157
|
+
return '(not responding)' if Time.now > deadline
|
|
123
158
|
|
|
124
159
|
sleep 0.05
|
|
125
160
|
end
|
|
126
|
-
|
|
161
|
+
rescue StandardError => e
|
|
162
|
+
"(#{e.message})"
|
|
127
163
|
ensure
|
|
128
164
|
serial&.close
|
|
129
165
|
end
|
|
@@ -3,14 +3,16 @@ require 'fileutils'
|
|
|
3
3
|
module Prremote
|
|
4
4
|
module Commands
|
|
5
5
|
class Install
|
|
6
|
-
def initialize(version: RUNTIME_VERSION)
|
|
6
|
+
def initialize(version: RUNTIME_VERSION, board: 'picow')
|
|
7
7
|
@version = version
|
|
8
|
+
@board = board
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def call
|
|
11
|
-
uf2_path = RuntimeManager.fetch(@version)
|
|
12
|
+
uf2_path = RuntimeManager.fetch(@version, @board)
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
device_label = @board == 'picow' ? 'Pico W' : 'Pico'
|
|
15
|
+
puts "Put the #{device_label} into BOOTSEL mode:"
|
|
14
16
|
puts ' 1. Hold the BOOTSEL button'
|
|
15
17
|
puts ' 2. Connect USB (or press RUN while holding BOOTSEL)'
|
|
16
18
|
puts ' 3. Release BOOTSEL — RPI-RP2 should appear as a USB drive'
|
|
@@ -10,18 +10,67 @@ module Prremote
|
|
|
10
10
|
|
|
11
11
|
def call
|
|
12
12
|
serial = Serial.new(@port, @baud)
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
serial.write("\x03")
|
|
14
|
+
|
|
15
|
+
# \x03 may trigger a watchdog reboot (if a script was running).
|
|
16
|
+
# wait_for_ready returns the active serial (original or reopened).
|
|
17
|
+
serial = wait_for_ready(serial)
|
|
15
18
|
|
|
16
19
|
serial.write(ERASE_MAGIC)
|
|
17
20
|
wait_for_erased(serial)
|
|
18
21
|
warn 'Flash erased. Device will no longer auto-run a script on boot.'
|
|
19
22
|
ensure
|
|
20
|
-
|
|
23
|
+
begin
|
|
24
|
+
serial&.close
|
|
25
|
+
rescue StandardError
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
21
28
|
end
|
|
22
29
|
|
|
23
30
|
private
|
|
24
31
|
|
|
32
|
+
# Returns the serial object in READY state (may be a new object after reboot).
|
|
33
|
+
def wait_for_ready(serial) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
34
|
+
buf = +''
|
|
35
|
+
deadline = Time.now + 10
|
|
36
|
+
loop do
|
|
37
|
+
begin
|
|
38
|
+
buf << (serial.read(256) || '').gsub("\r\n", "\n").gsub("\r", '')
|
|
39
|
+
rescue StandardError
|
|
40
|
+
# Watchdog reboot dropped USB; wait for device to re-enumerate.
|
|
41
|
+
begin
|
|
42
|
+
serial.close
|
|
43
|
+
rescue StandardError
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
serial = nil
|
|
47
|
+
reopen_deadline = [deadline, Time.now + 8].min
|
|
48
|
+
loop do
|
|
49
|
+
raise 'Timeout waiting for device to reconnect' if Time.now > reopen_deadline
|
|
50
|
+
|
|
51
|
+
candidate = Detector.find_device || @port
|
|
52
|
+
if candidate && File.exist?(candidate)
|
|
53
|
+
begin
|
|
54
|
+
serial = Serial.new(candidate, @baud)
|
|
55
|
+
@port = candidate
|
|
56
|
+
break
|
|
57
|
+
rescue StandardError
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
sleep 0.3
|
|
62
|
+
end
|
|
63
|
+
buf = +''
|
|
64
|
+
next
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
return serial if buf.include?('READY prremote-runtime/')
|
|
68
|
+
raise 'Timeout waiting for READY' if Time.now > deadline
|
|
69
|
+
|
|
70
|
+
sleep 0.05
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
25
74
|
def wait_for_erased(serial)
|
|
26
75
|
buf = +''
|
|
27
76
|
deadline = Time.now + 30
|
|
@@ -4,33 +4,32 @@ require 'fileutils'
|
|
|
4
4
|
|
|
5
5
|
module Prremote
|
|
6
6
|
module RuntimeManager
|
|
7
|
-
|
|
8
|
-
BOARD = 'picow'.freeze
|
|
7
|
+
BOARDS = %w[pico picow].freeze
|
|
9
8
|
|
|
10
|
-
def self.uf2_filename(version)
|
|
11
|
-
"prremote-#{
|
|
9
|
+
def self.uf2_filename(version, board)
|
|
10
|
+
"prremote-#{board}-runtime-#{version}.uf2"
|
|
12
11
|
end
|
|
13
12
|
|
|
14
|
-
def self.release_url(version)
|
|
15
|
-
"https://github.com
|
|
13
|
+
def self.release_url(version, board)
|
|
14
|
+
"https://github.com/lumbermill/prremote/releases/download/runtime-#{version}/#{uf2_filename(version, board)}"
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def self.cache_dir
|
|
19
18
|
File.join(Dir.home, '.prremote', 'runtime')
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
def self.cached_path(version)
|
|
23
|
-
File.join(cache_dir, uf2_filename(version))
|
|
21
|
+
def self.cached_path(version, board)
|
|
22
|
+
File.join(cache_dir, uf2_filename(version, board))
|
|
24
23
|
end
|
|
25
24
|
|
|
26
|
-
def self.fetch(version)
|
|
27
|
-
path = cached_path(version)
|
|
25
|
+
def self.fetch(version, board)
|
|
26
|
+
path = cached_path(version, board)
|
|
28
27
|
return path if File.exist?(path)
|
|
29
28
|
|
|
30
29
|
FileUtils.mkdir_p(cache_dir)
|
|
31
|
-
$stderr.print "Downloading #{uf2_filename(version)}..."
|
|
30
|
+
$stderr.print "Downloading #{uf2_filename(version, board)}..."
|
|
32
31
|
$stderr.flush
|
|
33
|
-
download(release_url(version), path)
|
|
32
|
+
download(release_url(version, board), path)
|
|
34
33
|
warn ' done.'
|
|
35
34
|
path
|
|
36
35
|
end
|
data/lib/prremote/version.rb
CHANGED