crubyflie 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }