procon_bypass_man 0.1.23 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/gitleacks.yml +11 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/docs/setup_raspi.md +0 -1
- data/lib/procon_bypass_man/buttons_setting_configuration/loader.rb +1 -1
- data/lib/procon_bypass_man/{commands → bypass}/bypass_command.rb +11 -19
- data/lib/procon_bypass_man/bypass.rb +6 -9
- data/lib/procon_bypass_man/commands/print_boot_message_command.rb +1 -2
- data/lib/procon_bypass_man/commands/send_error_command.rb +2 -2
- data/lib/procon_bypass_man/commands.rb +0 -3
- data/lib/procon_bypass_man/configuration.rb +21 -2
- data/lib/procon_bypass_man/device_connection/command.rb +28 -0
- data/lib/procon_bypass_man/{device_connector.rb → device_connection/executor.rb} +51 -38
- data/lib/procon_bypass_man/device_connection/output_report_generator.rb +42 -0
- data/lib/procon_bypass_man/device_connection/output_report_markerable.rb +28 -0
- data/lib/procon_bypass_man/device_connection/output_report_sub_command_table.rb +133 -0
- data/lib/procon_bypass_man/device_connection/output_report_watcher.rb +41 -0
- data/lib/procon_bypass_man/device_connection/pre_bypass.rb +67 -0
- data/lib/procon_bypass_man/device_connection/procon_setting_overrider.rb +78 -0
- data/lib/procon_bypass_man/device_connection/spoofing_output_report_watcher.rb +39 -0
- data/lib/procon_bypass_man/device_connection.rb +16 -0
- data/lib/procon_bypass_man/device_model.rb +17 -0
- data/lib/procon_bypass_man/io_monitor.rb +20 -1
- data/lib/procon_bypass_man/procon/macro_builder.rb +5 -3
- data/lib/procon_bypass_man/{commands → remote_pbm_action/commands}/run_remote_pbm_action_dispatch_command.rb +0 -0
- data/lib/procon_bypass_man/remote_pbm_action/restore_pbm_setting.rb +7 -1
- data/lib/procon_bypass_man/remote_pbm_action.rb +1 -0
- data/lib/procon_bypass_man/runner.rb +3 -7
- data/lib/procon_bypass_man/support/never_exit_accidentally.rb +3 -3
- data/lib/procon_bypass_man/support/usb_device_controller.rb +2 -2
- data/lib/procon_bypass_man/support/yaml_loader.rb +12 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man/websocket/client.rb +1 -4
- data/lib/procon_bypass_man.rb +65 -41
- data/project_template/app.rb +7 -1
- data/sig/main.rbs +3 -3
- metadata +17 -6
- data/lib/procon_bypass_man/commands/connect_device_command.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ca0c509c42d13cd0a9177c80b09c7f31bbeb6fad810e0f85210811cd69bffa2
|
4
|
+
data.tar.gz: ae97eb1796fb709840dcac7138e8ac8a2fd8be15f134585da8538f3958fb3442
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33f58604e017bc01b6f7057877ab79045456f7fb10ff880fe640b47195374c8f170f5d5e7f97f643148d5b06313a3b9c6cfbd77d0e2701875e3bd1e6d4e397b1
|
7
|
+
data.tar.gz: d69d376c75ef7692ae7d2c74e8715aa00bea4dfbe2ff6d7359b69bbdff5ef65cd39132f82dcaa297c60fd3459ac9aff66f0751d2cc2e818e613bbd53cef2f829
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## [0.2.0] - 2022-05-20
|
2
|
+
- 3つ以上のボタンを操作するマクロに対応する
|
3
|
+
- IOに関するログをデフォルトで無効にしました
|
4
|
+
- 有効にする場合はapp.rbに `config.io_monitor_logging = true` を記述してください
|
5
|
+
- 接続が安定化するまでの時間が短くなりました
|
6
|
+
- 接続中にプロコンのケーブルを抜くと、エラーを吐いて終了できなくなる不具合を修正しました
|
7
|
+
- プロセスをCtrl+Cで停止するときに終了するまでの時間が短くなりました
|
8
|
+
- 接続に成功するとhomeボタンのledが光るようになりました
|
9
|
+
- 無効にする場合はapp.rbに `config.enable_home_led_on_connect = false` を記述してください
|
10
|
+
|
1
11
|
## [0.1.23] - 2022-05-04
|
2
12
|
- プロセスを停止するとプロコンがBluetooth経由でSwitchと接続するようになりました
|
3
13
|
- 起動時に表示するdevice_idを一部のみ表示するようになりました
|
data/Gemfile.lock
CHANGED
data/docs/setup_raspi.md
CHANGED
@@ -33,7 +33,6 @@ https://github.com/splaplapla/procon_bypass_man/blob/master/docs/setup_raspi_by_
|
|
33
33
|
* chmod 755 ~/add_procon_gadget.sh
|
34
34
|
* sudo reboot
|
35
35
|
* sudo sh ~/add_procon_gadget.sh の実行に成功させる
|
36
|
-
* /etc/rc.local に sh /home/pi/add_procon_gadget.sh って書く
|
37
36
|
* cd ~ && mkdir -p src && cd ~/src && git clone https://github.com/jiikko/procon_bypass_man_sample && cd procon_bypass_man_sample
|
38
37
|
|
39
38
|
おわり. 起動する時は都度 sudo ruby app.rb を実行する
|
@@ -32,7 +32,7 @@ module ProconBypassMan
|
|
32
32
|
ProconBypassMan::ButtonsSettingConfiguration.instance.reset!
|
33
33
|
ProconBypassMan.reset!
|
34
34
|
|
35
|
-
yaml =
|
35
|
+
yaml = ProconBypassMan::YamlLoader.load(path: setting_path)
|
36
36
|
ProconBypassMan.config.raw_setting = yaml.dup
|
37
37
|
case yaml["version"]
|
38
38
|
when 1.0, nil
|
@@ -10,7 +10,7 @@ class ProconBypassMan::BypassCommand
|
|
10
10
|
@gadget = gadget
|
11
11
|
@procon = procon
|
12
12
|
|
13
|
-
ProconBypassMan::IOMonitor.start!
|
13
|
+
ProconBypassMan::IOMonitor.start! if ProconBypassMan.io_monitor_logging
|
14
14
|
ProconBypassMan::Background::JobRunner.queue.clear # forkしたときに残留物も移ってしまうため
|
15
15
|
ProconBypassMan::Background::JobRunner.start!
|
16
16
|
end
|
@@ -33,32 +33,22 @@ class ProconBypassMan::BypassCommand
|
|
33
33
|
monitor2 = ProconBypassMan::IOMonitor.new(label: "procon -> switch")
|
34
34
|
ProconBypassMan.logger.info "Thread1を起動します"
|
35
35
|
|
36
|
-
cycle_sleep = ProconBypassMan::CycleSleep.new(cycle_interval:
|
36
|
+
cycle_sleep = ProconBypassMan::CycleSleep.new(cycle_interval: 1, execution_cycle: ProconBypassMan.config.bypass_mode.gadget_to_procon_interval)
|
37
37
|
|
38
38
|
t1 = Thread.new do
|
39
|
-
|
40
|
-
|
39
|
+
if ProconBypassMan.config.bypass_mode.mode == ProconBypassMan::BypassMode::TYPE_AGGRESSIVE
|
40
|
+
ProconBypassMan.logger.info "TYPE_AGGRESSIVEなのでThread1を終了します"
|
41
|
+
monitor1.shutdown
|
42
|
+
next
|
43
|
+
end
|
44
|
+
|
41
45
|
loop do
|
42
46
|
break if $will_terminate_token
|
43
47
|
|
44
48
|
cycle_sleep.sleep_or_execute do
|
45
49
|
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor1)
|
46
|
-
!@did_first_step && timer.throw_if_timeout!
|
47
50
|
bypass.send_gadget_to_procon!
|
48
51
|
end
|
49
|
-
rescue ProconBypassMan::SafeTimeout::Timeout
|
50
|
-
case ProconBypassMan.config.bypass_mode.mode
|
51
|
-
when ProconBypassMan::BypassMode::TYPE_AGGRESSIVE
|
52
|
-
ProconBypassMan.logger.info "10秒経過したのでThread1を終了します"
|
53
|
-
monitor1.shutdown
|
54
|
-
break
|
55
|
-
when ProconBypassMan::BypassMode::TYPE_NORMAL
|
56
|
-
ProconBypassMan.logger.info "10秒経過したのでsend_intervalを長くします"
|
57
|
-
cycle_sleep = ProconBypassMan::CycleSleep.new(cycle_interval: 1, execution_cycle: ProconBypassMan.config.bypass_mode.gadget_to_procon_interval)
|
58
|
-
else
|
59
|
-
raise "unknown type"
|
60
|
-
end
|
61
|
-
@did_first_step = true
|
62
52
|
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
|
63
53
|
ProconBypassMan::SendErrorCommand.execute(error: "Switchとの切断されました.終了処理を開始します. #{e.full_message}")
|
64
54
|
Process.kill "TERM", Process.ppid
|
@@ -67,6 +57,7 @@ class ProconBypassMan::BypassCommand
|
|
67
57
|
ProconBypassMan::SendErrorCommand.execute(error: "Switchと意図せず切断されました.終了処理を開始します. #{e.full_message}")
|
68
58
|
Process.kill "TERM", Process.ppid
|
69
59
|
end
|
60
|
+
|
70
61
|
ProconBypassMan.logger.info "Thread1を終了します"
|
71
62
|
end
|
72
63
|
|
@@ -79,7 +70,6 @@ class ProconBypassMan::BypassCommand
|
|
79
70
|
if $will_terminate_token
|
80
71
|
if $will_terminate_token == WILL_TERMINATE_TOKEN::TERMINATE
|
81
72
|
bypass.direct_connect_switch_via_bluetooth
|
82
|
-
bypass.be_empty_procon
|
83
73
|
end
|
84
74
|
break
|
85
75
|
end
|
@@ -88,9 +78,11 @@ class ProconBypassMan::BypassCommand
|
|
88
78
|
rescue EOFError => e
|
89
79
|
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します. #{e.full_message}")
|
90
80
|
Process.kill "TERM", Process.ppid
|
81
|
+
break
|
91
82
|
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
|
92
83
|
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します2. #{e.full_message}")
|
93
84
|
Process.kill "TERM", Process.ppid
|
85
|
+
break
|
94
86
|
end
|
95
87
|
ProconBypassMan.logger.info "Thread2を終了します"
|
96
88
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "procon_bypass_man/bypass/usb_hid_logger"
|
2
|
+
require "procon_bypass_man/bypass/bypass_command"
|
2
3
|
|
3
4
|
class ProconBypassMan::Bypass
|
4
5
|
include ProconBypassMan::Bypass::UsbHidLogger
|
@@ -28,7 +29,6 @@ class ProconBypassMan::Bypass
|
|
28
29
|
|
29
30
|
raw_input = nil
|
30
31
|
begin
|
31
|
-
# TODO blocking readにしたいが、接続時のフェーズによって長さが違うので厳しい
|
32
32
|
raw_input = self.gadget.read_nonblock(64)
|
33
33
|
self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_input)
|
34
34
|
rescue IO::EAGAINWaitReadable
|
@@ -97,6 +97,10 @@ class ProconBypassMan::Bypass
|
|
97
97
|
# @return [void]
|
98
98
|
def direct_connect_switch_via_bluetooth
|
99
99
|
ProconBypassMan.logger.debug { "direct_connect_switch_via_bluetooth!" }
|
100
|
+
self.procon.write_nonblock(["010500000000000000003800"].pack("H*")) # home led off
|
101
|
+
self.procon.write_nonblock(["010600000000000000003800"].pack("H*")) # home led off
|
102
|
+
self.procon.write_nonblock(["010700000000000000003800"].pack("H*")) # home led off
|
103
|
+
self.procon.write_nonblock(["010800000000000000003800"].pack("H*")) # home led off
|
100
104
|
self.procon.write_nonblock(["8005"].pack("H*"))
|
101
105
|
self.procon.write_nonblock(["8005"].pack("H*"))
|
102
106
|
self.procon.write_nonblock(["8005"].pack("H*"))
|
@@ -104,13 +108,6 @@ class ProconBypassMan::Bypass
|
|
104
108
|
|
105
109
|
# @return [void] 入力してから取り出さないと接続しっぱなしになるっぽいのでこれが必要っぽい
|
106
110
|
def be_empty_procon
|
107
|
-
|
108
|
-
loop do
|
109
|
-
break if timer.timeout?
|
110
|
-
output = self.procon.read_nonblock(64)
|
111
|
-
ProconBypassMan.logger.debug { "[ProconBypassMan::Bypass#be_empty_procon] #{output.unpack("H*").first}" }
|
112
|
-
rescue IO::EAGAINWaitReadable
|
113
|
-
# no-op
|
114
|
-
end
|
111
|
+
# タイムアウトまでブロッキングされるので、プロセスに逃す
|
115
112
|
end
|
116
113
|
end
|
@@ -32,8 +32,8 @@ class ProconBypassMan::PrintBootMessageCommand
|
|
32
32
|
def to_s
|
33
33
|
booted_message = <<~EOF
|
34
34
|
----
|
35
|
-
RUBY_VERSION: #{@table[:ruby_version]}
|
36
35
|
ProconBypassMan::VERSION: #{@table[:pbm_version]}
|
36
|
+
RUBY_VERSION: #{@table[:ruby_version]}
|
37
37
|
Pbmenv::VERSION: #{@table[:pbmenv_version]}
|
38
38
|
pid: #{@table[:pid]}
|
39
39
|
root: #{@table[:root_path]}
|
@@ -58,7 +58,6 @@ class ProconBypassMan::PrintBootMessageCommand
|
|
58
58
|
def self.execute
|
59
59
|
message = BootMessage.new
|
60
60
|
ProconBypassMan::ReportBootJob.perform_async(message.to_hash)
|
61
|
-
ProconBypassMan::ReportLoadConfigJob.perform_async(ProconBypassMan.config.raw_setting)
|
62
61
|
puts message.to_s
|
63
62
|
end
|
64
63
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class ProconBypassMan::SendErrorCommand
|
2
2
|
# @param [String, Hash, Exception] error
|
3
3
|
# @return [void]
|
4
|
-
def self.execute(error: )
|
4
|
+
def self.execute(error: , stdout: true)
|
5
5
|
body =
|
6
6
|
case error
|
7
7
|
when String, Hash
|
@@ -12,7 +12,7 @@ class ProconBypassMan::SendErrorCommand
|
|
12
12
|
|
13
13
|
ProconBypassMan.logger.error body
|
14
14
|
ProconBypassMan.error_logger.error body
|
15
|
-
puts body
|
15
|
+
puts body if stdout
|
16
16
|
|
17
17
|
ProconBypassMan::ReportErrorJob.perform(error)
|
18
18
|
end
|
@@ -4,6 +4,3 @@ require "procon_bypass_man/commands/write_session_id_command"
|
|
4
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
|
-
require "procon_bypass_man/commands/connect_device_command"
|
8
|
-
require "procon_bypass_man/commands/bypass_command"
|
9
|
-
require "procon_bypass_man/commands/run_remote_pbm_action_dispatch_command"
|
@@ -47,10 +47,14 @@ class ProconBypassMan::Configuration
|
|
47
47
|
def fallback_setting_path
|
48
48
|
"/tmp/procon_bypass_man_fallback_setting.yaml"
|
49
49
|
end
|
50
|
+
|
51
|
+
def io_monitor_logging
|
52
|
+
config.io_monitor_logging
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
attr_accessor :enable_critical_error_logging
|
53
|
-
attr_writer :verbose_bypass_log, :raw_setting, :enable_reporting_pressed_buttons, :never_exit_accidentally
|
57
|
+
attr_writer :verbose_bypass_log, :raw_setting, :enable_reporting_pressed_buttons, :never_exit_accidentally, :io_monitor_logging, :enable_home_led_on_connect
|
54
58
|
|
55
59
|
def root=(path)
|
56
60
|
@root = path
|
@@ -186,12 +190,27 @@ class ProconBypassMan::Configuration
|
|
186
190
|
@raw_setting ||= {}
|
187
191
|
end
|
188
192
|
|
193
|
+
# @return [Boolean] default false
|
189
194
|
def enable_reporting_pressed_buttons
|
190
195
|
@enable_reporting_pressed_buttons ||= false
|
191
196
|
end
|
192
197
|
|
193
|
-
# @return [Boolean]
|
198
|
+
# @return [Boolean] default false
|
194
199
|
def never_exit_accidentally
|
195
200
|
@never_exit_accidentally || false
|
196
201
|
end
|
202
|
+
|
203
|
+
# @return [Boolean] default false
|
204
|
+
def io_monitor_logging
|
205
|
+
@io_monitor_logging ||= false
|
206
|
+
end
|
207
|
+
|
208
|
+
# @return [Boolean] default true
|
209
|
+
def enable_home_led_on_connect
|
210
|
+
if defined?(@enable_home_led_on_connect)
|
211
|
+
return @enable_home_led_on_connect
|
212
|
+
else
|
213
|
+
true
|
214
|
+
end
|
215
|
+
end
|
197
216
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ProconBypassMan::DeviceConnection::Command
|
2
|
+
MAX_RETRY_COUNT = 3
|
3
|
+
|
4
|
+
# @return [void]
|
5
|
+
def self.execute!(retry_count: 0)
|
6
|
+
begin
|
7
|
+
gadget, procon = ProconBypassMan::DeviceConnection::Executer.execute!
|
8
|
+
rescue ProconBypassMan::DeviceConnection::TimeoutErrorInConditionalRoute
|
9
|
+
if retry_count >= MAX_RETRY_COUNT
|
10
|
+
ProconBypassMan::SendErrorCommand.execute(error: "リトライしましたが、接続できませんでした")
|
11
|
+
raise ProconBypassMan::DeviceConnection::TimeoutError
|
12
|
+
else
|
13
|
+
ProconBypassMan::SendErrorCommand.execute(error: "接続に失敗したのでリトライします")
|
14
|
+
end
|
15
|
+
|
16
|
+
retry_count = retry_count + 1
|
17
|
+
retry
|
18
|
+
rescue ProconBypassMan::DeviceConnection::NotFoundProconError => e
|
19
|
+
raise
|
20
|
+
rescue ProconBypassMan::SafeTimeout::Timeout
|
21
|
+
raise ProconBypassMan::DeviceConnection::TimeoutError
|
22
|
+
end
|
23
|
+
|
24
|
+
ProconBypassMan::DeviceConnection::PreBypass.new(gadget: gadget, procon: procon).execute!
|
25
|
+
ProconBypassMan::DeviceConnection::ProconSettingOverrider.new(procon: procon).execute!
|
26
|
+
return [gadget, procon]
|
27
|
+
end
|
28
|
+
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
require "timeout"
|
2
2
|
|
3
|
-
class ProconBypassMan::
|
4
|
-
class BytesMismatchError < StandardError; end
|
5
|
-
class NotFoundProconError < StandardError; end
|
6
|
-
|
3
|
+
class ProconBypassMan::DeviceConnection::Executer
|
7
4
|
class Value
|
8
5
|
attr_accessor :read_from, :values, :call_block_if_receive, :block
|
9
6
|
|
@@ -15,33 +12,41 @@ class ProconBypassMan::DeviceConnector
|
|
15
12
|
end
|
16
13
|
end
|
17
14
|
|
18
|
-
def self.
|
19
|
-
|
20
|
-
|
15
|
+
def self.new_with_default_args
|
16
|
+
new(throw_error_if_timeout: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.execute!
|
20
|
+
s = new_with_default_args
|
21
|
+
s.add(expected_to_receive: [
|
21
22
|
["0000"],
|
22
23
|
["0000"],
|
23
24
|
["8005"],
|
24
25
|
["0000"],
|
25
26
|
], read_from: :switch)
|
26
27
|
# 1. Sends current connection status, and if the Joy-Con are connected,
|
27
|
-
s.add([["8001"]], read_from: :switch)
|
28
|
-
s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
|
28
|
+
s.add(expected_to_receive: [["8001"]], read_from: :switch)
|
29
|
+
s.add(expected_to_receive: [/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
|
29
30
|
# 2. Sends handshaking packets over UART to the Joy-Con or Pro Controller Broadcom chip. This command can only be called once per session.
|
30
|
-
s.add([["8002"]], read_from: :switch)
|
31
|
-
s.add([/^8102/], read_from: :procon)
|
31
|
+
s.add(expected_to_receive: [["8002"]], read_from: :switch)
|
32
|
+
s.add(expected_to_receive: [/^8102/], read_from: :procon)
|
32
33
|
# 3
|
33
|
-
s.add([/^0100/], read_from: :switch)
|
34
|
-
s.add([/^21/], read_from: :procon, call_block_if_receive: /^8101/) do |this|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
s.add(expected_to_receive: [/^0100/], read_from: :switch)
|
35
|
+
s.add(expected_to_receive: [/^21/], read_from: :procon, call_block_if_receive: /^8101/) do |this|
|
36
|
+
begin
|
37
|
+
ProconBypassMan.logger.info "(start special route)"
|
38
|
+
this.blocking_read_with_timeout_from_procon # <<< 810100032dbd42e9b698000
|
39
|
+
this.write_to_procon("8002")
|
40
|
+
this.blocking_read_with_timeout_from_procon # <<< 8102
|
41
|
+
this.write_to_procon("01000000000000000000033000000000000000000000000000000000000000000000000000000000000000000000000000")
|
42
|
+
this.blocking_read_with_timeout_from_procon # <<< 21
|
43
|
+
rescue ProconBypassMan::SafeTimeout::Timeout, Timeout::Error
|
44
|
+
raise ProconBypassMan::DeviceConnection::TimeoutErrorInConditionalRoute
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
48
|
# 4. Forces the Joy-Con or Pro Controller to only talk over USB HID without any timeouts. This is required for the Pro Controller to not time out and revert to Bluetooth.
|
44
|
-
s.add([["8004"]], read_from: :switch)
|
49
|
+
s.add(expected_to_receive: [["8004"]], read_from: :switch)
|
45
50
|
s.drain_all
|
46
51
|
return [s.switch, s.procon]
|
47
52
|
end
|
@@ -53,7 +58,8 @@ class ProconBypassMan::DeviceConnector
|
|
53
58
|
@throw_error_if_mismatch = throw_error_if_mismatch
|
54
59
|
end
|
55
60
|
|
56
|
-
def add(
|
61
|
+
def add(expected_to_receive: , read_from: , call_block_if_receive: nil, &block)
|
62
|
+
values = expected_to_receive
|
57
63
|
@queue << Value.new(values: values, read_from: read_from, call_block_if_receive: call_block_if_receive, &block)
|
58
64
|
end
|
59
65
|
|
@@ -67,6 +73,7 @@ class ProconBypassMan::DeviceConnector
|
|
67
73
|
item.values.each do |value|
|
68
74
|
raw_data = nil
|
69
75
|
timer = ProconBypassMan::SafeTimeout.new
|
76
|
+
|
70
77
|
begin
|
71
78
|
timer.throw_if_timeout!
|
72
79
|
raw_data = from_device(item).read_nonblock(64)
|
@@ -76,8 +83,11 @@ class ProconBypassMan::DeviceConnector
|
|
76
83
|
retry
|
77
84
|
end
|
78
85
|
|
79
|
-
if item.call_block_if_receive
|
80
|
-
|
86
|
+
if item.call_block_if_receive
|
87
|
+
ProconBypassMan.logger.info "call block if receive: #{item.call_block_if_receive}, actual: #{raw_data.unpack("H*")} from: #{item.read_from}"
|
88
|
+
if item.call_block_if_receive =~ raw_data.unpack("H*").first
|
89
|
+
raw_data = item.block.call(self)
|
90
|
+
end
|
81
91
|
end
|
82
92
|
|
83
93
|
result =
|
@@ -89,13 +99,14 @@ class ProconBypassMan::DeviceConnector
|
|
89
99
|
else
|
90
100
|
raise "#{value}は知りません"
|
91
101
|
end
|
102
|
+
|
92
103
|
if result
|
93
|
-
ProconBypassMan.logger.info "OK(expected: #{value}, got: #{raw_data.unpack("H*")})"
|
94
|
-
debug_log_buffer << "OK(expected: #{value}, got: #{raw_data.unpack("H*")})"
|
104
|
+
ProconBypassMan.logger.info "OK(expected: #{value}, got: #{raw_data.unpack("H*")}) from: #{item.read_from}"
|
105
|
+
debug_log_buffer << "OK(expected: #{value}, got: #{raw_data.unpack("H*")}) from: #{item.read_from}"
|
95
106
|
else
|
96
|
-
ProconBypassMan.logger.info "NG(expected: #{value}, got: #{raw_data.unpack("H*")})"
|
97
|
-
debug_log_buffer << "NG(expected: #{value}, got: #{raw_data.unpack("H*")})"
|
98
|
-
raise BytesMismatchError.new(debug_log_buffer) if @throw_error_if_mismatch
|
107
|
+
ProconBypassMan.logger.info "NG(expected: #{value}, got: #{raw_data.unpack("H*")}) from: #{item.read_from}"
|
108
|
+
debug_log_buffer << "NG(expected: #{value}, got: #{raw_data.unpack("H*")}) from: #{item.read_from}"
|
109
|
+
raise ProconBypassMan::DeviceConnection::BytesMismatchError.new(debug_log_buffer) if @throw_error_if_mismatch
|
99
110
|
end
|
100
111
|
to_device(item).write_nonblock(raw_data)
|
101
112
|
end
|
@@ -103,8 +114,8 @@ class ProconBypassMan::DeviceConnector
|
|
103
114
|
rescue ProconBypassMan::SafeTimeout::Timeout, Timeout::Error => e
|
104
115
|
ProconBypassMan.logger.error "timeoutになりました(#{e.message})"
|
105
116
|
compressed_buffer_text = ProconBypassMan::CompressArray.new(debug_log_buffer).compress.join("\n")
|
106
|
-
ProconBypassMan::SendErrorCommand.execute(error: compressed_buffer_text)
|
107
|
-
raise if @throw_error_if_timeout
|
117
|
+
ProconBypassMan::SendErrorCommand.execute(error: compressed_buffer_text, stdout: false)
|
118
|
+
raise ProconBypassMan::SafeTimeout::Timeout if @throw_error_if_timeout
|
108
119
|
end
|
109
120
|
|
110
121
|
def from_device(item)
|
@@ -143,23 +154,25 @@ class ProconBypassMan::DeviceConnector
|
|
143
154
|
return
|
144
155
|
end
|
145
156
|
ProconBypassMan::UsbDeviceController.init
|
157
|
+
ProconBypassMan::UsbDeviceController.reset
|
146
158
|
|
147
159
|
if path = ProconBypassMan::DeviceProconFinder.find
|
148
160
|
@procon = File.open(path, "w+b")
|
149
161
|
ProconBypassMan.logger.info "proconのデバイスファイルは#{path}を使います"
|
150
162
|
else
|
151
|
-
raise(ProconBypassMan::
|
163
|
+
raise(ProconBypassMan::DeviceConnection::NotFoundProconError)
|
152
164
|
end
|
153
|
-
@gadget = File.open('/dev/hidg0', "w+b")
|
154
165
|
|
155
|
-
|
166
|
+
begin
|
167
|
+
@gadget = File.open('/dev/hidg0', "w+b")
|
168
|
+
rescue Errno::ENXIO => e
|
169
|
+
# /dev/hidg0 をopenできないときがある
|
170
|
+
ProconBypassMan::SendErrorCommand.execute(error: "Errno::ENXIOが起きたのでresetします.\n #{e.full_message}", stdout: false)
|
171
|
+
ProconBypassMan::UsbDeviceController.reset
|
172
|
+
retry
|
173
|
+
end
|
156
174
|
|
157
175
|
@initialized_devices = true
|
158
|
-
rescue Errno::ENXIO => e
|
159
|
-
# /dev/hidg0 をopenできないときがある
|
160
|
-
ProconBypassMan::SendErrorCommand.execute(error: "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします.\n #{e.full_message}")
|
161
|
-
ProconBypassMan::UsbDeviceController.reset
|
162
|
-
retry
|
163
176
|
end
|
164
177
|
|
165
178
|
def blocking_read_with_timeout_from_procon
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ProconBypassMan::DeviceConnection::OutputReportGenerator
|
2
|
+
def initialize
|
3
|
+
@counter = 0
|
4
|
+
end
|
5
|
+
|
6
|
+
# @return [String]
|
7
|
+
def generate_by_step(step)
|
8
|
+
sub_command_with_arg = ProconBypassMan::DeviceConnection::ProconSettingOverrider::ALL_SETTINGS[step]&.join or raise("Unsupport step")
|
9
|
+
raw_data = generate(sub_command_with_arg)
|
10
|
+
count_up
|
11
|
+
raw_data
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
def generate_by_sub_command_with_arg(sub_command_with_arg)
|
16
|
+
raw_data = generate(sub_command_with_arg)
|
17
|
+
count_up
|
18
|
+
raw_data
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @return [String]
|
24
|
+
def generate(sub_command_with_arg)
|
25
|
+
[
|
26
|
+
["01", counter, "00" * 8, sub_command_with_arg].join
|
27
|
+
].pack("H*")
|
28
|
+
end
|
29
|
+
|
30
|
+
def count_up
|
31
|
+
@counter = @counter + 1
|
32
|
+
if @counter >= 256
|
33
|
+
@counter = 0
|
34
|
+
else
|
35
|
+
@counter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def counter
|
40
|
+
@counter.to_s(16).rjust(2, "0")
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ProconBypassMan::DeviceConnection::OutputReportMarkerable
|
2
|
+
OUTPUT_REPORT_FORMAT = /^01/
|
3
|
+
INPUT_REPORT_FORMAT = /^21/
|
4
|
+
|
5
|
+
# @param [String] raw_data
|
6
|
+
# @return [void]
|
7
|
+
def mark_as_send(raw_data)
|
8
|
+
data = raw_data.unpack("H*").first
|
9
|
+
case data
|
10
|
+
when OUTPUT_REPORT_FORMAT
|
11
|
+
sub_command = data[20..21]
|
12
|
+
sub_command_arg = data[22..23]
|
13
|
+
@hid_sub_command_request_table.mask_as_send(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [String] raw_data
|
18
|
+
# @return [void]
|
19
|
+
def mark_as_receive(raw_data)
|
20
|
+
data = raw_data.unpack("H*").first
|
21
|
+
case data
|
22
|
+
when INPUT_REPORT_FORMAT
|
23
|
+
sub_command = data[28..29]
|
24
|
+
sub_command_arg = data[30..31]
|
25
|
+
@hid_sub_command_request_table.mark_as_receive(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
class ProconBypassMan::DeviceConnection::OutputReportSubCommandTable
|
2
|
+
class HIDSubCommandResponse
|
3
|
+
attr_accessor :sub_command, :sub_command_arg
|
4
|
+
|
5
|
+
def initialize(sub_command: , sub_command_arg: )
|
6
|
+
@sub_command = sub_command
|
7
|
+
@sub_command_arg = sub_command_arg
|
8
|
+
end
|
9
|
+
|
10
|
+
def sub_command_with_arg
|
11
|
+
case @sub_command
|
12
|
+
when *SPECIAL_SUB_COMMANDS
|
13
|
+
@sub_command
|
14
|
+
else
|
15
|
+
if @sub_command_arg
|
16
|
+
"#{@sub_command}-#{@sub_command_arg}"
|
17
|
+
else
|
18
|
+
@sub_command
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
IGNORE_SUB_COMMANDS = {
|
25
|
+
"48-01" => true,
|
26
|
+
"04-00" => true,
|
27
|
+
}
|
28
|
+
# レスポンスに引数が含まれない
|
29
|
+
SPECIAL_SUB_COMMANDS = [
|
30
|
+
"01",
|
31
|
+
"02",
|
32
|
+
"03",
|
33
|
+
"30",
|
34
|
+
"38", # home led
|
35
|
+
"40",
|
36
|
+
"48",
|
37
|
+
]
|
38
|
+
|
39
|
+
EXPECTED_SUB_COMMANDS = [
|
40
|
+
"01-04",
|
41
|
+
"02-",
|
42
|
+
"04-00",
|
43
|
+
"08-00",
|
44
|
+
"10-00",
|
45
|
+
"10-50",
|
46
|
+
"10-80",
|
47
|
+
"10-98",
|
48
|
+
"10-10",
|
49
|
+
"10-28",
|
50
|
+
"30-",
|
51
|
+
"40-",
|
52
|
+
"48-", # Enable vibration
|
53
|
+
]
|
54
|
+
|
55
|
+
def initialize
|
56
|
+
@table = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [String] sub_command
|
60
|
+
# @param [String] sub_command_arg
|
61
|
+
# @return [void]
|
62
|
+
def mask_as_send(sub_command: , sub_command_arg: )
|
63
|
+
case sub_command
|
64
|
+
when *SPECIAL_SUB_COMMANDS
|
65
|
+
@table[sub_command] = false
|
66
|
+
else
|
67
|
+
response = HIDSubCommandResponse.new(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
68
|
+
@table[response.sub_command_with_arg] = false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @param [String] sub_command
|
73
|
+
# @param [String] sub_command_arg
|
74
|
+
# @return [void]
|
75
|
+
def mark_as_receive(sub_command: , sub_command_arg: )
|
76
|
+
response = HIDSubCommandResponse.new(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
77
|
+
if @table.key?(response.sub_command_with_arg)
|
78
|
+
@table[response.sub_command_with_arg] = true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @param [String] sub_command
|
83
|
+
# @param [String] sub_command_arg
|
84
|
+
# @return [Boolean]
|
85
|
+
def has_key?(sub_command: , sub_command_arg: )
|
86
|
+
if IGNORE_SUB_COMMANDS["#{sub_command}-#{sub_command_arg}"]
|
87
|
+
return true
|
88
|
+
end
|
89
|
+
|
90
|
+
case sub_command
|
91
|
+
when *SPECIAL_SUB_COMMANDS
|
92
|
+
@table.key?(sub_command)
|
93
|
+
else
|
94
|
+
response = HIDSubCommandResponse.new(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
95
|
+
@table.key?(response.sub_command_with_arg)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param [String] sub_command
|
100
|
+
# @param [String] sub_command_arg
|
101
|
+
# @return [Boolean]
|
102
|
+
def has_value?(sub_command: , sub_command_arg: )
|
103
|
+
if IGNORE_SUB_COMMANDS["#{sub_command}-#{sub_command_arg}"]
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
|
107
|
+
response = HIDSubCommandResponse.new(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
108
|
+
!!@table[response.sub_command_with_arg]
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Boolean]
|
112
|
+
def has_unreceived_command?
|
113
|
+
!@table.values.all?(&:itself)
|
114
|
+
end
|
115
|
+
|
116
|
+
# @return [String, NilClass]
|
117
|
+
def unreceived_sub_command_with_arg
|
118
|
+
sub_command = @table.detect { |_key, value| !value }&.first
|
119
|
+
if(arg = ProconBypassMan::DeviceConnection::ProconSettingOverrider::SPECIAL_SUB_COMMAND_ARGS[sub_command])
|
120
|
+
"#{sub_command}#{arg}"
|
121
|
+
else
|
122
|
+
sub_command
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Boolean]
|
127
|
+
def completed?
|
128
|
+
EXPECTED_SUB_COMMANDS.all? do |key|
|
129
|
+
sub_command, sub_command_arg = key.split("-")
|
130
|
+
has_value?(sub_command: sub_command, sub_command_arg: sub_command_arg)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|