Class: ProconBypassMan::Bypass::ProconToSwitch

Inherits:
Object
  • Object
show all
Extended by:
CallbacksRegisterable
Includes:
Callbacks
Defined in:
lib/procon_bypass_man/bypass/procon_to_switch.rb

Defined Under Namespace

Classes: CouldNotReadFromProconError, CouldNotWriteToSwitchError

Instance Attribute Summary collapse

Attributes included from CallbacksRegisterable

#callbacks

Instance Method Summary collapse

Methods included from CallbacksRegisterable

register_callback_module

Methods included from Callbacks

#get_callbacks, included, #run_callbacks

Constructor Details

#initialize(gadget:, procon:) ⇒ ProconToSwitch

Returns a new instance of ProconToSwitch.



20
21
22
23
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 20

def initialize(gadget: , procon: )
  self.gadget = gadget
  self.procon = procon
end

Instance Attribute Details

#bypass_valueObject

マルチプロセス化したので一旦無効にする register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)



18
19
20
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 18

def bypass_value
  @bypass_value
end

#gadgetObject

マルチプロセス化したので一旦無効にする register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)



18
19
20
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 18

def gadget
  @gadget
end

#proconObject

マルチプロセス化したので一旦無効にする register_callback_module(ProconBypassMan::ProconDisplay::BypassHook)



18
19
20
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 18

def procon
  @procon
end

Instance Method Details

#direct_connect_switch_via_bluetoothvoid

This method returns an undefined value.



109
110
111
112
113
114
115
116
117
118
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 109

def direct_connect_switch_via_bluetooth
  ProconBypassMan.logger.debug { "[BYPASS] プロコンとSwitchを無線接続へ切り替えます" }
  self.procon.write_nonblock(["010500000000000000003800"].pack("H*")) # home led off
  self.procon.write_nonblock(["010600000000000000003800"].pack("H*")) # home led off
  self.procon.write_nonblock(["010700000000000000003800"].pack("H*")) # home led off
  self.procon.write_nonblock(["010800000000000000003800"].pack("H*")) # home led off
  self.procon.write_nonblock(["8005"].pack("H*"))
  self.procon.write_nonblock(["8005"].pack("H*"))
  self.procon.write_nonblock(["8005"].pack("H*"))
end

#workvoid

This method returns an undefined value.

Raises:

  • (Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/procon_bypass_man/bypass/procon_to_switch.rb', line 27

def work(*)
  ProconBypassMan::Procon::PerformanceMeasurement.measure do |measurement|
    self.bypass_value = ProconBypassMan::Bypass::BypassValue.new(nil)

    next(run_callbacks(:work) {
      next(false) if will_terminate?

      raw_output = nil
      measurement.record_read_time do
        begin
          return(false) if will_terminate?
          raw_output = self.procon.read_nonblock(64)
        rescue IO::EAGAINWaitReadable
          sleep(0.002)
          retry
        rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT => e
          return(false) if will_terminate?
          raise
        end

        self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: raw_output)
      end

      # 後続処理で入力値を取得できるように詰めておく
      ProconBypassMan::ProconDisplay::Status.instance.current = bypass_value.binary.to_procon_reader.to_hash

      # NOTE: 外部からの入力を受け取る
      external_input_data = nil
      measurement.record_external_input_time do
        # TODO: シリアルぽーとから読み取ると252.chrみたいなゴミデータを受け取ってEncoding::UndefinedConversionErrorが発生する可能性がある. 発生したら上限までretryした方がいいかも
        if(data = ProconBypassMan::ExternalInput.read)
          begin
            external_input_data = ProconBypassMan::ExternalInput::ExternalData.parse!(data)
            ProconBypassMan.logger.debug { "[ExternalInput] 読み取った値: { hex: #{external_input_data.hex}, raw_data: '#{external_input_data.raw_data}', buttons: #{external_input_data.buttons} }" }
          rescue ProconBypassMan::ExternalInput::ParseError => e
            ProconBypassMan.logger.error "[ExternalInput][#{e}] #{data.force_encoding('UTF-8').scrub}, #{data.force_encoding('ASCII-8BIT').codepoints} をparseできませんでした"
          end
        end
      end

      result = measurement.record_write_time do
        begin
          ProconBypassMan::Retryable.retryable(tries: 5, on_no_retry: [Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT]) do
            begin
              # 終了処理を希望されているのでブロックを無視してメソッドを抜けてOK
              return(false) if will_terminate? # rubocop:disable Lint/NoReturnInBeginEndBlocks

              binary = ::ProconBypassMan::Procon::Rumbler.monitor do
                ProconBypassMan::Processor.new(bypass_value.binary).process(external_input_data: external_input_data)
              end
              self.gadget.write_nonblock(binary)

              if ProconBypassMan.ephemeral_config.enable_rumble_on_layer_change && ProconBypassMan::Procon::Rumbler.must_rumble?
                begin
                  self.procon.write_nonblock(ProconBypassMan::Procon::Rumbler.binary)
                  ProconBypassMan.logger.debug { ProconBypassMan::Procon::Rumbler.binary.unpack('H*').first }
                rescue => e
                  ProconBypassMan::SendErrorCommand.execute(error: e)
                end
              end

              next(true)
            rescue IO::EAGAINWaitReadable
              return(false) if will_terminate? # rubocop:disable Lint/NoReturnInBeginEndBlocks
              measurement.record_write_error
              raise CouldNotWriteToSwitchError
            rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN, Errno::ETIMEDOUT => e
              return(false) if will_terminate? # rubocop:disable Lint/NoReturnInBeginEndBlocks
              raise
            end
          end
        rescue CouldNotWriteToSwitchError
          next(false)
        end
      end

      next(result)
    })
  end
end