Module: E3DCMqtt::RSCP::DataType

Defined in:
lib/e3dc_mqtt/rscp/data_type.rb

Overview

RSCP value types. Each entry knows its byte representation, its fixed length (or nil for variable-length types), and how to pack/unpack a Ruby value.

Constant Summary collapse

NONE =
0x00
BOOL =
0x01
CHAR8 =
0x02
UCHAR8 =
0x03
INT16 =
0x04
UINT16 =
0x05
INT32 =
0x06
UINT32 =
0x07
INT64 =
0x08
UINT64 =
0x09
FLOAT32 =
0x0A
DOUBLE64 =
0x0B
BITFIELD =
0x0C
CSTRING =
0x0D
CONTAINER =
0x0E
TIMESTAMP =
0x0F
BYTEARRAY =
0x10
ERROR =
0xFF
NAMES =
{
  NONE => :none, BOOL => :bool, CHAR8 => :char8, UCHAR8 => :uchar8,
  INT16 => :int16, UINT16 => :uint16, INT32 => :int32, UINT32 => :uint32,
  INT64 => :int64, UINT64 => :uint64, FLOAT32 => :float32, DOUBLE64 => :double64,
  BITFIELD => :bitfield, CSTRING => :cstring, CONTAINER => :container,
  TIMESTAMP => :timestamp, BYTEARRAY => :bytearray, ERROR => :error
}.freeze
FIXED_LENGTHS =
{
  NONE => 0, BOOL => 1, CHAR8 => 1, UCHAR8 => 1,
  INT16 => 2, UINT16 => 2, INT32 => 4, UINT32 => 4,
  INT64 => 8, UINT64 => 8, FLOAT32 => 4, DOUBLE64 => 8,
  BITFIELD => 1, TIMESTAMP => 12, ERROR => 4
}.freeze
VARIABLE =
Set.new([CSTRING, CONTAINER, BYTEARRAY]).freeze

Class Method Summary collapse

Class Method Details

.fixed_length(type) ⇒ Object



51
52
53
# File 'lib/e3dc_mqtt/rscp/data_type.rb', line 51

def fixed_length(type)
  FIXED_LENGTHS[type]
end

.name(type) ⇒ Object



47
48
49
# File 'lib/e3dc_mqtt/rscp/data_type.rb', line 47

def name(type)
  NAMES.fetch(type) { raise UnknownDataType, "unknown data type 0x%02x" % type }
end

.pack(type, value) ⇒ Object

Pack a Ruby value into its wire bytes. ‘value` semantics per type:

NONE          -> nil
BOOL          -> true/false
*INT* / *CHAR -> Integer
FLOAT/DOUBLE  -> Float
BITFIELD      -> Integer (0..255)
CSTRING       -> String (binary-safe UTF-8 bytes written)
BYTEARRAY     -> String (binary)
CONTAINER     -> Array<Message>      (caller handles recursion)
TIMESTAMP     -> Time
ERROR         -> Integer (uint32 error code)


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
# File 'lib/e3dc_mqtt/rscp/data_type.rb', line 70

def pack(type, value)
  case type
  when NONE      then "".b
  when BOOL      then [value ? 1 : 0].pack("C")
  when CHAR8     then [value].pack("c")
  when UCHAR8    then [value].pack("C")
  when INT16     then [value].pack("s<")
  when UINT16    then [value].pack("S<")
  when INT32     then [value].pack("l<")
  when UINT32    then [value].pack("L<")
  when INT64     then [value].pack("q<")
  when UINT64    then [value].pack("Q<")
  when FLOAT32   then [value].pack("e")
  when DOUBLE64  then [value].pack("E")
  when BITFIELD  then [value].pack("C")
  when CSTRING   then value.to_s.b
  when BYTEARRAY then value.to_s.b
  when TIMESTAMP
    t = value.utc
    [t.to_i].pack("q<") + [(t.nsec)].pack("l<")
  when ERROR     then [value].pack("L<")
  when CONTAINER
    raise DataTypeMismatch, "CONTAINER must be packed by Message (recursive)"
  else
    raise UnknownDataType, "unknown data type 0x%02x" % type
  end
end

.unpack(type, bytes) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/e3dc_mqtt/rscp/data_type.rb', line 98

def unpack(type, bytes)
  case type
  when NONE      then nil
  when BOOL      then bytes.unpack1("C") != 0
  when CHAR8     then bytes.unpack1("c")
  when UCHAR8    then bytes.unpack1("C")
  when INT16     then bytes.unpack1("s<")
  when UINT16    then bytes.unpack1("S<")
  when INT32     then bytes.unpack1("l<")
  when UINT32    then bytes.unpack1("L<")
  when INT64     then bytes.unpack1("q<")
  when UINT64    then bytes.unpack1("Q<")
  when FLOAT32   then bytes.unpack1("e")
  when DOUBLE64  then bytes.unpack1("E")
  when BITFIELD  then bytes.unpack1("C")
  when CSTRING
    s = bytes.dup
    s.force_encoding(Encoding::UTF_8)
    s.valid_encoding? ? s : bytes.dup.force_encoding(Encoding::BINARY)
  when BYTEARRAY then bytes.dup.force_encoding(Encoding::BINARY)
  when TIMESTAMP
    secs, nsec = bytes.unpack("q<l<")
    Time.at(secs, nsec, :nsec).utc
  when ERROR     then bytes.unpack1("L<")
  when CONTAINER
    raise DataTypeMismatch, "CONTAINER must be unpacked by Message (recursive)"
  else
    raise UnknownDataType, "unknown data type 0x%02x" % type
  end
end

.variable?(type) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/e3dc_mqtt/rscp/data_type.rb', line 55

def variable?(type)
  VARIABLE.include?(type)
end