crubyflie 0.1.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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +99 -0
- data/Rakefile +15 -0
- data/bin/crubyflie +85 -0
- data/configs/joystick_default.yaml +48 -0
- data/crubyflie.gemspec +50 -0
- data/examples/params_and_logging.rb +87 -0
- data/lib/crubyflie/crazyflie/commander.rb +54 -0
- data/lib/crubyflie/crazyflie/console.rb +67 -0
- data/lib/crubyflie/crazyflie/log.rb +383 -0
- data/lib/crubyflie/crazyflie/log_conf.rb +57 -0
- data/lib/crubyflie/crazyflie/param.rb +220 -0
- data/lib/crubyflie/crazyflie/toc.rb +239 -0
- data/lib/crubyflie/crazyflie/toc_cache.rb +87 -0
- data/lib/crubyflie/crazyflie.rb +282 -0
- data/lib/crubyflie/crazyradio/crazyradio.rb +301 -0
- data/lib/crubyflie/crazyradio/radio_ack.rb +48 -0
- data/lib/crubyflie/crubyflie_logger.rb +74 -0
- data/lib/crubyflie/driver/crtp_packet.rb +146 -0
- data/lib/crubyflie/driver/radio_driver.rb +333 -0
- data/lib/crubyflie/exceptions.rb +36 -0
- data/lib/crubyflie/input/input_reader.rb +168 -0
- data/lib/crubyflie/input/joystick_input_reader.rb +280 -0
- data/lib/crubyflie/version.rb +22 -0
- data/lib/crubyflie.rb +31 -0
- data/spec/commander_spec.rb +67 -0
- data/spec/console_spec.rb +76 -0
- data/spec/crazyflie_spec.rb +176 -0
- data/spec/crazyradio_spec.rb +226 -0
- data/spec/crtp_packet_spec.rb +79 -0
- data/spec/crubyflie_logger_spec.rb +39 -0
- data/spec/crubyflie_spec.rb +20 -0
- data/spec/input_reader_spec.rb +136 -0
- data/spec/joystick_cfg.yaml +48 -0
- data/spec/joystick_input_reader_spec.rb +238 -0
- data/spec/log_spec.rb +266 -0
- data/spec/param_spec.rb +166 -0
- data/spec/radio_ack_spec.rb +43 -0
- data/spec/radio_driver_spec.rb +227 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/toc_cache_spec.rb +87 -0
- data/spec/toc_spec.rb +187 -0
- data/tools/sdl-joystick-axis.rb +69 -0
- metadata +222 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
require 'input/joystick_input_reader'
|
20
|
+
|
21
|
+
describe Joystick do
|
22
|
+
|
23
|
+
before :each do
|
24
|
+
@sdl_joystick = double("Joystick")
|
25
|
+
allow(SDL::Joystick).to receive(:update_all)
|
26
|
+
allow(SDL).to receive(:init).with(SDL::INIT_JOYSTICK)
|
27
|
+
allow(SDL::Joystick).to receive(:num).and_return(3)
|
28
|
+
allow(SDL::Joystick).to receive(:open).and_return(@sdl_joystick)
|
29
|
+
allow(SDL::Joystick).to receive(:index_name).and_return("My Joystick")
|
30
|
+
allow(SDL::Joystick).to receive(:poll).with(false)
|
31
|
+
expect(SDL::Joystick).not_to receive(:poll).with(true)
|
32
|
+
@path = File.join(File.dirname(__FILE__), 'joystick_cfg.yaml')
|
33
|
+
|
34
|
+
@joystick = Joystick.new(@path)
|
35
|
+
|
36
|
+
@logger = @joystick.logger
|
37
|
+
allow(@logger).to receive(:info)
|
38
|
+
@joystick.init()
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#initialize" do
|
42
|
+
it "should initialize a valid joystick supposing things go well" do
|
43
|
+
@joystick.axis.should == {
|
44
|
+
0 => :roll,
|
45
|
+
1 => :pitch,
|
46
|
+
2 => :yaw,
|
47
|
+
3 => :thrust
|
48
|
+
}
|
49
|
+
|
50
|
+
@joystick.buttons.should == {
|
51
|
+
0 => :switch_xmode,
|
52
|
+
1 => :close_link
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#read_configuration" do
|
58
|
+
it "should read a configuration correctly" do
|
59
|
+
cfg = {
|
60
|
+
:type => "Joystick",
|
61
|
+
:axis => {0 => {:action => :yaw}},
|
62
|
+
:buttons => {0 => {:action => :roll}}
|
63
|
+
}
|
64
|
+
expect(YAML).to receive(:load_file).and_return(cfg)
|
65
|
+
|
66
|
+
axis, buttons = @joystick.read_configuration('path')
|
67
|
+
@joystick.config[:type].should == "Joystick"
|
68
|
+
axis.should == { 0 => :yaw }
|
69
|
+
buttons.should == { 0 => :roll }
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise exception if it cannot load the configuration" do
|
73
|
+
expect {
|
74
|
+
@joystick.read_configuration('baa')
|
75
|
+
}.to raise_exception(JoystickException)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should raise exception if the configuration type is bad" do
|
79
|
+
cfg = {
|
80
|
+
:type => "BBOBOBO",
|
81
|
+
:axis => {0 => {:action => :yaw}},
|
82
|
+
:buttons => {0 => {:action => :roll}}
|
83
|
+
}
|
84
|
+
expect(YAML).to receive(:load_file).and_return(cfg)
|
85
|
+
m = "Configuration is not of type Joystick"
|
86
|
+
expect {
|
87
|
+
@joystick.read_configuration('baa')
|
88
|
+
}.to raise_exception(JoystickException, m)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should raise exception if the axis or buttons are missing" do
|
92
|
+
cfg = {
|
93
|
+
:type => "Joystick",
|
94
|
+
:axis => {0 => {:action => :yaw}},
|
95
|
+
}
|
96
|
+
expect(YAML).to receive(:load_file).and_return(cfg)
|
97
|
+
expect {
|
98
|
+
@joystick.read_configuration('baa')
|
99
|
+
}.to raise_exception(JoystickException, "No buttons section")
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should raise exception if an axis has no action" do
|
103
|
+
cfg = {
|
104
|
+
:type => "Joystick",
|
105
|
+
:axis => {0 => {:invert => true}},
|
106
|
+
:buttons => {0 => {:action => :roll}}
|
107
|
+
}
|
108
|
+
expect(YAML).to receive(:load_file).and_return(cfg)
|
109
|
+
expect {
|
110
|
+
@joystick.read_configuration('baa')
|
111
|
+
}.to raise_exception(JoystickException, "Axis 0 needs an action")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#init_sdl" do
|
116
|
+
it "should raise an exception if the joystick index is invalid" do
|
117
|
+
expect {
|
118
|
+
js = Joystick.new(@path, 33)
|
119
|
+
allow(js.logger).to receive(:info)
|
120
|
+
js.init()
|
121
|
+
}.to raise_exception(JoystickException, "No valid joystick index")
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should open the joystick" do
|
125
|
+
expect(SDL::Joystick).to receive(:open).with(2)
|
126
|
+
js = Joystick.new(@path, 2)
|
127
|
+
allow(js.logger).to receive(:info)
|
128
|
+
js.init()
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#read_axis" do
|
133
|
+
it "should read the axis value with all the defaults" do
|
134
|
+
@joystick.config[:axis][8] = {:action => :test}
|
135
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(-32768)
|
136
|
+
value = @joystick.read_axis(8)
|
137
|
+
value.should == -30
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should put values out of range in range" do
|
141
|
+
@joystick.config[:axis][8] = {:action => :test}
|
142
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(-40000)
|
143
|
+
value = @joystick.read_axis(8)
|
144
|
+
value.should == -30
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should invert values if requested" do
|
148
|
+
@joystick.config[:axis][8] = {:action => :test, :invert => true}
|
149
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(-32767)
|
150
|
+
value = @joystick.read_axis(8)
|
151
|
+
value.should == 30
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should put values in the deadzone as 0" do
|
155
|
+
@joystick.config[:axis][8] = {
|
156
|
+
:action => :test,
|
157
|
+
:dead_zone => "-40:40"
|
158
|
+
}
|
159
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(23)
|
160
|
+
value = @joystick.read_axis(8)
|
161
|
+
value.should == 0
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should normalize the thrust correctly" do
|
165
|
+
@joystick.config[:axis][8] = {
|
166
|
+
:action => :thrust,
|
167
|
+
:output_range => "0:100"
|
168
|
+
}
|
169
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(32767)
|
170
|
+
value = @joystick.read_axis(8)
|
171
|
+
value.should == 60000
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should throotle the change rate correctly" do
|
175
|
+
@joystick.config[:axis][8] = {
|
176
|
+
:action => :test,
|
177
|
+
:output_range => "100:200",
|
178
|
+
:input_range => "0:100",
|
179
|
+
:max_change_rate => 1,
|
180
|
+
:last_poll => 0.500,
|
181
|
+
:last_value => 150
|
182
|
+
}
|
183
|
+
allow(Time).to receive(:now).and_return(1.0) # 0.5 secs after
|
184
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(60)
|
185
|
+
value = @joystick.read_axis(8)
|
186
|
+
value.should == 150.5
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should not throotle the change rate when increasing thrust" do
|
190
|
+
@joystick.config[:axis][8] = {
|
191
|
+
:action => :thrust,
|
192
|
+
:output_range => "0:100",
|
193
|
+
:input_range => "0:100",
|
194
|
+
:max_change_rate => 1,
|
195
|
+
:last_poll => 0.500,
|
196
|
+
:last_value => 50
|
197
|
+
}
|
198
|
+
allow(Time).to receive(:now).and_return(1.0) # 0.5 secs after
|
199
|
+
expect(@sdl_joystick).to receive(:axis).with(8).and_return(100)
|
200
|
+
value = @joystick.read_axis(8)
|
201
|
+
value.should == 60000
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "#pre_normalize_thrust" do
|
206
|
+
it "should discard negative axis values" do
|
207
|
+
v = @joystick.send(:pre_normalize_thrust, -12, (-20..20), (0..100))
|
208
|
+
v.should == 0
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should pre-normalize to the expected" do
|
212
|
+
v = @joystick.send(:pre_normalize_thrust, 5, (-10..10), (0..50))
|
213
|
+
v.should == 50
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe "#normalize_thrust" do
|
218
|
+
it "should return values within the range expected by the CF" do
|
219
|
+
v = @joystick.send(:normalize_thrust, 50)
|
220
|
+
v.should == 34750
|
221
|
+
v.should be_an_instance_of Fixnum
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "#read button" do
|
226
|
+
it "should return 1 when pressed" do
|
227
|
+
expect(@sdl_joystick).to receive(:button).and_return(true)
|
228
|
+
v = @joystick.send(:read_button, 1)
|
229
|
+
v.should == 1
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should return -1 when not pressed" do
|
233
|
+
expect(@sdl_joystick).to receive(:button).and_return(false)
|
234
|
+
v = @joystick.send(:read_button, 0)
|
235
|
+
v.should == -1
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
data/spec/log_spec.rb
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
require 'crazyflie/log'
|
20
|
+
|
21
|
+
|
22
|
+
describe LogTOCElement do
|
23
|
+
describe "#initialize" do
|
24
|
+
it "should initialize correctly" do
|
25
|
+
data = [5, 23].pack('C*') + ['hello', 'world'].pack('Z*Z*')
|
26
|
+
lte = LogTOCElement.new(data)
|
27
|
+
lte.ident.should == 5
|
28
|
+
lte.group.should == 'hello'
|
29
|
+
lte.name.should == 'world'
|
30
|
+
lte.ctype.should == 'float'
|
31
|
+
lte.directive.should == 'e'
|
32
|
+
lte.access.should == 0x10
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe LogBlock do
|
38
|
+
describe "#initialize" do
|
39
|
+
it "should count blocks correctly" do
|
40
|
+
b1 = LogBlock.new([]) # 0
|
41
|
+
b2 = LogBlock.new([]) # 1
|
42
|
+
b3 = LogBlock.new([]) # 2
|
43
|
+
b3.ident.should == 2
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#unpack_log_data" do
|
48
|
+
it "should unpack some binary data and call the callback" do
|
49
|
+
result = nil
|
50
|
+
cb = Proc.new do |r|
|
51
|
+
result = r
|
52
|
+
end
|
53
|
+
|
54
|
+
var1 = LogConfVariable.new("var1", true, 0, 1)
|
55
|
+
var2 = LogConfVariable.new("var2", true, 0, 2)
|
56
|
+
var3 = LogConfVariable.new("var3", true, 0, 3)
|
57
|
+
|
58
|
+
variables = [var1, var2, var3]
|
59
|
+
|
60
|
+
# 1 uint8, 1 uint16 and 1 uint32
|
61
|
+
data = [255].pack('C') + [65535].pack('S<') + [16777215].pack('L<')
|
62
|
+
|
63
|
+
b = LogBlock.new(variables) #3
|
64
|
+
b.data_callback = cb
|
65
|
+
b.unpack_log_data(data)
|
66
|
+
result.should == {
|
67
|
+
'var1' => 255,
|
68
|
+
'var2' => 65535,
|
69
|
+
'var3' => 16777215
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe Log do
|
76
|
+
before :each do
|
77
|
+
@crazyflie = double("Crazyflie")
|
78
|
+
@queue = Queue.new
|
79
|
+
allow(@crazyflie).to receive(:crtp_queues).and_return({:logging =>
|
80
|
+
@queue})
|
81
|
+
allow(@crazyflie).to receive(:cache_folder).and_return(nil)
|
82
|
+
|
83
|
+
@log = Log.new(@crazyflie)
|
84
|
+
@logger = @log.logger
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#initialize" do
|
88
|
+
it "should intialize the Log facility" do
|
89
|
+
@log.toc.toc.should == {}
|
90
|
+
@log.log_blocks.should == {}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#refresh_toc" do
|
95
|
+
it "send the packet and fetch the TOC from the crazyflie" do
|
96
|
+
port = Crazyflie::CRTP_PORTS[:logging]
|
97
|
+
channel = TOC_CHANNEL
|
98
|
+
expect(@crazyflie).to receive(:send_packet).once
|
99
|
+
expect(@log.toc).to receive(:fetch_from_crazyflie).with(
|
100
|
+
@crazyflie,
|
101
|
+
port,
|
102
|
+
@queue)
|
103
|
+
@log.refresh_toc()
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#create_log_block" do
|
108
|
+
it "should send the create block package for toc variables" do
|
109
|
+
log_conf = double("LogConf")
|
110
|
+
|
111
|
+
var1 = LogConfVariable.new("var1", true, 0, 1)
|
112
|
+
|
113
|
+
var2 = LogConfVariable.new("var2", false, 0, 2, 2)
|
114
|
+
expect(var2).not_to receive(:name)
|
115
|
+
|
116
|
+
var3 = LogConfVariable.new("var3", true, 0, 3)
|
117
|
+
expect(var3).not_to receive(:address)
|
118
|
+
|
119
|
+
variables = [var1, var2, var3]
|
120
|
+
log_conf = LogConf.new(variables, {:period => 200})
|
121
|
+
|
122
|
+
# It is the 4th call to logblock.new in these specs
|
123
|
+
expect(@logger).to receive(:debug).with("Adding block 4")
|
124
|
+
|
125
|
+
packet = CRTPPacket.new()
|
126
|
+
packet.modify_header(nil, CRTP_PORTS[:logging],
|
127
|
+
LOG_SETTINGS_CHANNEL)
|
128
|
+
|
129
|
+
packet.data = [Log::CMD_CREATE_BLOCK] + [4] +
|
130
|
+
[1] + [1] + [2] + [2,0,0,0] + [3] + [32]
|
131
|
+
|
132
|
+
toc1 = TOCElement.new({:ident => 1})
|
133
|
+
toc3 = TOCElement.new({:ident => 32})
|
134
|
+
expect(@log.toc).to receive(:[]).with('var1').and_return(toc1)
|
135
|
+
expect(@log.toc).to receive(:[]).with('var3').and_return(toc3)
|
136
|
+
|
137
|
+
expect(@crazyflie).to receive(:send_packet) do |pk|
|
138
|
+
packet.header.should == pk.header
|
139
|
+
packet.data.should == pk.data
|
140
|
+
end
|
141
|
+
@log.create_log_block(log_conf).should == 4
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#start_logging" do
|
146
|
+
it "should send the start logging packet" do
|
147
|
+
logblock = double("logblock")
|
148
|
+
expect(logblock).to receive(:period).and_return(30)
|
149
|
+
expect(logblock).to receive(:data_callback=).with(an_instance_of(Proc))
|
150
|
+
expect(@log.log_blocks).to receive(:[]).with(5).and_return(logblock)
|
151
|
+
expect(@logger).to receive(:debug)
|
152
|
+
expect(@crazyflie).to receive(:send_packet) do |pk|
|
153
|
+
pk.data.should == [CMD_START_LOGGING, 5, 30]
|
154
|
+
end
|
155
|
+
@log.start_logging(5) do |values|
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#stop_logging" do
|
161
|
+
it "should send the stop logging packet" do
|
162
|
+
block = double("block")
|
163
|
+
expect(@log.log_blocks).to receive(:[]).with(5).and_return(block)
|
164
|
+
expect(@logger).to receive(:debug)
|
165
|
+
expect(@crazyflie).to receive(:send_packet) do |pk|
|
166
|
+
pk.data.should == [CMD_STOP_LOGGING, 5]
|
167
|
+
end
|
168
|
+
@log.stop_logging(5)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "#delete_block" do
|
173
|
+
it "should delete the block" do
|
174
|
+
block = double("block")
|
175
|
+
expect(@crazyflie).to receive(:send_packet) do |pk|
|
176
|
+
pk.data.should == [CMD_DELETE_BLOCK, 5]
|
177
|
+
end
|
178
|
+
expect(@log.log_blocks).to receive(:delete).with(5).and_return({})
|
179
|
+
|
180
|
+
@log.delete_block(5)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#[]" do
|
185
|
+
it "should return a block with the given ID" do
|
186
|
+
expect(@log.log_blocks).to receive(:[]).with(3)
|
187
|
+
@log[3]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "#start_packet_reader_thread" do
|
192
|
+
it "should start a thread and process a packet" do
|
193
|
+
packet = CRTPPacket.new()
|
194
|
+
packet.modify_header(nil, nil, 3)
|
195
|
+
packet.channel.should == 3 # We dont process this one
|
196
|
+
do_this = receive(:pop).and_return(packet).at_least(:once)
|
197
|
+
expect(@queue).to do_this
|
198
|
+
expect(@logger).to receive(:debug).at_least(:once)
|
199
|
+
@log.start_packet_reader_thread
|
200
|
+
sleep 0.1
|
201
|
+
@log.stop_packet_reader_thread
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "#handle_settings_packet" do
|
206
|
+
# This has not many secret
|
207
|
+
it "should go to CMD_CREATE_BLOCK case without error" do
|
208
|
+
packet = CRTPPacket.new()
|
209
|
+
packet.data = [CMD_CREATE_BLOCK, 33, 0]
|
210
|
+
expect(@log).not_to receive(:puts)
|
211
|
+
expect(@logger).to receive(:error).with("No log entry for 33")
|
212
|
+
@log.send(:handle_settings_packet, packet)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should go to CMD_CREATE_BLOCK case with error" do
|
216
|
+
packet = CRTPPacket.new()
|
217
|
+
packet.data = [CMD_CREATE_BLOCK, 33, 3]
|
218
|
+
expect(@logger).to receive(:error).with("Error creating block 33: 3")
|
219
|
+
expect(@log.log_blocks).to receive(:[]).with(33).and_return({})
|
220
|
+
@log.send(:handle_settings_packet, packet)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should go to CMD_START_LOGGING case without error" do
|
224
|
+
packet = CRTPPacket.new()
|
225
|
+
packet.data = [CMD_START_LOGGING, 33, 0]
|
226
|
+
expect(@logger).to receive(:debug).with("Logging started for 33")
|
227
|
+
@log.send(:handle_settings_packet, packet)
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should go to CMD_START_LOGGING case with error" do
|
231
|
+
packet = CRTPPacket.new()
|
232
|
+
packet.data = [CMD_START_LOGGING, 33, 3]
|
233
|
+
expect(@logger).to receive(:error).with("Error starting to log 33: 3")
|
234
|
+
@log.send(:handle_settings_packet, packet)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#handle_logdata_packet" do
|
239
|
+
it "should warn if no block exist" do
|
240
|
+
expect(@log.log_blocks).to receive(:[]).with(33).and_return(nil)
|
241
|
+
m = "No entry for logdata for block 33"
|
242
|
+
expect(@logger).to receive(:error).with(m)
|
243
|
+
packet = CRTPPacket.new()
|
244
|
+
packet.data = [33, 44, 45, 46]
|
245
|
+
@log.send(:handle_logdata_packet, packet)
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should call the unpack log data if the block exists" do
|
249
|
+
block = double("Block")
|
250
|
+
expect(block).to receive(:unpack_log_data).with([46,47].pack('C*'))
|
251
|
+
expect(@log.log_blocks).to receive(:[]).with(33).and_return(block)
|
252
|
+
expect(@logger).not_to receive(:error)
|
253
|
+
packet = CRTPPacket.new()
|
254
|
+
packet.data = [33, 44, 45, 46, 46, 47]
|
255
|
+
@log.send(:handle_logdata_packet, packet)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "#packet_factory" do
|
260
|
+
it "should return a new packet on logging port and settings channel" do
|
261
|
+
pk = @log.send(:packet_factory)
|
262
|
+
pk.channel.should == LOG_SETTINGS_CHANNEL
|
263
|
+
pk.port.should == CRTP_PORTS[:logging]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
data/spec/param_spec.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
require 'crazyflie/param'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
describe LogTOCElement do
|
24
|
+
describe "#initialize" do
|
25
|
+
it "should initialize correctly" do
|
26
|
+
data = [5, 23].pack('C*') + ['hello', 'world'].pack('Z*Z*')
|
27
|
+
lte = ParamTOCElement.new(data)
|
28
|
+
lte.ident.should == 5
|
29
|
+
lte.group.should == 'hello'
|
30
|
+
lte.name.should == 'world'
|
31
|
+
lte.ctype.should == 'double'
|
32
|
+
lte.directive.should == 'E'
|
33
|
+
lte.access.should == 0x10
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
describe Param do
|
40
|
+
before :each do
|
41
|
+
@crazyflie = double("Crazyflie")
|
42
|
+
@queue = Queue.new
|
43
|
+
allow(@crazyflie).to receive(:crtp_queues).and_return({:param =>
|
44
|
+
@queue})
|
45
|
+
allow(@crazyflie).to receive(:cache_folder).and_return(nil)
|
46
|
+
|
47
|
+
@param = Param.new(@crazyflie)
|
48
|
+
@logger = @param.logger
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#initialize" do
|
52
|
+
it "should initialize the Param instance" do
|
53
|
+
param = Param.new(@crazyflie)
|
54
|
+
@param.toc.toc.should == {}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#refresh_toc" do
|
59
|
+
it "send the packet and fetch the TOC from the crazyflie" do
|
60
|
+
port = Crazyflie::CRTP_PORTS[:param]
|
61
|
+
channel = Param::TOC_CHANNEL
|
62
|
+
expect(@param.toc).to receive(:fetch_from_crazyflie).with(
|
63
|
+
@crazyflie,
|
64
|
+
port,
|
65
|
+
@queue)
|
66
|
+
@param.refresh_toc()
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#set_value" do
|
71
|
+
it "should not do anything if the element is not in the TOC" do
|
72
|
+
expect(@logger).to receive(:error).with("Param abc not in TOC!")
|
73
|
+
expect(@crazyflie).not_to receive(:send_packet)
|
74
|
+
@param.set_value('abc', 45)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should set the value of a parameter and yield the response" do
|
78
|
+
toc_elem = TOCElement.new({
|
79
|
+
:ident => 3,
|
80
|
+
:group => "gr",
|
81
|
+
:name => "name",
|
82
|
+
:ctype => "int32_t",
|
83
|
+
:directive => "l<"
|
84
|
+
})
|
85
|
+
|
86
|
+
name = 'gr.name'
|
87
|
+
expect(@param.toc).to receive(:[]).with(name).and_return(toc_elem)
|
88
|
+
|
89
|
+
expect(@crazyflie).to receive(:send_packet) { |packet, expect|
|
90
|
+
packet.port.should == CRTP_PORTS[:param]
|
91
|
+
packet.channel == PARAM_WRITE_CHANNEL
|
92
|
+
packet.data.should == [3, 1, 0, 0, 0]
|
93
|
+
expect.should == true
|
94
|
+
}
|
95
|
+
|
96
|
+
res = CRTPPacket.new()
|
97
|
+
expect(@queue).to receive(:pop).and_return(res)
|
98
|
+
|
99
|
+
@param.set_value('gr.name', 1) do |response|
|
100
|
+
response.should == res
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should set the value of a parameter without a block_given" do
|
105
|
+
toc_elem = TOCElement.new({
|
106
|
+
:ident => 3,
|
107
|
+
:group => "gr",
|
108
|
+
:name => "name",
|
109
|
+
:ctype => "int32_t",
|
110
|
+
:directive => "l<"
|
111
|
+
})
|
112
|
+
|
113
|
+
name = 'gr.name'
|
114
|
+
expect(@param.toc).to receive(:[]).with(name).and_return(toc_elem)
|
115
|
+
|
116
|
+
expect(@crazyflie).to receive(:send_packet) { |packet, expect|
|
117
|
+
packet.port.should == CRTP_PORTS[:param]
|
118
|
+
packet.channel == PARAM_WRITE_CHANNEL
|
119
|
+
packet.data.should == [3, 1, 0, 0, 0]
|
120
|
+
expect.should == true
|
121
|
+
}
|
122
|
+
|
123
|
+
res = CRTPPacket.new()
|
124
|
+
expect(@queue).to receive(:pop).and_return(res)
|
125
|
+
|
126
|
+
m = "Got answer to setting param 'gr.name' with '1'"
|
127
|
+
expect(@logger).to receive(:debug).with(m)
|
128
|
+
@param.set_value('gr.name', 1)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#get_value" do
|
133
|
+
it "should not do anything if the element is not in the TOC" do
|
134
|
+
m = "Cannot update gr.name, not in TOC"
|
135
|
+
expect(@logger).to receive(:error).with(m)
|
136
|
+
|
137
|
+
@param.get_value('gr.name') {}
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should request an element and yield the value" do
|
141
|
+
toc_elem = TOCElement.new({
|
142
|
+
:ident => 3,
|
143
|
+
:group => "gr",
|
144
|
+
:name => "name",
|
145
|
+
:ctype => "int32_t",
|
146
|
+
:directive => "l<"
|
147
|
+
})
|
148
|
+
|
149
|
+
name = 'gr.name'
|
150
|
+
expect(@param.toc).to receive(:[]).with(name).and_return(toc_elem)
|
151
|
+
|
152
|
+
expect(@crazyflie).to receive(:send_packet) do |packet|
|
153
|
+
packet.port.should == CRTP_PORTS[:param]
|
154
|
+
packet.channel.should == PARAM_READ_CHANNEL
|
155
|
+
packet.data.should == [3]
|
156
|
+
end
|
157
|
+
|
158
|
+
res = CRTPPacket.new()
|
159
|
+
res.data = [3, 5, 0, 0, 0]
|
160
|
+
expect(@queue).to receive(:pop).and_return(res)
|
161
|
+
@param.get_value('gr.name') do |value|
|
162
|
+
value.should == 5
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|