procon_bypass_man 0.1.4 → 0.1.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 +40 -13
- data/.github/workflows/ruby.yml +33 -0
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +19 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +25 -3
- data/README.md +12 -9
- data/Rakefile +10 -1
- data/docs/setup_raspi.md +12 -7
- data/docs/setup_raspi.mitamae.rb +48 -0
- data/docs/setup_raspi_by_mitamae.md +14 -0
- data/examples/practical/app.rb +2 -2
- data/lib/procon_bypass_man/configuration/layer.rb +30 -6
- data/lib/procon_bypass_man/configuration/loader.rb +17 -16
- data/lib/procon_bypass_man/configuration/validator.rb +70 -5
- data/lib/procon_bypass_man/configuration.rb +10 -7
- data/lib/procon_bypass_man/device_connector.rb +336 -0
- data/lib/procon_bypass_man/procon/button_collection.rb +3 -2
- data/lib/procon_bypass_man/procon/pressed_button_helper.rb +1 -1
- data/lib/procon_bypass_man/procon.rb +9 -7
- data/lib/procon_bypass_man/runner.rb +16 -39
- data/lib/procon_bypass_man/timer.rb +14 -0
- data/lib/procon_bypass_man/uptime.rb +13 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man.rb +19 -4
- data/procon_bypass_man.gemspec +1 -1
- data/project_template/README.md +17 -0
- data/project_template/app.rb +18 -0
- data/project_template/setting.yml +35 -0
- data/project_template/systemd_units/pbm.service +13 -0
- metadata +16 -8
- data/examples/pbm.service +0 -27
- data/examples/simple.rb +0 -13
- data/lib/procon_bypass_man/device_registry.rb +0 -42
@@ -0,0 +1,336 @@
|
|
1
|
+
class ProconBypassMan::DeviceConnector
|
2
|
+
class BytesMismatchError < StandardError; end
|
3
|
+
|
4
|
+
class Value
|
5
|
+
attr_accessor :read_from, :values
|
6
|
+
def initialize(values: , read_from: )
|
7
|
+
@values = values
|
8
|
+
@read_from = read_from
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
PROCON_PATH = "/dev/hidraw0"
|
13
|
+
PROCON2_PATH = "/dev/hidraw1"
|
14
|
+
|
15
|
+
# 画面で再接続ができたが状況は変わらない
|
16
|
+
def self.reset_connection!
|
17
|
+
s = new
|
18
|
+
s.add([
|
19
|
+
["0000"],
|
20
|
+
["0000"],
|
21
|
+
["8005"],
|
22
|
+
["0000"],
|
23
|
+
["8001"],
|
24
|
+
], read_from: :switch)
|
25
|
+
s.drain_all
|
26
|
+
s.read_procon
|
27
|
+
s.write_switch("213c910080005db7723d48720a800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
28
|
+
sleep(10) # いらないかも
|
29
|
+
s
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.connect
|
33
|
+
s = new(throw_error_if_timeout: true, enable_at_exit: false)
|
34
|
+
s.add([
|
35
|
+
["0000"],
|
36
|
+
["0000"],
|
37
|
+
["8005"],
|
38
|
+
["0010"],
|
39
|
+
], read_from: :switch)
|
40
|
+
# 1. Sends current connection status, and if the Joy-Con are connected,
|
41
|
+
s.add([["8001"]], read_from: :switch)
|
42
|
+
s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
|
43
|
+
# 2. Sends handshaking packets over UART to the Joy-Con or Pro Controller Broadcom chip. This command can only be called once per session.
|
44
|
+
s.add([["8002"]], read_from: :switch)
|
45
|
+
s.add([/^8102/], read_from: :procon)
|
46
|
+
# 3
|
47
|
+
s.add([/^0100/], read_from: :switch)
|
48
|
+
s.add([/^21/], read_from: :procon)
|
49
|
+
# 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.
|
50
|
+
s.add([["8004"]], read_from: :switch)
|
51
|
+
s.drain_all
|
52
|
+
return [s.switch, s.procon]
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(throw_error_if_timeout: false, throw_error_if_mismatch: false , enable_at_exit: true)
|
56
|
+
@stack = []
|
57
|
+
@initialized_devices = false
|
58
|
+
@throw_error_if_timeout = throw_error_if_timeout
|
59
|
+
@throw_error_if_mismatch = throw_error_if_mismatch
|
60
|
+
@enable_at_exit = enable_at_exit
|
61
|
+
end
|
62
|
+
|
63
|
+
def add(values, read_from: )
|
64
|
+
@stack << Value.new(values: values, read_from: read_from)
|
65
|
+
end
|
66
|
+
|
67
|
+
def drain_all
|
68
|
+
unless @initialized_devices
|
69
|
+
init_devices
|
70
|
+
end
|
71
|
+
|
72
|
+
while(item = @stack.shift)
|
73
|
+
item.values.each do |value|
|
74
|
+
data = nil
|
75
|
+
timer = ProconBypassMan::Timer.new
|
76
|
+
begin
|
77
|
+
timer.throw_if_timeout!
|
78
|
+
data = from_device(item).read_nonblock(128)
|
79
|
+
rescue IO::EAGAINWaitReadable
|
80
|
+
retry
|
81
|
+
end
|
82
|
+
|
83
|
+
result =
|
84
|
+
case value
|
85
|
+
when String, Array
|
86
|
+
value == data.unpack("H*")
|
87
|
+
when Regexp
|
88
|
+
value =~ data.unpack("H*").first
|
89
|
+
else
|
90
|
+
raise "#{value}は知りません"
|
91
|
+
end
|
92
|
+
if result
|
93
|
+
ProconBypassMan.logger.info "OK(expected: #{value}, got: #{data.unpack("H*")})"
|
94
|
+
else
|
95
|
+
ProconBypassMan.logger.info "NG(expected: #{value}, got: #{data.unpack("H*")})"
|
96
|
+
raise BytesMismatchError if @throw_error_if_mismatch
|
97
|
+
end
|
98
|
+
to_device(item).write_nonblock(data)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
rescue ProconBypassMan::Timer::Timeout
|
102
|
+
ProconBypassMan.logger.error "timeoutになりました"
|
103
|
+
raise if @throw_error_if_timeout
|
104
|
+
end
|
105
|
+
|
106
|
+
# switchに任意の命令を入力して、switchから読み取る
|
107
|
+
def write_switch(data, only_write: false)
|
108
|
+
if data.encoding.name == "UTF-8"
|
109
|
+
data = [data].pack("H*")
|
110
|
+
end
|
111
|
+
unless @initialized_devices
|
112
|
+
init_devices
|
113
|
+
end
|
114
|
+
|
115
|
+
timer = ProconBypassMan::Timer.new
|
116
|
+
data = nil
|
117
|
+
begin
|
118
|
+
timer.throw_if_timeout!
|
119
|
+
switch.write_nonblock(data)
|
120
|
+
rescue IO::EAGAINWaitReadable
|
121
|
+
retry
|
122
|
+
rescue ProconBypassMan::Timer::Timeout
|
123
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
124
|
+
raise
|
125
|
+
end
|
126
|
+
return(data.unpack("H*")) if only_write
|
127
|
+
|
128
|
+
timer = ProconBypassMan::Timer.new
|
129
|
+
begin
|
130
|
+
timer.throw_if_timeout!
|
131
|
+
data = switch.read_nonblock(128)
|
132
|
+
ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
|
133
|
+
rescue IO::EAGAINWaitReadable
|
134
|
+
retry
|
135
|
+
rescue ProconBypassMan::Timer::Timeout
|
136
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
rescue ProconBypassMan::Timer::Timeout
|
140
|
+
raise if @throw_error_if_timeout
|
141
|
+
end
|
142
|
+
|
143
|
+
def write_procon(data, only_write: false)
|
144
|
+
if data.encoding.name == "UTF-8"
|
145
|
+
data = [data].pack("H*")
|
146
|
+
end
|
147
|
+
unless @initialized_devices
|
148
|
+
init_devices
|
149
|
+
end
|
150
|
+
|
151
|
+
timer = ProconBypassMan::Timer.new
|
152
|
+
begin
|
153
|
+
timer.throw_if_timeout!
|
154
|
+
procon.write_nonblock(data)
|
155
|
+
rescue IO::EAGAINWaitReadable
|
156
|
+
retry
|
157
|
+
rescue ProconBypassMan::Timer::Timeout
|
158
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
159
|
+
raise
|
160
|
+
end
|
161
|
+
return(data.unpack("H*")) if only_write
|
162
|
+
|
163
|
+
timer = ProconBypassMan::Timer.new
|
164
|
+
begin
|
165
|
+
timer.throw_if_timeout!
|
166
|
+
data = procon.read_nonblock(128)
|
167
|
+
ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
|
168
|
+
rescue IO::EAGAINWaitReadable
|
169
|
+
retry
|
170
|
+
rescue ProconBypassMan::Timer::Timeout
|
171
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
172
|
+
raise
|
173
|
+
end
|
174
|
+
rescue ProconBypassMan::Timer::Timeout
|
175
|
+
raise if @throw_error_if_timeout
|
176
|
+
end
|
177
|
+
|
178
|
+
def read_procon(only_read: false)
|
179
|
+
unless @initialized_devices
|
180
|
+
init_devices
|
181
|
+
end
|
182
|
+
|
183
|
+
data = nil
|
184
|
+
timer = ProconBypassMan::Timer.new
|
185
|
+
begin
|
186
|
+
timer.throw_if_timeout!
|
187
|
+
data = procon.read_nonblock(128)
|
188
|
+
ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
|
189
|
+
rescue IO::EAGAINWaitReadable
|
190
|
+
retry
|
191
|
+
rescue ProconBypassMan::Timer::Timeout
|
192
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
193
|
+
raise
|
194
|
+
end
|
195
|
+
return(data.unpack("H*")) if only_read
|
196
|
+
|
197
|
+
timer = ProconBypassMan::Timer.new
|
198
|
+
begin
|
199
|
+
timer.throw_if_timeout!
|
200
|
+
switch.write_nonblock(data)
|
201
|
+
rescue IO::EAGAINWaitReadable
|
202
|
+
retry
|
203
|
+
rescue ProconBypassMan::Timer::Timeout
|
204
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
205
|
+
raise
|
206
|
+
end
|
207
|
+
rescue ProconBypassMan::Timer::Timeout
|
208
|
+
raise if @throw_error_if_timeout
|
209
|
+
end
|
210
|
+
|
211
|
+
def read_switch(only_read: false)
|
212
|
+
unless @initialized_devices
|
213
|
+
init_devices
|
214
|
+
end
|
215
|
+
|
216
|
+
data = nil
|
217
|
+
timer = ProconBypassMan::Timer.new
|
218
|
+
begin
|
219
|
+
timer.throw_if_timeout!
|
220
|
+
data = switch.read_nonblock(128)
|
221
|
+
ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
|
222
|
+
rescue IO::EAGAINWaitReadable
|
223
|
+
retry
|
224
|
+
rescue ProconBypassMan::Timer::Timeout
|
225
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
226
|
+
raise
|
227
|
+
end
|
228
|
+
return(data.unpack("H*")) if only_read
|
229
|
+
|
230
|
+
timer = ProconBypassMan::Timer.new
|
231
|
+
begin
|
232
|
+
timer.throw_if_timeout!
|
233
|
+
procon.write_nonblock(data)
|
234
|
+
rescue IO::EAGAINWaitReadable
|
235
|
+
retry
|
236
|
+
rescue ProconBypassMan::Timer::Timeout
|
237
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
238
|
+
raise
|
239
|
+
end
|
240
|
+
rescue ProconBypassMan::Timer::Timeout
|
241
|
+
raise if @throw_error_if_timeout
|
242
|
+
end
|
243
|
+
|
244
|
+
def from_device(item)
|
245
|
+
case item.read_from
|
246
|
+
when :switch
|
247
|
+
switch
|
248
|
+
when :procon
|
249
|
+
procon
|
250
|
+
else
|
251
|
+
raise
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# fromの対になる
|
256
|
+
def to_device(item)
|
257
|
+
case item.read_from
|
258
|
+
when :switch
|
259
|
+
procon
|
260
|
+
when :procon
|
261
|
+
switch
|
262
|
+
else
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def switch
|
268
|
+
@gadget
|
269
|
+
end
|
270
|
+
|
271
|
+
def procon
|
272
|
+
@procon
|
273
|
+
end
|
274
|
+
|
275
|
+
def is_available_device?(path)
|
276
|
+
return false if !File.exist?(path)
|
277
|
+
|
278
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
279
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
280
|
+
sleep 0.5
|
281
|
+
|
282
|
+
file = File.open(path, "w+")
|
283
|
+
begin
|
284
|
+
file.read_nonblock(128)
|
285
|
+
rescue EOFError
|
286
|
+
file.close
|
287
|
+
return false
|
288
|
+
rescue IO::EAGAINWaitReadable
|
289
|
+
file.close
|
290
|
+
return true
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def to_bin(string)
|
295
|
+
string.unpack "H*"
|
296
|
+
end
|
297
|
+
|
298
|
+
def init_devices
|
299
|
+
if @initialized_devices
|
300
|
+
return
|
301
|
+
end
|
302
|
+
|
303
|
+
case
|
304
|
+
when is_available_device?(PROCON_PATH)
|
305
|
+
ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON_PATH}を使います"
|
306
|
+
@procon = File.open(PROCON_PATH, "w+")
|
307
|
+
@gadget = File.open('/dev/hidg0', "w+")
|
308
|
+
when is_available_device?(PROCON2_PATH)
|
309
|
+
ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
|
310
|
+
@procon = File.open(PROCON2_PATH, "w+")
|
311
|
+
@gadget = File.open('/dev/hidg0', "w+")
|
312
|
+
else
|
313
|
+
raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
|
314
|
+
end
|
315
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
316
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
317
|
+
sleep 0.5
|
318
|
+
|
319
|
+
@initialized_devices = true
|
320
|
+
|
321
|
+
if @enable_at_exit
|
322
|
+
at_exit do
|
323
|
+
@procon&.close
|
324
|
+
@gadget&.close
|
325
|
+
end
|
326
|
+
end
|
327
|
+
rescue Errno::ENXIO => e
|
328
|
+
# /dev/hidg0 をopenできないときがある
|
329
|
+
ProconBypassMan.logger.error "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします"
|
330
|
+
ProconBypassMan.logger.error e
|
331
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
332
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
333
|
+
sleep 2
|
334
|
+
retry
|
335
|
+
end
|
336
|
+
end
|
@@ -24,7 +24,7 @@ class ProconBypassMan::Procon::ButtonCollection
|
|
24
24
|
3 => [:zr, :r, :sr, :sl, :a, :b, :x, :y],
|
25
25
|
4 => [:grip, :_undefined_key, :cap, :home, :thumbl, :thumbr, :plus, :minus],
|
26
26
|
5 => [:zl, :l, :sl, :sr, :left, :right, :up, :down],
|
27
|
-
}
|
27
|
+
}.freeze
|
28
28
|
|
29
29
|
BUTTONS_MAP = BYTES_MAP.reduce({}) { |acc, value|
|
30
30
|
next acc if value[1].nil?
|
@@ -32,7 +32,8 @@ class ProconBypassMan::Procon::ButtonCollection
|
|
32
32
|
acc[button] = { byte_position: value[0], bit_position: index }
|
33
33
|
end
|
34
34
|
acc
|
35
|
-
}
|
35
|
+
}.freeze
|
36
|
+
BUTTONS = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.keys.freeze
|
36
37
|
|
37
38
|
def self.load(button_key)
|
38
39
|
Button.new(button_key)
|
@@ -13,7 +13,7 @@ module ProconBypassMan::Procon::PushedButtonHelper
|
|
13
13
|
@@compiled = false
|
14
14
|
def compile_if_not_compile_yet!
|
15
15
|
unless @@compiled
|
16
|
-
::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button,
|
16
|
+
::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button, _value|
|
17
17
|
define_method "pressed_#{button}?" do
|
18
18
|
pressed_button?(button)
|
19
19
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
class ProconBypassMan::Procon
|
2
|
+
require "procon_bypass_man/procon/data"
|
2
3
|
require "procon_bypass_man/procon/mode_registry"
|
3
4
|
require "procon_bypass_man/procon/macro_registry"
|
4
5
|
require "procon_bypass_man/procon/layer_changeable"
|
@@ -9,7 +10,7 @@ class ProconBypassMan::Procon
|
|
9
10
|
|
10
11
|
attr_accessor :user_operation
|
11
12
|
|
12
|
-
def self.
|
13
|
+
def self.reset!
|
13
14
|
@@status = {
|
14
15
|
buttons: {},
|
15
16
|
current_layer_key: :up,
|
@@ -17,7 +18,6 @@ class ProconBypassMan::Procon
|
|
17
18
|
ongoing_mode: ModeRegistry.load(:manual),
|
18
19
|
}
|
19
20
|
end
|
20
|
-
def self.reset!; reset_cvar!; end
|
21
21
|
reset!
|
22
22
|
|
23
23
|
def initialize(binary)
|
@@ -106,18 +106,20 @@ class ProconBypassMan::Procon
|
|
106
106
|
if !status[button]
|
107
107
|
user_operation.unpress_button(button)
|
108
108
|
end
|
109
|
-
|
110
|
-
|
111
|
-
user_operation.unpress_button(
|
109
|
+
|
110
|
+
options[:force_neutral]&.each do |force_neutral_button|
|
111
|
+
user_operation.pressed_button?(force_neutral_button) && user_operation.unpress_button(force_neutral_button)
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
current_layer.remaps.each do |from_button,
|
116
|
+
current_layer.remaps.each do |from_button, to_buttons|
|
117
117
|
if user_operation.pressed_button?(from_button)
|
118
118
|
user_operation.unpress_button(from_button)
|
119
119
|
# TODO 2重でpressしないようにしたい
|
120
|
-
|
120
|
+
to_buttons[:to].each do |to_button|
|
121
|
+
user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
|
122
|
+
end
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
@@ -1,12 +1,10 @@
|
|
1
1
|
require_relative "io_monitor"
|
2
|
+
require_relative "uptime"
|
2
3
|
|
3
4
|
class ProconBypassMan::Runner
|
4
5
|
class InterruptForRestart < StandardError; end
|
5
6
|
|
6
|
-
def initialize
|
7
|
-
@gadget = gadget
|
8
|
-
@procon = procon
|
9
|
-
|
7
|
+
def initialize
|
10
8
|
$will_interval_0_0_0_5 = 0
|
11
9
|
$will_interval_1_6 = 0
|
12
10
|
end
|
@@ -31,7 +29,7 @@ class ProconBypassMan::Runner
|
|
31
29
|
main_loop_pid = fork { main_loop }
|
32
30
|
|
33
31
|
begin
|
34
|
-
while
|
32
|
+
while(readable_io = IO.select([self_read]))
|
35
33
|
signal = readable_io.first[0].gets.strip
|
36
34
|
handle_signal(signal)
|
37
35
|
end
|
@@ -54,6 +52,7 @@ class ProconBypassMan::Runner
|
|
54
52
|
@gadget&.close
|
55
53
|
@procon&.close
|
56
54
|
FileUtils.rm_rf(ProconBypassMan.pid_path)
|
55
|
+
FileUtils.rm_rf(ProconBypassMan.digest_path)
|
57
56
|
exit 1
|
58
57
|
end
|
59
58
|
end
|
@@ -98,8 +97,11 @@ class ProconBypassMan::Runner
|
|
98
97
|
loop do
|
99
98
|
break if $will_terminate_token
|
100
99
|
bypass.send_procon_to_gadget!
|
100
|
+
rescue EOFError => e
|
101
|
+
ProconBypassMan.logger.error "Proconと通信ができませんでした.終了処理を開始します"
|
102
|
+
Process.kill "TERM", Process.ppid
|
101
103
|
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
102
|
-
ProconBypassMan.logger.error "Procon
|
104
|
+
ProconBypassMan.logger.error "Proconが切断されました。終了処理を開始します"
|
103
105
|
Process.kill "TERM", Process.ppid
|
104
106
|
end
|
105
107
|
ProconBypassMan.logger.info "Thread2を終了します"
|
@@ -119,7 +121,7 @@ class ProconBypassMan::Runner
|
|
119
121
|
|
120
122
|
ProconBypassMan.logger.info "子プロセスでgraceful shutdownの準備ができました"
|
121
123
|
begin
|
122
|
-
while
|
124
|
+
while(readable_io = IO.select([self_read]))
|
123
125
|
signal = readable_io.first[0].gets.strip
|
124
126
|
handle_signal(signal)
|
125
127
|
end
|
@@ -133,38 +135,12 @@ class ProconBypassMan::Runner
|
|
133
135
|
end
|
134
136
|
|
135
137
|
def first_negotiation
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
ProconBypassMan.logger.info("first negotiation is over")
|
143
|
-
break
|
144
|
-
end
|
145
|
-
break if $will_terminate_token
|
146
|
-
rescue IO::EAGAINWaitReadable
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# ...
|
151
|
-
# switch) 8001
|
152
|
-
# procon) 8101
|
153
|
-
# switch) 8002
|
154
|
-
# が返ってくるプロトコルがあって、これができていないならやり直す
|
155
|
-
loop do
|
156
|
-
begin
|
157
|
-
data = @procon.read_nonblock(128)
|
158
|
-
if data[0] == "\x81".b && data[1] == "\x01".b
|
159
|
-
ProconBypassMan.logger.debug { "接続を確認しました" }
|
160
|
-
@gadget.write_nonblock(data)
|
161
|
-
break
|
162
|
-
else
|
163
|
-
raise ::ProconBypassMan::FirstConnectionError
|
164
|
-
end
|
165
|
-
rescue IO::EAGAINWaitReadable
|
166
|
-
end
|
167
|
-
end
|
138
|
+
@gadget, @procon = ProconBypassMan::DeviceConnector.connect
|
139
|
+
rescue ProconBypassMan::Timer::Timeout
|
140
|
+
::ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
|
141
|
+
@gadget&.close
|
142
|
+
@procon&.close
|
143
|
+
raise ::ProconBypassMan::EternalConnectionError
|
168
144
|
end
|
169
145
|
|
170
146
|
def handle_signal(sig)
|
@@ -187,6 +163,7 @@ class ProconBypassMan::Runner
|
|
187
163
|
root: #{ProconBypassMan.root}
|
188
164
|
pid_path: #{ProconBypassMan.pid_path}
|
189
165
|
setting_path: #{ProconBypassMan::Configuration.instance.setting_path}
|
166
|
+
uptime from boot: #{ProconBypassMan::Uptime.from_boot} sec
|
190
167
|
----
|
191
168
|
EOF
|
192
169
|
ProconBypassMan.logger.info(booted_message)
|
data/lib/procon_bypass_man.rb
CHANGED
@@ -3,21 +3,27 @@ require 'yaml'
|
|
3
3
|
require "fileutils"
|
4
4
|
|
5
5
|
require_relative "procon_bypass_man/version"
|
6
|
-
require_relative "procon_bypass_man/
|
6
|
+
require_relative "procon_bypass_man/timer"
|
7
7
|
require_relative "procon_bypass_man/bypass"
|
8
|
+
require_relative "procon_bypass_man/device_connector"
|
8
9
|
require_relative "procon_bypass_man/runner"
|
9
10
|
require_relative "procon_bypass_man/processor"
|
10
|
-
require_relative "procon_bypass_man/procon/data"
|
11
11
|
require_relative "procon_bypass_man/configuration"
|
12
12
|
require_relative "procon_bypass_man/procon"
|
13
13
|
|
14
14
|
STDOUT.sync = true
|
15
15
|
Thread.abort_on_exception = true
|
16
16
|
|
17
|
+
# new feature from ruby3.0's
|
18
|
+
if GC.respond_to?(:auto_compact)
|
19
|
+
GC.auto_compact = true
|
20
|
+
end
|
21
|
+
|
17
22
|
module ProconBypassMan
|
18
23
|
class ProConRejected < StandardError; end
|
19
24
|
class CouldNotLoadConfigError < StandardError; end
|
20
25
|
class FirstConnectionError < StandardError; end
|
26
|
+
class EternalConnectionError < StandardError; end
|
21
27
|
|
22
28
|
def self.configure(setting_path: nil, &block)
|
23
29
|
unless setting_path
|
@@ -34,13 +40,18 @@ module ProconBypassMan
|
|
34
40
|
def self.run(setting_path: nil, &block)
|
35
41
|
configure(setting_path: setting_path, &block)
|
36
42
|
File.write(pid_path, $$)
|
37
|
-
|
38
|
-
Runner.new(gadget: registry.gadget, procon: registry.procon).run
|
43
|
+
Runner.new.run
|
39
44
|
rescue CouldNotLoadConfigError
|
40
45
|
ProconBypassMan.logger.error "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
|
41
46
|
puts "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
|
42
47
|
FileUtils.rm_rf(ProconBypassMan.pid_path)
|
48
|
+
FileUtils.rm_rf(ProconBypassMan.digest_path)
|
43
49
|
exit 1
|
50
|
+
rescue EternalConnectionError
|
51
|
+
ProconBypassMan.logger.error "接続の見込みがないのでsleepしまくります"
|
52
|
+
puts "接続の見込みがないのでsleepしまくります"
|
53
|
+
FileUtils.rm_rf(ProconBypassMan.pid_path)
|
54
|
+
sleep(999999999)
|
44
55
|
rescue FirstConnectionError
|
45
56
|
puts "接続を確立できませんでした。やりなおします。"
|
46
57
|
retry
|
@@ -81,4 +92,8 @@ module ProconBypassMan
|
|
81
92
|
def self.root=(path)
|
82
93
|
@@root = path
|
83
94
|
end
|
95
|
+
|
96
|
+
def self.digest_path
|
97
|
+
"#{root}/.setting_yaml_digest"
|
98
|
+
end
|
84
99
|
end
|
data/procon_bypass_man.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
|
11
11
|
spec.summary = "extension for Nintendo Switch Pro Controller"
|
12
12
|
spec.description = spec.summary
|
13
|
-
spec.homepage = "https://github.com/
|
13
|
+
spec.homepage = "https://github.com/splaplapla/procon_bypass_man"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
16
16
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Project Template
|
2
|
+
https://github.com/splaplapla/pbmenv で使っているファイルです
|
3
|
+
|
4
|
+
## systemd
|
5
|
+
* sudo ln -s /usr/share/pbm/current/systemd_units/pbm.service /etc/systemd/system/pbm.service
|
6
|
+
* commands
|
7
|
+
* systemctl daemon-reload
|
8
|
+
* systemctl enable pbm.service
|
9
|
+
* systemctl disable pbm.service
|
10
|
+
* systemctl start pbm.service
|
11
|
+
* systemctl status pbm.service
|
12
|
+
* systemctl restart pbm.service
|
13
|
+
* systemctl list-unit-files --type=service
|
14
|
+
|
15
|
+
### ログ
|
16
|
+
* journalctl -xe -f
|
17
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
8
|
+
gem 'procon_bypass_man', '0.1.8'
|
9
|
+
gem 'procon_bypass_man-splatoon2', github: 'splaplapla/procon_bypass_man-splatoon2', tag: "0.1.1"
|
10
|
+
end
|
11
|
+
|
12
|
+
ProconBypassMan.tap do |pbm|
|
13
|
+
pbm.root = File.expand_path(__dir__)
|
14
|
+
pbm.logger = Logger.new("#{ProconBypassMan.root}/app.log", 5, 1024 * 1024 * 10)
|
15
|
+
pbm.logger.level = :debug
|
16
|
+
end
|
17
|
+
|
18
|
+
ProconBypassMan.run(setting_path: "/usr/share/pbm/current/setting.yml")
|