nxt 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require_relative '../message_translator'
|
2
|
+
|
3
|
+
# OutputModeFlags can be used together with the mode_flags on SetOutputState
|
4
|
+
class OutputModeFlags
|
5
|
+
class << self
|
6
|
+
# turn on the specified motor
|
7
|
+
def MOTORON
|
8
|
+
0x01
|
9
|
+
end
|
10
|
+
|
11
|
+
# use run/brake instead of run/float in PWM
|
12
|
+
def BRAKE
|
13
|
+
0x02
|
14
|
+
end
|
15
|
+
|
16
|
+
# turns on the regulation
|
17
|
+
def REGULATED
|
18
|
+
0x04
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Regulation mode is an enumeration used to set how things work when
|
24
|
+
# in a REGULATED output mode
|
25
|
+
class RegulationMode
|
26
|
+
class << self
|
27
|
+
# no regulation will be enabled
|
28
|
+
def IDLE
|
29
|
+
0x00
|
30
|
+
end
|
31
|
+
|
32
|
+
# power control will be enabled on the specified output
|
33
|
+
def MOTOR_SPEED
|
34
|
+
0x01
|
35
|
+
end
|
36
|
+
|
37
|
+
# synchronization will be enabled
|
38
|
+
# (needs to be enabled on two outputs)
|
39
|
+
def MOTOR_SYNC
|
40
|
+
0x02
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Run state defines how the motor behaves from where it is
|
46
|
+
# and how it gets to the new state you have given it
|
47
|
+
class RunState
|
48
|
+
class << self
|
49
|
+
# output will be idle
|
50
|
+
def IDLE
|
51
|
+
0x00
|
52
|
+
end
|
53
|
+
|
54
|
+
# output will ramp-up
|
55
|
+
def RAMPUP
|
56
|
+
0x10
|
57
|
+
end
|
58
|
+
|
59
|
+
# output will be running
|
60
|
+
def RUNNING
|
61
|
+
0x20
|
62
|
+
end
|
63
|
+
|
64
|
+
# output will ramp-down
|
65
|
+
def RAMPDOWN
|
66
|
+
0x40
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Output state
|
72
|
+
class OutputState
|
73
|
+
include MessageTranslator
|
74
|
+
|
75
|
+
attr_reader :port, :power, :mode_flags, :regulation_mode,
|
76
|
+
:turn_ratio, :run_state, :tacho_limit
|
77
|
+
|
78
|
+
PORTS = {
|
79
|
+
:a => 0x00,
|
80
|
+
:b => 0x01,
|
81
|
+
:c => 0x02,
|
82
|
+
:all => 0xff
|
83
|
+
}
|
84
|
+
|
85
|
+
REGULATION_MODES = {
|
86
|
+
:idle => RegulationMode.IDLE,
|
87
|
+
:motor_speed => RegulationMode.MOTOR_SPEED,
|
88
|
+
:motor_sync => RegulationMode.MOTOR_SYNC
|
89
|
+
}
|
90
|
+
|
91
|
+
RUN_STATES = {
|
92
|
+
:idle => RunState.IDLE,
|
93
|
+
:ramp_up => RunState.RAMPUP,
|
94
|
+
:running => RunState.RUNNING,
|
95
|
+
:ramp_down => RunState.RAMPDOWN
|
96
|
+
}
|
97
|
+
|
98
|
+
class << self
|
99
|
+
def ports
|
100
|
+
PORTS.keys
|
101
|
+
end
|
102
|
+
|
103
|
+
def regulation_modes
|
104
|
+
REGULATION_MODES.keys
|
105
|
+
end
|
106
|
+
|
107
|
+
def run_states
|
108
|
+
RUN_STATES.keys
|
109
|
+
end
|
110
|
+
|
111
|
+
# used with the tacho_limit
|
112
|
+
def RUN_FOREVER
|
113
|
+
0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def initialize(options={})
|
118
|
+
options = {
|
119
|
+
:port => :all,
|
120
|
+
:power => 0,
|
121
|
+
:mode_flags => 0,
|
122
|
+
:regulation_mode => :idle,
|
123
|
+
:turn_ratio => 0,
|
124
|
+
:run_state => :idle,
|
125
|
+
:tacho_limit => 0
|
126
|
+
}.merge(options)
|
127
|
+
|
128
|
+
options.keys.each do |key|
|
129
|
+
self.send("#{key}=", options[key])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def ports
|
134
|
+
self.class.ports
|
135
|
+
end
|
136
|
+
|
137
|
+
def port=(port)
|
138
|
+
raise ArgumentError, "invalid port" unless ports.include? port
|
139
|
+
|
140
|
+
@port = port
|
141
|
+
end
|
142
|
+
|
143
|
+
def for_port(the_port)
|
144
|
+
self.port = the_port
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def power=(power)
|
149
|
+
raise ArgumentError, "power must be between -100 and 100" unless power.between?(-100, 100)
|
150
|
+
@power = power
|
151
|
+
end
|
152
|
+
|
153
|
+
def with_power(power)
|
154
|
+
self.power = power
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
def mode_flags=(mode_flags)
|
159
|
+
raise ArgumentError, "mode_flags must be a valid combination of OutputModeFlags flags (using bitwise-OR)" unless mode_flags.between?(0, 7)
|
160
|
+
@mode_flags = mode_flags
|
161
|
+
end
|
162
|
+
|
163
|
+
def with_mode_flags(mode_flags)
|
164
|
+
self.mode_flags = mode_flags
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
def regulation_modes
|
169
|
+
self.class.regulation_modes
|
170
|
+
end
|
171
|
+
|
172
|
+
def regulation_mode=(regulation_mode)
|
173
|
+
raise ArgumentError, "regulation_mode must be a valid regulation mode key" unless regulation_modes.include? regulation_mode
|
174
|
+
@regulation_mode = regulation_mode
|
175
|
+
end
|
176
|
+
|
177
|
+
def with_regulation_mode(regulation_mode)
|
178
|
+
self.regulation_mode = regulation_mode
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
def turn_ratio=(turn_ratio)
|
183
|
+
raise ArgumentError, "turn_ratio must be between -100 and 100" unless turn_ratio.between?(-100, 100)
|
184
|
+
@turn_ratio = turn_ratio
|
185
|
+
end
|
186
|
+
|
187
|
+
def with_turn_ratio(turn_ratio)
|
188
|
+
self.turn_ratio = turn_ratio
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
192
|
+
def run_states
|
193
|
+
self.class.run_states
|
194
|
+
end
|
195
|
+
|
196
|
+
def run_state=(run_state)
|
197
|
+
raise ArgumentError, "run_state must be :idle, :running, :ramp_up, or :ramp_down" unless run_states.include?(run_state)
|
198
|
+
@run_state = run_state
|
199
|
+
end
|
200
|
+
|
201
|
+
def with_run_state(run_state)
|
202
|
+
self.run_state = run_state
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def tacho_limit=(tacho_limit)
|
208
|
+
@tacho_limit = tacho_limit
|
209
|
+
end
|
210
|
+
|
211
|
+
def with_tacho_limit(tacho_limit)
|
212
|
+
self.tacho_limit = tacho_limit
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
216
|
+
def as_bytes
|
217
|
+
[
|
218
|
+
PORTS[port],
|
219
|
+
power,
|
220
|
+
mode_flags,
|
221
|
+
REGULATION_MODES[regulation_mode],
|
222
|
+
turn_ratio,
|
223
|
+
RUN_STATES[run_state]
|
224
|
+
].concat(integer_as_ulong_bytes(tacho_limit))
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
end
|
229
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../direct_command'
|
2
|
+
require_relative '../message_translator'
|
3
|
+
|
4
|
+
class PlaySoundFile < DirectCommand
|
5
|
+
include MessageTranslator
|
6
|
+
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(sound_filename, loop_sound=false, require_response=true)
|
10
|
+
raise ArgumentError, "sound_filename is required" if sound_filename.nil?
|
11
|
+
|
12
|
+
super(require_response)
|
13
|
+
@command = 0x02 # playsoundfile
|
14
|
+
@name = adjust_sound_filename(sound_filename)
|
15
|
+
@loop_sound = loop_sound
|
16
|
+
end
|
17
|
+
|
18
|
+
def loop_sound?
|
19
|
+
@loop_sound == true
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_bytes
|
23
|
+
bytes = super.concat(loop_sound_as_bytes).concat(filename_as_bytes)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def loop_sound_as_bytes
|
28
|
+
boolean_as_bytes(loop_sound?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def filename_as_bytes
|
32
|
+
string_as_bytes(@name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def adjust_sound_filename(name)
|
36
|
+
add_default_extension_if_missing(name, 'rso')
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative '../direct_command'
|
2
|
+
require_relative '../message_translator'
|
3
|
+
|
4
|
+
class PlayTone < DirectCommand
|
5
|
+
include MessageTranslator
|
6
|
+
|
7
|
+
attr_reader :frequency, :duration
|
8
|
+
|
9
|
+
def initialize(frequency_hz, duration_ms, require_response=true)
|
10
|
+
super(require_response)
|
11
|
+
@command = 0x03
|
12
|
+
validate_arguments(frequency_hz, duration_ms)
|
13
|
+
@frequency = frequency_hz
|
14
|
+
@duration = duration_ms
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_bytes
|
18
|
+
super.concat(integer_as_uword_bytes(@frequency)).concat(integer_as_uword_bytes(@duration))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def validate_arguments(frequency_hz, duration_ms)
|
23
|
+
validate_frequency(frequency_hz)
|
24
|
+
validate_duration(duration_ms)
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_frequency(frequency_hz)
|
28
|
+
raise ArgumentError, "The frequency must be between 200 and 14000 Hz" unless frequency_hz.between?(200, 14000)
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_duration(duration_ms)
|
32
|
+
raise ArgumentError, "The duration in milliseconds must be a positive number or zero" unless duration_ms >= 0
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
require_relative '../../message_translator'
|
3
|
+
|
4
|
+
class GetBatteryLevelReply < DirectCommandReply
|
5
|
+
include MessageTranslator
|
6
|
+
|
7
|
+
def initialize(bytes)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
integer_from_bytes(message_bytes)
|
13
|
+
end
|
14
|
+
|
15
|
+
def millivolts
|
16
|
+
message
|
17
|
+
end
|
18
|
+
|
19
|
+
def volts
|
20
|
+
millivolts/1000.0
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def validate_bytes(bytes)
|
25
|
+
super
|
26
|
+
raise ArgumentError, "Must be a reply for GetBatteryLevel (0x0B)" unless bytes[1] == 0x0B
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
require_relative '../../message_translator'
|
3
|
+
|
4
|
+
class GetCurrentProgramNameReply < DirectCommandReply
|
5
|
+
include MessageTranslator
|
6
|
+
|
7
|
+
def initialize(bytes)
|
8
|
+
super(bytes)
|
9
|
+
@message = parse_message_bytes_into_filename
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
@message
|
14
|
+
end
|
15
|
+
|
16
|
+
def program_name
|
17
|
+
message
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def validate_bytes(bytes)
|
22
|
+
super(bytes)
|
23
|
+
raise ArgumentError, "reply must be for a GetCurrentProgramName command" unless bytes[1] == 0x11
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_message_bytes_into_filename
|
27
|
+
string_from_bytes(message_bytes)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class PlaySoundFileReply < 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 PlaySoundFile command" unless bytes[1] == 0x02
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class PlayToneReply < DirectCommandReply
|
4
|
+
def initialize(bytes)
|
5
|
+
super(bytes)
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def validate_bytes(bytes)
|
10
|
+
super(bytes)
|
11
|
+
raise ArgumentError, "must be a reply for the PlayTone command" unless bytes[1] == 0x03
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class ResetMotorPositionReply < 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 ResetMotorPosition command" unless bytes[1] == 0x0A
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative '../../direct_command_reply'
|
2
|
+
|
3
|
+
class SetInputModeReply < 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 SetInputMode command" unless bytes[1] == 0x05
|
10
|
+
end
|
11
|
+
end
|