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,301 @@
|
|
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 'rubygems'
|
20
|
+
require 'libusb'
|
21
|
+
|
22
|
+
require 'exceptions'
|
23
|
+
require 'crazyradio/radio_ack'
|
24
|
+
|
25
|
+
module Crubyflie
|
26
|
+
|
27
|
+
# This module defines some Crazyradio-related constants
|
28
|
+
module CrazyradioConstants
|
29
|
+
# USB dongle vendor ID
|
30
|
+
CRAZYRADIO_VENDOR_ID = 0x1915
|
31
|
+
# USB dongle product ID
|
32
|
+
CRAZYRADIO_PRODUCT_ID = 0x7777
|
33
|
+
|
34
|
+
# Set radio channel instruction code
|
35
|
+
SET_RADIO_CHANNEL = 0x01
|
36
|
+
# Set address instruction code
|
37
|
+
SET_RADIO_ADDRESS = 0x02
|
38
|
+
# Set data rate instruction code. For values see below
|
39
|
+
SET_DATA_RATE = 0x03
|
40
|
+
# Set radio power instruction code. For valid values see below
|
41
|
+
SET_RADIO_POWER = 0x04
|
42
|
+
# Set ARD (Auto Retry Delay) instruction code
|
43
|
+
SET_RADIO_ARD = 0x05
|
44
|
+
# Set ARC (Auto Retry Count) instruction code
|
45
|
+
SET_RADIO_ARC = 0x06
|
46
|
+
# Set ack instruction code
|
47
|
+
ACK_ENABLE = 0x10
|
48
|
+
# Set control carrier instruction code
|
49
|
+
SET_CONT_CARRIER = 0x20
|
50
|
+
# Scan N channels instruction code
|
51
|
+
SCANN_CHANNELS = 0x21
|
52
|
+
# Launch bootloader instruction code
|
53
|
+
LAUNCH_BOOTLOADER = 0xFF
|
54
|
+
|
55
|
+
# Default channel to talk to a Crazyflie
|
56
|
+
DEFAULT_CHANNEL = 2
|
57
|
+
|
58
|
+
# 250 Kb/s datarate
|
59
|
+
DR_250KPS = 0
|
60
|
+
# 1 Mb/s datarate
|
61
|
+
DR_1MPS = 1
|
62
|
+
# 2 Mb/s datarate
|
63
|
+
DR_2MPS = 2
|
64
|
+
|
65
|
+
# 18db power attenuation
|
66
|
+
P_M18DBM = 0
|
67
|
+
# 12db power attenuation
|
68
|
+
P_M12DBM = 1
|
69
|
+
# 6db power attenuation
|
70
|
+
P_M6DBM = 2
|
71
|
+
# 0db power attenuation
|
72
|
+
P_0DBM = 3
|
73
|
+
end
|
74
|
+
|
75
|
+
# Driver for the USB crazyradio dongle
|
76
|
+
class Crazyradio
|
77
|
+
include CrazyradioConstants
|
78
|
+
# Default settings for Crazyradio
|
79
|
+
DEFAULT_SETTINGS = {
|
80
|
+
:data_rate => DR_2MPS,
|
81
|
+
:channel => 2,
|
82
|
+
:cont_carrier => false,
|
83
|
+
:address => [0xE7] * 5, #5 times 0xE7
|
84
|
+
:power => P_0DBM,
|
85
|
+
:arc => 3,
|
86
|
+
:ard_bytes => 32 # 32
|
87
|
+
}
|
88
|
+
|
89
|
+
attr_reader :device, :handle, :dev_handle
|
90
|
+
# Initialize a crazyradio
|
91
|
+
# @param device [LIBUSB::Device] A crazyradio USB device
|
92
|
+
# @param settings [Hash] Crazyradio settings. @see #DEFAULT_SETTINGS
|
93
|
+
# @raise [USBDongleException] when something goes wrong
|
94
|
+
def initialize(device=nil, settings={})
|
95
|
+
if device.nil? || !device.is_a?(LIBUSB::Device)
|
96
|
+
raise USBDongleException.new("Wrong USB device")
|
97
|
+
end
|
98
|
+
|
99
|
+
@device = device
|
100
|
+
reopen()
|
101
|
+
@settings = DEFAULT_SETTINGS
|
102
|
+
@settings.update(settings)
|
103
|
+
apply_settings()
|
104
|
+
end
|
105
|
+
|
106
|
+
# Initializes the device and the USB handle
|
107
|
+
# If they are open, it releases the resources first
|
108
|
+
def reopen
|
109
|
+
close()
|
110
|
+
@handle = @device.open()
|
111
|
+
# USB configuration 0 means unconfigured state
|
112
|
+
@handle.configuration = 1 # hardcoded
|
113
|
+
@handle.claim_interface(0) # hardcoded
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return some information as string
|
117
|
+
# @return [String] Dongle information
|
118
|
+
def self.status
|
119
|
+
cr = Crazyradio.factory()
|
120
|
+
serial = cr.device.serial_number
|
121
|
+
manufacturer = cr.device.manufacturer
|
122
|
+
cr.close()
|
123
|
+
return "Found #{serial} USB dongle from #{manufacturer}"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Release interface, reset device and close the handle
|
127
|
+
def close
|
128
|
+
@handle.release_interface(0) if @handle
|
129
|
+
@handle.reset_device() if @handle
|
130
|
+
# WARNING: This hangs badly and randomly!!!
|
131
|
+
# @handle.close() if @handle
|
132
|
+
@handle = nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# Determines if the dongle has hardware scanning.
|
136
|
+
# @return [nil] defaults to nil to mitigate a dongle bug
|
137
|
+
def has_fw_scan
|
138
|
+
# it seems there is a bug on fw scan
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
# Scans channels for crazyflies
|
143
|
+
def scan_channels(start, stop, packet=[0xFF])
|
144
|
+
if has_fw_scan()
|
145
|
+
send_vendor_setup(SCANN_CHANNELS, start, stop, packet)
|
146
|
+
return get_vendor_setup(SCANN_CHANNELS, 0, 0, 64)
|
147
|
+
end
|
148
|
+
|
149
|
+
result = []
|
150
|
+
(start..stop).each do |ch|
|
151
|
+
self[:channel] = ch
|
152
|
+
status = send_packet(packet)
|
153
|
+
result << ch if status && status.ack
|
154
|
+
end
|
155
|
+
return result
|
156
|
+
end
|
157
|
+
|
158
|
+
# Creates a Crazyradio object with the first USB dongle found
|
159
|
+
# @param settings [Hash] Crazyradio settings. @see #DEFAULT_SETTINGS
|
160
|
+
# @return [Crazyradio] a Crazyradio
|
161
|
+
# @raise [USBDongleException] when no USB dongle is found
|
162
|
+
def self.factory(settings={})
|
163
|
+
devs = Crazyradio.find_devices()
|
164
|
+
raise USBDongleException.new("No dongles found") if devs.empty?()
|
165
|
+
return Crazyradio.new(devs.first, settings)
|
166
|
+
end
|
167
|
+
|
168
|
+
# List crazyradio dongles
|
169
|
+
def self.find_devices
|
170
|
+
usb = LIBUSB::Context.new
|
171
|
+
usb.devices(:idVendor => CRAZYRADIO_VENDOR_ID,
|
172
|
+
:idProduct => CRAZYRADIO_PRODUCT_ID)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Send a data packet and reads the response into an Ack
|
176
|
+
# @param [Array] data to be sent
|
177
|
+
def send_packet(data)
|
178
|
+
out_args = {
|
179
|
+
:endpoint => 1,
|
180
|
+
:dataOut => data.pack('C*')
|
181
|
+
}
|
182
|
+
@handle.bulk_transfer(out_args)
|
183
|
+
in_args = {
|
184
|
+
:endpoint => 0x81,
|
185
|
+
:dataIn => 64
|
186
|
+
}
|
187
|
+
response = @handle.bulk_transfer(in_args)
|
188
|
+
|
189
|
+
return nil unless response
|
190
|
+
return RadioAck.from_raw(response, @settings[:arc])
|
191
|
+
end
|
192
|
+
|
193
|
+
# Set a crazyradio setting
|
194
|
+
# @param setting [Symbol] a valid Crazyradio setting name
|
195
|
+
# @param value [Object] the setting value
|
196
|
+
def []=(setting, value)
|
197
|
+
@settings[setting] = value
|
198
|
+
apply_settings(setting)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Get a crazyradio setting
|
202
|
+
# @param setting [Symbol] a valid Crazyradio setting name
|
203
|
+
# @return [Integer] the value
|
204
|
+
def [](setting)
|
205
|
+
return @settings[setting]
|
206
|
+
end
|
207
|
+
|
208
|
+
# Applies the indicated setting or all settings if not specified
|
209
|
+
# @param setting [Symbol] a valid crazyradio setting name
|
210
|
+
def apply_settings(setting=nil)
|
211
|
+
to_apply = setting.nil? ? @settings.keys() : [setting]
|
212
|
+
to_apply.each do |setting|
|
213
|
+
value = @settings[setting]
|
214
|
+
next if value.nil?
|
215
|
+
|
216
|
+
case setting
|
217
|
+
when :data_rate
|
218
|
+
set_data_rate(value)
|
219
|
+
when :channel
|
220
|
+
set_channel(value)
|
221
|
+
when :arc
|
222
|
+
set_arc(value)
|
223
|
+
when :cont_carrier
|
224
|
+
set_cont_carrier(value)
|
225
|
+
when :address
|
226
|
+
set_address(value)
|
227
|
+
when :power
|
228
|
+
set_power(value)
|
229
|
+
when :ard_bytes
|
230
|
+
set_ard_bytes(value)
|
231
|
+
else
|
232
|
+
@settings.delete(setting)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def send_vendor_setup(request, value, index=0, dataOut=[])
|
238
|
+
args = {
|
239
|
+
:bmRequestType => LIBUSB::REQUEST_TYPE_VENDOR,
|
240
|
+
:bRequest => request,
|
241
|
+
:wValue => value,
|
242
|
+
:wIndex => index,
|
243
|
+
:dataOut => dataOut.pack('C*')
|
244
|
+
}
|
245
|
+
@handle.control_transfer(args)
|
246
|
+
end
|
247
|
+
private :send_vendor_setup
|
248
|
+
|
249
|
+
def get_vendor_setup(request, value, index, dataIn=0)
|
250
|
+
args = {
|
251
|
+
# Why this mask?
|
252
|
+
:bmRequestType => LIBUSB::REQUEST_TYPE_VENDOR | 0x80,
|
253
|
+
:bRequest => request,
|
254
|
+
:wValue => value,
|
255
|
+
:wIndex => index,
|
256
|
+
:dataIn => dataIn
|
257
|
+
}
|
258
|
+
return @handle.control_transfer(args).unpack('C*')
|
259
|
+
end
|
260
|
+
private :get_vendor_setup
|
261
|
+
|
262
|
+
def set_channel(channel)
|
263
|
+
send_vendor_setup(SET_RADIO_CHANNEL, channel)
|
264
|
+
end
|
265
|
+
private :set_channel
|
266
|
+
|
267
|
+
def set_address(addr)
|
268
|
+
if addr.size != 5
|
269
|
+
raise USBDongleException.new("Address needs 5 bytes")
|
270
|
+
end
|
271
|
+
send_vendor_setup(SET_RADIO_ADDRESS, 0, 0, addr)
|
272
|
+
end
|
273
|
+
private :set_address
|
274
|
+
|
275
|
+
def set_data_rate(datarate)
|
276
|
+
send_vendor_setup(SET_DATA_RATE, datarate)
|
277
|
+
end
|
278
|
+
private :set_data_rate
|
279
|
+
|
280
|
+
def set_power(power)
|
281
|
+
send_vendor_setup(SET_RADIO_POWER, power)
|
282
|
+
end
|
283
|
+
private :set_power
|
284
|
+
|
285
|
+
def set_arc(arc)
|
286
|
+
send_vendor_setup(SET_RADIO_ARC, arc)
|
287
|
+
end
|
288
|
+
private :set_arc
|
289
|
+
|
290
|
+
def set_ard_bytes(nbytes)
|
291
|
+
# masking this way converts 32 to 0xA0 for example
|
292
|
+
send_vendor_setup(SET_RADIO_ARD, 0x80 | nbytes)
|
293
|
+
end
|
294
|
+
private :set_ard_bytes
|
295
|
+
|
296
|
+
def set_cont_carrier(active)
|
297
|
+
send_vendor_setup(SET_CONT_CARRIER, active ? 1 : 0)
|
298
|
+
end
|
299
|
+
private :set_cont_carrier
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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
|
+
module Crubyflie
|
20
|
+
# An acknowlegdement packet from the Crazyflie
|
21
|
+
class RadioAck
|
22
|
+
attr_accessor :ack, :powerDet, :retry_count, :data
|
23
|
+
|
24
|
+
# Initialize a Radio Ack
|
25
|
+
# @param ack [TrueClass,FalseClass] indicates if it is an ack
|
26
|
+
# @param powerDet [TrueClass,FalseClass] powerDet
|
27
|
+
# @param retry_count [Integer] the times we retried to send the packet
|
28
|
+
# @param data [Array] the payload of the ack packet
|
29
|
+
def initialize(ack=nil, powerDet=nil, retry_count=0, data=[])
|
30
|
+
@ack = ack
|
31
|
+
@powerDet = powerDet
|
32
|
+
@retry_count = retry_count
|
33
|
+
@data = data
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create from raw usb response
|
37
|
+
# @param data [String] binary data
|
38
|
+
# @return [RadioAck] a properly initialized RadioAck
|
39
|
+
def self.from_raw(data, arc=0)
|
40
|
+
response = data.unpack('C*')
|
41
|
+
header = response.shift()
|
42
|
+
ack = (header & 0x01) != 0
|
43
|
+
powerDet = (header & 0x02) != 0
|
44
|
+
retry_count = header != 0 ? header >> 4 : arc
|
45
|
+
return RadioAck.new(ack, powerDet, retry_count, response)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,74 @@
|
|
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
|
+
# A simple script to list SDL axis/button numbering and read values
|
20
|
+
|
21
|
+
# This module is included where needed and offers
|
22
|
+
# easy access to the logger
|
23
|
+
module Logging
|
24
|
+
# Give me a logger
|
25
|
+
# @return [CrubyflieLogger]
|
26
|
+
def self.logger
|
27
|
+
Logging.logger
|
28
|
+
end
|
29
|
+
|
30
|
+
# Lazy initialization for a logger
|
31
|
+
# @return [CrubyflieLogger]
|
32
|
+
def logger
|
33
|
+
@logger ||= CrubyflieLogger.new()
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set a logger
|
37
|
+
# @param logger [CrubyflieLogger] the new logger to use
|
38
|
+
def logger=(logger)
|
39
|
+
@logger = logger
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# A simple logger to log debug messages, info, warnings and errors
|
44
|
+
class CrubyflieLogger
|
45
|
+
# Initialize a logger and enable debug logs
|
46
|
+
# @param debug [TrueClass,nil] enable output of debug messages
|
47
|
+
def initialize(debug=$debug)
|
48
|
+
@@debug = debug
|
49
|
+
end
|
50
|
+
|
51
|
+
# Logs a debug message
|
52
|
+
# @param msg [String] the message to be logged
|
53
|
+
def debug(msg)
|
54
|
+
$stderr.puts "DEBUG: #{msg}" if @@debug
|
55
|
+
end
|
56
|
+
|
57
|
+
# Logs an info message to $stdout
|
58
|
+
# @param msg [String] the message to be logged
|
59
|
+
def info(msg)
|
60
|
+
$stdout.puts "INFO: #{msg}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Logs a warning message to $stderr
|
64
|
+
# @param msg [String] the message to be logged
|
65
|
+
def warn(msg)
|
66
|
+
$stderr.puts "WARNING: #{msg}"
|
67
|
+
end
|
68
|
+
|
69
|
+
# Logs an error message to $stderr
|
70
|
+
# @param msg [String] the message to be logged
|
71
|
+
def error(msg)
|
72
|
+
$stderr.puts "ERROR: #{msg}"
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,146 @@
|
|
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
|
+
|
20
|
+
module Crubyflie
|
21
|
+
|
22
|
+
# Constants related to CRTP Packets
|
23
|
+
module CRTPConstants
|
24
|
+
# The ports for the different facilities
|
25
|
+
CRTP_PORTS = {
|
26
|
+
:console => 0x00,
|
27
|
+
:param => 0x02,
|
28
|
+
:commander => 0x03,
|
29
|
+
:logging => 0x05,
|
30
|
+
:debugdriver => 0x0E,
|
31
|
+
:linkctrl => 0x0F,
|
32
|
+
:all => 0xFF
|
33
|
+
}
|
34
|
+
|
35
|
+
# How many seconds until we give up waiting for a packet to
|
36
|
+
# appear in a queue
|
37
|
+
WAIT_PACKET_TIMEOUT = 2
|
38
|
+
|
39
|
+
# TOC channel
|
40
|
+
TOC_CHANNEL = 0
|
41
|
+
|
42
|
+
# Channel to retrieve Log settings
|
43
|
+
LOG_SETTINGS_CHANNEL = 1
|
44
|
+
# Channel to retrieve Log data
|
45
|
+
LOG_DATA_CHANNEL = 2
|
46
|
+
|
47
|
+
# Channel to read parameters
|
48
|
+
PARAM_READ_CHANNEL = 1
|
49
|
+
# Channel to write parameters
|
50
|
+
PARAM_WRITE_CHANNEL = 2
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
# Command to request a TOC element
|
55
|
+
CMD_TOC_ELEMENT = 0
|
56
|
+
# Command to request TOC information
|
57
|
+
CMD_TOC_INFO = 1
|
58
|
+
# Create block command
|
59
|
+
CMD_CREATE_BLOCK = 0
|
60
|
+
# Append block command
|
61
|
+
CMD_APPEND_BLOCK = 1
|
62
|
+
# Delete block command
|
63
|
+
CMD_DELETE_BLOCK = 2
|
64
|
+
# Start logging command
|
65
|
+
CMD_START_LOGGING = 3
|
66
|
+
# Stop logging command
|
67
|
+
CMD_STOP_LOGGING = 4
|
68
|
+
# Reset logging command
|
69
|
+
CMD_RESET_LOGGING = 5
|
70
|
+
|
71
|
+
|
72
|
+
# These come from param.rb
|
73
|
+
# # TOC access command
|
74
|
+
# TOC_RESET = 0
|
75
|
+
# TOC_GETNEXT = 1
|
76
|
+
# TOC_GETCRC32 = 2
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# A data packet. Raw packet data is sent to the USB driver
|
83
|
+
# Some related docs:
|
84
|
+
# http://wiki.bitcraze.se/
|
85
|
+
# projects:crazyflie:firmware:comm_protocol#serial_port
|
86
|
+
class CRTPPacket
|
87
|
+
|
88
|
+
attr_reader :size, :header, :channel, :port, :data
|
89
|
+
# Initialize a package with a header and data
|
90
|
+
# @param header [Integer] represents an 8 bit header
|
91
|
+
# @param payload [Array] @see #set_data
|
92
|
+
def initialize(header=0, payload=[])
|
93
|
+
modify_header(header)
|
94
|
+
@data = payload || []
|
95
|
+
@size = data.size #+ 1 # header. Bytes
|
96
|
+
end
|
97
|
+
|
98
|
+
# Set new data for this packet and update the size
|
99
|
+
# @param new_data [Array] the new data
|
100
|
+
def data=(new_data)
|
101
|
+
@data = new_data
|
102
|
+
@size = @data.size
|
103
|
+
end
|
104
|
+
|
105
|
+
# Modify the full header, or the channel or the port
|
106
|
+
# @param header [Integer] a new full header. Prevails over the rest
|
107
|
+
# @param port [Integer] a new port (4 bits)
|
108
|
+
# @param channel [Integer] a new channel (2 bits)
|
109
|
+
def modify_header(header=nil, port=nil, channel=nil)
|
110
|
+
if header
|
111
|
+
@header = header
|
112
|
+
@channel = header & 0b11 # lowest 2 bits of header
|
113
|
+
@port = (header >> 4) & 0b1111 # bits 4-7
|
114
|
+
return
|
115
|
+
end
|
116
|
+
if channel
|
117
|
+
@channel = channel & 0b11 # 2 bits
|
118
|
+
@header = (@header & 0b11111100) | @channel
|
119
|
+
end
|
120
|
+
if port
|
121
|
+
@port = (port & 0b1111) # 4 bits
|
122
|
+
@header = (@header & 0b00001111) | @port << 4
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Creates a packet from a raw data array
|
127
|
+
def self.unpack(data)
|
128
|
+
return CRTPPacket.new() if !data.is_a?(Array) || data.empty?()
|
129
|
+
header = data[0]
|
130
|
+
data = data[1..-1]
|
131
|
+
CRTPPacket.new(header, data)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Concat the header and the data and return it
|
135
|
+
# @return [Array] header concatenated with data
|
136
|
+
def pack
|
137
|
+
[@header].concat(@data)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Pack the data of the packet into unsigned chars when needed
|
141
|
+
# @return [String] binary data
|
142
|
+
def data_repack
|
143
|
+
return @data.pack('C*')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|