rpremote 0.1.0

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.
data/sig/rpremote.rbs ADDED
@@ -0,0 +1,404 @@
1
+ module Rpremote
2
+ VERSION: String
3
+
4
+ class Error < StandardError
5
+ end
6
+
7
+ module Language
8
+ SUPPORTED: Array[String]
9
+
10
+ def self.validate!: (String language) -> String
11
+ end
12
+
13
+ class Target
14
+ DEFAULT_LANGUAGE: String
15
+ DEFAULT_LANGUAGE_VERSION: String
16
+ DEFAULT_BOARD: String
17
+ DEFAULT_CACHE_DIR: String
18
+ IDENTIFIER_PATTERN: Regexp
19
+
20
+ attr_reader language: String
21
+ attr_reader language_version: String
22
+ attr_reader board: String
23
+ attr_reader cache_dir: String
24
+
25
+ def initialize: (
26
+ ?language: String,
27
+ ?language_version: String,
28
+ ?board: String,
29
+ ?cache_dir: String,
30
+ ?firmware: String?
31
+ ) -> void
32
+ def source_dir: (?root: String) -> String
33
+ def firmware_path: (?root: String?) -> String
34
+ end
35
+
36
+ module Checksum
37
+ def self.crc16: (String data, ?Integer initial) -> Integer
38
+ def self.crc32: (String data, ?Integer initial) -> Integer
39
+ end
40
+
41
+ module RemotePath
42
+ PREFIX: String
43
+
44
+ def self.remote?: (String path) -> bool
45
+ def self.unwrap: (String path) -> String
46
+ def self.validate: (String path) -> String
47
+ end
48
+
49
+ class Config
50
+ DEFAULT_PATH: String
51
+ OPTION_TYPES: Hash[Symbol, untyped]
52
+ COMMAND_OPTIONS: Hash[String, Array[Symbol]]
53
+
54
+ class Result < Data
55
+ attr_reader path: String
56
+ attr_reader created: bool
57
+ end
58
+
59
+ class Error < Rpremote::Error
60
+ end
61
+
62
+ def self.load: (
63
+ String command,
64
+ ?filename: String,
65
+ ?required: bool,
66
+ ?cwd: String
67
+ ) -> Hash[Symbol, untyped]
68
+ def self.extract_option!: (Array[String] args) -> [String, bool]
69
+ def self.load_command: (String? command, filename: String, required: bool) -> Hash[Symbol, untyped]
70
+ def self.setup: (?filename: String, ?cwd: String) -> Result
71
+ end
72
+
73
+ class PicoModem
74
+ CHUNK_SIZE: Integer
75
+ DEFAULT_TIMEOUT: Float
76
+ DFU_START: Integer
77
+ DFU_ACK: Integer
78
+ DFU_MAGIC: String
79
+ DFU_VERSION: Integer
80
+ DFU_TYPES: Array[String]
81
+
82
+ class Error < Rpremote::Error
83
+ end
84
+
85
+ class TimeoutError < Error
86
+ end
87
+
88
+ class ProtocolError < Error
89
+ end
90
+
91
+ class ChecksumError < ProtocolError
92
+ end
93
+
94
+ class DeviceError < Error
95
+ end
96
+
97
+ attr_reader io: untyped
98
+ attr_reader timeout: Float
99
+
100
+ def initialize: (untyped io, ?timeout: Float) -> void
101
+ def upload: (String path, String data) -> Integer
102
+ def download: (String path) -> String
103
+ def dfu: (String data, type: String) -> Integer
104
+ def send_frame: (Integer command, ?String payload) -> Integer
105
+ def receive_frame: () -> [Integer, String]
106
+ end
107
+
108
+ class Device
109
+ class NotFoundError < Rpremote::Error
110
+ end
111
+
112
+ class MultipleDevicesError < Rpremote::Error
113
+ end
114
+
115
+ def self.ports: () -> Array[String]
116
+ def self.main_port: (?String? explicit_port, ?available_ports: Array[String]) -> String
117
+ end
118
+
119
+ class Serial
120
+ BAUD_RATE: Integer
121
+
122
+ class ConfigurationError < Rpremote::Error
123
+ end
124
+
125
+ def self.open: [T] (String path, ?baud: Integer) { (Serial) -> T } -> T
126
+ | (String path, ?baud: Integer) -> Serial
127
+
128
+ attr_reader path: String
129
+ attr_reader baud: Integer
130
+ attr_reader io: File
131
+
132
+ def initialize: (String path, ?baud: Integer) -> void
133
+ def read_nonblock: (Integer length) -> String
134
+ def write: (String data) -> Integer
135
+ def flush: () -> untyped
136
+ def close: () -> untyped
137
+ def closed?: () -> bool
138
+ def to_io: () -> File
139
+ end
140
+
141
+ class LanguageSource
142
+ class Error < Rpremote::Error
143
+ end
144
+
145
+ class DownloadError < Error
146
+ end
147
+
148
+ class ExtractError < Error
149
+ end
150
+
151
+ attr_reader language: String
152
+ attr_reader version: String
153
+ attr_reader cache_dir: String
154
+
155
+ def initialize: (
156
+ ?language: String,
157
+ ?version: String,
158
+ ?cache_dir: String,
159
+ ?fetcher: untyped,
160
+ ?extractor: untyped,
161
+ ?preparer: untyped
162
+ ) -> void
163
+ def setup: (?force: bool) -> String
164
+ def archive_url: () -> String
165
+ def archive_path: () -> String
166
+ def source_dir: () -> String
167
+ end
168
+
169
+ class Builder
170
+ class Error < Rpremote::Error
171
+ end
172
+
173
+ def initialize: (?root: String, ?runner: untyped, ?mrbgems_class: untyped) -> void
174
+ def build: (
175
+ ?language: String,
176
+ ?language_version: String,
177
+ ?board: String,
178
+ ?cache_dir: String,
179
+ ?firmware: String?,
180
+ ?mrbgems: String | false | nil,
181
+ ?output: IO,
182
+ ?error: IO
183
+ ) -> void
184
+ def clean: (?output: IO) -> void
185
+ end
186
+
187
+ class Mrbgems
188
+ DEFAULT_PATH: String
189
+ DEFAULT_LOCK_PATH: String
190
+ LOCK_VERSION: Integer
191
+
192
+ class Error < Rpremote::Error
193
+ end
194
+
195
+ class DefinitionError < Error
196
+ end
197
+
198
+ class LockError < Error
199
+ end
200
+
201
+ class Dependency < Data
202
+ attr_reader type: Symbol
203
+ attr_reader source: String
204
+ attr_reader branch: String?
205
+ attr_reader commit: String?
206
+ attr_reader path: String?
207
+ end
208
+
209
+ class Overlay < Data
210
+ attr_reader path: String
211
+ attr_reader fingerprint: String
212
+ end
213
+
214
+ attr_reader path: String
215
+ attr_reader lock_path: String
216
+
217
+ def initialize: (
218
+ ?path: String,
219
+ ?lock_path: String?,
220
+ ?cwd: String,
221
+ ?resolver: untyped
222
+ ) -> void
223
+ def exist?: () -> bool
224
+ def dependencies: () -> Array[Dependency]
225
+ def vm: () -> Symbol?
226
+ def check: () -> Array[Dependency]
227
+ def lock: (?update: bool) -> Hash[String, untyped]
228
+ def read_lock: (?required: bool) -> Hash[String, untyped]?
229
+ def generate_overlay: (
230
+ base_config: String,
231
+ target: String,
232
+ directory: String,
233
+ ?update: bool
234
+ ) -> Overlay
235
+ end
236
+
237
+ class Shell
238
+ DEFAULT_TIMEOUT: Float
239
+ PROMPT_START: String
240
+ PROMPT_END: String
241
+ CURSOR_POSITION_QUERY: String
242
+ CURSOR_POSITION_RESPONSE: String
243
+
244
+ class Error < Rpremote::Error
245
+ end
246
+
247
+ class TimeoutError < Error
248
+ end
249
+
250
+ class ProtocolError < Error
251
+ end
252
+
253
+ class CommandError < Error
254
+ end
255
+
256
+ attr_reader io: untyped
257
+ attr_reader timeout: Float
258
+
259
+ def self.quote_argument: (String argument) -> String
260
+ def initialize: (untyped io, ?timeout: Float) -> void
261
+ def synchronize!: () -> nil
262
+ def send_command: (String command) -> nil
263
+ def execute: (String command) -> String
264
+ end
265
+
266
+ class Terminal
267
+ EXIT_BYTE: Integer
268
+ BUFFER_SIZE: Integer
269
+
270
+ attr_reader serial_io: untyped
271
+ attr_reader input: IO
272
+ attr_reader output: IO
273
+
274
+ def initialize: (
275
+ untyped serial_io,
276
+ ?input: IO,
277
+ ?output: IO,
278
+ ?selector: untyped
279
+ ) -> void
280
+ def run: (?exit_sequence: String?) -> nil
281
+ end
282
+
283
+ class Runner
284
+ REMOTE_DIRECTORY: String
285
+
286
+ attr_reader io: untyped
287
+ attr_reader timeout: Float
288
+
289
+ def initialize: (
290
+ untyped io,
291
+ ?timeout: Float,
292
+ ?modem_class: untyped,
293
+ ?shell_class: untyped,
294
+ ?path_factory: untyped
295
+ ) -> void
296
+ def run: (String data) -> String
297
+ end
298
+
299
+ class Resetter
300
+ DEFAULT_TIMEOUT: Float
301
+ RETRY_INTERVAL: Float
302
+ PROBE_TIMEOUT: Float
303
+
304
+ class TimeoutError < Rpremote::Error
305
+ end
306
+
307
+ def initialize: (
308
+ ?serial: untyped,
309
+ ?timeout: Numeric,
310
+ ?shell_class: untyped,
311
+ ?sleeper: untyped,
312
+ ?clock: untyped,
313
+ ?port_probe: untyped
314
+ ) -> void
315
+ def reset: (String port_path, ?baud: Integer) -> String
316
+ end
317
+
318
+ class Flasher
319
+ DEFAULT_VOLUMES_ROOT: String
320
+ DEFAULT_TIMEOUT: Float
321
+ INFO_FILE: String
322
+
323
+ class Result < Data
324
+ attr_reader mount: String
325
+ attr_reader destination: String
326
+ attr_reader port: String
327
+ end
328
+
329
+ class Error < Rpremote::Error
330
+ end
331
+
332
+ class MountNotFoundError < Error
333
+ end
334
+
335
+ class InvalidTargetError < Error
336
+ end
337
+
338
+ class TimeoutError < Error
339
+ end
340
+
341
+ attr_reader volumes_root: String
342
+ attr_reader timeout: Float
343
+
344
+ def initialize: (
345
+ ?volumes_root: String,
346
+ ?timeout: Numeric,
347
+ ?mount_probe: untyped,
348
+ ?port_probe: untyped,
349
+ ?sleeper: untyped
350
+ ) -> void
351
+ def flash: (String uf2_path, ?mount: String?, ?port: String?) -> Result
352
+ def find_mount: (?String? explicit_mount) -> String
353
+ end
354
+
355
+ class DfuCommand
356
+ DEFAULT_TIMEOUT: Float
357
+ TYPES: Hash[String, String]
358
+
359
+ def self.run: (
360
+ Array[String] args,
361
+ defaults: Hash[Symbol, untyped],
362
+ ?output: IO,
363
+ ?serial: untyped,
364
+ ?device: untyped,
365
+ ?services: Hash[Symbol, untyped]
366
+ ) -> void
367
+ end
368
+
369
+ class DfuCompiler
370
+ class Error < Rpremote::Error
371
+ end
372
+
373
+ def self.compile: (String source, target: Target, ?destination: String?, ?output: IO, ?runner: untyped) -> String
374
+ end
375
+
376
+ class SetupCommand
377
+ def self.run: (
378
+ Array[String] args,
379
+ defaults: Hash[Symbol, untyped],
380
+ config: untyped,
381
+ config_filename: String,
382
+ ?output: IO
383
+ ) -> void
384
+ end
385
+
386
+ class BuildCommand
387
+ def self.run: (
388
+ Array[String] args,
389
+ defaults: Hash[Symbol, untyped],
390
+ ?output: IO,
391
+ ?error: IO,
392
+ ?builder: Builder
393
+ ) -> void
394
+ end
395
+
396
+ class FlashCommand
397
+ def self.run: (
398
+ Array[String] args,
399
+ defaults: Hash[Symbol, untyped],
400
+ ?output: IO,
401
+ ?flasher: untyped
402
+ ) -> void
403
+ end
404
+ end
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "fileutils"
5
+
6
+ REPOSITORY_ROOT = File.expand_path(ENV.fetch("RPREMOTE_ROOT", File.expand_path("../..", __dir__)))
7
+ DEFAULT_BOARD = "pico2"
8
+ SUPPORTED_BOARDS = %w[pico2 pico2_w].freeze
9
+
10
+ def command!(*command, chdir:, env: {})
11
+ prefix = env.map { |key, value| "#{key}=#{value}" }.join(" ")
12
+ puts "+ #{prefix} #{command.join(" ")}".strip
13
+ abort "Command failed: #{command.join(" ")}" unless system(env, *command, chdir: chdir)
14
+ end
15
+
16
+ language = ENV.fetch("RPREMOTE_LANGUAGE", "picoruby")
17
+ target_version = ENV.fetch("RPREMOTE_LANGUAGE_VERSION", "4.0.3")
18
+ board = ENV.fetch("RPREMOTE_BOARD", DEFAULT_BOARD)
19
+ abort "Unsupported language: #{language}" unless language == "picoruby"
20
+ abort "Unsupported board: #{board}" unless SUPPORTED_BOARDS.include?(board)
21
+
22
+ picoruby_root = File.expand_path(ENV.fetch("PICORUBY_DIR"))
23
+ config_name = ENV.fetch("RPREMOTE_CONFIG_NAME", "r2p2-#{language}-#{board}")
24
+ base_config_path = File.join(picoruby_root, "build_config", "#{config_name}.rb")
25
+ config_path = ENV.fetch("RPREMOTE_MRUBY_CONFIG", base_config_path)
26
+ fingerprint = ENV.fetch("RPREMOTE_MRBGEMS_FINGERPRINT", nil)
27
+ build_name = [config_name, target_version, fingerprint].compact.join("-")
28
+ r2p2_gem_dir = File.join(picoruby_root, "mrbgems/picoruby-r2p2")
29
+ pico_sdk_path = File.join(r2p2_gem_dir, "lib/pico-sdk")
30
+ pico_extras_path = File.join(r2p2_gem_dir, "lib/pico-extras")
31
+ output_dir = File.join(REPOSITORY_ROOT, "build", build_name)
32
+ mruby_build_dir = File.join(picoruby_root, "build", config_name)
33
+ cmake_source_dir = File.join(r2p2_gem_dir, "cmake")
34
+
35
+ unless File.file?(File.join(picoruby_root, "Rakefile"))
36
+ abort "PicoRuby source not found: #{picoruby_root}\nSet PICORUBY_DIR to a PicoRuby checkout."
37
+ end
38
+ abort "Build config not found: #{base_config_path}" unless File.file?(base_config_path)
39
+ abort "Generated build config not found: #{config_path}" unless File.file?(config_path)
40
+ build_config = File.read(base_config_path)
41
+ mrubyc_vm = build_config.match?(/mrubyc_hal|conf\.femtoruby/)
42
+ uses_wifi = build_config.match?(/\bUSE_WIFI\b/)
43
+ command!("rake", "r2p2:setup", chdir: picoruby_root) unless File.directory?(pico_sdk_path)
44
+
45
+ version_header = File.join(picoruby_root, "include/version.h")
46
+ version = File.read(version_header)[/#define PICORUBY_VERSION "(.+?)"/, 1]
47
+ abort "Could not determine PicoRuby version from #{version_header}" unless version
48
+ abort "PicoRuby source is #{version}, but #{target_version} was requested." unless version == target_version
49
+
50
+ cache_file = File.join(output_dir, "CMakeCache.txt")
51
+ if File.file?(cache_file) && !File.read(cache_file).include?("CMAKE_HOME_DIRECTORY:INTERNAL=#{cmake_source_dir}")
52
+ puts "Removing stale CMake output: #{output_dir}"
53
+ FileUtils.rm_rf(output_dir)
54
+ end
55
+ FileUtils.mkdir_p(output_dir)
56
+ build_env = {
57
+ "MRUBY_CONFIG" => config_path,
58
+ "PICORB_BOARD" => board,
59
+ "PICO_SDK_PATH" => pico_sdk_path,
60
+ "PICO_EXTRAS_PATH" => pico_extras_path
61
+ }
62
+
63
+ # PicoRuby's build directory is keyed by the target name, not by MRUBY_CONFIG.
64
+ # A generated overlay therefore shares the base target's objects. In particular,
65
+ # mrblib.c includes picogem_init.c, but Make does not track that generated include
66
+ # as a dependency. Reusing the directory can leave a removed or added local
67
+ # mrbgem out of libmruby.a. Custom mrbgems must start from a fresh target build.
68
+ if fingerprint && File.directory?(mruby_build_dir)
69
+ puts "Removing stale PicoRuby build output: #{mruby_build_dir}"
70
+ FileUtils.rm_rf(mruby_build_dir)
71
+ end
72
+ command!("rake", chdir: picoruby_root, env: build_env)
73
+
74
+ cmake_definitions = [
75
+ "-D", "PICORUBY_ROOT=#{picoruby_root}",
76
+ "-D", "R2P2_GEM_DIR=#{r2p2_gem_dir}",
77
+ "-D", "EXTRA_LIBRARY_PATH=#{File.join(mruby_build_dir, "lib")}",
78
+ "-D", "EXTRA_INCLUDE_DIR=#{File.join(mruby_build_dir, "include")}",
79
+ "-D", "PICO_CYW43_SUPPORTED=1",
80
+ "-D", "MRUBY_CONFIG=#{config_name}",
81
+ "-D", "PICORB_VM_MRUBY=#{mrubyc_vm ? 0 : 1}",
82
+ "-D", "PICORB_VM_MRUBYC=#{mrubyc_vm ? 1 : 0}",
83
+ "-D", "R2P2_NAME=R2P2-PICORUBY",
84
+ "-D", "R2P2_BOARD_NAME=#{board.upcase}",
85
+ "-D", "R2P2_VERSION=#{version}",
86
+ "-D", "PICO_PLATFORM=rp2350",
87
+ "-D", "PICO_BOARD=#{board}",
88
+ "-D", "CMAKE_BUILD_TYPE=Release",
89
+ "-D", "NDEBUG=1",
90
+ "-D", "R2P2_NO_SHARED_ALLOC=OFF"
91
+ ]
92
+ cmake_definitions.push("-D", "USE_WIFI=1") if uses_wifi
93
+ command!("cmake", "-S", cmake_source_dir, "-B", output_dir, *cmake_definitions,
94
+ chdir: picoruby_root, env: build_env)
95
+ command!("cmake", "--build", output_dir, chdir: picoruby_root)
96
+
97
+ uf2_files = Dir[File.join(output_dir, "*.uf2")]
98
+ abort "Build finished but no UF2 file was created in #{output_dir}" if uf2_files.empty?
99
+
100
+ built_firmware = uf2_files.max_by { |path| File.mtime(path) }
101
+ destination = ENV.fetch("RPREMOTE_FIRMWARE", nil)
102
+ if destination
103
+ FileUtils.mkdir_p(File.dirname(destination))
104
+ FileUtils.cp(built_firmware, destination)
105
+ puts "Built custom firmware: #{destination}"
106
+ else
107
+ puts "Built custom firmware: #{built_firmware}"
108
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "release_check"
4
+
5
+ namespace :release do
6
+ desc "Validate and smoke-test the release gem without publishing it"
7
+ task check: %i[spec rubocop] do
8
+ sh "bundle exec rbs validate"
9
+ sh "gem build rpremote.gemspec"
10
+ Rpremote::ReleaseCheck.call
11
+ end
12
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "bundler"
5
+ require "open3"
6
+ require "rbconfig"
7
+ require "rubygems/package"
8
+ require "tmpdir"
9
+ require_relative "../lib/rpremote/version"
10
+
11
+ module Rpremote
12
+ module ReleaseCheck
13
+ EXPECTED_FILES = %w[
14
+ CHANGELOG.md
15
+ LICENSE
16
+ README.md
17
+ README.ja.md
18
+ RELEASING.md
19
+ THIRD_PARTY_NOTICES.md
20
+ exe/rpremote
21
+ tasks/firmware_build.rb
22
+ ].freeze
23
+
24
+ module_function
25
+
26
+ def call
27
+ gem_file = File.expand_path("rpremote-#{Rpremote::VERSION}.gem")
28
+ validate_package(gem_file)
29
+ smoke_test(gem_file)
30
+ puts "release check passed: #{File.basename(gem_file)}"
31
+ end
32
+
33
+ def validate_package(gem_file)
34
+ package = Gem::Package.new(gem_file)
35
+ specification = package.spec
36
+ missing_files = EXPECTED_FILES - package.contents
37
+ changelog_entry = "## [#{Rpremote::VERSION}]"
38
+
39
+ unless specification.version.to_s == Rpremote::VERSION
40
+ abort "built gem version does not match #{Rpremote::VERSION}"
41
+ end
42
+ unless File.read("CHANGELOG.md").include?(changelog_entry)
43
+ abort "CHANGELOG.md has no entry for #{Rpremote::VERSION}"
44
+ end
45
+ abort "built gem is missing: #{missing_files.join(", ")}" unless missing_files.empty?
46
+ abort "built gem does not require MFA" unless specification.metadata["rubygems_mfa_required"] == "true"
47
+ end
48
+
49
+ def smoke_test(gem_file)
50
+ Dir.mktmpdir("rpremote-release-") do |directory|
51
+ gem_home = File.join(directory, "gems")
52
+ bin_dir = File.join(directory, "bin")
53
+ FileUtils.mkdir_p([gem_home, bin_dir])
54
+ environment = { "GEM_HOME" => gem_home, "GEM_PATH" => gem_home }
55
+
56
+ install_gem(environment, gem_home, bin_dir, gem_file)
57
+ run_cli(environment, bin_dir)
58
+ end
59
+ end
60
+
61
+ def install_gem(environment, gem_home, bin_dir, gem_file)
62
+ command = [
63
+ RbConfig.ruby, "-S", "gem", "install", "--local", "--no-document",
64
+ "--install-dir", gem_home, "--bindir", bin_dir, gem_file
65
+ ]
66
+ run!(environment, command, "isolated gem install")
67
+ end
68
+
69
+ def run_cli(environment, bin_dir)
70
+ stdout = run!(environment, [File.join(bin_dir, "rpremote"), "--version"], "installed CLI")
71
+ abort "installed CLI reported #{stdout.strip.inspect}" unless stdout.strip == Rpremote::VERSION
72
+ end
73
+
74
+ def run!(environment, command, description)
75
+ stdout, stderr, status = Bundler.with_unbundled_env do
76
+ Open3.capture3(environment, *command)
77
+ end
78
+ abort "#{description} failed:\n#{stdout}#{stderr}" unless status.success?
79
+
80
+ stdout
81
+ end
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rpremote
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ogom
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Embed public or local mrbgems in reproducible R2P2 firmware, flash it,
13
+ and control the device.
14
+ email:
15
+ - ogom@users.noreply.github.com
16
+ executables:
17
+ - rpremote
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CHANGELOG.md
22
+ - LICENSE
23
+ - README.ja.md
24
+ - README.md
25
+ - RELEASING.md
26
+ - THIRD_PARTY_NOTICES.md
27
+ - exe/rpremote
28
+ - lib/rpremote.rb
29
+ - lib/rpremote/build_command.rb
30
+ - lib/rpremote/builder.rb
31
+ - lib/rpremote/checksum.rb
32
+ - lib/rpremote/cli.rb
33
+ - lib/rpremote/config.rb
34
+ - lib/rpremote/device.rb
35
+ - lib/rpremote/dfu_command.rb
36
+ - lib/rpremote/dfu_compiler.rb
37
+ - lib/rpremote/flash_command.rb
38
+ - lib/rpremote/flasher.rb
39
+ - lib/rpremote/help.rb
40
+ - lib/rpremote/language.rb
41
+ - lib/rpremote/language_source.rb
42
+ - lib/rpremote/mrbgems.rb
43
+ - lib/rpremote/mrbgems_command.rb
44
+ - lib/rpremote/picomodem.rb
45
+ - lib/rpremote/remote_path.rb
46
+ - lib/rpremote/resetter.rb
47
+ - lib/rpremote/runner.rb
48
+ - lib/rpremote/serial.rb
49
+ - lib/rpremote/setup_command.rb
50
+ - lib/rpremote/shell.rb
51
+ - lib/rpremote/target.rb
52
+ - lib/rpremote/terminal.rb
53
+ - lib/rpremote/version.rb
54
+ - sig/rpremote.rbs
55
+ - tasks/firmware_build.rb
56
+ - tasks/release.rake
57
+ - tasks/release_check.rb
58
+ homepage: https://github.com/ogom/rpremote
59
+ licenses:
60
+ - MIT
61
+ metadata:
62
+ homepage_uri: https://github.com/ogom/rpremote
63
+ source_code_uri: https://github.com/ogom/rpremote/tree/main/packages/rpremote
64
+ rubygems_mfa_required: 'true'
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 4.0.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 4.0.10
80
+ specification_version: 4
81
+ summary: Build and control custom PicoRuby firmware on Raspberry Pi Pico
82
+ test_files: []