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,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
|