procon_bypass_man 0.1.3 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|