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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +674 -0
  5. data/README.md +99 -0
  6. data/Rakefile +15 -0
  7. data/bin/crubyflie +85 -0
  8. data/configs/joystick_default.yaml +48 -0
  9. data/crubyflie.gemspec +50 -0
  10. data/examples/params_and_logging.rb +87 -0
  11. data/lib/crubyflie/crazyflie/commander.rb +54 -0
  12. data/lib/crubyflie/crazyflie/console.rb +67 -0
  13. data/lib/crubyflie/crazyflie/log.rb +383 -0
  14. data/lib/crubyflie/crazyflie/log_conf.rb +57 -0
  15. data/lib/crubyflie/crazyflie/param.rb +220 -0
  16. data/lib/crubyflie/crazyflie/toc.rb +239 -0
  17. data/lib/crubyflie/crazyflie/toc_cache.rb +87 -0
  18. data/lib/crubyflie/crazyflie.rb +282 -0
  19. data/lib/crubyflie/crazyradio/crazyradio.rb +301 -0
  20. data/lib/crubyflie/crazyradio/radio_ack.rb +48 -0
  21. data/lib/crubyflie/crubyflie_logger.rb +74 -0
  22. data/lib/crubyflie/driver/crtp_packet.rb +146 -0
  23. data/lib/crubyflie/driver/radio_driver.rb +333 -0
  24. data/lib/crubyflie/exceptions.rb +36 -0
  25. data/lib/crubyflie/input/input_reader.rb +168 -0
  26. data/lib/crubyflie/input/joystick_input_reader.rb +280 -0
  27. data/lib/crubyflie/version.rb +22 -0
  28. data/lib/crubyflie.rb +31 -0
  29. data/spec/commander_spec.rb +67 -0
  30. data/spec/console_spec.rb +76 -0
  31. data/spec/crazyflie_spec.rb +176 -0
  32. data/spec/crazyradio_spec.rb +226 -0
  33. data/spec/crtp_packet_spec.rb +79 -0
  34. data/spec/crubyflie_logger_spec.rb +39 -0
  35. data/spec/crubyflie_spec.rb +20 -0
  36. data/spec/input_reader_spec.rb +136 -0
  37. data/spec/joystick_cfg.yaml +48 -0
  38. data/spec/joystick_input_reader_spec.rb +238 -0
  39. data/spec/log_spec.rb +266 -0
  40. data/spec/param_spec.rb +166 -0
  41. data/spec/radio_ack_spec.rb +43 -0
  42. data/spec/radio_driver_spec.rb +227 -0
  43. data/spec/spec_helper.rb +51 -0
  44. data/spec/toc_cache_spec.rb +87 -0
  45. data/spec/toc_spec.rb +187 -0
  46. data/tools/sdl-joystick-axis.rb +69 -0
  47. metadata +222 -0
@@ -0,0 +1,43 @@
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/radio_ack'
20
+
21
+ describe RadioAck do
22
+ describe "#initialize" do
23
+ it "should initialize a RadioAck" do
24
+ rack = RadioAck.new(true, 1, 5, [1,2,3])
25
+ rack.ack.should == true
26
+ rack.powerDet.should == 1
27
+ rack.retry_count.should == 5
28
+ rack.data.should == [1,2,3]
29
+ end
30
+ end
31
+ describe "#from_raw" do
32
+ it "should create a radio ack from raw USB data" do
33
+ header = 0b11110101 # ack = 1, powerDet = 0, retry_c = 1111
34
+ data = [0xFF] * 31
35
+ packet = [header].concat(data)
36
+ rack = RadioAck.from_raw(packet.pack('C*'))
37
+ rack.ack.should == true
38
+ rack.powerDet.should == false
39
+ rack.retry_count.should == 15
40
+ rack.data == data
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,227 @@
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/radio_driver'
20
+
21
+ describe RadioDriver do
22
+ before :each do
23
+ @radiodriver = RadioDriver.new()
24
+ @link_error_cb = Proc.new {|m| m}
25
+ @link_quality_cb = Proc.new {|m| m}
26
+ @connect_params = ['radio://0/2/1M',{
27
+ :link_quality_cb => @link_quality_cb,
28
+ :link_error_cb => @link_error_cb
29
+ }]
30
+ @crazyradio = double("Crazyradio")
31
+ allow(@crazyradio).to receive(:close)
32
+ @ack = RadioAck.new(true, true, 3, [1,2,3])
33
+ allow(@crazyradio).to receive(:send_packet).and_return(@ack)
34
+ allow(Crazyradio).to receive(:new).and_return(@crazyradio)
35
+ allow(Crazyradio).to receive(:factory).and_return(@crazyradio)
36
+
37
+ end
38
+
39
+ describe "#initialize" do
40
+ it "should intialize the radio driver" do
41
+ rd = RadioDriver.new()
42
+ rd.should be_an_instance_of RadioDriver
43
+ rd.uri.should be_nil
44
+ end
45
+ end
46
+
47
+ describe "#connect" do
48
+ it "should connect" do
49
+ expect(@radiodriver).to receive(:start_radio_thread)
50
+
51
+ @radiodriver.connect(*@connect_params)
52
+
53
+ expected_retries = RadioDriver::RETRIES_BEFORE_DISCONNECT
54
+ expected_queue_size = RadioDriver::OUT_QUEUE_MAX_SIZE
55
+ @radiodriver.retries_before_disconnect.should == expected_retries
56
+ @radiodriver.out_queue_max_size.should == expected_queue_size
57
+ @radiodriver.disconnect()
58
+ end
59
+
60
+
61
+ it "should raise an exception if the link is active" do
62
+ @radiodriver.connect(*@connect_params)
63
+ mesg = "Active link to radio://0/2/1M. Disconnect first"
64
+ expect {
65
+ @radiodriver.connect('radio://1/2/2M')
66
+ }.to raise_exception(OpenLink, mesg)
67
+ @radiodriver.disconnect()
68
+ end
69
+
70
+ it "should raise an exception a callback is missing" do
71
+ expect {
72
+ @radiodriver.connect('radio://1/2/2M', {
73
+ :link_quality_cb => Proc.new {}
74
+ })
75
+ }.to raise_exception(CallbackMissing,
76
+ "Callback link_error_cb mandatory")
77
+ end
78
+ end
79
+
80
+ describe "#disconnect" do
81
+ it "should disconnect if it is not connected" do
82
+ expect(@crazyradio).not_to receive(:close)
83
+ @radiodriver.disconnect()
84
+ end
85
+
86
+ it "should disconnect if it is connected" do
87
+ expect(@crazyradio).to receive(:close)
88
+ @radiodriver.connect(*@connect_params)
89
+ @radiodriver.disconnect()
90
+ end
91
+
92
+ it "should kill the thread if disconnect is called with true" do
93
+ expect_any_instance_of(Thread).to receive(:kill)
94
+ @radiodriver.connect(*@connect_params)
95
+ @radiodriver.disconnect(true)
96
+ end
97
+ end
98
+
99
+ describe "#send_packet" do
100
+ it "should do nothing when not connected" do
101
+ #expect_any_instance_of(Queue).not_to receive(:push)
102
+ @radiodriver.send_packet([1,2,3])
103
+ end
104
+
105
+ it "should push a packet to the queue and send it" do
106
+ #expect_any_instance_of(Queue).to receive(:push)
107
+ expect(@crazyradio).to receive(:send_packet)
108
+ @radiodriver.connect(*@connect_params)
109
+ @radiodriver.send_packet(CRTPPacket.unpack([1,2,3]))
110
+ @radiodriver.disconnect()
111
+ end
112
+
113
+ it "should call the link error callback if max size is reached" do
114
+ # prevent consuming packages
115
+ expect(@radiodriver).to receive(:start_radio_thread)
116
+ @radiodriver.connect(*@connect_params)
117
+ max = @radiodriver.out_queue_max_size
118
+ m = "Reached #{max} elements in outgoing queue"
119
+ # When it reaches 50 it disconnects and not send anymore
120
+ expect(@link_error_cb).to receive(:call).with(m).once
121
+ (1..52).each do
122
+ @radiodriver.send_packet([4,5,6])
123
+ end
124
+ @radiodriver.disconnect()
125
+ end
126
+ end
127
+
128
+ describe "#receive_packet" do
129
+ # note that thread sends control packages all the time
130
+ it "should receive nil if queue is empty" do
131
+ @radiodriver.connect(*@connect_params)
132
+ @radiodriver.disconnect() #empty queues
133
+ @radiodriver.receive_packet(true).should be_nil
134
+ end
135
+
136
+ it "should raise error if Crazyradio complains" do
137
+ e = USBDongleException
138
+ expect(@crazyradio).to receive(:send_packet).and_raise(e, "aa")
139
+ m = "Error talking to Crazyradio: aa"
140
+ expect(@link_error_cb).to receive(:call).with(m)
141
+ @radiodriver.connect(*@connect_params)
142
+ sleep 0.1
143
+ @radiodriver.disconnect()
144
+ end
145
+
146
+ it "should raise error if nil is returned as response" do
147
+ allow(@crazyradio).to receive(:send_packet).and_return(nil)
148
+ m = "Dongle communication error (ack is nil)"
149
+ expect(@link_error_cb).to receive(:call).with(m)
150
+ @radiodriver.connect(*@connect_params)
151
+ sleep 0.1
152
+ @radiodriver.disconnect()
153
+ end
154
+
155
+ it "should suicide if too many packets are lost" do
156
+ allow(@ack).to receive(:ack).and_return(false)
157
+ m = "Too many packets lost"
158
+ expect(@link_error_cb).to receive(:call).with(m).once
159
+ @radiodriver.connect(*@connect_params)
160
+ sleep 0.1
161
+ @radiodriver.disconnect()
162
+ end
163
+
164
+ it "should receive a packet" do
165
+ expect(@link_quality_cb).to receive(:call).with(70).at_least(:once)
166
+ @radiodriver.connect(*@connect_params)
167
+ @radiodriver.send_packet(CRTPPacket.unpack([1,2,3]))
168
+ packet = @radiodriver.receive_packet(false)
169
+ # send package returns an ack with [1,2,3] as data
170
+ expect(packet).to be_an_instance_of CRTPPacket
171
+ packet.size.should == 2
172
+ packet.header.should == 1
173
+ packet.data.should == [2,3]
174
+ @radiodriver.disconnect()
175
+ end
176
+ end
177
+
178
+ describe "#scan_interface" do
179
+ it "should complain if link is open" do
180
+ @radiodriver.connect(*@connect_params)
181
+ expect {
182
+ @radiodriver.scan_interface()
183
+ }.to raise_exception(OpenLink, "Cannot scan when link is open")
184
+ @radiodriver.disconnect()
185
+ end
186
+
187
+ it "should return the found some uris" do
188
+ allow(@crazyradio).to receive(:scan_channels).and_return([1,2,3],
189
+ [7,8,9],
190
+ [21,22,4])
191
+ expect(@crazyradio).to receive(:[]=).with(:arc, 1)
192
+ expect(@crazyradio).to receive(:[]=).with(:data_rate,
193
+ Crazyradio::DR_250KPS)
194
+ expect(@crazyradio).to receive(:[]=).with(:data_rate,
195
+ Crazyradio::DR_1MPS)
196
+ expect(@crazyradio).to receive(:[]=).with(:data_rate,
197
+ Crazyradio::DR_2MPS)
198
+ expect(@crazyradio).to receive(:close)
199
+ @radiodriver.scan_interface().should == [
200
+ 'radio://0/1/250K',
201
+ 'radio://0/2/250K',
202
+ 'radio://0/3/250K',
203
+ 'radio://0/7/1M',
204
+ 'radio://0/8/1M',
205
+ 'radio://0/9/1M',
206
+ 'radio://0/21/2M',
207
+ 'radio://0/22/2M',
208
+ 'radio://0/4/2M']
209
+ end
210
+
211
+ it "should raise a usb dongle exception it it happens" do
212
+ e = USBDongleException
213
+ allow(@crazyradio).to receive(:scan_channels).and_raise(e)
214
+ allow(@crazyradio).to receive(:[]=)
215
+ expect {
216
+ @radiodriver.scan_interface()
217
+ }.to raise_exception(e)
218
+ end
219
+ end
220
+
221
+ describe "#get_status" do
222
+ it "should get status" do
223
+ allow(Crazyradio).to receive(:status).and_return("hola")
224
+ @radiodriver.get_status.should == "hola"
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,51 @@
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 'simplecov'
20
+ SimpleCov.at_exit do
21
+ SimpleCov.minimum_coverage 95
22
+ SimpleCov.result.format!
23
+ end
24
+ SimpleCov.start do
25
+ add_group "Libraries", "lib"
26
+ add_group "Specs", "spec"
27
+ end
28
+
29
+
30
+ $: << File.join(File.dirname(__FILE__), "lib")
31
+ $: << File.join(File.dirname(__FILE__))
32
+
33
+ require 'crubyflie'
34
+ include Crubyflie
35
+ include CRTPConstants
36
+
37
+ require 'radio_ack_spec'
38
+ require 'crtp_packet_spec'
39
+ require 'crazyradio_spec'
40
+ require 'radio_driver_spec'
41
+ require 'radio_ack_spec'
42
+ require 'toc_cache_spec'
43
+ require 'toc_spec'
44
+ require 'crazyflie_spec'
45
+ require 'log_spec'
46
+ require 'param_spec'
47
+ require 'console_spec'
48
+ require 'commander_spec'
49
+ require 'joystick_input_reader_spec'
50
+ require 'input_reader_spec'
51
+ require 'crubyflie_logger_spec'
@@ -0,0 +1,87 @@
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/toc_cache'
20
+
21
+ describe TOCCache do
22
+
23
+ before :each do
24
+ allow_any_instance_of(TOCCache).to receive(:warn)
25
+
26
+
27
+ allow(File).to receive(:exist?).with('baa').and_return(true)
28
+ allow(File).to receive(:directory?).with('baa').and_return(true)
29
+ expect(FileUtils).to receive(:touch)
30
+ expect(FileUtils).to receive(:rm)
31
+ @cache = TOCCache.new('baa')
32
+ end
33
+
34
+ describe "#initialize" do
35
+ it "shoud not create a folder where it does not have permissions" do
36
+ allow(File).to receive(:exist?).with('baa').and_return(false)
37
+ do_this = receive(:mkdir_p).with('baa').and_raise(Errno::EACCES)
38
+ expect(FileUtils).to do_this
39
+ m = "Deactivating cache. Cannot create folder"
40
+ expect_any_instance_of(TOCCache).to receive(:warn).with(m)
41
+ cache = TOCCache.new('baa')
42
+ end
43
+
44
+ it "should veryfy the cache folder is a directory" do
45
+ allow(File).to receive(:exist?).with('baa').and_return(true)
46
+ allow(File).to receive(:directory?).with('baa').and_return(false)
47
+ m = "Deactivating cache. Folder is not a directory"
48
+ expect_any_instance_of(TOCCache).to receive(:warn).with(m)
49
+ cache = TOCCache.new('baa')
50
+ end
51
+
52
+ it "should test if the cache folder is writable" do
53
+ allow(File).to receive(:exist?).with('baa').and_return(true)
54
+ allow(File).to receive(:directory?).with('baa').and_return(true)
55
+ allow(FileUtils).to receive(:touch).and_raise(Errno::EACCES)
56
+ expect(FileUtils).not_to receive(:rm)
57
+ m = "Deactivating cache. Cannot write to folder"
58
+ expect_any_instance_of(TOCCache).to receive(:warn).with(m)
59
+ cache = TOCCache.new('baa')
60
+ end
61
+
62
+ it "initialize correctly otherwise" do
63
+ allow(File).to receive(:exist?).with('baa').and_return(true)
64
+ allow(File).to receive(:directory?).with('baa').and_return(true)
65
+ expect(FileUtils).not_to receive(:mkdir_p)
66
+ expect(FileUtils).to receive(:touch)
67
+ expect(FileUtils).to receive(:rm)
68
+ cache = TOCCache.new('baa')
69
+ end
70
+ end
71
+
72
+ describe "#fetch" do
73
+ it "should return nil if file does not exist" do
74
+ allow(File).to receive(:open).and_raise(Errno::ENOENT)
75
+ expect(Marshal).not_to receive(:load)
76
+ @cache.fetch("123").should be_nil
77
+ end
78
+ end
79
+
80
+ describe "#insert" do
81
+ it "should do nothing if an error happens" do
82
+ allow(File).to receive(:open).and_raise(Errno::EACCES)
83
+ expect(Marshal).not_to receive(:dump)
84
+ @cache.insert("123",{})
85
+ end
86
+ end
87
+ end
data/spec/toc_spec.rb ADDED
@@ -0,0 +1,187 @@
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/toc'
20
+
21
+ describe TOCElement do
22
+ describe "#initialize" do
23
+ it "should assign the variables correctly" do
24
+ te = TOCElement.new({
25
+ :ident => 1,
26
+ :group => 2,
27
+ :name => 3,
28
+ :ctype => 4,
29
+ :directive => 'C*',
30
+ :access => 6
31
+ })
32
+ te.ident.should == 1
33
+ te.group.should == 2
34
+ te.name.should == 3
35
+ te.ctype.should == 4
36
+ te.directive.should == 'C*'
37
+ te.access.should == 6
38
+ end
39
+ end
40
+ end
41
+
42
+ describe TOC do
43
+ before :each do
44
+ @cache = double("TOCCache")
45
+ allow(TOCCache).to receive(:new).and_return(@cache)
46
+ @toc = TOC.new()
47
+ @element = TOCElement.new({
48
+ :ident => 1,
49
+ :group => "mygroup",
50
+ :name => "myname",
51
+ :ctype => 4,
52
+ :rtype => 5,
53
+ :access => 6
54
+ })
55
+ @logger = @toc.logger
56
+ end
57
+
58
+ describe "#initialize" do
59
+ it "should setup the cache" do
60
+ expect(TOCCache).to receive(:new).with('abc')
61
+ toc = TOC.new('abc')
62
+ end
63
+ end
64
+
65
+ describe "#[]" do
66
+ it "should find an element by name only" do
67
+ @toc.insert(@element)
68
+ @toc["myname",:by_name].should == @element
69
+ @toc["mygroup.myname",:by_name].should == @element
70
+ @toc[1,:by_name].should be_nil
71
+ end
72
+
73
+ it "should find an element by id only" do
74
+ @toc.insert(@element)
75
+ @toc["myname",:by_id].should be_nil
76
+ @toc[1,:by_id].should == @element
77
+ end
78
+
79
+ it "should find an element by both name and id" do
80
+ @toc.insert(@element)
81
+ @toc["myname"].should == @element
82
+ @toc[1].should == @element
83
+ end
84
+
85
+ it "should return nil when the element is not found" do
86
+ @toc.insert(@element)
87
+ @toc["baa"].should be_nil
88
+ end
89
+ end
90
+
91
+ describe "#insert" do
92
+ it "should insert correctly an element" do
93
+ @toc[1].should be_nil
94
+ @toc.insert(@element)
95
+ @toc[1].should == @element
96
+ end
97
+ end
98
+
99
+ describe "#import/#export" do
100
+ it "should import and export" do
101
+ expect(@cache).to receive(:insert).with('abc', @toc.toc)
102
+ expect(@cache).to receive(:fetch).with('abc').and_return({:a => 3})
103
+
104
+ @toc.insert(@element)
105
+ @toc.export_to_cache('abc')
106
+ @toc.import_from_cache('abc')
107
+ @toc.toc.should == {:a => 3}
108
+ end
109
+ end
110
+
111
+ describe "#fetch_from_crazyflie" do
112
+ it "should import from cache when the TOC is in it" do
113
+ cf = double("Crazyflie")
114
+ queue = Queue.new
115
+ resp = CRTPPacket.new()
116
+ resp.modify_header(nil, 0, TOC_CHANNEL)
117
+ resp.data = [0, 5, 0x01, 0x00, 0x00, 0x00, 0x00]
118
+ bad_resp = CRTPPacket.new()
119
+ bad_resp.modify_header(nil, 0, 33)
120
+
121
+ allow(@cache).to receive(:fetch).and_return({:abc => "def"}).once
122
+
123
+ expect(queue).to receive(:pop).and_return(bad_resp, resp).twice
124
+ expect(queue).to receive(:<<).with(bad_resp)
125
+ expect(cf).to receive(:send_packet).with(anything, true).once
126
+ m = "Got a non-TOC packet. Requeueing..."
127
+ m2 = "TOC crc #{1}, 5 items"
128
+ m3 = "TOC found in cache"
129
+ expect(@logger).to receive(:debug).with(m)
130
+ expect(@logger).to receive(:debug).with(m2)
131
+ expect(@logger).to receive(:debug).with(m3)
132
+
133
+ @toc.fetch_from_crazyflie(cf, 0, queue)
134
+ end
135
+
136
+ it "should request the elements in the TOC when it is not in cache" do
137
+ cf = double("Crazyflie")
138
+ queue = Queue.new
139
+ resp = CRTPPacket.new()
140
+ resp.modify_header(nil, 0, TOC_CHANNEL)
141
+ resp.data = [0, 5, 0x01, 0x00, 0x00, 0x00, 0x00]
142
+
143
+ resp_elem = CRTPPacket.new()
144
+ resp_elem.modify_header(nil, 0, TOC_CHANNEL)
145
+ resp_elem.data = [0, 0, 0xFF, 0xFF]
146
+
147
+ allow(@cache).to receive(:fetch).and_return(nil).once
148
+
149
+ do_this = receive(:pop).and_return(resp,
150
+ resp_elem).exactly(6).times
151
+ expect(queue).to do_this
152
+ expect(cf).to receive(:send_packet).with(anything,
153
+ true).exactly(6).times
154
+
155
+ mw = "Not in cache"
156
+ m = "TOC crc 1, 5 items"
157
+ m0 = "Added 0 to TOC"
158
+ m1 = "Added 1 to TOC"
159
+ m2 = "Added 2 to TOC"
160
+ m3 = "Added 3 to TOC"
161
+ m4 = "Added 4 to TOC"
162
+
163
+ expect(@logger).to receive(:debug).with(mw)
164
+ expect(@logger).to receive(:debug).with(m)
165
+ expect(@logger).to receive(:debug).with(m0)
166
+ expect(@logger).to receive(:debug).with(m1)
167
+ expect(@logger).to receive(:debug).with(m2)
168
+ expect(@logger).to receive(:debug).with(m3)
169
+ expect(@logger).to receive(:debug).with(m4)
170
+
171
+ one = { :ident => 0 }
172
+ two = { :ident => 1 }
173
+ three = { :ident => 2 }
174
+ four = { :ident => 3 }
175
+ five = { :ident => 4 }
176
+ allow(TOCElement).to receive(:new).and_return(
177
+ TOCElement.new(one),
178
+ TOCElement.new(two),
179
+ TOCElement.new(three),
180
+ TOCElement.new(four),
181
+ TOCElement.new(five))
182
+
183
+ expect(@cache).to receive(:insert).with("1", anything)
184
+ @toc.fetch_from_crazyflie(cf, 0, queue)
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
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
+ # A simple script to list SDL axis/button numbering and read values
20
+
21
+ require 'sdl'
22
+ require 'pp'
23
+
24
+ warn "Welcome to Crubyflie joystick utility. Ctrl-C to exit."
25
+ warn "--"
26
+ Signal.trap("SIGINT") do
27
+ warn "\n\n"
28
+ warn "Bye bye!"
29
+ SDL.quit
30
+ exit 0
31
+ end
32
+
33
+ SDL.init(SDL::INIT_JOYSTICK)
34
+ n_joy = SDL::Joystick.num
35
+ if n_joy == 0
36
+ warn "No joysticks found"
37
+ exit 1
38
+ end
39
+
40
+
41
+ warn "Total number of Joysticks: #{n_joy}"
42
+ n_joy.times do |i|
43
+ warn "#{i}: #{SDL::Joystick.index_name(i)}"
44
+ end
45
+ warn "--"
46
+ print "Which one should we use (0-#{n_joy-1}): "
47
+ joy_id = gets.to_i
48
+ joy = SDL::Joystick.open(joy_id)
49
+ warn "Opened Joystick #{joy_id}"
50
+ warn "Name: SDL::Joystick.index_name(#{joy_id})"
51
+ warn "Number of Axes: #{joy.num_axes}"
52
+ warn "Number of buttons: #{joy.num_buttons}"
53
+ warn "Here is the reading for axis and buttons:"
54
+ loop {
55
+ SDL::Joystick.update_all
56
+ joy.num_axes.times do |i|
57
+ print "A##{i}: #{joy.axis(i)} | "
58
+ end
59
+
60
+ print " || "
61
+
62
+ button_read = []
63
+ joy.num_buttons.times do |i|
64
+ print "B##{i}: #{joy.button(i) ? 1 : 0} | "
65
+ end
66
+ print "\r"
67
+ $stdout.flush
68
+ sleep 0.05
69
+ }