procon_bypass_man 0.1.3 → 0.1.7
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/.rubocop.yml +24 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +26 -3
- data/README.md +13 -10
- data/docs/setup_raspi.md +12 -7
- data/docs/setup_raspi.mitamae.rb +45 -0
- data/docs/setup_raspi_by_mitamae.md +13 -0
- data/examples/practical/app.rb +3 -2
- data/examples/practical/setting.yml +1 -1
- data/lib/procon_bypass_man/configuration/layer.rb +39 -10
- 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/flip_cache.rb +22 -0
- data/lib/procon_bypass_man/procon/pressed_button_helper.rb +1 -1
- data/lib/procon_bypass_man/procon.rb +20 -11
- data/lib/procon_bypass_man/runner.rb +24 -42
- data/lib/procon_bypass_man/timer.rb +14 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man.rb +25 -8
- data/procon_bypass_man.gemspec +1 -1
- data/project_template/README.md +16 -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 +15 -8
- data/examples/pbm.service +0 -27
- data/examples/simple.rb +0 -13
- data/lib/procon_bypass_man/device_registry.rb +0 -42
@@ -1,24 +1,22 @@
|
|
1
1
|
module ProconBypassMan
|
2
2
|
class Configuration
|
3
3
|
module Loader
|
4
|
+
require 'digest/md5'
|
5
|
+
|
4
6
|
def self.load(setting_path: )
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
instance.errors[:base] << "yamlのシンタックスエラーです"
|
14
|
-
next(instance)
|
7
|
+
ProconBypassMan::Configuration.switch_new_context(:validation) do |validation_instance|
|
8
|
+
yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
|
9
|
+
validation_instance.instance_eval(yaml["setting"])
|
10
|
+
validator = Validator.new(validation_instance)
|
11
|
+
if validator.valid?
|
12
|
+
next
|
13
|
+
else
|
14
|
+
raise ProconBypassMan::CouldNotLoadConfigError, validator.errors
|
15
15
|
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if !validation_instance.errors.empty?
|
21
|
-
raise ProconBypassMan::CouldNotLoadConfigError, validation_instance.errors
|
16
|
+
rescue SyntaxError
|
17
|
+
raise ProconBypassMan::CouldNotLoadConfigError, "Rubyのシンタックスエラーです"
|
18
|
+
rescue Psych::SyntaxError
|
19
|
+
raise ProconBypassMan::CouldNotLoadConfigError, "yamlのシンタックスエラーです"
|
22
20
|
end
|
23
21
|
|
24
22
|
yaml = YAML.load_file(setting_path)
|
@@ -33,6 +31,9 @@ module ProconBypassMan
|
|
33
31
|
ProconBypassMan.logger.warn "不明なバージョンです。failoverします"
|
34
32
|
ProconBypassMan::Configuration.instance.instance_eval(yaml["setting"])
|
35
33
|
end
|
34
|
+
|
35
|
+
File.write(ProconBypassMan.digest_path, Digest::MD5.hexdigest(yaml["setting"]))
|
36
|
+
|
36
37
|
ProconBypassMan::Configuration.instance
|
37
38
|
end
|
38
39
|
|
@@ -1,13 +1,19 @@
|
|
1
1
|
module ProconBypassMan
|
2
2
|
class Configuration
|
3
|
-
|
3
|
+
class Validator
|
4
|
+
def initialize(config)
|
5
|
+
@layers = config.layers
|
6
|
+
@prefix_keys = config.prefix_keys
|
7
|
+
end
|
8
|
+
|
4
9
|
# @return [Boolean]
|
5
10
|
def valid?
|
6
11
|
@errors = Hash.new {|h,k| h[k] = [] }
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
|
13
|
+
validate_require_prefix_keys
|
14
|
+
validate_config_of_button_lonely
|
15
|
+
validate_verify_button_existence
|
16
|
+
validate_flip_and_remap_are_hate_each_other
|
11
17
|
|
12
18
|
@errors.empty?
|
13
19
|
end
|
@@ -21,6 +27,65 @@ module ProconBypassMan
|
|
21
27
|
def errors
|
22
28
|
@errors ||= Hash.new {|h,k| h[k] = [] }
|
23
29
|
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_config_of_button_lonely
|
34
|
+
@layers.each do |layer_key, value|
|
35
|
+
if ProconBypassMan::Procon::ModeRegistry::PRESETS.key?(value.mode)
|
36
|
+
next
|
37
|
+
else
|
38
|
+
if !value.flips.empty? || !value.macros.empty?
|
39
|
+
@errors[:layers] << "#{layer_key}でmodeを設定しているのでボタンの設定はできません。"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_require_prefix_keys
|
46
|
+
if @prefix_keys.empty?
|
47
|
+
@errors[:prefix_keys] ||= []
|
48
|
+
@errors[:prefix_keys] << "prefix_keys_for_changing_layerに値が入っていません。"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_verify_button_existence
|
53
|
+
@layers.each do |layer_key, value|
|
54
|
+
unverified_buttons = []
|
55
|
+
# teplevel target button
|
56
|
+
value.flips.keys.map(&:to_sym).each { |b| unverified_buttons << b }
|
57
|
+
value.remaps.keys.map(&:to_sym).each { |b| unverified_buttons << b }
|
58
|
+
# internal target button
|
59
|
+
value.flips.flat_map { |_flip_button, flip_option|
|
60
|
+
flip_option.flat_map { |flip_option_key, flip_option_target_button|
|
61
|
+
next if flip_option_key == :flip_interval
|
62
|
+
next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
|
63
|
+
flip_option_target_button
|
64
|
+
}
|
65
|
+
}.compact.each { |b| unverified_buttons << b }
|
66
|
+
value.remaps.flat_map { |_button, option|
|
67
|
+
option.flat_map { |_flip_option_key, flip_option_target_button|
|
68
|
+
next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
|
69
|
+
flip_option_target_button
|
70
|
+
}
|
71
|
+
}.compact.each { |b| unverified_buttons << b }
|
72
|
+
unless(nunsupport_buttons = (unverified_buttons - ProconBypassMan::Procon::ButtonCollection::BUTTONS)).length.zero?
|
73
|
+
@errors[:layers] << "#{layer_key}で存在しないボタン#{nunsupport_buttons.join(", ")}があります"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def validate_flip_and_remap_are_hate_each_other
|
79
|
+
@layers.each do |layer_key, value|
|
80
|
+
flip_buttons = []
|
81
|
+
remap_buttons = []
|
82
|
+
value.flips.keys.map(&:to_sym).each { |b| flip_buttons << b }
|
83
|
+
value.remaps.keys.map(&:to_sym).each { |b| remap_buttons << b }
|
84
|
+
if(duplicated_buttons = flip_buttons & remap_buttons).length > 0
|
85
|
+
@errors[:layers] << "レイヤー#{layer_key}で、連打とリマップの定義が重複しているボタン#{duplicated_buttons.join(", ")}があります"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
24
89
|
end
|
25
90
|
end
|
26
91
|
end
|
@@ -4,7 +4,6 @@ require "procon_bypass_man/configuration/layer"
|
|
4
4
|
|
5
5
|
module ProconBypassMan
|
6
6
|
class Configuration
|
7
|
-
include Validator
|
8
7
|
|
9
8
|
attr_accessor :layers,
|
10
9
|
:setting_path,
|
@@ -19,13 +18,12 @@ module ProconBypassMan
|
|
19
18
|
@@context[@@current_context_key] ||= new
|
20
19
|
end
|
21
20
|
|
22
|
-
def self.
|
23
|
-
@@context[key]
|
21
|
+
def self.switch_new_context(key)
|
22
|
+
@@context[key] = new
|
24
23
|
previous_key = @@current_context_key
|
25
24
|
if block_given?
|
26
25
|
@@current_context_key = key
|
27
26
|
value = yield(@@context[key])
|
28
|
-
@@context[key].reset!
|
29
27
|
@@current_context_key = previous_key
|
30
28
|
return value
|
31
29
|
else
|
@@ -39,11 +37,16 @@ module ProconBypassMan
|
|
39
37
|
|
40
38
|
MODES = [:manual]
|
41
39
|
def layer(direction, mode: :manual, &block)
|
42
|
-
|
43
|
-
|
40
|
+
if mode.respond_to?(:name)
|
41
|
+
mode_name = mode.name.to_sym
|
42
|
+
else
|
43
|
+
mode_name = mode
|
44
|
+
end
|
45
|
+
unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
|
46
|
+
raise("#{mode_name} mode is unknown")
|
44
47
|
end
|
45
48
|
|
46
|
-
layer = Layer.new(mode:
|
49
|
+
layer = Layer.new(mode: mode_name)
|
47
50
|
layer.instance_eval(&block) if block_given?
|
48
51
|
self.layers[direction] = layer
|
49
52
|
self
|
@@ -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
|
41
|
+
s.add([["8001"]], read_from: :switch)
|
42
|
+
s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
|
43
|
+
# 2
|
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
|
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
|