procon_bypass_man 0.3.5 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +4 -0
  3. data/CHANGELOG.md +10 -3
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +3 -1
  6. data/Steepfile +0 -1
  7. data/bin/console +3 -0
  8. data/bin/generate_output_report +18 -0
  9. data/bin/validate_external_input +19 -0
  10. data/docs/getting_started.md +5 -0
  11. data/docs/setting/integration_external_input_serial_port.md +56 -0
  12. data/docs/setting/integration_external_input_serial_port_format.md +36 -0
  13. data/lib/procon_bypass_man/background/jobs/post_completed_remote_action_job.rb +20 -0
  14. data/lib/procon_bypass_man/background/jobs/report_info_log_job.rb +11 -0
  15. data/lib/procon_bypass_man/background/jobs/report_procon_performance_measurements_job.rb +1 -0
  16. data/lib/procon_bypass_man/background.rb +1 -0
  17. data/lib/procon_bypass_man/bypass/procon_to_switch.rb +19 -1
  18. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +2 -0
  19. data/lib/procon_bypass_man/commands/send_info_log_command.rb +11 -0
  20. data/lib/procon_bypass_man/commands.rb +1 -0
  21. data/lib/procon_bypass_man/configuration.rb +7 -1
  22. data/lib/procon_bypass_man/external_input/channels/base.rb +12 -0
  23. data/lib/procon_bypass_man/external_input/channels/serial_port_channel.rb +48 -0
  24. data/lib/procon_bypass_man/external_input/channels/tcpip.rb +16 -0
  25. data/lib/procon_bypass_man/external_input/channels.rb +12 -0
  26. data/lib/procon_bypass_man/external_input/external_data.rb +79 -0
  27. data/lib/procon_bypass_man/external_input.rb +35 -0
  28. data/lib/procon_bypass_man/processor.rb +3 -2
  29. data/lib/procon_bypass_man/procon/button_collection.rb +5 -0
  30. data/lib/procon_bypass_man/procon/performance_measurement/measurements_summarizer.rb +4 -0
  31. data/lib/procon_bypass_man/procon/performance_measurement.rb +7 -1
  32. data/lib/procon_bypass_man/procon.rb +38 -12
  33. data/lib/procon_bypass_man/procon_display/status.rb +1 -2
  34. data/lib/procon_bypass_man/procon_display.rb +0 -1
  35. data/lib/procon_bypass_man/{remote_macro → remote_action}/queue_over_process.rb +2 -2
  36. data/lib/procon_bypass_man/{remote_macro/remote_macro_object.rb → remote_action/remote_action_object.rb} +1 -1
  37. data/lib/procon_bypass_man/{remote_macro/remote_macro_receiver.rb → remote_action/remote_action_receiver.rb} +8 -7
  38. data/lib/procon_bypass_man/remote_action/remote_action_sender.rb +9 -0
  39. data/lib/procon_bypass_man/remote_action/remote_pbm_job/base_action.rb +55 -0
  40. data/lib/procon_bypass_man/remote_action/remote_pbm_job/change_pbm_version_action.rb +31 -0
  41. data/lib/procon_bypass_man/remote_action/remote_pbm_job/commands/run_remote_pbm_job_dispatch_command.rb +29 -0
  42. data/lib/procon_bypass_man/{remote_pbm_action/commands/update_remote_pbm_action_status_command.rb → remote_action/remote_pbm_job/commands/update_remote_pbm_job_status_command.rb} +2 -2
  43. data/lib/procon_bypass_man/remote_action/remote_pbm_job/reboot_os_action.rb +24 -0
  44. data/lib/procon_bypass_man/remote_action/remote_pbm_job/report_procon_status.rb +25 -0
  45. data/lib/procon_bypass_man/remote_action/remote_pbm_job/restore_pbm_setting.rb +42 -0
  46. data/lib/procon_bypass_man/remote_action/remote_pbm_job/stop_pbm_action.rb +23 -0
  47. data/lib/procon_bypass_man/{remote_pbm_action/value_objects/remote_pbm_action_object.rb → remote_action/remote_pbm_job/value_objects/remote_pbm_job_object.rb} +2 -2
  48. data/lib/procon_bypass_man/remote_action/remote_pbm_job.rb +45 -0
  49. data/lib/procon_bypass_man/remote_action/task.rb +14 -0
  50. data/lib/procon_bypass_man/{remote_macro → remote_action}/task_queue.rb +1 -1
  51. data/lib/procon_bypass_man/remote_action.rb +19 -0
  52. data/lib/procon_bypass_man/support/callbacks.rb +1 -0
  53. data/lib/procon_bypass_man/support/retryable.rb +4 -2
  54. data/lib/procon_bypass_man/support/{update_remote_pbm_action_status_http_client.rb → update_remote_pbm_job_status_http_client.rb} +1 -1
  55. data/lib/procon_bypass_man/support/web_connectivity_checker.rb +39 -0
  56. data/lib/procon_bypass_man/version.rb +1 -1
  57. data/lib/procon_bypass_man/websocket/client.rb +42 -26
  58. data/lib/procon_bypass_man.rb +12 -8
  59. data/project_template/app.rb +10 -1
  60. data/project_template/app.rb.erb +11 -1
  61. data/sig/main.rbs +0 -6
  62. metadata +34 -20
  63. data/lib/procon_bypass_man/procon_display/bypass_hook.rb +0 -12
  64. data/lib/procon_bypass_man/remote_macro/remote_macro_sender.rb +0 -8
  65. data/lib/procon_bypass_man/remote_macro/task.rb +0 -2
  66. data/lib/procon_bypass_man/remote_macro.rb +0 -16
  67. data/lib/procon_bypass_man/remote_pbm_action/base_action.rb +0 -53
  68. data/lib/procon_bypass_man/remote_pbm_action/change_pbm_version_action.rb +0 -29
  69. data/lib/procon_bypass_man/remote_pbm_action/commands/run_remote_pbm_action_dispatch_command.rb +0 -21
  70. data/lib/procon_bypass_man/remote_pbm_action/reboot_os_action.rb +0 -22
  71. data/lib/procon_bypass_man/remote_pbm_action/restore_pbm_setting.rb +0 -41
  72. data/lib/procon_bypass_man/remote_pbm_action/stop_pbm_action.rb +0 -21
  73. data/lib/procon_bypass_man/remote_pbm_action.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4ffa6c5a0eca5298143505c133f6895f7bb33b6061a36e6123c27e19a0ffcbb
4
- data.tar.gz: 74e77a823d913769a75b2dd698991bb1fed6a62a1da9a65928e00b86773e90df
3
+ metadata.gz: 86e705d2907d51077191585d2cd16fb198a8a55226613d25f44b15b5e58f8806
4
+ data.tar.gz: a13290f301295913bbc30a06a1e06689dc5aae328cadd39ed1e91982ff7586d2
5
5
  SHA512:
6
- metadata.gz: 90cbb299a402bbab3fae219fc17b359155b48c67cf34761ad69c63ee5ba72ed7cf356d5829ee003d19558c7418f07444d7f35619d82bebc124975ab1c40cb85f
7
- data.tar.gz: f03f39550078285114b0a7ac209938dee7b335c99689cba48ed4d4f4d62e659b0fb1fcea51bd800acfe61839cc92c235f5112e3adc5a3896e033f5dbfa224373
6
+ metadata.gz: 30618560c54d7c7a730bf97d74b601fce287d6900ed3eaf3c54b1071349b8a7d8b9e346c9099f6dbfad25a568710c5aaa4ce09ad4b12805a2f6d2d3a8134b27f
7
+ data.tar.gz: 96c796ecbbfa544a0427537a50ea17a0b7f10eee360bc6b072872c7621627dccf5403e78bdc2b580e5957fc5758f9b58979ef1f7f341da1a58b849a693ae79f8
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/CHANGELOG.md CHANGED
@@ -1,7 +1,14 @@
1
- ## [0.3.5] - 2022-2-9
2
- * 設定ファイルに起動な必要なPBMのバージョンを表記できるようになりました
1
+ ## [0.3.7] 2023-04-06
2
+ * PBM-Cloudと連携しているかをbootメッセージに表示ようになりました
3
+ * シリアルポート経由でPBMに入力ができるようになりました
4
+
5
+ ## [0.3.6] 2023-03-12
6
+ - プロコンの入力状態をpbm-cloudサーバに送信できるようになりました
7
+
8
+ ## [0.3.5] - 2023-2-9
9
+ * 設定ファイルに起動に必要なPBMのバージョンを表記できるようになりました
3
10
  * https://github.com/splaplapla/procon_bypass_man/pull/238
4
- * レイヤー変更ボタン(prefix_keys_for_changing_layer)が空欄の時に設定ファイルをエラーにしないようになりました
11
+ * レイヤー変更ボタン(prefix_keys_for_changing_layer)が空欄の時に設定ファイルをエラーが起きないようにしました
5
12
  * PBM-CloudからPBMをアップグレードするときに、古いバージョンを削除するようにしました
6
13
 
7
14
  ## [0.3.4] - 2022-12-26
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.5)
4
+ procon_bypass_man (0.3.7)
5
5
  action_cable_client
6
6
  blue_green_process (= 0.1.4.2)
7
7
  pbmenv (>= 0.1.11)
@@ -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/Steepfile CHANGED
@@ -40,7 +40,6 @@ target :lib do
40
40
  check 'lib/procon_bypass_man/support/on_memory_cache'
41
41
  check 'lib/procon_bypass_man/support/uptime.rb'
42
42
  check 'lib/procon_bypass_man/support/safe_timeout'
43
- check 'lib/procon_bypass_man/support/update_remote_pbm_action_status_http_client'
44
43
  check 'lib/procon_bypass_man/support/compress_array'
45
44
 
46
45
  signature 'sig'
data/bin/console CHANGED
@@ -14,6 +14,9 @@ require "pry"
14
14
 
15
15
  require "irb"
16
16
 
17
+ # TODO: replのときチェックが入らないので、書く詳細な実装に触れないようにする。PBM_ENVを参照するなどをする
18
+ ProconBypassMan::ExternalInput.prepare_channels
19
+
17
20
  ProconBypassMan.config.logger = Logger.new($stdout)
18
21
 
19
22
  IRB.start(__FILE__)
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "procon_bypass_man"
5
+ require "pry"
6
+
7
+ # \x30のみ生成する
8
+ # Usage:
9
+ # $ `generate_output_report x zl y` のように、引数にボタン名を渡す
10
+
11
+ no_action_binary = ["30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000"].pack("H*")
12
+ user_operation = ProconBypassMan::Procon::UserOperation.new(no_action_binary)
13
+
14
+ ARGV.map { |x| x.to_sym }.each do |button|
15
+ user_operation.press_button(button)
16
+ end
17
+
18
+ puts user_operation.binary.unpack.first
@@ -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
@@ -18,6 +18,7 @@
18
18
  * [設定ファイルの書き方がわからない、エラーが起きるとき](#設定ファイルの書き方がわからない、エラーが起きるとき)
19
19
  * [procon_bypass_manのアップグレード方法](#procon_bypass_manのアップグレード方法)
20
20
  * [procon_bypass_man_cloudについて](#procon_bypass_man_cloudについて)
21
+ * [シリアルポート・GPIOから読み取る](#シリアルポートから読み取る)
21
22
  * [最適化について](#最適化について)
22
23
 
23
24
  ## はじめに
@@ -251,6 +252,10 @@ procon_bypass_man_cloudとの接続が完了後、Raspberry Piを起動時にpro
251
252
 
252
253
  セットアップ方法は https://pbm-cloud.jiikko.com/faq に書いています。
253
254
 
255
+ ## シリアルポートから読み取る
256
+ * [ラズベリーパイのシリアルポート(GPIO)へ書き込んでPBM経由してSwitchへ入力をする方法](/docs/setting/integration_external_input_serial_port.md)
257
+ * [ラズベリーパイのシリアルポート(GPIO)に書き込むフォーマットについて](/docs/setting/integration_external_input_serial_port_format.md)
258
+
254
259
  ## 最適化について
255
260
  本稿では、Rubyの最適化について書きます。上級者向けです。適用しなくても普通に動きますが、逆に適用したことで何らかのケースで遅くなる場合があるかもしれません。
256
261
 
@@ -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
+ 以上。
@@ -0,0 +1,20 @@
1
+ class ProconBypassMan::PostCompletedRemoteActionJob < ProconBypassMan::BaseJob
2
+ extend ProconBypassMan::HasExternalApiSetting
3
+
4
+ # @param [Symbol] status
5
+ def self.perform(job_id)
6
+ ProconBypassMan::RemoteMacroHttpClient.new(
7
+ path: path,
8
+ server: api_server,
9
+ ).post(job_id: job_id)
10
+ end
11
+
12
+ def self.path
13
+ device_id = ProconBypassMan.device_id
14
+ "/api/devices/#{ProconBypassMan.device_id}/completed_pbm_remote_macro_jobs"
15
+ end
16
+
17
+ def self.re_enqueue_if_failed
18
+ true
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ class ProconBypassMan::ReportInfoLogJob < ProconBypassMan::ReportEventBaseJob
2
+ extend ProconBypassMan::HasExternalApiSetting
3
+
4
+ # @param [String] body
5
+ def self.perform(body)
6
+ ProconBypassMan::ReportHttpClient.new(
7
+ path: path,
8
+ server: api_server,
9
+ ).post(body: body, event_type: :info)
10
+ end
11
+ end
@@ -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,
@@ -10,6 +10,7 @@ require "procon_bypass_man/background/jobs/report_error_reload_config_job"
10
10
  require "procon_bypass_man/background/jobs/report_load_config_job"
11
11
  require "procon_bypass_man/background/jobs/report_error_job"
12
12
  require "procon_bypass_man/background/jobs/report_warning_job"
13
+ require "procon_bypass_man/background/jobs/report_info_log_job"
13
14
  require "procon_bypass_man/background/jobs/report_completed_upgrade_pbm_job"
14
15
  require "procon_bypass_man/background/jobs/report_procon_performance_measurements_job"
15
16
  require "procon_bypass_man/background/jobs/sync_device_stats_job"
@@ -47,14 +47,32 @@ class ProconBypassMan::Bypass::ProconToSwitch
47
47
  self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_output)
48
48
  end
49
49
 
50
+ # 後続処理で入力値を取得できるように詰めておく
51
+ ProconBypassMan::ProconDisplay::Status.instance.current = bypass_value.binary.to_procon_reader.to_hash
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
+
50
67
  result = measurement.record_write_time do
51
68
  begin
52
69
  ProconBypassMan::Retryable.retryable(tries: 5, on_no_retry: [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]) do
53
70
  begin
54
71
  # 終了処理を希望されているのでブロックを無視してメソッドを抜けてOK
55
72
  return(false) if will_terminate? # rubocop:disable Lint/NoReturnInBeginEndBlocks
73
+
56
74
  binary = ::ProconBypassMan::Procon::Rumbler.monitor do
57
- ProconBypassMan::Processor.new(bypass_value.binary).process
75
+ ProconBypassMan::Processor.new(bypass_value.binary).process(external_input_data: external_input_data)
58
76
  end
59
77
  self.gadget.write_nonblock(binary)
60
78
 
@@ -34,6 +34,7 @@ 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)}
37
38
  pid: #{@table[:pid]}
38
39
  root: #{@table[:root_path]}
39
40
  pid_path: #{@table[:pid_path]}
@@ -56,6 +57,7 @@ class ProconBypassMan::PrintBootMessageCommand
56
57
  def self.execute
57
58
  message = BootMessage.new
58
59
  ProconBypassMan::ReportBootJob.perform_async(message.to_hash)
60
+ ProconBypassMan.logger.info message.to_s
59
61
  puts message.to_s
60
62
  end
61
63
  end
@@ -0,0 +1,11 @@
1
+ class ProconBypassMan::SendInfoLogCommand
2
+ # @param [String] message
3
+ # @return [void]
4
+ def self.execute(message: , stdout: true)
5
+ body = message
6
+ ProconBypassMan.logger.info(body)
7
+ puts body if stdout
8
+
9
+ ProconBypassMan::ReportInfoLogJob.perform(body)
10
+ end
11
+ end
@@ -5,3 +5,4 @@ require "procon_bypass_man/commands/write_device_id_command"
5
5
  require "procon_bypass_man/commands/send_reload_config_event_command"
6
6
  require "procon_bypass_man/commands/send_error_command"
7
7
  require "procon_bypass_man/commands/send_warning_command"
8
+ require "procon_bypass_man/commands/send_info_log_command"
@@ -54,6 +54,7 @@ class ProconBypassMan::Configuration
54
54
 
55
55
  attr_accessor :enable_critical_error_logging
56
56
  attr_writer :verbose_bypass_log, :raw_setting, :never_exit_accidentally, :enable_home_led_on_connect
57
+ attr_writer :external_input_channels
57
58
  # 削除予定
58
59
  attr_writer :enable_reporting_pressed_buttons
59
60
 
@@ -149,7 +150,7 @@ class ProconBypassMan::Configuration
149
150
  end
150
151
 
151
152
  # @return [Boolean]
152
- def enable_remote_macro?
153
+ def enable_remote_action?
153
154
  enable_ws?
154
155
  end
155
156
 
@@ -193,4 +194,9 @@ class ProconBypassMan::Configuration
193
194
  true
194
195
  end
195
196
  end
197
+
198
+ # @return [Array<ProconBypassMan::ExternalInput::Channel::TCPIP, ProconBypassMan::ExternalInput::Channel::SerialPort>]
199
+ def external_input_channels
200
+ @external_input_channels || []
201
+ end
196
202
  end
@@ -0,0 +1,12 @@
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
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,48 @@
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
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # TODO: 実装する
2
+ # module ProconBypassMan
3
+ # module ExternalInput
4
+ # module Channels
5
+ # class TCPIP < Base
6
+ # def initialize(port: )
7
+ # super()
8
+ # # TODO: ここでTCPサーバを起動する(port)
9
+ # end
10
+ #
11
+ # def read
12
+ # end
13
+ # end
14
+ # end
15
+ # end
16
+ # end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProconBypassMan
4
+ module ExternalInput
5
+ module Channels
6
+ end
7
+ end
8
+ end
9
+
10
+ require "procon_bypass_man/external_input/channels/base"
11
+ require "procon_bypass_man/external_input/channels/serial_port_channel"
12
+ require "procon_bypass_man/external_input/channels/tcpip"
@@ -0,0 +1,79 @@
1
+ module ProconBypassMan
2
+ module ExternalInput
3
+ class ExternalData
4
+ UNPRESS_BUTTONS = Set.new(ProconBypassMan::Procon::ButtonCollection.available.map { |x| "un#{x}".to_sym })
5
+
6
+ # @return [String, NilClass] 16進数表現のデータ
7
+ attr_reader :hex
8
+
9
+ # @return [String, NilClass] ログに表示する用
10
+ attr_reader :raw_data
11
+
12
+ # @raise [ParseError]
13
+ # @return [ExternalData] JSON か カンマ区切りのbuttons
14
+ def self.parse!(raw_data)
15
+ raise ParseError unless raw_data.ascii_only?
16
+
17
+ if is_json(raw_data)
18
+ begin
19
+ json = JSON.parse(raw_data)
20
+ return new(hex: json['hex'], buttons: json['buttons'])
21
+ rescue JSON::ParserError
22
+ raise ParseError
23
+ end
24
+ end
25
+
26
+ return new(hex: nil, buttons: raw_data.scan(/:\w+:/).map { |x| x.gsub(':', '') }, raw_data: raw_data)
27
+ end
28
+
29
+ # @param [String] raw_data
30
+ # @return [Boolean]
31
+ def self.is_json(raw_data)
32
+ raw_data.start_with?('{')
33
+ end
34
+
35
+ # @param [String, NilClass] hex
36
+ # @param [Array<String>, NilClass] buttons
37
+ # @param [String, NilClass] raw_data
38
+ def initialize(hex: , buttons: , raw_data: nil)
39
+ @hex = hex
40
+ @buttons = buttons || []
41
+ @raw_data = raw_data
42
+ end
43
+
44
+ # @return [String, NilClass]
45
+ def to_binary
46
+ return nil if @hex.nil?
47
+ [@hex].pack('H*')
48
+ end
49
+
50
+ # @return [Array<Symbol>]
51
+ def press_buttons
52
+ buttons.select do |button|
53
+ ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP[button]
54
+ end
55
+ end
56
+
57
+ # @return [Array<Symbol>]
58
+ def unpress_buttons
59
+ buttons.select { |button|
60
+ UNPRESS_BUTTONS.include?(button)
61
+ }.map { |b| to_button(b.to_s).to_sym }
62
+ end
63
+
64
+ # NOTE: ログに表示する用
65
+ # @return [Array<Symbol>]
66
+ def buttons
67
+ @buttons.map(&:to_sym)
68
+ end
69
+
70
+ private
71
+
72
+ # @return [String]
73
+ # NOTE: un#{button} って名前をbuttonに変換する
74
+ def to_button(button)
75
+ button.sub(/^un/, '')
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProconBypassMan
4
+ module ExternalInput
5
+ class ParseError < StandardError; end
6
+
7
+ @@channels = nil
8
+
9
+ # @return [Array<ProconBypassMan::ExternalInput::Channels::Base>]
10
+ def self.channels
11
+ @@channels
12
+ end
13
+
14
+ # @return [void]
15
+ def self.prepare_channels
16
+ @@channels = ProconBypassMan.config.external_input_channels
17
+ end
18
+
19
+ # @return [NilClass, String]
20
+ # NOTE: 外部入力からのreadがボトルネックになるなら、Concurrent::Futureを使ってプロコンからの読み出しと並列化することを検討する
21
+ def self.read
22
+ raise '外部入力が未初期化です' if @@channels.nil?
23
+
24
+ value = nil
25
+ @@channels.each do |channel|
26
+ value = channel.read
27
+ break if value
28
+ end
29
+ value
30
+ end
31
+ end
32
+ end
33
+
34
+ require "procon_bypass_man/external_input/external_data"
35
+ require "procon_bypass_man/external_input/channels.rb"
@@ -5,12 +5,13 @@ class ProconBypassMan::Processor
5
5
  @binary = binary
6
6
  end
7
7
 
8
+ # @param [ProconBypassMan::ExternalInput::ExternalData, NilClass] external_input_data
8
9
  # @return [String] 加工後の入力データ
9
- def process
10
+ def process(external_input_data: nil)
10
11
  return @binary.raw unless @binary.user_operation_data?
11
12
 
12
13
  procon = ProconBypassMan::Procon.new(@binary.raw)
13
14
  procon.apply!
14
- procon.to_binary
15
+ procon.to_binary(external_input_data: external_input_data)
15
16
  end
16
17
  end
@@ -37,4 +37,9 @@ class ProconBypassMan::Procon::ButtonCollection
37
37
  BUTTONS = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.keys.freeze
38
38
 
39
39
  LEFT_ANALOG_STICK = { byte_position: 6..8 }
40
+
41
+ # @return [Array<Symbol>]
42
+ def self.available
43
+ BUTTONS
44
+ end
40
45
  end