Class: Vissen::Input::Message::Base

Inherits:
Object
  • Object
show all
Includes:
Vissen::Input::Message
Defined in:
lib/vissen/input/message/base.rb

Overview

This is the base message implementaion. This class should never be used directly, but rather be subclassed to create the various messages that the system understands.

The Base class keeps track of subclasses and can produce a message factory for all the implementations that it knows about (see .factory).

Constant Summary collapse

DATA_LENGTH =
3
STATUS =
0

Constants included from Vissen::Input::Message

CHANNEL_MASK, STATUS_MASK

Instance Attribute Summary

Attributes included from Vissen::Input::Message

#data, #timestamp

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Vissen::Input::Message

#channel, #initialize, #status

Class Method Details

.[](channel, number = nil) ⇒ Object

Alias to #matcher that swaps named arguments for positional ones.



79
80
81
# File 'lib/vissen/input/message/base.rb', line 79

def [](channel, number = nil)
  matcher channel: channel, number: number
end

.create(*bytes, status: self::STATUS, channel: 0, timestamp: Time.now.to_f) ⇒ Base

Build a new instance of Message::Base, or a subclass, using more intuitive arguments. Subclasses of Base can utilize the same functionality by simply redefining DATA_LENGTH to correspond to their message length.

Note that status and channel are masked using the default masks, and not the constants that may have been defined by a subclass.

Parameters:

  • bytes (Array<Integer>)

    the message data byte values. Unspecified values default to 0.

  • status (Integer) (defaults to: self::STATUS)

    the status to use for the new message.

  • channel (Integer) (defaults to: 0)

    the channel to use for the new message.

  • timestamp (Float) (defaults to: Time.now.to_f)

    the timestamp to use for the new message.

Returns:

  • (Base)

    a new instance of this class.

Raises:

  • (ArgumentError)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/vissen/input/message/base.rb', line 97

def create(*bytes, status: self::STATUS,
           channel: 0,
           timestamp: Time.now.to_f)
  raise ArgumentError if bytes.length >= self::DATA_LENGTH

  validate_status status
  validate_channel channel

  data = Array.new self::DATA_LENGTH, 0

  # Note: this line line must reference
  #       STATUS_MASK and not self::STATUS_MASK
  data[0] = (status & STATUS_MASK) + (channel & CHANNEL_MASK)

  # Copy the bytes
  bytes.each_with_index { |value, index| data[index + 1] = value }

  new data, timestamp
end

.factoryMessageFactory

Creates a new factory with all the subclasses of base added to it as matchers.

Returns:

  • (MessageFactory)

    a factory configured to build all subclasses of Base.

Raises:

  • (RuntimeError)


70
71
72
73
# File 'lib/vissen/input/message/base.rb', line 70

def factory
  raise RuntimeError unless defined? @subclasses
  MessageFactory.new @subclasses.map(&:matcher)
end

.match?(message) ⇒ true, false

Accessor for the class default matcher.

Parameters:

  • message (#to_a)

    the message or data to match.

Returns:

  • (true, false)

    see ‘Matcher#match?`.



61
62
63
# File 'lib/vissen/input/message/base.rb', line 61

def match?(message)
  matcher.match? message
end

.matcher(channel: nil, number: nil) ⇒ Matcher

Returns a new instance of a Matcher, configured to match this particular Message class. Subclasses of Base can utilize the same functionality by simply redefining STATUS and, if necessary, STATUS_MASK.

By supplying the optional named arguments channel and number

Raises a RangeError if the channel is given and is outside its valid range of (0..15). Raises a RangeError if number is given and is outside its valid range of (0..127).

Parameters:

  • channel (nil, Integer) (defaults to: nil)

    the channel to match, or nil to match all channels.

  • number (nil, Integer) (defaults to: nil)

    the second byte value to match, or nil to match all values.

Returns:

  • (Matcher)

    the matcher that fulfills the requirements.



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/vissen/input/message/base.rb', line 45

def matcher(channel: nil, number: nil)
  return klass_matcher unless channel || number
  val, mask = status_value_and_mask channel

  if number
    raise RangeError unless (0...128).cover? number
    Matcher.new(self) { |d| (d[0] & mask) == val && d[1] == number }
  else
    Matcher.new(self) { |d| (d[0] & mask) == val }
  end
end

Instance Method Details

#valid?true, false

Checks message data consistency with the class default matcher.

Returns:

  • (true, false)

    true if the message data matches the class matcher.



23
24
25
# File 'lib/vissen/input/message/base.rb', line 23

def valid?
  self.class.matcher.match? data
end