procon_bypass_man 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8326aa72e03d6b2b8ebe7342778c357ba7595019617683e075694c93d870960c
4
- data.tar.gz: fc1df85f7d880ec11c8b5f7d47d46c1a21e726d862cc18000310571e8a072011
3
+ metadata.gz: 5780c7567981a37aef9f32801868f1e59db9d70e47f5cb65dc302cc16a22252e
4
+ data.tar.gz: e1f6d212b9076c0e081e720f3f3c75217183d3bdb4cbab660ab14abc61a35671
5
5
  SHA512:
6
- metadata.gz: bc6aeb40ae12912216e0c40e4b538ab0337ef963c0bcc8e3ac46bafa858a56f44d140f8db694c2200eb1444bf53edf2e49ebc80e9ee63073af29287e556fcd7a
7
- data.tar.gz: bdcb9405fe592e390073e70c2b7eb75d9336bf5f26a6ab08dc1db768e45217103abee62c06eb1dc847d80ff03a600135a0a8b3b41564d1ca68f5161b484df60a
6
+ metadata.gz: 4ea7163f5d33b68c1cfe9e65c15bbe40414435ecf6c5c3fdadc9c70e29eb77f8fa4bbd8897cc8306f2d9cb8b42d231cce240973828f30e8e24771a66235c7304
7
+ data.tar.gz: d829cdf3cd7d3428247a55eb2e5140344d79d6c0b48321a4a7bdcbc3f3e122c66066fa31839bc260016643375b104847f9c8435dfe151f9afa027990b98df630
data/CHANGELOG.md CHANGED
@@ -1,4 +1,13 @@
1
- ## [0.1.4] - 2021-0
1
+ ## [0.1.5] - 2021-07-29
2
+ - siwtch, proコンが電源OFF時にCPU使いまくるのを修正した
3
+ - 連打中に無視するボタンを複数登録できるようにした
4
+ - キーのリマップ先に複数ボタンを登録できるようにした
5
+ - 1つのボタンへ連打とリマップをできないようにしました
6
+ - NG ex)
7
+ - flip :zr, if_pressed: [:y]
8
+ - remap :zr, to: [:x]
9
+
10
+ ## [0.1.4] - 2021-07-11
2
11
  - ProconBypassMan.rootの定義を、gem rootからproject rootへ変更した
3
12
  - 連打の頻度を変更できるようにした
4
13
  - シグナルで設定ファイルを読み直すとpid_pathが消滅する不具合を修正した
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- procon_bypass_man (0.1.4)
4
+ procon_bypass_man (0.1.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -60,9 +60,9 @@ Switch <-- (PBM): ZR連打
60
60
  ## 開発系
61
61
  ```ruby
62
62
  ProconBypassMan.tap do |pbm|
63
+ pbm.root = File.expand_path(__dir__)
63
64
  pbm.logger = Logger.new("#{ProconBypassMan.root}/app.log", 5, 1024 * 1024 * 10)
64
65
  pbm.logger.level = :debug
65
- pbm.root = File.expand_path(__dir__)
66
66
  end
67
67
  ```
68
68
 
@@ -3,11 +3,11 @@ require 'yaml'
3
3
  require "fileutils"
4
4
 
5
5
  require_relative "procon_bypass_man/version"
6
- require_relative "procon_bypass_man/device_registry"
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
 
@@ -18,6 +18,7 @@ module ProconBypassMan
18
18
  class ProConRejected < StandardError; end
19
19
  class CouldNotLoadConfigError < StandardError; end
20
20
  class FirstConnectionError < StandardError; end
21
+ class EternalConnectionError < StandardError; end
21
22
 
22
23
  def self.configure(setting_path: nil, &block)
23
24
  unless setting_path
@@ -34,13 +35,17 @@ module ProconBypassMan
34
35
  def self.run(setting_path: nil, &block)
35
36
  configure(setting_path: setting_path, &block)
36
37
  File.write(pid_path, $$)
37
- registry = ProconBypassMan::DeviceRegistry.new
38
- Runner.new(gadget: registry.gadget, procon: registry.procon).run
38
+ Runner.new.run
39
39
  rescue CouldNotLoadConfigError
40
40
  ProconBypassMan.logger.error "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
41
41
  puts "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
42
42
  FileUtils.rm_rf(ProconBypassMan.pid_path)
43
43
  exit 1
44
+ rescue EternalConnectionError
45
+ ProconBypassMan.logger.error "接続の見込みがないのでsleepしまくります"
46
+ puts "接続の見込みがないのでsleepしまくります"
47
+ FileUtils.rm_rf(ProconBypassMan.pid_path)
48
+ sleep(999999999999999999)
44
49
  rescue FirstConnectionError
45
50
  puts "接続を確立できませんでした。やりなおします。"
46
51
  retry
@@ -39,11 +39,16 @@ module ProconBypassMan
39
39
 
40
40
  MODES = [:manual]
41
41
  def layer(direction, mode: :manual, &block)
42
- unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode)
43
- raise("#{mode} mode is unknown")
42
+ if mode.respond_to?(:name)
43
+ mode_name = mode.name.to_sym
44
+ else
45
+ mode_name = mode
46
+ end
47
+ unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
48
+ raise("#{mode_name} mode is unknown")
44
49
  end
45
50
 
46
- layer = Layer.new(mode: mode)
51
+ layer = Layer.new(mode: mode_name)
47
52
  layer.instance_eval(&block) if block_given?
48
53
  self.layers[direction] = layer
49
54
  self
@@ -16,7 +16,7 @@ module ProconBypassMan
16
16
  case if_pressed
17
17
  when TrueClass
18
18
  if_pressed = [button]
19
- when Symbol
19
+ when Symbol, String
20
20
  if_pressed = [if_pressed]
21
21
  when Array, FalseClass
22
22
  # sono mama
@@ -25,8 +25,16 @@ module ProconBypassMan
25
25
  end
26
26
  hash = { if_pressed: if_pressed }
27
27
  if force_neutral
28
- hash[:force_neutral] = force_neutral
28
+ case force_neutral
29
+ when TrueClass, FalseClass
30
+ raise "ボタンを渡してください"
31
+ when Symbol, String
32
+ hash[:force_neutral] = [force_neutral]
33
+ when Array
34
+ hash[:force_neutral] = force_neutral
35
+ end
29
36
  end
37
+
30
38
  if flip_interval
31
39
  if /\A(\d+)F\z/i =~ flip_interval
32
40
  interval = ((frame = $1.to_i) / 60.0).floor(2)
@@ -35,17 +43,33 @@ module ProconBypassMan
35
43
  end
36
44
  hash[:flip_interval] = interval
37
45
  end
38
- self.flips[button] = hash
46
+ if self.flips[button]
47
+ raise "#{button}への設定をすでに割り当て済みです"
48
+ else
49
+ self.flips[button] = hash
50
+ end
39
51
  end
40
52
 
41
53
  PRESET_MACROS = [:fast_return]
42
54
  def macro(name, if_pressed: )
43
- self.macros[name] = { if_pressed: if_pressed }
55
+ if name.respond_to?(:name)
56
+ macro_name = name.name.to_sym
57
+ else
58
+ macro_name = name
59
+ end
60
+ self.macros[macro_name] = { if_pressed: if_pressed }
44
61
  end
45
62
 
46
63
  def remap(button, to: )
47
- raise "シンボル以外は設定できません" unless to.is_a?(Symbol)
48
- self.remaps[button] = to
64
+ case to
65
+ when TrueClass, FalseClass
66
+ raise "ボタンを渡してください"
67
+ when Symbol, String
68
+ self.remaps[button] = { to: [to] }
69
+ when Array
70
+ raise "ボタンを渡してください" if to.size.zero?
71
+ self.remaps[button] = { to: to }
72
+ end
49
73
  end
50
74
 
51
75
  # @return [Array]
@@ -4,10 +4,11 @@ module ProconBypassMan
4
4
  # @return [Boolean]
5
5
  def valid?
6
6
  @errors = Hash.new {|h,k| h[k] = [] }
7
- if prefix_keys.empty?
8
- @errors[:prefix_keys] ||= []
9
- @errors[:prefix_keys] << "prefix_keys_for_changing_layerに値が入っていません。"
10
- end
7
+
8
+ validate_require_prefix_keys
9
+ validate_config_of_button_lonely
10
+ validate_verify_button_existence
11
+ validate_flip_and_remap_are_hate_each_other
11
12
 
12
13
  @errors.empty?
13
14
  end
@@ -21,6 +22,69 @@ module ProconBypassMan
21
22
  def errors
22
23
  @errors ||= Hash.new {|h,k| h[k] = [] }
23
24
  end
25
+
26
+ private
27
+
28
+ def validate_config_of_button_lonely
29
+ @layers.each do |layer_key, value|
30
+ if ProconBypassMan::Procon::ModeRegistry::PRESETS.key?(value.mode)
31
+ next
32
+ else
33
+ if !value.flips.empty? || !value.macros.empty?
34
+ @errors[:layers] << "#{layer_key}でmodeを設定しているのでボタンの設定はできません。"
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def validate_require_prefix_keys
41
+ if prefix_keys.empty?
42
+ @errors[:prefix_keys] ||= []
43
+ @errors[:prefix_keys] << "prefix_keys_for_changing_layerに値が入っていません。"
44
+ end
45
+ end
46
+
47
+ def validate_verify_button_existence
48
+ @layers.each do |layer_key, value|
49
+ unverified_buttons = []
50
+ # teplevel target button
51
+ value.instance_eval { @flips.keys }.map(&:to_sym).each { |b| unverified_buttons << b }
52
+ value.instance_eval { @remaps.keys }.map(&:to_sym).each { |b| unverified_buttons << b }
53
+ # internal target button
54
+ value.instance_eval {
55
+ @flips.flat_map { |flip_button, flip_option|
56
+ flip_option.flat_map { |flip_option_key, flip_option_target_button|
57
+ next if flip_option_key == :flip_interval
58
+ next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
59
+ flip_option_target_button
60
+ }
61
+ }
62
+ }.compact.each { |b| unverified_buttons << b }
63
+ value.instance_eval {
64
+ @remaps.flat_map { |button, option|
65
+ option.flat_map { |flip_option_key, flip_option_target_button|
66
+ next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
67
+ flip_option_target_button
68
+ }
69
+ }
70
+ }.compact.each { |b| unverified_buttons << b }
71
+ unless(nunsupport_buttons = (unverified_buttons - ProconBypassMan::Procon::ButtonCollection::BUTTONS)).length.zero?
72
+ @errors[:layers] << "#{layer_key}で存在しないボタン#{nunsupport_buttons.join(", ")}があります"
73
+ end
74
+ end
75
+ end
76
+
77
+ def validate_flip_and_remap_are_hate_each_other
78
+ @layers.each do |layer_key, value|
79
+ flip_buttons = []
80
+ remap_buttons = []
81
+ value.instance_eval { @flips.keys }.map(&:to_sym).each { |b| flip_buttons << b }
82
+ value.instance_eval { @remaps.keys }.map(&:to_sym).each { |b| remap_buttons << b }
83
+ if(duplicated_buttons = flip_buttons & remap_buttons).length > 0
84
+ @errors[:layers] << "レイヤー#{layer_key}で、連打とリマップの定義が重複しているボタン#{duplicated_buttons.join(", ")}があります"
85
+ end
86
+ end
87
+ end
24
88
  end
25
89
  end
26
90
  end
@@ -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(throw_error_if_timeout: true, enable_at_exit: false)
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
@@ -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.reset_cvar!
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
- if options[:force_neutral] && user_operation.pressed_button?(options[:force_neutral])
110
- button = options[:force_neutral]
111
- user_operation.unpress_button(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, to_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
- user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
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
 
@@ -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)
@@ -3,10 +3,7 @@ require_relative "io_monitor"
3
3
  class ProconBypassMan::Runner
4
4
  class InterruptForRestart < StandardError; end
5
5
 
6
- def initialize(gadget: , procon: )
7
- @gadget = gadget
8
- @procon = procon
9
-
6
+ def initialize
10
7
  $will_interval_0_0_0_5 = 0
11
8
  $will_interval_1_6 = 0
12
9
  end
@@ -98,8 +95,11 @@ class ProconBypassMan::Runner
98
95
  loop do
99
96
  break if $will_terminate_token
100
97
  bypass.send_procon_to_gadget!
98
+ rescue EOFError => e
99
+ ProconBypassMan.logger.error "Proconと通信ができませんでした.終了処理を開始します"
100
+ Process.kill "TERM", Process.ppid
101
101
  rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
102
- ProconBypassMan.logger.error "Proconが切断されました.終了処理を開始します"
102
+ ProconBypassMan.logger.error "Proconが切断されました。終了処理を開始します"
103
103
  Process.kill "TERM", Process.ppid
104
104
  end
105
105
  ProconBypassMan.logger.info "Thread2を終了します"
@@ -133,38 +133,14 @@ class ProconBypassMan::Runner
133
133
  end
134
134
 
135
135
  def first_negotiation
136
- loop do
137
- begin
138
- input = @gadget.read_nonblock(128)
139
- ProconBypassMan.logger.debug { ">>> #{input.unpack("H*")}" }
140
- @procon.write_nonblock(input)
141
- if input[0] == "\x80".b && input[1] == "\x01".b
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
136
+ return if $will_terminate_token
137
+
138
+ @gadget, @procon = ProconBypassMan::DeviceConnector.connect(throw_error_if_timeout: true, enable_at_exit: false)
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)
@@ -0,0 +1,14 @@
1
+ module ProconBypassMan
2
+ class Timer
3
+ class Timeout < StandardError; end
4
+
5
+ # 5秒後がタイムアウト
6
+ def initialize(timeout: Time.now + 5)
7
+ @timeout = timeout
8
+ end
9
+
10
+ def throw_if_timeout!
11
+ raise Timeout if @timeout < Time.now
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProconBypassMan
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.5"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: procon_bypass_man
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - jiikko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-10 00:00:00.000000000 Z
11
+ date: 2021-07-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: extension for Nintendo Switch Pro Controller
14
14
  email:
@@ -41,7 +41,7 @@ files:
41
41
  - lib/procon_bypass_man/configuration/layer.rb
42
42
  - lib/procon_bypass_man/configuration/loader.rb
43
43
  - lib/procon_bypass_man/configuration/validator.rb
44
- - lib/procon_bypass_man/device_registry.rb
44
+ - lib/procon_bypass_man/device_connector.rb
45
45
  - lib/procon_bypass_man/io_monitor.rb
46
46
  - lib/procon_bypass_man/processor.rb
47
47
  - lib/procon_bypass_man/procon.rb
@@ -54,6 +54,7 @@ files:
54
54
  - lib/procon_bypass_man/procon/pressed_button_helper.rb
55
55
  - lib/procon_bypass_man/procon/user_operation.rb
56
56
  - lib/procon_bypass_man/runner.rb
57
+ - lib/procon_bypass_man/timer.rb
57
58
  - lib/procon_bypass_man/version.rb
58
59
  - procon_bypass_man.gemspec
59
60
  homepage: https://github.com/splaspla-hacker/procon_bypass_man
@@ -1,42 +0,0 @@
1
- class ProconBypassMan::DeviceRegistry
2
- PROCON_PATH = "/dev/hidraw0"
3
- PROCON2_PATH = "/dev/hidraw1"
4
-
5
- def gadget
6
- @gadget
7
- end
8
-
9
- def procon
10
- @procon
11
- end
12
-
13
- def initialize
14
- init_devices
15
- end
16
-
17
- # @return [void]
18
- def init_devices
19
- loop do
20
- case
21
- when File.exist?(PROCON_PATH)
22
- system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
23
- system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
24
- sleep 0.5
25
- @gadget = File.open('/dev/hidg0', "w+")
26
- @procon = File.open(PROCON_PATH, "w+")
27
- break
28
- when File.exist?(PROCON2_PATH)
29
- system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
30
- system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
31
- sleep 0.5
32
- @gadget = File.open('/dev/hidg0', "w+")
33
- @procon = File.open(PROCON2_PATH, "w+")
34
- break
35
- else
36
- puts "プロコンをラズベイに挿してください"
37
- ProconBypassMan.logger.info("プロコンをラズベイに挿してください")
38
- sleep(1)
39
- end
40
- end
41
- end
42
- end