Class: VoltronicDeviceOperation

Inherits:
Object
  • Object
show all
Defined in:
lib/voltronic_device_operation.rb

Overview

A convenient immutable object to encapsulate the logic of a Voltronic Device operation consisting of: Command, parameter validation and result parser

@author: Johan van der Vyver

Defined Under Namespace

Classes: NAKReceivedError, RS232ParseError

Instance Method Summary collapse

Constructor Details

#initialize(input, &blk) ⇒ VoltronicDeviceOperation

Returns a new instance of VoltronicDeviceOperation.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/voltronic_device_operation.rb', line 11

def initialize(input, &blk)
  input = {}.merge(input) rescue (raise ::ArgumentError.new("Expected an input hash")) 

  @command = begin
    as_lambda(input.fetch(:command))
  rescue ::StandardError => err
    err = "#{err.class.name.to_s} thrown; #{err.message.to_s}"
    raise ::ArgumentError.new("Expected :command to be a String with a device command or Proc (#{err})")
  end

  @error_on_nak = (true == input.fetch(:error_on_nak, true))

  @parser = begin
    as_lambda(input.fetch(:parser))
  rescue ::StandardError => err
    err = "#{err.class.name.to_s} thrown; #{err.message.to_s}"
    raise ::ArgumentError.new("Expected :parser to be a Proc or Lambda (#{err})")
  end

  @read_timeout = Integer(input.fetch(:serial_read_timeout_seconds, 2))
  @retry_timeout = Integer(input.fetch(:serial_retry_timeout_milliseconds, 50))

  @termination_character = begin
    parse = input.fetch(:serial_termination_character, "\r").to_s
    raise ::ArgumentError.new("Expected :serial_termination_character to be a single character") unless (parse.length == 1)
    parse.freeze
  end

  freeze
end

Instance Method Details

#command(*args) ⇒ Object

Create an VoltronicRS232 object containing a command and optional parameter to execute on the device



70
71
72
# File 'lib/voltronic_device_operation.rb', line 70

def command(*args)
  RS232_PROTO.new(@command.yield(*args))
end

#inspectObject

:nodoc:



92
93
94
# File 'lib/voltronic_device_operation.rb', line 92

def inspect # :nodoc:
  self.to_s
end

#issue_command(serial, *args) ⇒ Object

Issue a command to the device and parse the output result



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/voltronic_device_operation.rb', line 44

def issue_command(serial, *args)
  serial.read_timeout = -1 rescue nil # Prevent locking on serial

  serial.write(command(*args).bytes)
  result = begin
    parse = ''
    read_timeout = ::Time.now.to_i + @read_timeout # 2 seconds
    while(true)
      ch = serial.getc # Retrieve a single character from Serial port
      if ch.nil?
        raise ::IOError.new("Read timeout reached on serial port, giving up") if (Time.now.to_i > read_timeout)
        sleep (@retry_timeout/1000.0) # Pause before polling again
        next
      end
      parse += ch
      break if (@termination_character == ch)
    end
    parse
  end

  parse_result(result[0..-4])
end

#parse_result(result) ⇒ Object

Parse the command output returned from the Voltronic device



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/voltronic_device_operation.rb', line 76

def parse_result(result)
  result = RS232_PROTO.new(result)
  if (@error_on_nak && ('(NAK' == result.data.upcase))
    raise NAKReceivedError.new("Received NAK from device, this usually means an error occured, an invalid value was supplied or the command is not supported")
  end
  @parser.yield(result)
rescue ::StandardError, ::ScriptError => err
  raise err if err.is_a?(NAKReceivedError)
  err = "#{err.class.name.to_s} thrown; #{err.message.to_s}"
  raise RS232ParseError.new("Could not parse the result, the output format may have changed (#{err})")
end

#to_sObject

:nodoc:



88
89
90
# File 'lib/voltronic_device_operation.rb', line 88

def to_s # :nodoc:
  "#{self.class.name.to_s.split('::').last}"
end