class ProconBypassMan::DeviceConnector

Constants

PROCON2_PATH
PROCON_PATH

Public Class Methods

connect() click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 32
def self.connect
  s = new(throw_error_if_timeout: true, enable_at_exit: false)
  s.add([
    ["0000"],
    ["0000"],
    ["8005"],
    ["0010"],
  ], read_from: :switch)
  # 1
  s.add([["8001"]], read_from: :switch)
  s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
  # 2
  s.add([["8002"]], read_from: :switch)
  s.add([/^8102/], read_from: :procon)
  # 3
  s.add([/^0100/], read_from: :switch)
  s.add([/^21/], read_from: :procon)
  # 4
  s.add([["8004"]], read_from: :switch)
  s.drain_all
  return [s.switch, s.procon]
end
new(throw_error_if_timeout: false, throw_error_if_mismatch: false , enable_at_exit: true) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 55
def initialize(throw_error_if_timeout: false, throw_error_if_mismatch: false , enable_at_exit: true)
  @stack = []
  @initialized_devices = false
  @throw_error_if_timeout = throw_error_if_timeout
  @throw_error_if_mismatch = throw_error_if_mismatch
  @enable_at_exit = enable_at_exit
end
reset_connection!() click to toggle source

画面で再接続ができたが状況は変わらない

# File lib/procon_bypass_man/device_connector.rb, line 16
def self.reset_connection!
  s = new
  s.add([
    ["0000"],
    ["0000"],
    ["8005"],
    ["0000"],
    ["8001"],
  ], read_from: :switch)
  s.drain_all
  s.read_procon
  s.write_switch("213c910080005db7723d48720a800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
  sleep(10) # いらないかも
  s
end

Public Instance Methods

add(values, read_from: ) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 63
def add(values, read_from: )
  @stack << Value.new(values: values, read_from: read_from)
end
drain_all() click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 67
def drain_all
  unless @initialized_devices
    init_devices
  end

  while(item = @stack.shift)
    item.values.each do |value|
      data = nil
      timer = ProconBypassMan::Timer.new
      begin
        timer.throw_if_timeout!
        data = from_device(item).read_nonblock(128)
      rescue IO::EAGAINWaitReadable
        retry
      end

      result =
        case value
        when String, Array
          value == data.unpack("H*")
        when Regexp
          value =~ data.unpack("H*").first
        else
          raise "#{value}は知りません"
        end
      if result
        ProconBypassMan.logger.info "OK(expected: #{value}, got: #{data.unpack("H*")})"
      else
        ProconBypassMan.logger.info "NG(expected: #{value}, got: #{data.unpack("H*")})"
        raise BytesMismatchError if @throw_error_if_mismatch
      end
      to_device(item).write_nonblock(data)
    end
  end
rescue ProconBypassMan::Timer::Timeout
  ProconBypassMan.logger.error "timeoutになりました"
  raise if @throw_error_if_timeout
end
from_device(item) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 244
def from_device(item)
  case item.read_from
  when :switch
    switch
  when :procon
    procon
  else
    raise
  end
end
init_devices() click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 298
def init_devices
  if @initialized_devices
    return
  end

  case
  when is_available_device?(PROCON_PATH)
    ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON_PATH}を使います"
    @procon = File.open(PROCON_PATH, "w+")
    @gadget = File.open('/dev/hidg0', "w+")
  when is_available_device?(PROCON2_PATH)
    ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
    @procon = File.open(PROCON2_PATH, "w+")
    @gadget = File.open('/dev/hidg0', "w+")
  else
    raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
  end
  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
  sleep 0.5

  @initialized_devices = true

  if @enable_at_exit
    at_exit do
      @procon&.close
      @gadget&.close
    end
  end
rescue Errno::ENXIO => e
  # /dev/hidg0 をopenできないときがある
  ProconBypassMan.logger.error "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします"
  ProconBypassMan.logger.error e
  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
  sleep 2
  retry
end
is_available_device?(path) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 275
def is_available_device?(path)
  return false if !File.exist?(path)

  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
  sleep 0.5

  file = File.open(path, "w+")
  begin
    file.read_nonblock(128)
  rescue EOFError
    file.close
    return false
  rescue IO::EAGAINWaitReadable
    file.close
    return true
  end
end
procon() click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 271
def procon
  @procon
end
read_procon(only_read: false) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 178
def read_procon(only_read: false)
  unless @initialized_devices
    init_devices
  end

  data = nil
  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    data = procon.read_nonblock(128)
    ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "readでtimeoutになりました"
    raise
  end
  return(data.unpack("H*")) if only_read

  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    switch.write_nonblock(data)
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "writeでtimeoutになりました"
    raise
  end
rescue ProconBypassMan::Timer::Timeout
  raise if @throw_error_if_timeout
end
read_switch(only_read: false) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 211
def read_switch(only_read: false)
  unless @initialized_devices
    init_devices
  end

  data = nil
  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    data = switch.read_nonblock(128)
    ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "readでtimeoutになりました"
    raise
  end
  return(data.unpack("H*")) if only_read

  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    procon.write_nonblock(data)
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "writeでtimeoutになりました"
    raise
  end
rescue ProconBypassMan::Timer::Timeout
  raise if @throw_error_if_timeout
end
switch() click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 267
def switch
  @gadget
end
to_bin(string) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 294
def to_bin(string)
  string.unpack "H*"
end
to_device(item) click to toggle source

fromの対になる

# File lib/procon_bypass_man/device_connector.rb, line 256
def to_device(item)
  case item.read_from
  when :switch
    procon
  when :procon
    switch
  else
    raise
  end
end
write_procon(data, only_write: false) click to toggle source
# File lib/procon_bypass_man/device_connector.rb, line 143
def write_procon(data, only_write: false)
  if data.encoding.name == "UTF-8"
    data = [data].pack("H*")
  end
  unless @initialized_devices
    init_devices
  end

  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    procon.write_nonblock(data)
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "writeでtimeoutになりました"
    raise
  end
  return(data.unpack("H*")) if only_write

  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    data = procon.read_nonblock(128)
    ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "readでtimeoutになりました"
    raise
  end
rescue ProconBypassMan::Timer::Timeout
  raise if @throw_error_if_timeout
end
write_switch(data, only_write: false) click to toggle source

switchに任意の命令を入力して、switchから読み取る

# File lib/procon_bypass_man/device_connector.rb, line 107
def write_switch(data, only_write: false)
  if data.encoding.name == "UTF-8"
    data = [data].pack("H*")
  end
  unless @initialized_devices
    init_devices
  end

  timer = ProconBypassMan::Timer.new
  data = nil
  begin
    timer.throw_if_timeout!
    switch.write_nonblock(data)
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "writeでtimeoutになりました"
    raise
  end
  return(data.unpack("H*")) if only_write

  timer = ProconBypassMan::Timer.new
  begin
    timer.throw_if_timeout!
    data = switch.read_nonblock(128)
    ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
  rescue IO::EAGAINWaitReadable
    retry
  rescue ProconBypassMan::Timer::Timeout
    ProconBypassMan.logger.error "readでtimeoutになりました"
    raise
  end
rescue ProconBypassMan::Timer::Timeout
  raise if @throw_error_if_timeout
end