hybridgroup-crubyflie 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +8 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +674 -0
- data/README.md +127 -0
- data/Rakefile +15 -0
- data/bin/crubyflie +94 -0
- data/configs/joystick_default.yaml +106 -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 +363 -0
- data/lib/crubyflie/exceptions.rb +36 -0
- data/lib/crubyflie/input/input_reader.rb +190 -0
- data/lib/crubyflie/input/joystick_input_reader.rb +328 -0
- data/lib/crubyflie/version.rb +22 -0
- data/lib/crubyflie.rb +36 -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 +228 -0
- data/spec/crtp_packet_spec.rb +79 -0
- data/spec/crubyflie_logger_spec.rb +39 -0
- data/spec/crubyflie_spec.rb +21 -0
- data/spec/input_reader_spec.rb +136 -0
- data/spec/joystick_cfg.yaml +44 -0
- data/spec/joystick_input_reader_spec.rb +323 -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 +53 -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 +225 -0
@@ -0,0 +1,176 @@
|
|
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'
|
20
|
+
|
21
|
+
|
22
|
+
describe Crazyflie do
|
23
|
+
before :all do
|
24
|
+
end
|
25
|
+
before :each do
|
26
|
+
@facility = double("Facility")
|
27
|
+
allow(Commander).to receive(:new).and_return(@facility)
|
28
|
+
allow(Param).to receive(:new).and_return(@facility)
|
29
|
+
allow(Log).to receive(:new).and_return(@facility)
|
30
|
+
allow(Commander).to receive(:new).and_return(@facility)
|
31
|
+
allow(@facility).to receive(:send_setpoint)
|
32
|
+
allow(@facility).to receive(:refresh_toc)
|
33
|
+
allow(@facility).to receive(:start_packet_reader_thread)
|
34
|
+
allow(@facility).to receive(:stop_packet_reader_thread)
|
35
|
+
@link = double("RadioDriver")
|
36
|
+
@uri = 'radio://0/0/1M'
|
37
|
+
allow(RadioDriver).to receive(:new).and_return(@link)
|
38
|
+
allow(@link).to receive(:connect)
|
39
|
+
allow(@link).to receive(:disconnect)
|
40
|
+
allow(@link).to receive(:receive_packet)
|
41
|
+
allow(@link).to receive(:uri).and_return(CrubyflieURI.new(@uri))
|
42
|
+
|
43
|
+
#allow_any_instance_of(CrubyflieLogger).to receive(:info)
|
44
|
+
|
45
|
+
@cf = Crazyflie.new()
|
46
|
+
@logger = @cf.logger
|
47
|
+
|
48
|
+
@default_pk = CRTPPacket.new(0b00001100, [1,2,3])
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
describe "#initialize" do
|
53
|
+
it "should initalize correctly" do
|
54
|
+
Crazyflie::CALLBACKS.each do |cb|
|
55
|
+
@cf.callbacks[cb].size.should >= 0
|
56
|
+
end
|
57
|
+
|
58
|
+
Crazyflie::CRTP_PORTS.keys().each do |port|
|
59
|
+
@cf.crtp_queues[port].should be_an_instance_of Queue
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
describe "#open_link" do
|
66
|
+
it "should connect to a crazyradio url" do
|
67
|
+
expect(@link).to receive(:receive_packet).and_return(@default_pk)
|
68
|
+
m = "Connection initiated to radio://0/0/1M"
|
69
|
+
m2 = "Disconnected from radio://0/0/1M"
|
70
|
+
m3 = "TOCs extracted from #{@uri}"
|
71
|
+
expect(@logger).to receive(:info).with(m)
|
72
|
+
expect(@logger).to receive(:info).with("Connected!")
|
73
|
+
expect(@logger).to receive(:info).with("Connection ready!")
|
74
|
+
expect(@logger).to receive(:info).with(m2)
|
75
|
+
expect(@logger).to receive(:debug).with(m3)
|
76
|
+
|
77
|
+
|
78
|
+
expect(@facility).to receive(:refresh_toc).twice
|
79
|
+
# only log facility gets this
|
80
|
+
expect(@facility).to receive(:start_packet_reader_thread).once
|
81
|
+
expect(@facility).to receive(:stop_packet_reader_thread).twice
|
82
|
+
@cf.open_link(@uri)
|
83
|
+
@cf.close_link()
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should close the link if something happens" do
|
87
|
+
expect(@link).to receive(:connect).and_raise(Exception)
|
88
|
+
mesg = "Connection failed: Exception"
|
89
|
+
expect(@logger).to receive(:info).at_least(:once)
|
90
|
+
expect(@logger).to receive(:error).with(mesg)
|
91
|
+
expect(@facility).not_to receive(:refresh_toc)
|
92
|
+
@cf.open_link(@uri)
|
93
|
+
@cf.close_link()
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#close_link" do
|
98
|
+
it "should close the link" do
|
99
|
+
expect(@facility).to receive(:send_setpoint)
|
100
|
+
expect(@link).to receive(:disconnect)
|
101
|
+
m1 = "Connection initiated to radio://0/0/1M"
|
102
|
+
m2 = "Connection ready!"
|
103
|
+
m3 = "Disconnected from radio://0/0/1M"
|
104
|
+
expect(@logger).to receive(:debug)
|
105
|
+
expect(@logger).to receive(:info).with(m1)
|
106
|
+
expect(@logger).to receive(:info).with(m2)
|
107
|
+
expect(@logger).to receive(:info).with(m3)
|
108
|
+
|
109
|
+
@cf.open_link(@uri)
|
110
|
+
@cf.close_link()
|
111
|
+
@cf.crtp_queues.each do |k,q|
|
112
|
+
q.should be_empty
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should not break closing a non existing link" do
|
117
|
+
expect(@facility).not_to receive(:send_setpoint)
|
118
|
+
expect_any_instance_of(NilClass).not_to receive(:disconnect)
|
119
|
+
expect(@cf).not_to receive(:puts)
|
120
|
+
expect_any_instance_of(Thread).not_to receive(:kill)
|
121
|
+
expect(@logger).to receive(:info).with("Disconnected from nowhere")
|
122
|
+
@cf.close_link()
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#send_packet" do
|
127
|
+
it "should send a packet without expecting answer" do
|
128
|
+
expect(@cf).not_to receive(:setup_retry)
|
129
|
+
expect(@link).to receive(:send_packet).with(@default_pk)
|
130
|
+
expect(@logger).to receive(:info).at_least(:once)
|
131
|
+
expect(@logger).to receive(:debug)
|
132
|
+
@cf.open_link(@uri)
|
133
|
+
@cf.send_packet(@default_pk)
|
134
|
+
@cf.close_link()
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should send a packet and set up a timer when expecting answer" do
|
138
|
+
pk = @default_pk
|
139
|
+
expect(@link).to receive(:send_packet).with(pk).at_least(:twice)
|
140
|
+
expect(@logger).to receive(:info).at_least(:once)
|
141
|
+
expect(@logger).to receive(:debug).at_least(:once)
|
142
|
+
@cf.open_link(@uri)
|
143
|
+
@cf.send_packet(@default_pk, true)
|
144
|
+
sleep 0.5
|
145
|
+
@cf.close_link()
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "#receive_packet" do
|
150
|
+
it " should receive a packet, trigger callbacks" do
|
151
|
+
proc = Proc.new do
|
152
|
+
puts "port 0 ch 0 callback"
|
153
|
+
end
|
154
|
+
|
155
|
+
proc2 = Proc.new do |pk|
|
156
|
+
puts "Received packet"
|
157
|
+
end
|
158
|
+
|
159
|
+
@cf.callbacks[:received_packet][:log] = proc
|
160
|
+
@cf.callbacks[:received_packet][:log2] = proc2
|
161
|
+
|
162
|
+
allow_any_instance_of(Thread).to receive(:new).and_return(nil)
|
163
|
+
expect(@link).to receive(:receive_packet).and_return(@default_pk)
|
164
|
+
expect(proc).to receive(:call).with(@default_pk).at_least(:once)
|
165
|
+
expect(proc2).to receive(:call).with(@default_pk).at_least(:once)
|
166
|
+
expect(@cf.crtp_queues[:console]).to receive(:<<).once
|
167
|
+
expect(@logger).to receive(:info).at_least(:once)
|
168
|
+
expect(@logger).to receive(:debug)
|
169
|
+
@cf.open_link(@uri)
|
170
|
+
@cf.send(:receive_packet)
|
171
|
+
# Received packet comes on port 0 - console
|
172
|
+
|
173
|
+
@cf.close_link()
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,228 @@
|
|
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 'crazyradio/crazyradio'
|
20
|
+
|
21
|
+
describe Crazyradio do
|
22
|
+
before :each do
|
23
|
+
@device = double("LIBUSB::Device")
|
24
|
+
@handle = double("LIBUSB::DevHandler")
|
25
|
+
|
26
|
+
allow(@device).to receive(:is_a?).and_return(LIBUSB::Device)
|
27
|
+
allow(@device).to receive(:open).and_return(@handle)
|
28
|
+
allow(@device).to receive(:serial_number).and_return("serial123")
|
29
|
+
allow(@device).to receive(:manufacturer).and_return("Bitcraze")
|
30
|
+
allow(@handle).to receive(:configuration=)
|
31
|
+
allow(@handle).to receive(:claim_interface)
|
32
|
+
tr_result = [1,2,3].pack('C*')
|
33
|
+
allow(@handle).to receive(:control_transfer).and_return(tr_result)
|
34
|
+
allow(@handle).to receive(:release_interface)
|
35
|
+
allow(@handle).to receive(:reset_device)
|
36
|
+
allow(@handle).to receive(:close)
|
37
|
+
|
38
|
+
@crazyradio = Crazyradio.new(@device)
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#initialize" do
|
42
|
+
it "should initialize the dongle correctly" do
|
43
|
+
settings = [:data_rate, :channel, :cont_carrier,
|
44
|
+
:address, :power, :arc, :ard_bytes]
|
45
|
+
ssize = settings.size
|
46
|
+
expect(@device).to receive(:open)
|
47
|
+
expect(@handle).to receive(:configuration=).with(1)
|
48
|
+
expect(@handle).to receive(:claim_interface).with(0)
|
49
|
+
expect(@handle).to receive(:control_transfer).exactly(ssize).times
|
50
|
+
crazyradio = Crazyradio.new(@device)
|
51
|
+
defaults = Crazyradio::DEFAULT_SETTINGS
|
52
|
+
settings.each do |setting|
|
53
|
+
crazyradio[setting].should == defaults[setting]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not initialize with a nil device" do
|
58
|
+
expect { Crazyradio.new() }.to raise_error(USBDongleException,
|
59
|
+
"Wrong USB device")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#status" do
|
64
|
+
it "should return a status" do
|
65
|
+
allow(Crazyradio).to receive(:factory).and_return(@crazyradio)
|
66
|
+
status = "Found serial123 USB dongle from Bitcraze"
|
67
|
+
Crazyradio.status().should == status
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#close" do
|
72
|
+
it "should close the USB" do
|
73
|
+
expect(@handle).to receive(:release_interface).with(0)
|
74
|
+
expect(@handle).to receive(:reset_device)
|
75
|
+
#expect(@handle).to receive(:close)
|
76
|
+
@crazyradio.close()
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#has_fw_scan" do
|
81
|
+
it "should say false" do
|
82
|
+
@crazyradio.has_fw_scan.should be_false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#scan_channels" do
|
87
|
+
it "should scan channels and return them" do
|
88
|
+
ack = RadioAck.new(true)
|
89
|
+
do_this = receive(:send_packet).with([0xFF]).and_return(ack)
|
90
|
+
allow(@crazyradio).to do_this
|
91
|
+
@crazyradio.scan_channels(0, 125).should == (0..125).to_a
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should scan channels with fw_scan and return them" do
|
95
|
+
allow(@crazyradio).to receive(:has_fw_scan).and_return(true)
|
96
|
+
@crazyradio.scan_channels(0, 125).should == [1,2,3]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should not include bad channels in a scan" do
|
100
|
+
ack = RadioAck.new(false)
|
101
|
+
do_this = receive(:send_packet).with([0xFF]).and_return(ack)
|
102
|
+
allow(@crazyradio).to do_this
|
103
|
+
@crazyradio.scan_channels(0, 125).should == []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#factory" do
|
108
|
+
it "should raise an exception if no dongles are found" do
|
109
|
+
context = double("Context")
|
110
|
+
expect(LIBUSB::Context).to receive(:new).and_return(context)
|
111
|
+
expect(context).to receive(:devices).and_return([])
|
112
|
+
|
113
|
+
expect { Crazyradio.factory() }.to raise_error(USBDongleException,
|
114
|
+
"No dongles found")
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should provide a new crazyradio item" do
|
118
|
+
context = double("Context")
|
119
|
+
expect(LIBUSB::Context).to receive(:new).and_return(context)
|
120
|
+
expect(context).to receive(:devices).and_return([@device])
|
121
|
+
Crazyradio.factory()
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#send_packet" do
|
126
|
+
it "should send a packet and get a response" do
|
127
|
+
dataout = { :endpoint => 1, :dataOut => [1,2,3,4,5].pack('C*')}
|
128
|
+
datain = { :endpoint => 0x81, :dataIn => 64}
|
129
|
+
response = ([0xFF] * 64).pack('C*')
|
130
|
+
do_this = receive(:bulk_transfer)
|
131
|
+
expect(@handle).to do_this.with(dataout).and_return(response)
|
132
|
+
expect(@handle).to do_this.with(datain).and_return(response)
|
133
|
+
|
134
|
+
ack = @crazyradio.send_packet([1,2,3,4,5])
|
135
|
+
ack.should be_an_instance_of RadioAck
|
136
|
+
ack.ack.should == true
|
137
|
+
ack.data.should == [0xFF] * 63
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "#[]=" do
|
142
|
+
it "should set a setting" do
|
143
|
+
expect(@crazyradio).to receive(:set_data_rate).with(58)
|
144
|
+
@crazyradio[:data_rate] = 58
|
145
|
+
end
|
146
|
+
it "should no set a bad setting" do
|
147
|
+
expect(@crazyradio).not_to receive(:set_data_rate)
|
148
|
+
expect(@crazyradio).not_to receive(:set_channel)
|
149
|
+
expect(@crazyradio).not_to receive(:set_arc)
|
150
|
+
expect(@crazyradio).not_to receive(:set_cont_carrier)
|
151
|
+
expect(@crazyradio).not_to receive(:set_address)
|
152
|
+
expect(@crazyradio).not_to receive(:set_power)
|
153
|
+
expect(@crazyradio).not_to receive(:set_ard_bytes)
|
154
|
+
@crazyradio[:abc] = 3
|
155
|
+
@crazyradio[:abc].should be_nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "[]" do
|
160
|
+
it "should get a setting value" do
|
161
|
+
expected = Crazyradio::DEFAULT_SETTINGS[:channel]
|
162
|
+
@crazyradio[:channel].should == expected
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#apply_settings" do
|
167
|
+
it "should apply one setting" do
|
168
|
+
d = Crazyradio::DEFAULT_SETTINGS
|
169
|
+
expect(@crazyradio).to receive(:set_channel).with(d[:channel])
|
170
|
+
expect(@crazyradio).to receive(:set_data_rate).with(d[:data_rate])
|
171
|
+
expect(@crazyradio).to receive(:set_arc).with(d[:arc])
|
172
|
+
scr = :set_cont_carrier
|
173
|
+
expect(@crazyradio).to receive(scr).with(d[:cont_carrier])
|
174
|
+
expect(@crazyradio).to receive(:set_address).with(d[:address])
|
175
|
+
expect(@crazyradio).to receive(:set_power).with(d[:power])
|
176
|
+
expect(@crazyradio).to receive(:set_ard_bytes).with(d[:ard_bytes])
|
177
|
+
@crazyradio.apply_settings(:channel)
|
178
|
+
@crazyradio.apply_settings(:data_rate)
|
179
|
+
@crazyradio.apply_settings(:arc)
|
180
|
+
@crazyradio.apply_settings(:cont_carrier)
|
181
|
+
@crazyradio.apply_settings(:power)
|
182
|
+
@crazyradio.apply_settings(:ard_bytes)
|
183
|
+
@crazyradio.apply_settings(:address)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should apply all settings" do
|
187
|
+
d = Crazyradio::DEFAULT_SETTINGS
|
188
|
+
expect(@crazyradio).to receive(:set_channel).with(d[:channel])
|
189
|
+
expect(@crazyradio).to receive(:set_data_rate).with(d[:data_rate])
|
190
|
+
expect(@crazyradio).to receive(:set_arc).with(d[:arc])
|
191
|
+
scr = :set_cont_carrier
|
192
|
+
expect(@crazyradio).to receive(scr).with(d[:cont_carrier])
|
193
|
+
expect(@crazyradio).to receive(:set_address).with(d[:address])
|
194
|
+
expect(@crazyradio).to receive(:set_power).with(d[:power])
|
195
|
+
expect(@crazyradio).to receive(:set_ard_bytes).with(d[:ard_bytes])
|
196
|
+
@crazyradio.apply_settings()
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#send_vendor_setup" do
|
201
|
+
it "should make a control_transfer with the proper args set" do
|
202
|
+
args = {
|
203
|
+
:bmRequestType => LIBUSB::REQUEST_TYPE_VENDOR,
|
204
|
+
:bRequest => 38,
|
205
|
+
:wValue => 3,
|
206
|
+
:wIndex => 2,
|
207
|
+
:dataOut => ""
|
208
|
+
}
|
209
|
+
expect(@handle).to receive(:control_transfer).with(args)
|
210
|
+
@crazyradio.send(:send_vendor_setup, 38, 3, 2)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#get_vendor_setup" do
|
215
|
+
it "should make a control_transfer with the proper args set" do
|
216
|
+
args = {
|
217
|
+
:bmRequestType => LIBUSB::REQUEST_TYPE_VENDOR | 0x80,
|
218
|
+
:bRequest => 38,
|
219
|
+
:wValue => 3,
|
220
|
+
:wIndex => 2,
|
221
|
+
:dataIn => 0
|
222
|
+
}
|
223
|
+
expect(@handle).to receive(:control_transfer).with(args)
|
224
|
+
resp = @crazyradio.send(:get_vendor_setup, 38, 3, 2)
|
225
|
+
resp.should == [1,2,3]
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,79 @@
|
|
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 'driver/crtp_packet'
|
20
|
+
|
21
|
+
describe CRTPPacket do
|
22
|
+
describe "#initalize" do
|
23
|
+
it "should initialize correctly a packet" do
|
24
|
+
header = 0b11101010 # channel 10; port 1110
|
25
|
+
payload = [1,2,3]
|
26
|
+
packet = CRTPPacket.new(header, payload)
|
27
|
+
packet.size.should == 3
|
28
|
+
packet.header.should == header
|
29
|
+
packet.data.should == payload
|
30
|
+
packet.channel.should == 0b10
|
31
|
+
packet.port.should == 0b1110
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#modify_header" do
|
36
|
+
it "should modify only with header if provided" do
|
37
|
+
header = 0b11101010 # channel 10; port 1110
|
38
|
+
payload = [1,2,3]
|
39
|
+
packet = CRTPPacket.new(header, payload)
|
40
|
+
packet.modify_header(0, 3, 4)
|
41
|
+
packet.header.should == 0
|
42
|
+
packet.channel.should == 0
|
43
|
+
packet.port.should == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should modify channel and port and set the header" do
|
47
|
+
channel = 0b10
|
48
|
+
port = 0b1101
|
49
|
+
payload = [1,2,3]
|
50
|
+
packet = CRTPPacket.new(0, payload)
|
51
|
+
packet.modify_header(nil, port, channel)
|
52
|
+
packet.header.should == 0b11010010
|
53
|
+
packet.channel.should == 0b10
|
54
|
+
packet.port.should == 0b1101
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#unpack" do
|
59
|
+
it "should return an empty package if data is empty or not array" do
|
60
|
+
CRTPPacket.unpack("abc").pack.should == [0]
|
61
|
+
CRTPPacket.unpack([]).pack.should == [0]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should unpack a data array correctly into header and data" do
|
65
|
+
packet = CRTPPacket.unpack([1,2,3])
|
66
|
+
packet.data.should == [2,3]
|
67
|
+
packet.header.should == 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#pack" do
|
72
|
+
it "should concat header and data" do
|
73
|
+
header = 0b11101010 # channel 10; port 1110
|
74
|
+
payload = [1,2,3]
|
75
|
+
packet = CRTPPacket.new(header, payload)
|
76
|
+
packet.pack.should == [0b11101010, 1, 2, 3]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,39 @@
|
|
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
|
+
describe Logging do
|
20
|
+
it "should provide a logger" do
|
21
|
+
include Logging
|
22
|
+
logger.should be_an_instance_of CrubyflieLogger
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe CrubyflieLogger do
|
27
|
+
|
28
|
+
it "should log to debug, info, warn" do
|
29
|
+
l = CrubyflieLogger.new(true)
|
30
|
+
expect($stderr).to receive(:puts).with("DEBUG: a")
|
31
|
+
expect($stdout).to receive(:puts).with("INFO: a")
|
32
|
+
expect($stderr).to receive(:puts).with("ERROR: a")
|
33
|
+
expect($stderr).to receive(:puts).with("WARNING: a")
|
34
|
+
l.debug "a"
|
35
|
+
l.info "a"
|
36
|
+
l.warn "a"
|
37
|
+
l.error "a"
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
+
$: << File.dirname(__FILE__)
|
20
|
+
require 'rspec'
|
21
|
+
require 'spec_helper'
|
@@ -0,0 +1,136 @@
|
|
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
|
+
describe InputReader do
|
20
|
+
|
21
|
+
before :each do
|
22
|
+
@sdl_joystick = double("Joystick")
|
23
|
+
allow(SDL::Joystick).to receive(:update_all)
|
24
|
+
allow(SDL).to receive(:init).with(SDL::INIT_JOYSTICK)
|
25
|
+
allow(SDL::Joystick).to receive(:num).and_return(3)
|
26
|
+
allow(SDL::Joystick).to receive(:open).and_return(@sdl_joystick)
|
27
|
+
allow(SDL::Joystick).to receive(:index_name).and_return("My Joystick")
|
28
|
+
allow(SDL::Joystick).to receive(:poll).with(false)
|
29
|
+
expect(SDL::Joystick).not_to receive(:poll).with(true)
|
30
|
+
path = File.join(File.dirname(__FILE__), 'joystick_cfg.yaml')
|
31
|
+
@joystick = Joystick.new(path)
|
32
|
+
|
33
|
+
@logger = @joystick.logger
|
34
|
+
allow(@logger).to receive(:info)
|
35
|
+
@joystick.init()
|
36
|
+
|
37
|
+
@cf = double("Crazyflie")
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#read_input" do
|
41
|
+
it "should read axis and buttons" do
|
42
|
+
do_this = receive(:axis).and_return(0,32768,0,-32767)
|
43
|
+
do_this = do_this.exactly(4).times
|
44
|
+
expect(@sdl_joystick).to do_this
|
45
|
+
|
46
|
+
expect(@sdl_joystick).to receive(:button) { |arg|
|
47
|
+
false
|
48
|
+
}.twice
|
49
|
+
|
50
|
+
@joystick.read_input()
|
51
|
+
@joystick.axis_readings.should == {
|
52
|
+
:roll => 0,
|
53
|
+
:pitch => -30,
|
54
|
+
:yaw => 0,
|
55
|
+
:thrust => 49900
|
56
|
+
}
|
57
|
+
|
58
|
+
@joystick.button_readings.should == {
|
59
|
+
:switch_xmode => 0,
|
60
|
+
:close_link => 0
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
describe "#apply_input" do
|
67
|
+
it "should apply the read input to an active crazyflie" do
|
68
|
+
do_this = receive(:axis).and_return(0,32768,0,-32767)
|
69
|
+
do_this = do_this.exactly(4).times
|
70
|
+
expect(@sdl_joystick).to do_this
|
71
|
+
|
72
|
+
expect(@sdl_joystick).to receive(:button) { |arg|
|
73
|
+
false
|
74
|
+
}.twice
|
75
|
+
|
76
|
+
expect(@cf).to receive(:active?).and_return(true).twice
|
77
|
+
cmder = double("Commander")
|
78
|
+
expect(@cf).to receive(:commander).and_return(cmder)
|
79
|
+
expect(cmder).to receive(:send_setpoint).with(0, -30, 0,
|
80
|
+
49900, false)
|
81
|
+
@joystick.read_input()
|
82
|
+
@joystick.apply_input(@cf)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not send commands to a non active crazyflie" do
|
86
|
+
do_this = receive(:axis).and_return(0,32768,0,-32767)
|
87
|
+
do_this = do_this.exactly(4).times
|
88
|
+
expect(@sdl_joystick).to do_this
|
89
|
+
|
90
|
+
expect(@sdl_joystick).to receive(:button) { |arg|
|
91
|
+
false
|
92
|
+
}.twice
|
93
|
+
|
94
|
+
expect(@cf).to receive(:active?).and_return(false)
|
95
|
+
expect(@cf).not_to receive(:commander)
|
96
|
+
@joystick.read_input()
|
97
|
+
@joystick.apply_input(@cf)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should close the link to the crazyflie" do
|
101
|
+
do_this = receive(:axis).and_return(0,32768,0,-32767)
|
102
|
+
do_this = do_this.exactly(4).times
|
103
|
+
expect(@sdl_joystick).to do_this
|
104
|
+
|
105
|
+
expect(@sdl_joystick).to receive(:button) { |arg|
|
106
|
+
arg == 0 ? false : true
|
107
|
+
}.twice
|
108
|
+
|
109
|
+
expect(@cf).to receive(:active?).and_return(true, false).twice
|
110
|
+
expect(@cf).not_to receive(:commander)
|
111
|
+
expect(@cf).to receive(:close_link)
|
112
|
+
@joystick.read_input()
|
113
|
+
@joystick.apply_input(@cf)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should enable xmode" do
|
117
|
+
do_this = receive(:axis).and_return(0,32768,0,-32767)
|
118
|
+
do_this = do_this.exactly(4).times
|
119
|
+
expect(@sdl_joystick).to do_this
|
120
|
+
|
121
|
+
expect(@sdl_joystick).to receive(:button) { |arg|
|
122
|
+
arg == 1 ? false : true
|
123
|
+
}.twice
|
124
|
+
|
125
|
+
expect(@cf).to receive(:active?).and_return(true).twice
|
126
|
+
cmder = double("Commander")
|
127
|
+
expect(@cf).to receive(:commander).and_return(cmder)
|
128
|
+
expect(cmder).to receive(:send_setpoint).with(0, -30, 0,
|
129
|
+
49900, true)
|
130
|
+
@joystick.read_input()
|
131
|
+
@joystick.apply_input(@cf)
|
132
|
+
@joystick.xmode.should == true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|