procon_bypass_man 0.3.6 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +4 -0
- data/.github/workflows/gitleacks.yml +1 -1
- data/.github/workflows/release.yml +1 -1
- data/.github/workflows/ruby.yml +2 -2
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +4 -2
- data/README.md +2 -2
- data/bin/validate_external_input +19 -0
- data/docs/getting_started.md +28 -0
- data/docs/setting/integration_external_input_serial_port.md +56 -0
- data/docs/setting/integration_external_input_serial_port_format.md +36 -0
- data/lib/procon_bypass_man/background/jobs/report_procon_performance_measurements_job.rb +1 -0
- data/lib/procon_bypass_man/bypass/procon_to_switch.rb +16 -1
- data/lib/procon_bypass_man/commands/print_boot_message_command.rb +4 -1
- data/lib/procon_bypass_man/configuration.rb +31 -14
- data/lib/procon_bypass_man/external_input/boot_message.rb +21 -0
- data/lib/procon_bypass_man/external_input/channels/base.rb +22 -0
- data/lib/procon_bypass_man/external_input/channels/serial_port_channel.rb +56 -0
- data/lib/procon_bypass_man/external_input/channels/tcpip_channel.rb +131 -0
- data/lib/procon_bypass_man/external_input/channels.rb +12 -0
- data/lib/procon_bypass_man/external_input/external_data.rb +79 -0
- data/lib/procon_bypass_man/external_input.rb +31 -0
- data/lib/procon_bypass_man/processor.rb +3 -2
- data/lib/procon_bypass_man/procon/button_collection.rb +5 -0
- data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +4 -0
- data/lib/procon_bypass_man/procon/performance_measurement.rb +7 -1
- data/lib/procon_bypass_man/procon.rb +17 -2
- data/lib/procon_bypass_man/procon_display/status.rb +0 -2
- data/lib/procon_bypass_man/support/forever.rb +51 -0
- data/lib/procon_bypass_man/support/proccess_cheacker.rb +14 -0
- data/lib/procon_bypass_man/support/retryable.rb +5 -2
- data/lib/procon_bypass_man/support/simple_tcp_server.rb +63 -0
- data/lib/procon_bypass_man/support/watchdog.rb +23 -0
- data/lib/procon_bypass_man/support/web_connectivity_checker.rb +41 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man/websocket/client.rb +11 -9
- data/lib/procon_bypass_man.rb +16 -3
- data/project_template/app.rb +11 -1
- data/project_template/app.rb.erb +11 -1
- data/sig/main.rbs +2 -2
- metadata +17 -4
- data/lib/procon_bypass_man/websocket/forever.rb +0 -47
- data/lib/procon_bypass_man/websocket/watchdog.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1933db5fe8c39267f980712a5477a457277cdd3ce9148a81966c1e1d818805e8
|
4
|
+
data.tar.gz: 404ce5c7ada74a92afb5abf2b2f583c3fe1c87bbc4d3ae2372e0ff3f961d9245
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eeeb32ff42fc02d2b40b19be2a1eba55a9fc5ffc6a3f08af47b4ed86bb67edba60dc7ef409f892ba9ef21953a349abda01a28d04f4a4f99f0032382a68c2f904
|
7
|
+
data.tar.gz: 811f537dd6ea2659678911678022c02734a2a21ef099d7ed140067a56e88edf0fabc4aec8264c052e8e8e9759c54085a17ab7a72c668a338560250b880395e2f
|
data/.circleci/config.yml
CHANGED
@@ -119,6 +119,7 @@ build_jobs: &build_jobs
|
|
119
119
|
- "3.0.1"
|
120
120
|
- "3.0.2"
|
121
121
|
- "3.1.2"
|
122
|
+
- "3.2.2"
|
122
123
|
- bundle_install:
|
123
124
|
matrix:
|
124
125
|
parameters:
|
@@ -127,6 +128,7 @@ build_jobs: &build_jobs
|
|
127
128
|
- "3.0.1"
|
128
129
|
- "3.0.2"
|
129
130
|
- "3.1.2"
|
131
|
+
- "3.2.2"
|
130
132
|
- lint:
|
131
133
|
matrix:
|
132
134
|
parameters:
|
@@ -135,6 +137,7 @@ build_jobs: &build_jobs
|
|
135
137
|
- "3.0.1"
|
136
138
|
- "3.0.2"
|
137
139
|
- "3.1.2"
|
140
|
+
- "3.2.2"
|
138
141
|
requires:
|
139
142
|
- bundle_install
|
140
143
|
- type_check:
|
@@ -154,6 +157,7 @@ build_jobs: &build_jobs
|
|
154
157
|
- "3.0.1"
|
155
158
|
- "3.0.2"
|
156
159
|
- "3.1.2"
|
160
|
+
- "3.2.2"
|
157
161
|
requires:
|
158
162
|
- bundle_install
|
159
163
|
workflows:
|
data/.github/workflows/ruby.yml
CHANGED
@@ -16,10 +16,10 @@ jobs:
|
|
16
16
|
timeout-minutes: 5
|
17
17
|
strategy:
|
18
18
|
matrix:
|
19
|
-
ruby-version: ['3.0.1', '3.
|
19
|
+
ruby-version: ['3.0', '3.1', '3.2']
|
20
20
|
|
21
21
|
steps:
|
22
|
-
- uses: actions/checkout@
|
22
|
+
- uses: actions/checkout@v3
|
23
23
|
- name: Set up Ruby
|
24
24
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
25
25
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## [0.3.8] 2023-05-03
|
2
|
+
* TCP/IP経由でPBMに入力ができるようになりました
|
3
|
+
* 多重起動ができないようにしました
|
4
|
+
* pbm-cloudとの連携時に、pbmenvを使っているかの判定を修正しました
|
5
|
+
* actioncable(websocket)serverのURLをpbm-cloudから取得するようにしました
|
6
|
+
|
7
|
+
## [0.3.7] 2023-04-06
|
8
|
+
* PBM-Cloudと連携しているかをbootメッセージに表示ようになりました
|
9
|
+
* シリアルポート経由でPBMに入力ができるようになりました
|
10
|
+
|
1
11
|
## [0.3.6] 2023-03-12
|
2
12
|
- プロコンの入力状態をpbm-cloudサーバに送信できるようになりました
|
3
13
|
|
data/Gemfile
CHANGED
@@ -13,6 +13,7 @@ gem "rubocop", require: false
|
|
13
13
|
gem "sinatra", require: false
|
14
14
|
gem "webrick", require: false
|
15
15
|
gem "stackprof", require: false
|
16
|
+
gem "serialport" # シリアル通信をする時に必要。通常はいらない
|
16
17
|
|
17
18
|
if Gem::Version.new(RUBY_VERSION) > Gem::Version.new("2.6.0")
|
18
19
|
gem 'typeprof', require: false
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
procon_bypass_man (0.3.
|
4
|
+
procon_bypass_man (0.3.8)
|
5
5
|
action_cable_client
|
6
6
|
blue_green_process (= 0.1.4.2)
|
7
7
|
pbmenv (>= 0.1.11)
|
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
parallel (1.21.0)
|
39
39
|
parser (3.0.3.2)
|
40
40
|
ast (~> 2.4.1)
|
41
|
-
pbmenv (0.1.
|
41
|
+
pbmenv (0.1.12)
|
42
42
|
pry (0.14.1)
|
43
43
|
coderay (~> 1.1)
|
44
44
|
method_source (~> 1.0)
|
@@ -80,6 +80,7 @@ GEM
|
|
80
80
|
parser (>= 3.0.1.1)
|
81
81
|
ruby-progressbar (1.11.0)
|
82
82
|
ruby2_keywords (0.0.5)
|
83
|
+
serialport (1.3.2)
|
83
84
|
set (1.0.3)
|
84
85
|
sinatra (2.2.0)
|
85
86
|
mustermann (~> 1.0)
|
@@ -134,6 +135,7 @@ DEPENDENCIES
|
|
134
135
|
rbs
|
135
136
|
rspec
|
136
137
|
rubocop
|
138
|
+
serialport
|
137
139
|
sinatra
|
138
140
|
stackprof
|
139
141
|
steep
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
https://user-images.githubusercontent.com/1664497/171327108-f12f56a5-fc36-48da-95a5-65e976553a20.mov
|
13
13
|
|
14
|
-
##
|
14
|
+
## 必要なハードウェア
|
15
15
|
* Nintendo Switch Proコントローラー
|
16
16
|
* Switch本体とドック
|
17
17
|
* Raspberry Pi4 (Raspberry Pi OS)
|
@@ -38,7 +38,7 @@ https://user-images.githubusercontent.com/1664497/171327108-f12f56a5-fc36-48da-9
|
|
38
38
|
* レイヤーを切り替える方法は?
|
39
39
|
* 設定ファイルに記述している `prefix_keys_for_changing_layer`の後ろにあるキーを同時押しながら、十字キーのどれかを押すことで任意のレイヤーに切り替わります
|
40
40
|
* このツールでできることは?
|
41
|
-
* キーリマップ, 連射,
|
41
|
+
* キーリマップ, 連射, マクロ, 外部ツールからの入力
|
42
42
|
* リマップは1つのキーを別のキーに割り当てます
|
43
43
|
* 連射中には特定のキーの入力を無視したり、複数のキーをトリガーに連射することができます
|
44
44
|
* どうしてsudoが必要なの?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Usage:
|
4
|
+
# NOTE: JSON形式の文字列がどういう形で読み込まれるかを確認できます
|
5
|
+
# $ echo '{"hex":"hogehoge", "buttons": ["a","b", "zr"]}' | bin/validate_external_input
|
6
|
+
# => 読み取った値: {:hex=>"hogehoge", :buttons=>["a", "b", "zr"]}
|
7
|
+
|
8
|
+
require "bundler/setup"
|
9
|
+
require "json"
|
10
|
+
require "procon_bypass_man"
|
11
|
+
require "procon_bypass_man/external_input"
|
12
|
+
|
13
|
+
begin
|
14
|
+
json_str = ARGF.read
|
15
|
+
external_data = ProconBypassMan::ExternalInput::ExternalData.parse!(json_str)
|
16
|
+
puts("読み取った値: #{{ hex: external_data.hex, buttons: external_data.buttons }}")
|
17
|
+
rescue JSON::ParserError => e
|
18
|
+
puts "failed to parse JSON: #{e.message}"
|
19
|
+
end
|
data/docs/getting_started.md
CHANGED
@@ -18,6 +18,8 @@
|
|
18
18
|
* [設定ファイルの書き方がわからない、エラーが起きるとき](#設定ファイルの書き方がわからない、エラーが起きるとき)
|
19
19
|
* [procon_bypass_manのアップグレード方法](#procon_bypass_manのアップグレード方法)
|
20
20
|
* [procon_bypass_man_cloudについて](#procon_bypass_man_cloudについて)
|
21
|
+
* [シリアルポート連携](#シリアルポート連携)
|
22
|
+
* [TCPIP連携](#TCPIP連携)
|
21
23
|
* [最適化について](#最適化について)
|
22
24
|
|
23
25
|
## はじめに
|
@@ -251,6 +253,32 @@ procon_bypass_man_cloudとの接続が完了後、Raspberry Piを起動時にpro
|
|
251
253
|
|
252
254
|
セットアップ方法は https://pbm-cloud.jiikko.com/faq に書いています。
|
253
255
|
|
256
|
+
## シリアルポート連携
|
257
|
+
* [ラズベリーパイのシリアルポート(GPIO)へ書き込んでPBM経由してSwitchへ入力をする方法](/docs/setting/integration_external_input_serial_port.md)
|
258
|
+
* [ラズベリーパイのシリアルポート(GPIO)に書き込むフォーマットについて](/docs/setting/integration_external_input_serial_port_format.md)
|
259
|
+
|
260
|
+
## TCPIP連携
|
261
|
+
procon_bypass_man: 0.3.8 からTCP/IP経由で入力ができるようになりました。
|
262
|
+
書き込みフォーマットはJSONのみに対応しています。JSONの詳細な仕様については [ラズベリーパイのシリアルポート(GPIO)に書き込むフォーマットについて](/docs/setting/integration_external_input_serial_port_format.md) を参照してください。
|
263
|
+
|
264
|
+
次は、PBM側の設定方法についてです。app.rbに以下の行を追加すると、連携するためのTCPサーバを起動するようになります。
|
265
|
+
|
266
|
+
```diff
|
267
|
+
+ config.external_input_channels = [
|
268
|
+
+ ProconBypassMan::ExternalInput::Channels::TCPIPChannel.new(port: 9000),
|
269
|
+
+ ]
|
270
|
+
```
|
271
|
+
|
272
|
+
クライアント側のサンプル実装は次の通りです。これを実行するとAボタンを入力します。
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
socket = TCPSocket.new('ras1.local', 9000)
|
276
|
+
json = { buttons: [:a] }.to_json
|
277
|
+
message = "#{json}\r\n"
|
278
|
+
socket.write(message)
|
279
|
+
puts socket.gets
|
280
|
+
```
|
281
|
+
|
254
282
|
## 最適化について
|
255
283
|
本稿では、Rubyの最適化について書きます。上級者向けです。適用しなくても普通に動きますが、逆に適用したことで何らかのケースで遅くなる場合があるかもしれません。
|
256
284
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# ラズベリーパイのシリアルポート(GPIO)へ書き込んでPBM経由してSwitchへ入力をする方法
|
2
|
+
* procon_bypass_man: 0.3.7以上が必要です
|
3
|
+
* GPIOからSwitchへ入力できます。本テキストでは設定方法を記載します
|
4
|
+
|
5
|
+
## 1. シリアルポートへ書き込みができるようにラズベリーパイのセットアップする
|
6
|
+
https://toki-blog.com/pi-serial/ の「汎用シリアルとして使う」 を実施してください
|
7
|
+
|
8
|
+
## 2. GPIOへケーブルを挿す
|
9
|
+
対応しているケーブルをGPIOとPCに接続してください。
|
10
|
+
|
11
|
+
## 3. PBMのapp.rbを編集し、シリアルポートから読み出せるようにPBMのapp.rbを編集する
|
12
|
+
`gemの追加`と`デバイスファイルを指す修正` の2つ必要です。
|
13
|
+
|
14
|
+
* 1) シリアルポートから読み出すために追加でgemが必要です。 `app.rb` に `gem "serialport"` を追加してください。
|
15
|
+
|
16
|
+
```diff
|
17
|
+
gemfile do
|
18
|
+
source 'https://rubygems.org'
|
19
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
20
|
+
gem 'procon_bypass_man', '0.3.7'
|
21
|
+
+ gem "serialport"
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
* 2) 以下を参考にして`config.external_input_channels`の行を追加してください。
|
26
|
+
|
27
|
+
```diff
|
28
|
+
ProconBypassMan.configure do |config|
|
29
|
+
config.root = File.expand_path(__dir__)
|
30
|
+
config.logger = Logger.new("#{ProconBypassMan.root}/app.log", 1, 1024 * 1024 * 1)
|
31
|
+
config.logger.level = :debug
|
32
|
+
|
33
|
+
# バイパスするログを全部app.logに流すか
|
34
|
+
config.verbose_bypass_log = false
|
35
|
+
|
36
|
+
# webからProconBypassManを操作できるwebサービスと連携します
|
37
|
+
# 連携中はエラーログ、パフォーマンスに関するメトリクスを送信します
|
38
|
+
# config.api_servers = 'https://pbm-cloud.jiikko.com'
|
39
|
+
|
40
|
+
# エラーが起きたらerror.logに書き込みます
|
41
|
+
config.enable_critical_error_logging = true
|
42
|
+
|
43
|
+
# pbm-cloudで使う場合はnever_exitにtrueをセットしてください. trueがセットされている場合、不慮の事故が発生してもプロセスが終了しなくなります
|
44
|
+
config.never_exit_accidentally = true
|
45
|
+
|
46
|
+
# 接続に成功したらコントローラーのHOME LEDを光らせるか
|
47
|
+
config.enable_home_led_on_connect = true
|
48
|
+
|
49
|
+
+ config.external_input_channels = [
|
50
|
+
+ ProconBypassMan::ExternalInput::Channels::SerialPortChannel.new(device_path: '/dev/serial0', baud_rate: 9600),
|
51
|
+
+ ]
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
以上で設定は完了です。PBMを起動し、連携ツールからGPIOへ書き込んでください。
|
56
|
+
書き込みフォーマットについては [ラズベリーパイのシリアルポート(GPIO)に書き込むフォーマットについて](/docs/setting/integration_external_input_serial_port_format.md) を参照してください。
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# ラズベリーパイのシリアルポート(GPIO)に書き込むフォーマットについて
|
2
|
+
* procon_bypass_man: 0.3.7からGPIOを経由してSwitchへ入力できるようになりました。本テキストではPBMが読み取れるフォーマットについて記載します
|
3
|
+
|
4
|
+
## フォーマット
|
5
|
+
JSON形式, plain textに対応しています
|
6
|
+
|
7
|
+
* JSON形式
|
8
|
+
* 受付可能なカラム
|
9
|
+
* hex
|
10
|
+
* 16進数でエンコードした`INPUT 0x30` を書いてください。スティック操作を除くボタン部分のみが読み込まれます
|
11
|
+
* https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/ac8093c84194b3232acb675ac1accce9bcb456a3/bluetooth_hid_notes.md#input-0x30
|
12
|
+
* ex: '30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000'
|
13
|
+
* buttons
|
14
|
+
* 「入力したいボタン」「入力したくないボタン」を配列で渡してください
|
15
|
+
* 「入力したいボタン」
|
16
|
+
* `"y", "x", "b", "a", "sl", "sr", "r", "zr", "minus", "plus", "thumbr", "thumbl", "home", "cap", "down", "up", "right", "left", "l", "zl"`
|
17
|
+
* 「入力したくないボタン」
|
18
|
+
* `"uny", "unx", "unb", "una", "unsl", "unsr", "unr", "unzr", "unminus", "unplus", "unthumbr", "unthumbl", "unhome", "uncap", "undown", "unup", "unright", "unleft", "unl", "unzl"`
|
19
|
+
* ex: `['a', 'b']`
|
20
|
+
* 仕様
|
21
|
+
* JSONにhex, buttonsの両方が含まれている場合、hexを優先し、buttonsは無視します
|
22
|
+
* JSONの例
|
23
|
+
* `'{"hex":"30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000", "buttons": ["a"] }'`
|
24
|
+
* plain text
|
25
|
+
* コロンで囲ったボタンを1つの入力として解釈します
|
26
|
+
* `:a::b::uny:` を入力した場合には、a, b, uny を読み込みます
|
27
|
+
|
28
|
+
## 正しいJSONかを検証する
|
29
|
+
本リポジトリにJSONを検証する `bin/validate_external_input` を同梱しています。実行例を以下に示します。
|
30
|
+
|
31
|
+
```shell
|
32
|
+
$ echo '{"hex":"30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000", "buttons": ["a"] }' | bin/validate_external_input
|
33
|
+
読み取った値: {:hex=>"30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000", :buttons=>[:a]}
|
34
|
+
```
|
35
|
+
|
36
|
+
以上。
|
@@ -21,6 +21,7 @@ class ProconBypassMan::ReportProconPerformanceMeasurementsJob < ProconBypassMan:
|
|
21
21
|
time_taken_p50: metric.time_taken_p50,
|
22
22
|
time_taken_p95: metric.time_taken_p95,
|
23
23
|
time_taken_p99: metric.time_taken_p99,
|
24
|
+
external_input_time_max: metric.external_input_time_max,
|
24
25
|
read_error_count: metric.read_error_count,
|
25
26
|
write_error_count: metric.write_error_count,
|
26
27
|
gc_count: metric.gc_count,
|
@@ -50,14 +50,29 @@ class ProconBypassMan::Bypass::ProconToSwitch
|
|
50
50
|
# 後続処理で入力値を取得できるように詰めておく
|
51
51
|
ProconBypassMan::ProconDisplay::Status.instance.current = bypass_value.binary.to_procon_reader.to_hash
|
52
52
|
|
53
|
+
# NOTE: 外部からの入力を受け取る
|
54
|
+
external_input_data = nil
|
55
|
+
measurement.record_external_input_time do
|
56
|
+
# TODO: シリアルぽーとから読み取ると252.chrみたいなゴミデータを受け取ってEncoding::UndefinedConversionErrorが発生する可能性がある. 発生したら上限までretryした方がいいかも
|
57
|
+
if(data = ProconBypassMan::ExternalInput.read)
|
58
|
+
begin
|
59
|
+
external_input_data = ProconBypassMan::ExternalInput::ExternalData.parse!(data)
|
60
|
+
ProconBypassMan.logger.debug { "[ExternalInput] 読み取った値: { hex: #{external_input_data.hex}, raw_data: '#{external_input_data.raw_data}', buttons: #{external_input_data.buttons} }" }
|
61
|
+
rescue ProconBypassMan::ExternalInput::ParseError => e
|
62
|
+
ProconBypassMan.logger.error "[ExternalInput][#{e}] #{data.force_encoding('UTF-8').scrub}, #{data.force_encoding('ASCII-8BIT').codepoints} をparseできませんでした"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
53
67
|
result = measurement.record_write_time do
|
54
68
|
begin
|
55
69
|
ProconBypassMan::Retryable.retryable(tries: 5, on_no_retry: [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]) do
|
56
70
|
begin
|
57
71
|
# 終了処理を希望されているのでブロックを無視してメソッドを抜けてOK
|
58
72
|
return(false) if will_terminate? # rubocop:disable Lint/NoReturnInBeginEndBlocks
|
73
|
+
|
59
74
|
binary = ::ProconBypassMan::Procon::Rumbler.monitor do
|
60
|
-
ProconBypassMan::Processor.new(bypass_value.binary).process
|
75
|
+
ProconBypassMan::Processor.new(bypass_value.binary).process(external_input_data: external_input_data)
|
61
76
|
end
|
62
77
|
self.gadget.write_nonblock(binary)
|
63
78
|
|
@@ -10,7 +10,7 @@ class ProconBypassMan::PrintBootMessageCommand
|
|
10
10
|
@table[:pid_path] = ProconBypassMan.pid_path
|
11
11
|
@table[:setting_path] = ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path
|
12
12
|
@table[:uptime_from_boot] = ProconBypassMan::Uptime.from_boot
|
13
|
-
@table[:use_pbmenv] =
|
13
|
+
@table[:use_pbmenv] = ProconBypassMan.root.start_with?(Pbmenv::PBM_DIR)
|
14
14
|
@table[:session_id] = ProconBypassMan.session_id
|
15
15
|
@table[:device_id] = ProconBypassMan.device_id
|
16
16
|
@table[:never_exit_accidentally] = ProconBypassMan.config.never_exit_accidentally
|
@@ -34,6 +34,8 @@ class ProconBypassMan::PrintBootMessageCommand
|
|
34
34
|
ProconBypassMan::VERSION: #{@table[:pbm_version]}
|
35
35
|
RUBY_VERSION: #{@table[:ruby_version]}
|
36
36
|
Pbmenv::VERSION: #{@table[:pbmenv_version]}
|
37
|
+
PBM-Cloud Integration: #{ProconBypassMan::WebConnectivityChecker.new(ProconBypassMan.config.api_server, ProconBypassMan.config.current_ws_server_url)}
|
38
|
+
ExternalInput Integration: #{ProconBypassMan::ExternalInput::BootMessage.new(channels: ProconBypassMan::ExternalInput.channels)}
|
37
39
|
pid: #{@table[:pid]}
|
38
40
|
root: #{@table[:root_path]}
|
39
41
|
pid_path: #{@table[:pid_path]}
|
@@ -56,6 +58,7 @@ class ProconBypassMan::PrintBootMessageCommand
|
|
56
58
|
def self.execute
|
57
59
|
message = BootMessage.new
|
58
60
|
ProconBypassMan::ReportBootJob.perform_async(message.to_hash)
|
61
|
+
ProconBypassMan.logger.info message.to_s
|
59
62
|
puts message.to_s
|
60
63
|
end
|
61
64
|
end
|
@@ -19,9 +19,11 @@ class ProconBypassMan::Configuration
|
|
19
19
|
@@pid_path ||= File.expand_path("#{root}/pbm_pid", __dir__).freeze
|
20
20
|
end
|
21
21
|
|
22
|
-
# @return [Integer]
|
22
|
+
# @return [Integer, nil]
|
23
23
|
def pid
|
24
24
|
File.read(pid_path).to_i
|
25
|
+
rescue Errno::ENOENT
|
26
|
+
nil
|
25
27
|
end
|
26
28
|
|
27
29
|
def digest_path
|
@@ -54,6 +56,7 @@ class ProconBypassMan::Configuration
|
|
54
56
|
|
55
57
|
attr_accessor :enable_critical_error_logging
|
56
58
|
attr_writer :verbose_bypass_log, :raw_setting, :never_exit_accidentally, :enable_home_led_on_connect
|
59
|
+
attr_writer :external_input_channels
|
57
60
|
# 削除予定
|
58
61
|
attr_writer :enable_reporting_pressed_buttons
|
59
62
|
|
@@ -69,6 +72,7 @@ class ProconBypassMan::Configuration
|
|
69
72
|
if defined?(@root)
|
70
73
|
@root
|
71
74
|
else
|
75
|
+
ProconBypassMan.logger.warn 'root pathが未設定です'
|
72
76
|
File.expand_path('..', __dir__ || ".").freeze
|
73
77
|
end
|
74
78
|
end
|
@@ -125,22 +129,30 @@ class ProconBypassMan::Configuration
|
|
125
129
|
end
|
126
130
|
|
127
131
|
# @return [String, NilClass]
|
128
|
-
def
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
+
def current_ws_server_url
|
133
|
+
return @current_ws_server_url if defined?(@current_ws_server_url)
|
134
|
+
return unless api_server
|
135
|
+
|
136
|
+
response_json = ProconBypassMan::HttpClient.new(server: api_server, path: '/api/v1/configuration').get
|
137
|
+
ws_server_url = response_json&.fetch("ws_server_url", nil)
|
138
|
+
|
139
|
+
begin
|
140
|
+
uri = URI.parse(ws_server_url)
|
141
|
+
if uri.scheme == 'ws'
|
142
|
+
@current_ws_server_url = uri.to_s
|
143
|
+
return @current_ws_server_url
|
144
|
+
elsif uri.scheme == 'wss' # NOTE: SSL_CTX_use_certificate: ee key too small (OpenSSL::SSL::SSLError) が起きるので
|
145
|
+
uri.scheme = 'ws'
|
146
|
+
@current_ws_server_url = uri.to_s
|
147
|
+
return @current_ws_server_url
|
132
148
|
else
|
133
|
-
|
149
|
+
ProconBypassMan.logger.warn { "#{ws_server_url} is invalid." }
|
150
|
+
return nil
|
134
151
|
end
|
152
|
+
rescue URI::InvalidURIError => e
|
153
|
+
ProconBypassMan.logger.warn { "#{ws_server_url} is invalid. #{e}" }
|
154
|
+
nil
|
135
155
|
end
|
136
|
-
rescue URI::InvalidURIError
|
137
|
-
nil
|
138
|
-
end
|
139
|
-
|
140
|
-
# @return [String, NilClass]
|
141
|
-
def current_ws_server_url
|
142
|
-
return unless current_ws_server
|
143
|
-
"#{current_ws_server}/websocket/"
|
144
156
|
end
|
145
157
|
|
146
158
|
# @return [Boolean]
|
@@ -193,4 +205,9 @@ class ProconBypassMan::Configuration
|
|
193
205
|
true
|
194
206
|
end
|
195
207
|
end
|
208
|
+
|
209
|
+
# @return [Array<ProconBypassMan::ExternalInput::Channel::TCPIP, ProconBypassMan::ExternalInput::Channel::SerialPort>]
|
210
|
+
def external_input_channels
|
211
|
+
@external_input_channels || []
|
212
|
+
end
|
196
213
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ProconBypassMan
|
4
|
+
module ExternalInput
|
5
|
+
class BootMessage
|
6
|
+
# @return [ProconBypassMan::ExternalInput::Channels::Base]
|
7
|
+
def initialize(channels: )
|
8
|
+
@channels = channels
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String]
|
12
|
+
def to_s
|
13
|
+
if @channels.nil? or @channels.empty?
|
14
|
+
return 'DISABLE'
|
15
|
+
end
|
16
|
+
|
17
|
+
@channels.map(&:display_name_for_boot_message).join(', ')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ProconBypassMan
|
2
|
+
module ExternalInput
|
3
|
+
module Channels
|
4
|
+
class Base
|
5
|
+
# @return [String, NilClass]
|
6
|
+
def read
|
7
|
+
raise NotImplementedError
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [void]
|
11
|
+
def shutdown
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String]
|
16
|
+
def display_name_for_boot_message
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ProconBypassMan
|
2
|
+
module ExternalInput
|
3
|
+
module Channels
|
4
|
+
class SerialPortChannel < Base
|
5
|
+
attr_reader :serial_port
|
6
|
+
|
7
|
+
# @param [String] device_path
|
8
|
+
# @param [Integer] baud_rate
|
9
|
+
def initialize(device_path: , baud_rate: 9600)
|
10
|
+
require 'serialport'
|
11
|
+
|
12
|
+
super()
|
13
|
+
# data_bitsあたりは必要があれば設定ができるようにしたいがよくわからないのでとりあえずnilを入れる
|
14
|
+
data_bits = 8
|
15
|
+
stop_bits = 1
|
16
|
+
parity = SerialPort::NONE
|
17
|
+
@serial_port = SerialPort.new(device_path, baud_rate, data_bits, stop_bits, parity)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String, NilClass]
|
21
|
+
# NOTE: この実装では、::IO::EAGAINWaitReadableを実質的な終端として扱っているので、高速に書き込みがされると取りこぼす可能性がある.
|
22
|
+
# NOTE: read_nonblockでバッファから読み出すとき、バッファが空になるまでは::IO::EAGAINWaitReadableが起きない前提で実装している.
|
23
|
+
# NOTE: 取りこぼししないよう精度を上げるには、終端文字が来るまで1文字ずつ読む必要があるがパフォーマンスが犠牲になってしまう. この対策をするには、bypass処理の開始で非同期に1文字ずつ読み込むことをすると多少マシになるはず
|
24
|
+
def read
|
25
|
+
buffer = ''
|
26
|
+
loop do
|
27
|
+
begin
|
28
|
+
buffer += @serial_port.read_nonblock(1024) || ''
|
29
|
+
rescue ::IO::EAGAINWaitReadable
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
return nil if buffer.empty?
|
35
|
+
|
36
|
+
# NOTE: 高速に書き込まれた場合、複数のチャンクを含む可能性があるので、最初だけを切り取る
|
37
|
+
chunks = buffer.split("\n")
|
38
|
+
if(chunks.size > 1)
|
39
|
+
ProconBypassMan::SendErrorCommand.execute(
|
40
|
+
error: "[ExternalInput] シリアルポートから読み込んだchunkが複数あります. 高い書き込み頻度に耐えられていないので実装を見直してください。 (chunks.size: #{chunks.size})"
|
41
|
+
)
|
42
|
+
end
|
43
|
+
chunks.first
|
44
|
+
end
|
45
|
+
|
46
|
+
def shutdown
|
47
|
+
# no-op
|
48
|
+
end
|
49
|
+
|
50
|
+
def display_name_for_boot_message
|
51
|
+
'SerialPort'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|