nxt 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +45 -0
- data/lib/communication/bluetooth_communication.rb +85 -0
- data/lib/communication/serial_port_profile.rb +71 -0
- data/lib/nxt.rb +111 -20
- data/lib/ruby-nxt.sublime-project +8 -0
- data/lib/ruby-nxt.sublime-workspace +288 -0
- data/lib/telegrams/commands/direct/get_battery_level.rb +8 -0
- data/lib/telegrams/commands/direct/get_current_program_name.rb +8 -0
- data/lib/{nxt/commands/sound.rb → telegrams/commands/direct/get_input_values.rb} +0 -0
- data/lib/{nxt/commands/tone.rb → telegrams/commands/direct/keep_alive.rb} +0 -0
- data/lib/telegrams/commands/direct/ls_get_status.rb +0 -0
- data/lib/telegrams/commands/direct/ls_read.rb +0 -0
- data/lib/telegrams/commands/direct/ls_write.rb +0 -0
- data/lib/telegrams/commands/direct/message_read.rb +0 -0
- data/lib/telegrams/commands/direct/message_write.rb +0 -0
- data/lib/telegrams/commands/direct/output_state.rb +229 -0
- data/lib/telegrams/commands/direct/play_sound_file.rb +38 -0
- data/lib/telegrams/commands/direct/play_tone.rb +34 -0
- data/lib/telegrams/commands/direct/replies/get_battery_level_reply.rb +28 -0
- data/lib/telegrams/commands/direct/replies/get_current_program_name_reply.rb +30 -0
- data/lib/telegrams/commands/direct/replies/play_sound_file_reply.rb +13 -0
- data/lib/telegrams/commands/direct/replies/play_tone_reply.rb +14 -0
- data/lib/telegrams/commands/direct/replies/reset_motor_position_reply.rb +13 -0
- data/lib/telegrams/commands/direct/replies/set_input_mode_reply.rb +11 -0
- data/lib/telegrams/commands/direct/replies/set_output_state_reply.rb +11 -0
- data/lib/telegrams/commands/direct/replies/start_program_reply.rb +13 -0
- data/lib/telegrams/commands/direct/replies/stop_program_reply.rb +13 -0
- data/lib/telegrams/commands/direct/replies/stop_sound_playback_reply.rb +13 -0
- data/lib/telegrams/commands/direct/reset_input_scaled_value.rb +0 -0
- data/lib/telegrams/commands/direct/reset_motor_position.rb +8 -0
- data/lib/telegrams/commands/direct/set_input_mode.rb +101 -0
- data/lib/telegrams/commands/direct/set_output_state.rb +29 -0
- data/lib/telegrams/commands/direct/start_program.rb +30 -0
- data/lib/telegrams/commands/direct/stop_program.rb +9 -0
- data/lib/telegrams/commands/direct/stop_sound_playback.rb +8 -0
- data/lib/telegrams/commands/direct_command.rb +8 -0
- data/lib/telegrams/commands/direct_command_reply.rb +10 -0
- data/lib/telegrams/commands/message_translator.rb +46 -0
- data/lib/telegrams/commands/system/get_device_info.rb +8 -0
- data/lib/telegrams/commands/system/replies/get_device_info_reply.rb +41 -0
- data/lib/telegrams/commands/system_command.rb +8 -0
- data/lib/telegrams/messages/error.rb +0 -0
- data/lib/telegrams/messages/message.rb +0 -0
- data/lib/telegrams/messages/success.rb +0 -0
- data/lib/telegrams/no_message_reply.rb +10 -0
- data/lib/telegrams/reply.rb +82 -0
- data/lib/telegrams/respondable_telegram.rb +29 -0
- data/lib/telegrams/telegram.rb +14 -0
- data/spec/communication/bluetooth_communication_spec.rb +170 -0
- data/spec/communication/serial_port_profile_spec.rb +139 -0
- data/spec/helper.rb +1 -0
- data/spec/nxt_spec.rb +438 -0
- data/spec/telegrams/commands/direct/get_battery_level_spec.rb +26 -0
- data/spec/telegrams/commands/direct/get_current_program_name_spec.rb +26 -0
- data/spec/telegrams/commands/direct/output_state_spec.rb +198 -0
- data/spec/telegrams/commands/direct/play_sound_file_spec.rb +75 -0
- data/spec/telegrams/commands/direct/play_tone_spec.rb +63 -0
- data/spec/telegrams/commands/direct/replies/get_battery_level_reply_spec.rb +40 -0
- data/spec/telegrams/commands/direct/replies/get_current_program_name_reply_spec.rb +33 -0
- data/spec/telegrams/commands/direct/replies/play_sound_file_reply_spec.rb +13 -0
- data/spec/telegrams/commands/direct/replies/play_tone_reply_spec.rb +14 -0
- data/spec/telegrams/commands/direct/replies/reset_motor_position_reply_spec.rb +13 -0
- data/spec/telegrams/commands/direct/replies/set_input_mode_reply_spec.rb +12 -0
- data/spec/telegrams/commands/direct/replies/set_output_state_reply_spec.rb +12 -0
- data/spec/telegrams/commands/direct/replies/start_program_reply_spec.rb +12 -0
- data/spec/telegrams/commands/direct/replies/stop_program_reply_spec.rb +13 -0
- data/spec/telegrams/commands/direct/replies/stop_sound_playback_reply_spec.rb +13 -0
- data/spec/telegrams/commands/direct/reset_motor_position_spec.rb +31 -0
- data/spec/telegrams/commands/direct/set_input_mode_spec.rb +122 -0
- data/spec/telegrams/commands/direct/set_output_state_spec.rb +72 -0
- data/spec/telegrams/commands/direct/start_program_spec.rb +58 -0
- data/spec/telegrams/commands/direct/stop_program_spec.rb +34 -0
- data/spec/telegrams/commands/direct/stop_sound_playback_spec.rb +34 -0
- data/spec/telegrams/commands/direct_command_reply_spec.rb +7 -0
- data/spec/telegrams/commands/direct_command_spec.rb +34 -0
- data/spec/telegrams/commands/system/get_device_info_spec.rb +16 -0
- data/spec/telegrams/commands/system/replies/get_device_info_reply_spec.rb +63 -0
- data/spec/telegrams/commands/system_command_spec.rb +26 -0
- data/spec/telegrams/no_message_reply_spec.rb +12 -0
- data/spec/telegrams/reply_spec.rb +63 -0
- data/spec/telegrams/respondable_telegram_spec.rb +66 -0
- data/spec/telegrams/telegram_spec.rb +38 -0
- metadata +97 -116
- data/README.markdown +0 -52
- data/Rakefile +0 -35
- data/lib/nxt/commands/base.rb +0 -51
- data/lib/nxt/commands/input.rb +0 -60
- data/lib/nxt/commands/output.rb +0 -105
- data/lib/nxt/commands/program.rb +0 -70
- data/lib/nxt/connectors/base.rb +0 -35
- data/lib/nxt/connectors/input/color.rb +0 -30
- data/lib/nxt/connectors/input/touch.rb +0 -11
- data/lib/nxt/connectors/input/ultrasonic.rb +0 -11
- data/lib/nxt/connectors/output/motor.rb +0 -114
- data/lib/nxt/errors.rb +0 -25
- data/lib/nxt/exceptions.rb +0 -26
- data/lib/nxt/interfaces/base.rb +0 -36
- data/lib/nxt/interfaces/serial_port.rb +0 -88
- data/lib/nxt/interfaces/usb.rb +0 -8
- data/lib/nxt/nxt_brick.rb +0 -167
- data/lib/nxt/patches/module.rb +0 -22
- data/lib/nxt/patches/string.rb +0 -29
- data/lib/nxt/utils/accessors.rb +0 -24
- data/spec/matchers.rb +0 -7
- data/spec/nxt/connectors/output/motor_spec.rb +0 -55
- data/spec/nxt/interfaces/serial_port_spec.rb +0 -73
- data/spec/nxt/nxt_brick_spec.rb +0 -199
- data/spec/spec_helper.rb +0 -4
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class SetOutputStateReply < DirectCommandReply
|
4
|
+
def initialize(bytes)
|
5
|
+
super(bytes)
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_bytes(bytes)
|
9
|
+
raise ArgumentError, "must be a reply for a SetOutputState command" unless bytes[1] == 0x04
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class StartProgramReply < DirectCommandReply
|
4
|
+
def initialize(bytes)
|
5
|
+
super(bytes)
|
6
|
+
end
|
7
|
+
|
8
|
+
# override
|
9
|
+
def validate_bytes(bytes)
|
10
|
+
super(bytes)
|
11
|
+
raise ArgumentError, "must be a reply for a StartProgram command" unless bytes[1] == 0x00
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class StopProgramReply < DirectCommandReply
|
4
|
+
def initialize(bytes)
|
5
|
+
super(bytes)
|
6
|
+
end
|
7
|
+
|
8
|
+
# override
|
9
|
+
def validate_bytes(bytes)
|
10
|
+
super(bytes)
|
11
|
+
raise ArgumentError, "must be a reply for a StopProgram command" unless bytes[1] == 0x01
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class StopSoundPlaybackReply < DirectCommandReply
|
4
|
+
def initialize(bytes)
|
5
|
+
super(bytes)
|
6
|
+
end
|
7
|
+
|
8
|
+
# override
|
9
|
+
def validate_bytes(bytes)
|
10
|
+
super(bytes)
|
11
|
+
raise ArgumentError, "must be a reply for a StopSoundPlayback command" unless bytes[1] == 0x0C
|
12
|
+
end
|
13
|
+
end
|
File without changes
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require_relative '../direct_command'
|
2
|
+
|
3
|
+
class SetInputMode < DirectCommand
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def input_ports; INPUT_PORTS.keys; end
|
7
|
+
def sensor_types; SENSOR_TYPES.keys; end
|
8
|
+
def sensor_modes; SENSOR_MODES.keys; end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :input_port, :sensor_type, :sensor_mode
|
12
|
+
|
13
|
+
def initialize(input_port, sensor_type, sensor_mode, response_required=true)
|
14
|
+
super(response_required)
|
15
|
+
@command = 0x05
|
16
|
+
|
17
|
+
validate_arguments(input_port, sensor_type, sensor_mode)
|
18
|
+
@input_port = input_port
|
19
|
+
@sensor_type = sensor_type
|
20
|
+
@sensor_mode = sensor_mode
|
21
|
+
end
|
22
|
+
|
23
|
+
INPUT_PORTS = {
|
24
|
+
one: 0x00,
|
25
|
+
two: 0x01,
|
26
|
+
three: 0x02,
|
27
|
+
four: 0x03
|
28
|
+
}
|
29
|
+
|
30
|
+
SENSOR_TYPES = {}
|
31
|
+
[:no_sensor,
|
32
|
+
:switch,
|
33
|
+
:temperature,
|
34
|
+
:reflection,
|
35
|
+
:angle,
|
36
|
+
:light_active,
|
37
|
+
:light_inactive,
|
38
|
+
:sound_db,
|
39
|
+
:sound_dba,
|
40
|
+
:custom,
|
41
|
+
:lowspeed,
|
42
|
+
:lowspeed_9v,
|
43
|
+
:highspeed,
|
44
|
+
:colorfull,
|
45
|
+
:colorred,
|
46
|
+
:colorgreen,
|
47
|
+
:colorblue,
|
48
|
+
:colornone
|
49
|
+
].each_with_index do |key, index|
|
50
|
+
SENSOR_TYPES[key] = index
|
51
|
+
end
|
52
|
+
|
53
|
+
SENSOR_MODES = {
|
54
|
+
:rawmode => 0x00,
|
55
|
+
:booleanmode => 0x20,
|
56
|
+
:transitioncntmode => 0x40,
|
57
|
+
:periodcountermode => 0x60,
|
58
|
+
:pctfullscalemode => 0x80,
|
59
|
+
:celsiusmode => 0xA0,
|
60
|
+
:fahrenheitmode => 0xC0,
|
61
|
+
:anglestepmode => 0xE0,
|
62
|
+
:slopemask => 0x1F,
|
63
|
+
:modemask => 0xE0
|
64
|
+
}
|
65
|
+
|
66
|
+
def sensor_types
|
67
|
+
self.class.sensor_types
|
68
|
+
end
|
69
|
+
|
70
|
+
def sensor_modes
|
71
|
+
self.class.sensor_modes
|
72
|
+
end
|
73
|
+
|
74
|
+
def input_ports
|
75
|
+
self.class.input_ports
|
76
|
+
end
|
77
|
+
|
78
|
+
def as_bytes
|
79
|
+
super << INPUT_PORTS[@input_port] << SENSOR_TYPES[@sensor_type] << SENSOR_MODES[@sensor_mode]
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def validate_arguments(input_port, sensor_type, sensor_mode)
|
84
|
+
validate_input_port(input_port)
|
85
|
+
validate_sensor_type(sensor_type)
|
86
|
+
validate_sensor_mode(sensor_mode)
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_input_port(input_port)
|
90
|
+
raise ArgumentError, "Invalid input port" unless input_ports.include? input_port
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_sensor_type(sensor_type)
|
94
|
+
raise ArgumentError, "Invalid sensor type" unless sensor_types.include? sensor_type
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate_sensor_mode(sensor_mode)
|
98
|
+
raise ArgumentError, "Invalid sensor mode" unless sensor_modes.include? sensor_mode
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../direct_command'
|
2
|
+
require_relative './output_state'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
class SetOutputState < DirectCommand
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def initialize(output_state, wait_for_reply=true)
|
9
|
+
super(wait_for_reply)
|
10
|
+
@command = 0x04
|
11
|
+
|
12
|
+
raise ArgumentError, "output_state must be a valid OutputState object" if output_state.nil?
|
13
|
+
@output_state = output_state
|
14
|
+
end
|
15
|
+
|
16
|
+
def as_bytes
|
17
|
+
super.concat(@output_state.as_bytes)
|
18
|
+
end
|
19
|
+
|
20
|
+
# follow Law of Demeter and hide internal access to output_state
|
21
|
+
def_delegators :@output_state, :port, :power, :mode_flags, :regulation_mode,
|
22
|
+
:turn_ratio, :run_state, :tacho_limit
|
23
|
+
|
24
|
+
private
|
25
|
+
def output_state
|
26
|
+
@output_state
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../direct_command'
|
2
|
+
require_relative '../message_translator'
|
3
|
+
|
4
|
+
class StartProgram < DirectCommand
|
5
|
+
include MessageTranslator
|
6
|
+
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(program_name, require_response=true)
|
10
|
+
raise ArgumentError, "program_name is required" if program_name.nil?
|
11
|
+
|
12
|
+
super(require_response)
|
13
|
+
@command = 0x00 # startprogram
|
14
|
+
@name = adjust_program_name(program_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_bytes
|
18
|
+
bytes = super
|
19
|
+
bytes.concat program_name_as_bytes
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def program_name_as_bytes
|
24
|
+
string_as_bytes(@name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def adjust_program_name(name)
|
28
|
+
add_default_extension_if_missing(name, 'rxe')
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module MessageTranslator
|
2
|
+
FILENAME_MAX_LENGTH = 20 # 15.3 + null terminator
|
3
|
+
|
4
|
+
def string_as_bytes(string, max_length=FILENAME_MAX_LENGTH)
|
5
|
+
# pad out to max length with null characters and then
|
6
|
+
# convert all to ASCIIZ (null-terminated ascii string)
|
7
|
+
string.ljust(max_length, "\0").unpack('C*')
|
8
|
+
end
|
9
|
+
|
10
|
+
def string_from_bytes(bytes)
|
11
|
+
# convert from ASCIIZ (null-terminated ascii), removing all the
|
12
|
+
# trailing null characters
|
13
|
+
bytes.pack("C*").strip
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_default_extension_if_missing(filename, default_extension)
|
17
|
+
/.+\.[A-Za-z0-9]{3}$/.match(filename).nil? ? "#{filename}.#{default_extension}" : filename
|
18
|
+
end
|
19
|
+
|
20
|
+
def boolean_as_bytes(boolean)
|
21
|
+
boolean ? [0xff] : [0x00]
|
22
|
+
end
|
23
|
+
|
24
|
+
def boolean_from_bytes(bytes)
|
25
|
+
bytes == [0x00] ? false : true
|
26
|
+
end
|
27
|
+
|
28
|
+
def integer_as_uword_bytes(integer)
|
29
|
+
integer_as_bytes(integer, 4) # make sure number is 4 bytes, or 2, 2 digit hex values
|
30
|
+
end
|
31
|
+
|
32
|
+
def integer_as_ulong_bytes(integer)
|
33
|
+
integer_as_bytes(integer, 8) # (4 bytes as 2 digit hex values each)
|
34
|
+
end
|
35
|
+
|
36
|
+
def integer_as_bytes(integer, bytes_length)
|
37
|
+
uword_byte_length = bytes_length
|
38
|
+
bytes_string = integer.to_s(16).rjust(uword_byte_length, "0")
|
39
|
+
[bytes_string].pack('H*').bytes.to_a.reverse # reverse because it's MSB
|
40
|
+
end
|
41
|
+
|
42
|
+
def integer_from_bytes(bytes)
|
43
|
+
bytes.reverse.pack('C*').unpack('H*')[0].hex
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative '../../../reply'
|
2
|
+
|
3
|
+
class GetDeviceInfoReply < Reply
|
4
|
+
attr_reader :nxt_brick_name, :bt_address,
|
5
|
+
:signal_strength, :free_user_flash_memory_bytes
|
6
|
+
|
7
|
+
def initialize(bytes)
|
8
|
+
super
|
9
|
+
raise ArgumentError, "must be a GetDeviceInfoReply (0x9B)" unless bytes[1] == 0x9B
|
10
|
+
|
11
|
+
@nxt_brick_name = parse_brick_name(bytes)
|
12
|
+
@bt_address = parse_bt_address(bytes)
|
13
|
+
@signal_strength = parse_signal_strength(bytes)
|
14
|
+
@free_user_flash_memory_bytes = parse_free_user_flash_memory(bytes)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def parse_brick_name(bytes)
|
19
|
+
bytes[3..17].pack("C*").strip
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_bt_address(bytes)
|
23
|
+
# skip the null terminator, so 18-23 with 24 at null terminator
|
24
|
+
address = bytes[18..23].map { | byte | byte.to_s(8).rjust(2, "0") }
|
25
|
+
"btspp://#{address.join('')}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_signal_strength(bytes)
|
29
|
+
signal_strength_bytes = bytes[25..28]
|
30
|
+
convert_byte_array_of_little_endian_to_number(signal_strength_bytes)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_free_user_flash_memory(bytes)
|
34
|
+
free_memory_bytes = bytes[29..32]
|
35
|
+
convert_byte_array_of_little_endian_to_number(free_memory_bytes)
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert_byte_array_of_little_endian_to_number(byte_array)
|
39
|
+
byte_array.pack('C*').unpack('v*')[0]
|
40
|
+
end
|
41
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require_relative './telegram'
|
2
|
+
|
3
|
+
class Reply < Telegram
|
4
|
+
COMMAND_TYPE = 0x02
|
5
|
+
SUCCESS = 0x00
|
6
|
+
STATUS_MESSAGES = {
|
7
|
+
SUCCESS => 'Success',
|
8
|
+
# base error messages
|
9
|
+
0x81 => 'No more handles',
|
10
|
+
0x82 => 'No space',
|
11
|
+
0x83 => 'No more files',
|
12
|
+
0x84 => 'End of file expected',
|
13
|
+
0x85 => 'End of file',
|
14
|
+
0x86 => 'Not a linear file',
|
15
|
+
0x87 => 'File not found',
|
16
|
+
0x88 => 'Handle all ready closed',
|
17
|
+
0x89 => 'No linear space',
|
18
|
+
0x8A => 'Undefined error',
|
19
|
+
0x8B => 'File is busy',
|
20
|
+
0x8C => 'No write buffers',
|
21
|
+
0x8D => 'Append not possible',
|
22
|
+
0x8E => 'File is full',
|
23
|
+
0x8F => 'File exists',
|
24
|
+
0x90 => 'Module not found',
|
25
|
+
0x91 => 'Out of boundary',
|
26
|
+
0x92 => 'Illegal file name',
|
27
|
+
0x93 => 'Illegal handle',
|
28
|
+
|
29
|
+
# command replies
|
30
|
+
0x20 => 'Pending communication transaction in progress',
|
31
|
+
0x40 => 'Specified mailbox queue is empty',
|
32
|
+
0xBD => 'Request failed (i.e., specified file not found)',
|
33
|
+
0xBE => 'Unknown command opcode',
|
34
|
+
0xBF => 'Insane packet',
|
35
|
+
0xC0 => 'Data contains out-of-range values',
|
36
|
+
0xDD => 'Communication bus error',
|
37
|
+
0xDE => 'No free memory in communication buffer',
|
38
|
+
0xDF => 'Specified channel/connection is not valid',
|
39
|
+
0xE0 => 'Specified channel/connection not configured or busy',
|
40
|
+
0xEC => 'No active program',
|
41
|
+
0xED => 'Illegal size specified',
|
42
|
+
0xEE => 'Illegal mailbox queue ID specified',
|
43
|
+
0xEF => 'Attempted to access invalid field of a structure',
|
44
|
+
0xF0 => 'Bad input or output specified',
|
45
|
+
0xFB => 'Insufficient memory available',
|
46
|
+
0xFF => 'Bad arguments'
|
47
|
+
}
|
48
|
+
|
49
|
+
attr_accessor :type, :command, :status, :message_bytes, :status_description
|
50
|
+
|
51
|
+
def initialize(bytes=nil)
|
52
|
+
validate_bytes(bytes)
|
53
|
+
@type = bytes[0]
|
54
|
+
@command = bytes[1]
|
55
|
+
@status = bytes[2]
|
56
|
+
@message_bytes = bytes[3..-1]
|
57
|
+
set_status_description
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def success?
|
62
|
+
status == SUCCESS
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def message
|
67
|
+
# override in subclasses to translate bytes to something meaningful
|
68
|
+
message_bytes
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
private
|
73
|
+
def validate_bytes(bytes)
|
74
|
+
raise ArgumentError, "must be non-nil" if bytes.nil?
|
75
|
+
raise ArgumentError, "must have a type, command, and status" unless bytes.size && bytes.size >= 3
|
76
|
+
raise ArgumentError, "must be a reply telegram" unless bytes[0] == COMMAND_TYPE
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_status_description
|
80
|
+
@status_description = STATUS_MESSAGES.include?(status) ? STATUS_MESSAGES[status] : ''
|
81
|
+
end
|
82
|
+
end
|