ruby-nxt 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +340 -0
- data/README +49 -0
- data/examples/commands.rb +180 -0
- data/examples/drb_client.rb +11 -0
- data/examples/drb_server.rb +40 -0
- data/examples/mary.rb +78 -0
- data/examples/move_by_degrees.rb +42 -0
- data/examples/nxt_comm_demo.rb +65 -0
- data/examples/nxt_remote_control.rb +70 -0
- data/examples/socket_server.rb +37 -0
- data/lib/autodetect_nxt.rb +36 -0
- data/lib/brick.rb +53 -0
- data/lib/commands.rb +40 -0
- data/lib/commands/light_sensor.rb +82 -0
- data/lib/commands/mixins/motor.rb +84 -0
- data/lib/commands/mixins/sensor.rb +38 -0
- data/lib/commands/motor.rb +136 -0
- data/lib/commands/move.rb +210 -0
- data/lib/commands/rotation_sensor.rb +72 -0
- data/lib/commands/sound.rb +102 -0
- data/lib/commands/sound_sensor.rb +67 -0
- data/lib/commands/touch_sensor.rb +84 -0
- data/lib/commands/ultrasonic_sensor.rb +84 -0
- data/lib/motor.rb +235 -0
- data/lib/nxt.rb +189 -0
- data/lib/nxt_comm.rb +596 -0
- data/lib/sensors/light_sensor.rb +45 -0
- data/lib/sensors/sensor.rb +93 -0
- data/lib/sensors/sound_sensor.rb +48 -0
- data/lib/sensors/touch_sensor.rb +35 -0
- data/lib/sensors/ultrasonic_sensor.rb +95 -0
- data/lib/ultrasonic_comm.rb +102 -0
- data/test/bt_test.rb +10 -0
- data/test/interactive/interactive_test_helper.rb +89 -0
- data/test/interactive/test_sensors.rb +236 -0
- data/test/test.rb +22 -0
- data/test/test_helper.rb +1 -0
- data/test/unit/motor_test.rb +177 -0
- data/test/unit/nxt_comm_test.rb +155 -0
- data/test/unit/nxt_test.rb +60 -0
- metadata +95 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class LightSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_3)
|
24
|
+
super(nxt, port)
|
25
|
+
use_illuminated_mode
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the current light level as a float from 0 to 1.0.
|
29
|
+
# 1.0 is maximum, 0 is minimum.
|
30
|
+
def get_light_level
|
31
|
+
# TODO: probably need to calibrate this... light level never really reaches 1023
|
32
|
+
(read_data[:value_scaled]).to_f / 1023.to_f
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def use_illuminated_mode
|
37
|
+
set_input_mode(NXTComm::LIGHT_ACTIVE, NXTComm::RAWMODE)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def use_ambient_mode
|
42
|
+
set_input_mode(NXTComm::LIGHT_INACTIVE, NXTComm::RAWMODE)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/../brick'
|
20
|
+
|
21
|
+
# Controls and reads an NXT sensor.
|
22
|
+
class Sensor < Brick
|
23
|
+
|
24
|
+
POLL_INTERVAL = 0.25
|
25
|
+
|
26
|
+
# TODO: internal sensor numbering is 0x00 to 0x03, but sensor ports on the brick are marked 1 to 4...
|
27
|
+
# need to come up with some way to make sure there isn't confusion (or maybe it's okay, since
|
28
|
+
# if the user probably never uses the Sensor classes directly, only interacting via the NXT
|
29
|
+
# class?)
|
30
|
+
|
31
|
+
|
32
|
+
def initialize(nxt, port)
|
33
|
+
super(nxt, port)
|
34
|
+
@port = port
|
35
|
+
end
|
36
|
+
|
37
|
+
def name
|
38
|
+
"#{@port + 1}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_input_mode(type, mode)
|
42
|
+
@nxt.set_input_mode(@port, type, mode)
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_data
|
46
|
+
data = @nxt.get_input_values(@port)
|
47
|
+
|
48
|
+
debug(data.inspect, :read_data)
|
49
|
+
return data
|
50
|
+
end
|
51
|
+
|
52
|
+
# Continuously evalutes the given block until it returns at
|
53
|
+
# least the given value (that is, until the block returns a
|
54
|
+
# value equal or greater than the given argument). If no
|
55
|
+
# value is specified, the block will be continuously
|
56
|
+
# evaluated until it returns true. Optionally, a comparison
|
57
|
+
# operator can be specified as the second parameter,
|
58
|
+
# otherwise >= is used (or == if expected value is Boolean).
|
59
|
+
#
|
60
|
+
# Simple example:
|
61
|
+
#
|
62
|
+
# ts = TouchSensor.new(@nxt)
|
63
|
+
# ts.wait_for_event { ts.is_pressed? }
|
64
|
+
#
|
65
|
+
# Example with an expected value:
|
66
|
+
#
|
67
|
+
# ls = LightSensor.new(@nxt)
|
68
|
+
# ls.wait_for_event(0.55) do
|
69
|
+
# ls.get_light_level
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
def wait_for_event(expected = true, operator = nil)
|
73
|
+
if operator
|
74
|
+
comp = operator
|
75
|
+
elsif expected.respond_to? '>='.intern
|
76
|
+
comp = ">="
|
77
|
+
else
|
78
|
+
comp = "=="
|
79
|
+
end
|
80
|
+
|
81
|
+
while true
|
82
|
+
value = yield
|
83
|
+
return value if eval("value #{comp} expected")
|
84
|
+
sleep(POLL_INTERVAL)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def off
|
89
|
+
# Turns off the sensor.
|
90
|
+
set_input_mode(NXTComm::NO_SENSOR, NXTComm::RAWMODE)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class SoundSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_2)
|
24
|
+
super(nxt, port)
|
25
|
+
use_adjusted_mode
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the current sound level as a float from 0 to 1.0.
|
29
|
+
# 1.0 is maximum, 0 is minimum.
|
30
|
+
def get_sound_level
|
31
|
+
# TODO: should probably do some basic calibration here...
|
32
|
+
read_data[:value_normal] / 1023.to_f
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sound level measurement is NOT adjusted to match the psychoacoustic properties
|
36
|
+
# of human hearing. Sounds that may not be loud to the human ear may show up as loud
|
37
|
+
# and vice versa.
|
38
|
+
def use_unadjusted_mode
|
39
|
+
set_input_mode(NXTComm::SOUND_DB, NXTComm::RAWMODE)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sound level measurement is adjusted to match the psychoacoustic properties of
|
43
|
+
# human hearing. This is on by default.
|
44
|
+
def use_adjusted_mode
|
45
|
+
set_input_mode(NXTComm::SOUND_DBA, NXTComm::RAWMODE)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class TouchSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_1)
|
24
|
+
super(nxt, port)
|
25
|
+
set_input_mode(NXTComm::SWITCH, NXTComm::BOOLEANMODE)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if the touch sensor is pressed, false otherwise.
|
29
|
+
# (The sensor seems to read as "pressed" when it is pushed in about half way)
|
30
|
+
def is_pressed?
|
31
|
+
read_data[:value_scaled] > 0
|
32
|
+
end
|
33
|
+
alias_method :pressed?, :is_pressed?
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
#
|
17
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
18
|
+
require File.dirname(File.expand_path(__FILE__))+'/../ultrasonic_comm'
|
19
|
+
|
20
|
+
class UltrasonicSensor < Sensor
|
21
|
+
|
22
|
+
INCHES_PER_CM = 0.3937008
|
23
|
+
|
24
|
+
def initialize(nxt, port = NXTComm::SENSOR_4)
|
25
|
+
super(nxt, port)
|
26
|
+
|
27
|
+
# The Ultrasonic sensor is digital and unlike the other sensors it
|
28
|
+
# uses the lowspeed communication protocol.
|
29
|
+
set_input_mode(NXTComm::LOWSPEED_9V, NXTComm::RAWMODE)
|
30
|
+
|
31
|
+
# Read the sensor in case there was some garbage data in the buffer waiting to be read
|
32
|
+
@nxt.ls_read(@port)
|
33
|
+
|
34
|
+
# Set the sensor to continuously send pings
|
35
|
+
@nxt.ls_write(@port, UltrasonicComm.continuous_measurement_command)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return the measured distance in the default units (the default units being centimeters).
|
39
|
+
# A value of 255 is returned when the sensor cannot get an accurate reading (because
|
40
|
+
# the object is out of range, or there is too much interference, etc.)
|
41
|
+
# Note that the sensor's real-world range is at best 175 cm. At larger distances it
|
42
|
+
# will almost certainly just return 255.
|
43
|
+
def get_distance
|
44
|
+
@nxt.ls_write(@port, UltrasonicComm.read_measurement_byte(0))
|
45
|
+
|
46
|
+
# Keep checking until we have 1 byte of data to read
|
47
|
+
while @nxt.ls_get_status(@port)[0] < 1
|
48
|
+
sleep(0.1)
|
49
|
+
@nxt.ls_write(@port, UltrasonicComm.read_measurement_byte(0))
|
50
|
+
# TODO: implement timeout so we don't get stuck if the expected data never comes
|
51
|
+
end
|
52
|
+
|
53
|
+
resp = @nxt.ls_read(@port)
|
54
|
+
# TODO: probably need a better error message here...
|
55
|
+
raise "ls_read returned more than one byte!" if resp[:bytes_read] > 1
|
56
|
+
raise "ls_read did not return any data!" if resp[:bytes_read] < 1
|
57
|
+
|
58
|
+
# If the sensor cannot determine the distance, it will return
|
59
|
+
# 0xff (255)... this usually means that the object is out of
|
60
|
+
# sensor range, but it can also mean that there is too much
|
61
|
+
# interference or that the object is too close to the sensor.
|
62
|
+
# I considered returning nil or false under such cases, but
|
63
|
+
# this makes numeric comparison (i.e. greather than/less than)
|
64
|
+
# more difficult
|
65
|
+
d = resp[:data][0]
|
66
|
+
end
|
67
|
+
alias_method :get_distance_in_cm, :get_distance
|
68
|
+
|
69
|
+
# Return the measured distance in inches.
|
70
|
+
def get_distance_in_inches
|
71
|
+
get_distance.to_f * INCHES_PER_CM
|
72
|
+
end
|
73
|
+
|
74
|
+
# Same as get_distance, but raises an UnmeasurableDistance
|
75
|
+
# exception when the sensor cannot accurately determine
|
76
|
+
# the distance.
|
77
|
+
def get_distance!
|
78
|
+
d = get_distance
|
79
|
+
if d == 255
|
80
|
+
raise UnmeasurableDistance
|
81
|
+
else
|
82
|
+
return d
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias_method :get_distance_in_cm!, :get_distance!
|
86
|
+
|
87
|
+
def get_distance_in_inches!
|
88
|
+
get_distance!.to_f * INCHES_PER_CM
|
89
|
+
end
|
90
|
+
|
91
|
+
# Exception thrown by get_distance! and related methods when
|
92
|
+
# the sensor cannot determine the distance.
|
93
|
+
class UnmeasurableDistance < Exception; end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
|
18
|
+
# Low-level interface for communicating with the NXT's Ultrasonic
|
19
|
+
# sensor. Unlike the other sensors, the Ultrasonic sensor is digital
|
20
|
+
# and uses the low-speed I2C protocol for communication. This is
|
21
|
+
# defined in Appendix 7 of the Lego Mindstorms NXT SDK.
|
22
|
+
class UltrasonicComm
|
23
|
+
|
24
|
+
@@i2c_dev = 0x02
|
25
|
+
|
26
|
+
# first value is the i2c address, second value is the expected number of bytes returned
|
27
|
+
@@const_codes = {
|
28
|
+
'read_version' => [0x00, 8],
|
29
|
+
'read_product_id' => [0x08, 8],
|
30
|
+
'read_sensor_type' => [0x10, 8],
|
31
|
+
'read_factory_zero' => [0x11, 1],
|
32
|
+
'read_factory_scale_factor' => [0x12, 1],
|
33
|
+
'read_factory_scale_divisor' => [0x13, 1],
|
34
|
+
'read_measurement_units' => [0x14, 7],
|
35
|
+
}
|
36
|
+
|
37
|
+
# value is the i2c address (all of these ops always expect to return 1 byte)
|
38
|
+
@@var_codes = {
|
39
|
+
'read_continuous_measurements_interval' => 0x40,
|
40
|
+
'read_command_state' => 0x41,
|
41
|
+
'read_measurement_byte_0' => 0x42,
|
42
|
+
'read_measurement_byte_1' => 0x43,
|
43
|
+
'read_measurement_byte_2' => 0x44,
|
44
|
+
'read_measurement_byte_3' => 0x45,
|
45
|
+
'read_measurement_byte_4' => 0x46,
|
46
|
+
'read_measurement_byte_5' => 0x47,
|
47
|
+
'read_measurement_byte_6' => 0x48,
|
48
|
+
'read_measurement_byte_7' => 0x49,
|
49
|
+
'read_actual_zero' => 0x50,
|
50
|
+
'read_actual_scale_factor' => 0x51,
|
51
|
+
'read_actual_scale_divisor' => 0x52,
|
52
|
+
}
|
53
|
+
|
54
|
+
# first value is the i2c address, second value is the command
|
55
|
+
@@cmd_codes = {
|
56
|
+
'off_command' => [0x41, 0x00],
|
57
|
+
'single_shot_command' => [0x41, 0x01],
|
58
|
+
'continuous_measurement_command' => [0x41, 0x02],
|
59
|
+
'event_capture_command' => [0x41, 0x03],
|
60
|
+
'request_warm_reset' => [0x41, 0x04],
|
61
|
+
'set_continuous_measurement_interval' => [0x40],
|
62
|
+
'set_actual_zero' => [0x50],
|
63
|
+
'set_actual_scale_factor' => [0x51],
|
64
|
+
'set_actual_scale_divisor' => [0x52]
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
def self.read_measurement_byte(num)
|
69
|
+
eval "self.read_measurement_byte_#{num}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.method_missing(name, *args)
|
73
|
+
name = name.to_s
|
74
|
+
if @@const_codes.has_key? name
|
75
|
+
type = :const
|
76
|
+
op = @@const_codes[name]
|
77
|
+
addr = op[0]
|
78
|
+
rx_len = op[1]
|
79
|
+
elsif @@var_codes.has_key? name
|
80
|
+
type = :var
|
81
|
+
op = @@var_codes[name]
|
82
|
+
addr = op
|
83
|
+
rx_len = 1
|
84
|
+
elsif @@cmd_codes.has_key? name
|
85
|
+
type = :cmd
|
86
|
+
op = @@cmd_codes[name]
|
87
|
+
addr = op[0]
|
88
|
+
if op[1] then value = op[1]
|
89
|
+
elsif args[0] then value = args[0]
|
90
|
+
else raise "Missing argument for command #{name}" end
|
91
|
+
rx_len = 0
|
92
|
+
else
|
93
|
+
raise "Unknown ultrasonic sensor command: #{name}"
|
94
|
+
end
|
95
|
+
|
96
|
+
data = [@@i2c_dev, addr]
|
97
|
+
data += [value] if type == :cmd
|
98
|
+
|
99
|
+
[data.size, rx_len] + data
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
data/test/bt_test.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'rubygems'
|
19
|
+
require_gem "term-ansicolor"
|
20
|
+
$COLOUR = true
|
21
|
+
rescue LoadError
|
22
|
+
$COLOUR = false
|
23
|
+
puts "Please install term-ansicolor gem to get colour output."
|
24
|
+
puts "Colour output will be disabled..."
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
module InteractiveTestHelper
|
29
|
+
def info(msg)
|
30
|
+
msg = Term::ANSIColor.white(msg) if $COLOUR
|
31
|
+
puts "#{msg}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def notice(msg)
|
35
|
+
msg = Term::ANSIColor.yellow(msg) if $COLOUR
|
36
|
+
puts "#{msg}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def prompt(msg)
|
40
|
+
msg = Term::ANSIColor.cyan(msg) if $COLOUR
|
41
|
+
puts "#{msg}"
|
42
|
+
return gets
|
43
|
+
end
|
44
|
+
|
45
|
+
def pass(msg)
|
46
|
+
msg = Term::ANSIColor.green(msg) if $COLOUR
|
47
|
+
msg = Term::ANSIColor.bold(msg) if $COLOUR
|
48
|
+
puts "#{msg}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def fail(msg)
|
52
|
+
msg = Term::ANSIColor.red(msg) if $COLOUR
|
53
|
+
msg = Term::ANSIColor.red(msg) if $COLOUR
|
54
|
+
puts "#{msg}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def puts_sameline(msg)
|
58
|
+
puts "#{msg}"
|
59
|
+
puts "\e[2A"
|
60
|
+
end
|
61
|
+
|
62
|
+
def meter(value, label = "Level", threshold = nil, max = 100, min = 0)
|
63
|
+
width = 40
|
64
|
+
if value.nil?
|
65
|
+
bars = "?" * width
|
66
|
+
spaces = ""
|
67
|
+
percent_formatted = " ??? "
|
68
|
+
else
|
69
|
+
if value >= max
|
70
|
+
percent = 1.0
|
71
|
+
else
|
72
|
+
percent = ((value - min) / max.to_f)
|
73
|
+
end
|
74
|
+
bars = "|" * (percent * width)
|
75
|
+
spaces = " " * ((1 - percent) * width)
|
76
|
+
|
77
|
+
percent_formatted = "%5.1f" % (percent * 100)
|
78
|
+
end
|
79
|
+
meterbar = bars + spaces
|
80
|
+
|
81
|
+
if threshold
|
82
|
+
threshold_pos = (((threshold - min) / max.to_f) * 40).to_i
|
83
|
+
meterbar[threshold_pos] = "!"
|
84
|
+
end
|
85
|
+
|
86
|
+
puts_sameline " #{label}: (#{percent_formatted}%) [#{min}]#{meterbar}[#{max}]"
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|