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
@@ -1,114 +0,0 @@
|
|
1
|
-
module NXT
|
2
|
-
module Connector
|
3
|
-
module Output
|
4
|
-
class Motor
|
5
|
-
include NXT::Command::Output
|
6
|
-
extend NXT::Utils::Accessors
|
7
|
-
|
8
|
-
DURATION_TYPE = [:seconds, :degrees, :rotations].freeze
|
9
|
-
DURATION_AFTER = [:coast, :brake].freeze
|
10
|
-
DIRECTION = [:forwards, :backwards].freeze
|
11
|
-
|
12
|
-
attr_accessor :port, :interface
|
13
|
-
|
14
|
-
attr_combined_accessor :duration, 0
|
15
|
-
attr_combined_accessor :duration_type, :seconds
|
16
|
-
attr_combined_accessor :duration_after, :brake
|
17
|
-
attr_combined_accessor :direction, :forwards
|
18
|
-
|
19
|
-
attr_setter :direction, is_in: DIRECTION
|
20
|
-
attr_setter :duration_after, is_in: DURATION_AFTER
|
21
|
-
attr_setter :duration_type, is_in: DURATION_TYPE
|
22
|
-
|
23
|
-
def initialize(port, interface)
|
24
|
-
@port = port
|
25
|
-
@interface = interface
|
26
|
-
end
|
27
|
-
|
28
|
-
def duration=(duration, options = {})
|
29
|
-
raise TypeError.new('Expected duration to be a number') unless duration.is_a?(Integer)
|
30
|
-
@duration = duration
|
31
|
-
|
32
|
-
self.duration_type = options[:type] if options.include?(:type)
|
33
|
-
|
34
|
-
if options.include?(:after)
|
35
|
-
raise TypeError.new('The after option is only available when the unit duration is in seconds.') if self.duration_type != :seconds
|
36
|
-
self.duration_after = options[:after]
|
37
|
-
end
|
38
|
-
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
def forwards
|
43
|
-
self.direction = :forwards
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
def backwards
|
48
|
-
self.direction = :backwards
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def stop(type = :coast)
|
53
|
-
self.power = 0
|
54
|
-
self.mode = :coast
|
55
|
-
|
56
|
-
self.move
|
57
|
-
end
|
58
|
-
|
59
|
-
# takes block for response, or can return the response instead.
|
60
|
-
def move
|
61
|
-
response_required = (self.duration > 0 && self.duration_type != :seconds)
|
62
|
-
|
63
|
-
set_motor_output_state(response_required)
|
64
|
-
|
65
|
-
if self.duration > 0 && self.duration_type == :seconds
|
66
|
-
sleep(self.duration)
|
67
|
-
self.reset
|
68
|
-
self.stop(self.duration_after)
|
69
|
-
else
|
70
|
-
self.reset
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def reset
|
75
|
-
self.duration = 0
|
76
|
-
self.direction = :forwards
|
77
|
-
self.power = 75
|
78
|
-
self.mode = :motor_on
|
79
|
-
self.regulation_mode = :idle
|
80
|
-
self.run_state = :running
|
81
|
-
self.tacho_limit = 0
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
private
|
86
|
-
def set_motor_output_state(response_required=true)
|
87
|
-
original_tacho_limit = self.tacho_limit
|
88
|
-
adjust_tacho_limit
|
89
|
-
|
90
|
-
original_power = self.power
|
91
|
-
adjust_power
|
92
|
-
|
93
|
-
set_output_state(response_required)
|
94
|
-
|
95
|
-
self.power = original_power
|
96
|
-
self.tacho_limit = original_tacho_limit
|
97
|
-
end
|
98
|
-
|
99
|
-
def adjust_tacho_limit
|
100
|
-
case self.duration_type
|
101
|
-
when :rotations
|
102
|
-
self.tacho_limit = self.duration * 360
|
103
|
-
when :degrees
|
104
|
-
self.tacho_limit = self.duration
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def adjust_power
|
109
|
-
self.power *= -1 if self.direction == :backwards
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
data/lib/nxt/errors.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module NXT
|
2
|
-
module Errors
|
3
|
-
SUCCESS = 0x00
|
4
|
-
CODES = {
|
5
|
-
SUCCESS => 'Success',
|
6
|
-
0x20 => 'Pending communication transaction in progress',
|
7
|
-
0x40 => 'Specified mailbox queue is empty',
|
8
|
-
0xBD => 'Request failed (i.e., specified file not found)',
|
9
|
-
0xBE => 'Unknown command opcode',
|
10
|
-
0xBF => 'Insane packet',
|
11
|
-
0xC0 => 'Data contains out-of-range values',
|
12
|
-
0xDD => 'Communication bus error',
|
13
|
-
0xDE => 'No free memory in communication buffer',
|
14
|
-
0xDF => 'Specified channel/connection is not valid',
|
15
|
-
0xE0 => 'Specified channel/connection not configured or busy',
|
16
|
-
0xEC => 'No active program',
|
17
|
-
0xED => 'Illegal size specified',
|
18
|
-
0xEE => 'Illegal mailbox queue ID specified',
|
19
|
-
0xEF => 'Attempted to access invalid field of a structure',
|
20
|
-
0xF0 => 'Bad input or output specified',
|
21
|
-
0xFB => 'Insufficient memory available',
|
22
|
-
0xFF => 'Bad arguments'
|
23
|
-
}
|
24
|
-
end
|
25
|
-
end
|
data/lib/nxt/exceptions.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module NXT
|
2
|
-
module Exceptions
|
3
|
-
# Raised when a class has not implemented a method from the base class
|
4
|
-
# that is required to be overriden.
|
5
|
-
class InterfaceNotImplemented < NotImplementedError; end
|
6
|
-
|
7
|
-
# Raised when an invalid interface is attempted to be constructed.
|
8
|
-
class InvalidInterfaceError < TypeError; end
|
9
|
-
|
10
|
-
# Raised when a port is attempted to be named when it already has been.
|
11
|
-
class PortTakenError < TypeError; end
|
12
|
-
|
13
|
-
# Raised when an invalid name is attempted to be given to a port.
|
14
|
-
class InvalidIdentifierError < TypeError; end
|
15
|
-
|
16
|
-
# Raised when the device file attempted to be used for communication is
|
17
|
-
# for whatever reason does not exist or is not correct.
|
18
|
-
class InvalidDeviceError < TypeError; end
|
19
|
-
|
20
|
-
# Raised when communication with a Serial Port connection fails.
|
21
|
-
class SerialPortConnectionError < RuntimeError; end
|
22
|
-
|
23
|
-
# Raised when a command returns a reply message error
|
24
|
-
class CommandError < RuntimeError; end
|
25
|
-
end
|
26
|
-
end
|
data/lib/nxt/interfaces/base.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require_relative '../commands/base' #TODO: bad code smell here
|
2
|
-
|
3
|
-
module NXT
|
4
|
-
module Interface
|
5
|
-
class Base
|
6
|
-
def send_and_receive(msg, response_required = true)
|
7
|
-
if response_required
|
8
|
-
msg[0] = msg[0] | (response_required ? 0x00 : 0x80)
|
9
|
-
end
|
10
|
-
|
11
|
-
self.send(msg)
|
12
|
-
|
13
|
-
if response_required
|
14
|
-
response = self.receive
|
15
|
-
response
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def send
|
20
|
-
raise InterfaceNotImplemented.new('The #send method must be implemented.')
|
21
|
-
end
|
22
|
-
|
23
|
-
def receive
|
24
|
-
raise InterfaceNotImplemented.new('The #receive method must be implemented.')
|
25
|
-
end
|
26
|
-
|
27
|
-
def connect
|
28
|
-
raise InterfaceNotImplemented.new('The #connect method must be implemented')
|
29
|
-
end
|
30
|
-
|
31
|
-
def disconnect
|
32
|
-
raise InterfaceNotImplemented.new('The #disconnect method must be implemented')
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'serialport'
|
2
|
-
|
3
|
-
module NXT
|
4
|
-
module Interface
|
5
|
-
class SerialPort < Base
|
6
|
-
include NXT::Exceptions
|
7
|
-
|
8
|
-
attr_reader :dev
|
9
|
-
|
10
|
-
BAUD_RATE = 57600
|
11
|
-
DATA_BITS = 8
|
12
|
-
STOP_BITS = 1
|
13
|
-
PARITY = ::SerialPort::NONE
|
14
|
-
READ_TIMEOUT = 5000
|
15
|
-
|
16
|
-
def initialize(dev)
|
17
|
-
self.dev = (dev)
|
18
|
-
end
|
19
|
-
|
20
|
-
def dev=(dev)
|
21
|
-
raise InvalidDeviceError unless File.exists?(dev)
|
22
|
-
@dev = dev
|
23
|
-
end
|
24
|
-
|
25
|
-
def connect
|
26
|
-
@connection = ::SerialPort.new(@dev, BAUD_RATE, DATA_BITS, STOP_BITS, PARITY)
|
27
|
-
|
28
|
-
if !@connection.nil?
|
29
|
-
@connection.flow_control = ::SerialPort::HARD
|
30
|
-
@connection.read_timeout = READ_TIMEOUT
|
31
|
-
else
|
32
|
-
raise SerialPortConnectionError.new("Could not establish a SerialPort connection to #{dev}")
|
33
|
-
end
|
34
|
-
|
35
|
-
@connection
|
36
|
-
rescue ArgumentError
|
37
|
-
raise SerialPortConnectionError.new("The #{dev} device is not a valid SerialPort")
|
38
|
-
end
|
39
|
-
|
40
|
-
def disconnect
|
41
|
-
@connection.close if @connection && !@connection.closed?
|
42
|
-
end
|
43
|
-
|
44
|
-
def connected?
|
45
|
-
!@connection.closed?
|
46
|
-
end
|
47
|
-
|
48
|
-
def send(msg)
|
49
|
-
# The expected data package structure for NXT Bluetooth communication is:
|
50
|
-
#
|
51
|
-
# [Length Byte 1, Length Byte 2, Command Type, Command, ...]
|
52
|
-
#
|
53
|
-
# So here we calculate the two leading length bytes, and rely on the
|
54
|
-
# passed in argument to give us the rest of the message to send.
|
55
|
-
#
|
56
|
-
# Note that the length is stored in Little Endian ie. LSB -> MSB
|
57
|
-
#
|
58
|
-
# Reference: Appendix 1, Page 22
|
59
|
-
msg = [(msg.length & 255), (msg.length >> 8)] + msg
|
60
|
-
|
61
|
-
msg.each do |b|
|
62
|
-
@connection.putc(b)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def receive
|
67
|
-
# This gets the length of the received data from the header that was sent
|
68
|
-
# to us. We unpack it, as it's stored as a 16-bit Little Endian number.
|
69
|
-
#
|
70
|
-
# Reference: Appendix 1, Page 22
|
71
|
-
length = @connection.sysread(2)
|
72
|
-
actual_length = length.unpack('v')[0]
|
73
|
-
response_bytes = @connection.sysread(actual_length)
|
74
|
-
response_array = response_bytes.unpack('C*')
|
75
|
-
response = {
|
76
|
-
:reply => response_array[0] == 0x02,
|
77
|
-
:for_command => response_array[1],
|
78
|
-
:status => response_array[2]
|
79
|
-
}
|
80
|
-
response[:message] = NXT::Errors::CODES[response[:status]]
|
81
|
-
response[:for_command_name] = NXT::Command::Base::COMMANDS[response[:for_command]]
|
82
|
-
response[:data] = response_array[3..-1] if response_array.size > 3
|
83
|
-
|
84
|
-
response
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
data/lib/nxt/interfaces/usb.rb
DELETED
data/lib/nxt/nxt_brick.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
# This class is the entry point for end-users creating their own list of
|
2
|
-
# commands to execute remotely on a Lego NXT brick.
|
3
|
-
#
|
4
|
-
# An instance of this class provides all the endpoints necessary to:
|
5
|
-
#
|
6
|
-
# * educate the API on the connected input and output devices; and,
|
7
|
-
# * access these input and output devices and run commands using them.
|
8
|
-
#
|
9
|
-
# @example Creating an instance using a block, with one motor output.
|
10
|
-
#
|
11
|
-
# NXTBrick.new(interface) do |nxt|
|
12
|
-
# nxt.add_motor_output(:a, :front_left)
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# @example Creating an instance without a block, with one motor and one light sensor.
|
16
|
-
#
|
17
|
-
# nxt = NXTBrick.new(interface)
|
18
|
-
# nxt.add_motor_output(:a, :front_left)
|
19
|
-
# # ...
|
20
|
-
# nxt.disconnect
|
21
|
-
class NXTBrick
|
22
|
-
include NXT::Exceptions
|
23
|
-
|
24
|
-
# An enumeration of possible ports, both input and output, that the NXT brick
|
25
|
-
# can have connectors attached to.
|
26
|
-
PORTS = [:a, :b, :c, :one, :two, :three, :four]
|
27
|
-
|
28
|
-
# Get the instance of the interface that this runner class is using to connect
|
29
|
-
# to the NXT brick.
|
30
|
-
attr_accessor :interface
|
31
|
-
|
32
|
-
# Accessors for output ports on the NXT brick. These will be populated with
|
33
|
-
# the appropriate instances of their respective output connectors.
|
34
|
-
attr_reader :a, :b, :c
|
35
|
-
|
36
|
-
# Accessors for input ports on the NXT brick. These will be populated with the
|
37
|
-
# appropriate instances of their respective input connectors.
|
38
|
-
attr_reader :one, :two, :three, :four
|
39
|
-
|
40
|
-
# We mandate that all added port connections have an identifier associated
|
41
|
-
# with it. This is so that code is not fragile when port swapping needs to
|
42
|
-
# be done.
|
43
|
-
attr_reader :port_identifiers
|
44
|
-
|
45
|
-
def initialize(interface_type, *interface_args)
|
46
|
-
@port_identifiers = {}
|
47
|
-
interface_type = interface_type.to_s.classify
|
48
|
-
|
49
|
-
validate_interface(interface_type)
|
50
|
-
self.interface = NXT::Interface.const_get(interface_type).new(*interface_args)
|
51
|
-
|
52
|
-
if block_given?
|
53
|
-
begin
|
54
|
-
self.connect
|
55
|
-
yield(self)
|
56
|
-
ensure
|
57
|
-
self.disconnect
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# Connect using the given interface to the NXT brick.
|
63
|
-
def connect
|
64
|
-
self.interface.connect
|
65
|
-
end
|
66
|
-
|
67
|
-
# Close the connection to the NXT brick, and dispose of any resources that
|
68
|
-
# this instance of NXTBrick is using. Any commands run against this runner
|
69
|
-
# after calling disconnect will fail.
|
70
|
-
def disconnect
|
71
|
-
self.interface.disconnect
|
72
|
-
end
|
73
|
-
|
74
|
-
# Add a new connector instance, binding a specific identifier to the given
|
75
|
-
# port.
|
76
|
-
#
|
77
|
-
# If the given port already is bound, an exception will be thrown. The
|
78
|
-
# instance given though can be of any class, presuming it talks the
|
79
|
-
# correct language.
|
80
|
-
#
|
81
|
-
# @param Symbol port The port to bind to.
|
82
|
-
# @param Symbol identifier The identifier to associate with this port.
|
83
|
-
# @param Class klass The Class to instantiate as the instance of this
|
84
|
-
# port. There is no limitation on what type this can
|
85
|
-
# be, though it must be able to hook in correctly
|
86
|
-
# with the NXT library.
|
87
|
-
def add(port, identifier, klass)
|
88
|
-
raise TypeError.new('Expected port to be a Symbol') unless port.is_a?(Symbol)
|
89
|
-
raise TypeError.new('Expected identifier to be a Symbol') unless identifier.is_a?(Symbol)
|
90
|
-
raise TypeError.new('Expected klass to be a Class') unless klass.is_a?(Class)
|
91
|
-
|
92
|
-
unless PORTS.include?(port)
|
93
|
-
raise TypeError.new("Expected port to be one of: :#{PORTS.join(', :')}")
|
94
|
-
end
|
95
|
-
|
96
|
-
port_variable = :"@#{port}"
|
97
|
-
|
98
|
-
if !self.respond_to?(identifier)
|
99
|
-
# Makes a new instance of the class and pushes it into our instance variable
|
100
|
-
# for the given port.
|
101
|
-
self.instance_variable_set(port_variable, klass.new(port, self.interface))
|
102
|
-
|
103
|
-
# Given that that succeeded, all that remains is to add the identifier
|
104
|
-
# to our lookup Hash. We'll use this Hash later on within method_missing.
|
105
|
-
@port_identifiers[identifier] = port
|
106
|
-
|
107
|
-
# Define a method on the eigenclass of this instance.
|
108
|
-
(class << self; self; end).send(:define_method, identifier) do
|
109
|
-
self.instance_variable_get(port_variable)
|
110
|
-
end
|
111
|
-
else
|
112
|
-
if !self.instance_variable_get(port_variable).nil?
|
113
|
-
raise PortTakenError.new("Port #{port} is already set, call remove first")
|
114
|
-
else
|
115
|
-
raise InvalidIdentifierError.new("Cannot use identifier #{identifier}, a method on #{self.class} is already using it.")
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Remove the assigned (if any) connector instance from the given
|
121
|
-
# identifier.
|
122
|
-
#
|
123
|
-
# @param Symbol identifier The identifier to search for and remove.
|
124
|
-
def remove(identifier)
|
125
|
-
raise TypeError.new('Expected identifier to be a Symbol') unless identifier.is_a?(Symbol)
|
126
|
-
!!@port_identifiers.delete(identifier)
|
127
|
-
end
|
128
|
-
|
129
|
-
# This will dynamically add methods like:
|
130
|
-
#
|
131
|
-
# * add_light_input
|
132
|
-
# * add_motor_output
|
133
|
-
# * add_ultrasonic_input
|
134
|
-
#
|
135
|
-
# This means they don't have to provide the class each and every time. For
|
136
|
-
# connectors they have added themselves, it's likely best to use the
|
137
|
-
# {#add} method.
|
138
|
-
NXT::Connector.constants.each do |type_const|
|
139
|
-
NXT::Connector.const_get(type_const).constants.each do |const|
|
140
|
-
# We don't use a splat here for the args, because that way when
|
141
|
-
# people don't pass in the correct number of params, it says helpfully
|
142
|
-
# '1 of 2' args passed (or something similar).
|
143
|
-
define_method("add_#{const.to_s.underscore}_#{type_const.to_s.underscore}") do |port, identifier|
|
144
|
-
self.add(port, identifier, NXT::Connector.const_get(type_const).const_get(const))
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def start_program(name)
|
150
|
-
NXT::Command::Output::Program.start(self.interface, name)
|
151
|
-
end
|
152
|
-
|
153
|
-
def stop_program
|
154
|
-
NXT::Command::Output::Program.stop(self.interface)
|
155
|
-
end
|
156
|
-
|
157
|
-
def running_program_name
|
158
|
-
NXT::Command::Output::Program.get_running_name(self.interface)
|
159
|
-
end
|
160
|
-
|
161
|
-
private
|
162
|
-
def validate_interface(interface_type_name_string)
|
163
|
-
unless NXT::Interface.constants.include?(interface_type_name_string.to_sym)
|
164
|
-
raise InvalidInterfaceError.new("There is no interface of type #{interface_type_name_string}.")
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|