cmake remove circular linking and reorganize

- px4_add_module now requires MAIN
 - px4_add_library doesn't automatically link
This commit is contained in:
Daniel Agar
2018-04-11 15:10:51 -04:00
parent a8bc3d187f
commit ea3acb7121
576 changed files with 1406 additions and 2014 deletions
+7 -19
View File
@@ -33,9 +33,7 @@
set(SRCS
airspeed.cpp
battery.cpp
board_serial.c
bson/tinybson.c
circuit_breaker.cpp
conversions.c
cpuload.c
@@ -43,7 +41,6 @@ set(SRCS
hysteresis/hysteresis.cpp
mavlink_log.c
otp.c
perf_counter.c
pid/pid.c
pwm_limit/pwm_limit.c
rc_check.c
@@ -53,8 +50,6 @@ if(${OS} STREQUAL "nuttx")
list(APPEND SRCS
err.c
printload.c
flashparams/flashparams.c
flashparams/flashfs.c
)
elseif ("${CONFIG_SHMEM}" STREQUAL "1")
list(APPEND SRCS
@@ -66,18 +61,11 @@ else()
)
endif()
if(NOT ${OS} STREQUAL "qurt")
list(APPEND SRCS
hx_stream.c
)
# TODO: find a better way to do this
if (NOT "${CONFIG}" MATCHES "px4io")
px4_add_library(systemlib ${SRCS})
target_compile_options(systemlib PRIVATE -Wno-sign-compare)
else()
add_library(systemlib ${PX4_SOURCE_DIR}/src/platforms/empty.c)
add_dependencies(systemlib prebuild_targets)
endif()
px4_add_module(
MODULE modules__systemlib
COMPILE_FLAGS
-Wno-sign-compare
SRCS ${SRCS}
DEPENDS
platforms__common
)
# vim: set noet ft=cmake fenc=utf-8 ff=unix :
-237
View File
@@ -1,237 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2016 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file battery.cpp
*
* Library calls for battery functionality.
*
* @author Julian Oes <julian@oes.ch>
*/
#include "battery.h"
#include <mathlib/mathlib.h>
Battery::Battery() :
ModuleParams(nullptr),
_warning(battery_status_s::BATTERY_WARNING_NONE),
_last_timestamp(0)
{
}
void
Battery::reset(battery_status_s *battery_status)
{
memset(battery_status, 0, sizeof(*battery_status));
battery_status->current_a = -1.f;
battery_status->remaining = 1.f;
battery_status->scale = 1.f;
battery_status->cell_count = _n_cells.get();
// TODO: check if it is sane to reset warning to NONE
battery_status->warning = battery_status_s::BATTERY_WARNING_NONE;
battery_status->connected = false;
}
void
Battery::updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a,
bool connected, bool selected_source, int priority,
float throttle_normalized,
bool armed, battery_status_s *battery_status)
{
reset(battery_status);
battery_status->timestamp = timestamp;
filterVoltage(voltage_v);
filterThrottle(throttle_normalized);
filterCurrent(current_a);
sumDischarged(timestamp, current_a);
estimateRemaining(_voltage_filtered_v, _current_filtered_a, _throttle_filtered, armed);
computeScale();
if (_battery_initialized) {
determineWarning(connected);
}
if (_voltage_filtered_v > 2.1f) {
_battery_initialized = true;
battery_status->voltage_v = voltage_v;
battery_status->voltage_filtered_v = _voltage_filtered_v;
battery_status->scale = _scale;
battery_status->current_a = current_a;
battery_status->current_filtered_a = _current_filtered_a;
battery_status->discharged_mah = _discharged_mah;
battery_status->warning = _warning;
battery_status->remaining = _remaining;
battery_status->connected = connected;
battery_status->system_source = selected_source;
battery_status->priority = priority;
}
}
void
Battery::filterVoltage(float voltage_v)
{
if (!_battery_initialized) {
_voltage_filtered_v = voltage_v;
}
// TODO: inspect that filter performance
const float filtered_next = _voltage_filtered_v * 0.99f + voltage_v * 0.01f;
if (PX4_ISFINITE(filtered_next)) {
_voltage_filtered_v = filtered_next;
}
}
void
Battery::filterCurrent(float current_a)
{
if (!_battery_initialized) {
_current_filtered_a = current_a;
}
// ADC poll is at 100Hz, this will perform a low pass over approx 500ms
const float filtered_next = _current_filtered_a * 0.98f + current_a * 0.02f;
if (PX4_ISFINITE(filtered_next)) {
_current_filtered_a = filtered_next;
}
}
void Battery::filterThrottle(float throttle)
{
if (!_battery_initialized) {
_throttle_filtered = throttle;
}
const float filtered_next = _throttle_filtered * 0.99f + throttle * 0.01f;
if (PX4_ISFINITE(filtered_next)) {
_throttle_filtered = filtered_next;
}
}
void
Battery::sumDischarged(hrt_abstime timestamp, float current_a)
{
// Not a valid measurement
if (current_a < 0.f) {
// Because the measurement was invalid we need to stop integration
// and re-initialize with the next valid measurement
_last_timestamp = 0;
return;
}
// Ignore first update because we don't know dt.
if (_last_timestamp != 0) {
const float dt = (timestamp - _last_timestamp) / 1e6;
// mAh since last loop: (current[A] * 1000 = [mA]) * (dt[s] / 3600 = [h])
_discharged_mah_loop = (current_a * 1e3f) * (dt / 3600.f);
_discharged_mah += _discharged_mah_loop;
}
_last_timestamp = timestamp;
}
void
Battery::estimateRemaining(float voltage_v, float current_a, float throttle, bool armed)
{
// remaining battery capacity based on voltage
float cell_voltage = voltage_v / _n_cells.get();
// correct battery voltage locally for load drop to avoid estimation fluctuations
if (_r_internal.get() >= 0.f) {
cell_voltage += _r_internal.get() * current_a;
} else {
// assume linear relation between throttle and voltage drop
cell_voltage += throttle * _v_load_drop.get();
}
_remaining_voltage = math::gradual(cell_voltage, _v_empty.get(), _v_charged.get(), 0.f, 1.f);
// choose which quantity we're using for final reporting
if (_capacity.get() > 0.f) {
// if battery capacity is known, fuse voltage measurement with used capacity
if (!_battery_initialized) {
// initialization of the estimation state
_remaining = _remaining_voltage;
} else {
// The lower the voltage the more adjust the estimate with it to avoid deep discharge
const float weight_v = 3e-4f * (1 - _remaining_voltage);
_remaining = (1 - weight_v) * _remaining + weight_v * _remaining_voltage;
// directly apply current capacity slope calculated using current
_remaining -= _discharged_mah_loop / _capacity.get();
_remaining = math::max(_remaining, 0.f);
}
} else {
// else use voltage
_remaining = _remaining_voltage;
}
}
void
Battery::determineWarning(bool connected)
{
if (connected) {
// propagate warning state only if the state is higher, otherwise remain in current warning state
if (_remaining < _emergency_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_EMERGENCY)) {
_warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
} else if (_remaining < _crit_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_CRITICAL)) {
_warning = battery_status_s::BATTERY_WARNING_CRITICAL;
} else if (_remaining < _low_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_LOW)) {
_warning = battery_status_s::BATTERY_WARNING_LOW;
}
}
}
void
Battery::computeScale()
{
const float voltage_range = (_v_charged.get() - _v_empty.get());
// reusing capacity calculation to get single cell voltage before drop
const float bat_v = _v_empty.get() + (voltage_range * _remaining_voltage);
_scale = _v_charged.get() / bat_v;
if (_scale > 1.3f) { // Allow at most 30% compensation
_scale = 1.3f;
} else if (!PX4_ISFINITE(_scale) || _scale < 1.f) { // Shouldn't ever be more than the power at full battery
_scale = 1.f;
}
}
-121
View File
@@ -1,121 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2016, 2017 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file battery.h
*
* Library calls for battery functionality.
*
* @author Julian Oes <julian@oes.ch>
*/
#pragma once
#include <uORB/topics/battery_status.h>
#include <drivers/drv_hrt.h>
#include <px4_module_params.h>
class Battery : public ModuleParams
{
public:
Battery();
/**
* Reset all battery stats and report invalid/nothing.
*/
void reset(battery_status_s *battery_status);
/**
* Get the battery cell count
*/
int cell_count() { return _n_cells.get(); }
/**
* Get the empty voltage per cell
*/
float empty_cell_voltage() { return _v_empty.get(); }
/**
* Get the full voltage per cell
*/
float full_cell_voltage() { return _v_charged.get(); }
/**
* Update current battery status message.
*
* @param voltage_v: current voltage in V
* @param current_a: current current in A
* @param connected: Battery is connected
* @param selected_source: This battery is on the brick that the selected source for selected_source
* @param priority: The brick number -1. The term priority refers to the Vn connection on the LTC4417
* @param throttle_normalized: throttle from 0 to 1
*/
void updateBatteryStatus(hrt_abstime timestamp, float voltage_v, float current_a,
bool connected, bool selected_source, int priority,
float throttle_normalized,
bool armed, battery_status_s *status);
private:
void filterVoltage(float voltage_v);
void filterThrottle(float throttle);
void filterCurrent(float current_a);
void sumDischarged(hrt_abstime timestamp, float current_a);
void estimateRemaining(float voltage_v, float current_a, float throttle, bool armed);
void determineWarning(bool connected);
void computeScale();
DEFINE_PARAMETERS(
(ParamFloat<px4::params::BAT_V_EMPTY>) _v_empty,
(ParamFloat<px4::params::BAT_V_CHARGED>) _v_charged,
(ParamInt<px4::params::BAT_N_CELLS>) _n_cells,
(ParamFloat<px4::params::BAT_CAPACITY>) _capacity,
(ParamFloat<px4::params::BAT_V_LOAD_DROP>) _v_load_drop,
(ParamFloat<px4::params::BAT_R_INTERNAL>) _r_internal,
(ParamFloat<px4::params::BAT_LOW_THR>) _low_thr,
(ParamFloat<px4::params::BAT_CRIT_THR>) _crit_thr,
(ParamFloat<px4::params::BAT_EMERGEN_THR>) _emergency_thr
)
bool _battery_initialized = false;
float _voltage_filtered_v = -1.f;
float _throttle_filtered = -1.f;
float _current_filtered_a = -1.f;
float _discharged_mah = 0.f;
float _discharged_mah_loop = 0.f;
float _remaining_voltage = -1.f; ///< normalized battery charge level remaining based on voltage
float _remaining = -1.f; ///< normalized battery charge level, selected based on config param
float _scale = 1.f;
uint8_t _warning;
hrt_abstime _last_timestamp;
};
-198
View File
@@ -1,198 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2013-2017 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file battery_params.c
*
* Parameters defined by the battery lib.
*
* @author Julian Oes <julian@oes.ch>
*/
#include <px4_config.h>
#include <systemlib/param/param.h>
/**
* Empty cell voltage (5C load)
*
* Defines the voltage where a single cell of the battery is considered empty.
* The voltage should be chosen before the steep dropoff to 2.8V. A typical
* lithium battery can only be discharged down to 10% before it drops off
* to a voltage level damaging the cells.
*
* @group Battery Calibration
* @unit V
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.5f);
/**
* Full cell voltage (5C load)
*
* Defines the voltage where a single cell of the battery is considered full
* under a mild load. This will never be the nominal voltage of 4.2V
*
* @group Battery Calibration
* @unit V
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.05f);
/**
* Low threshold
*
* Sets the threshold when the battery will be reported as low.
* This has to be higher than the critical threshold.
*
* @group Battery Calibration
* @unit norm
* @min 0.12
* @max 0.4
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_LOW_THR, 0.15f);
/**
* Critical threshold
*
* Sets the threshold when the battery will be reported as critically low.
* This has to be lower than the low threshold. This threshold commonly
* will trigger RTL.
*
* @group Battery Calibration
* @unit norm
* @min 0.05
* @max 0.1
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_CRIT_THR, 0.07f);
/**
* Emergency threshold
*
* Sets the threshold when the battery will be reported as dangerously low.
* This has to be lower than the critical threshold. This threshold commonly
* will trigger landing.
*
* @group Battery Calibration
* @unit norm
* @min 0.03
* @max 0.07
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_EMERGEN_THR, 0.05f);
/**
* Voltage drop per cell on full throttle
*
* This implicitely defines the internal resistance
* to maximum current ratio and assumes linearity.
* A good value to use is the difference between the
* 5C and 20-25C load. Not used if BAT_R_INTERNAL is
* set.
*
* @group Battery Calibration
* @unit V
* @min 0.07
* @max 0.5
* @decimal 2
* @increment 0.01
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_V_LOAD_DROP, 0.3f);
/**
* Explicitly defines the per cell internal resistance
*
* If non-negative, then this will be used in place of
* BAT_V_LOAD_DROP for all calculations.
*
* @group Battery Calibration
* @unit Ohms
* @min -1.0
* @max 0.2
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_R_INTERNAL, -1.0f);
/**
* Number of cells.
*
* Defines the number of cells the attached battery consists of.
*
* @group Battery Calibration
* @unit S
* @value 0 Unconfigured
* @value 2 2S Battery
* @value 3 3S Battery
* @value 4 4S Battery
* @value 5 5S Battery
* @value 6 6S Battery
* @value 7 7S Battery
* @value 8 8S Battery
* @value 9 9S Battery
* @value 10 10S Battery
* @value 11 11S Battery
* @value 12 12S Battery
* @value 13 13S Battery
* @value 14 14S Battery
* @value 15 15S Battery
* @value 16 16S Battery
* @reboot_required true
*/
PARAM_DEFINE_INT32(BAT_N_CELLS, 0);
/**
* Battery capacity.
*
* Defines the capacity of the attached battery.
*
* @group Battery Calibration
* @unit mAh
* @decimal 0
* @min -1.0
* @max 100000
* @increment 50
* @reboot_required true
*/
PARAM_DEFINE_FLOAT(BAT_CAPACITY, -1.0f);
-628
View File
@@ -1,628 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file tinybson.c
*
* A simple subset SAX-style BSON parser and generator.
*/
#include <px4_posix.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <systemlib/err.h>
#include "tinybson.h"
#if 0
# define debug(fmt, args...) do { PX4_INFO("BSON: " fmt, ##args); } while(0)
#else
# define debug(fmt, args...) do { } while(0)
#endif
#define CODER_CHECK(_c) do { if (_c->dead) { debug("coder dead"); return -1; }} while(0)
#define CODER_KILL(_c, _reason) do { debug("killed: %s", _reason); _c->dead = true; return -1; } while(0)
#define BSON_READ read
#define BSON_WRITE write
#define BSON_FSYNC fsync
static int
read_x(bson_decoder_t decoder, void *p, size_t s)
{
CODER_CHECK(decoder);
if (decoder->fd > -1) {
return (BSON_READ(decoder->fd, p, s) == (int)s) ? 0 : -1;
}
if (decoder->buf != NULL) {
/* staged operations to avoid integer overflow for corrupt data */
if (s >= decoder->bufsize) {
CODER_KILL(decoder, "buffer too small for read");
}
if ((decoder->bufsize - s) < decoder->bufpos) {
CODER_KILL(decoder, "not enough data for read");
}
memcpy(p, (decoder->buf + decoder->bufpos), s);
decoder->bufpos += s;
return 0;
}
debug("no source");
return -1;
}
static int
read_int8(bson_decoder_t decoder, int8_t *b)
{
return read_x(decoder, b, sizeof(*b));
}
static int
read_int32(bson_decoder_t decoder, int32_t *i)
{
return read_x(decoder, i, sizeof(*i));
}
static int
read_int64(bson_decoder_t decoder, int64_t *i)
{
return read_x(decoder, i, sizeof(*i));
}
static int
read_double(bson_decoder_t decoder, double *d)
{
return read_x(decoder, d, sizeof(*d));
}
int
bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *priv)
{
int32_t junk;
decoder->fd = fd;
decoder->buf = NULL;
decoder->dead = false;
decoder->callback = callback;
decoder->priv = priv;
decoder->nesting = 1;
decoder->pending = 0;
decoder->node.type = BSON_UNDEFINED;
/* read and discard document size */
if (read_int32(decoder, &junk)) {
CODER_KILL(decoder, "failed discarding length");
}
/* ready for decoding */
return 0;
}
int
bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback,
void *priv)
{
int32_t len;
/* argument sanity */
if ((buf == NULL) || (callback == NULL)) {
return -1;
}
decoder->fd = -1;
decoder->buf = (uint8_t *)buf;
decoder->dead = false;
if (bufsize == 0) {
decoder->bufsize = *(uint32_t *)buf;
debug("auto-detected %u byte object", decoder->bufsize);
} else {
decoder->bufsize = bufsize;
}
decoder->bufpos = 0;
decoder->callback = callback;
decoder->priv = priv;
decoder->nesting = 1;
decoder->pending = 0;
decoder->node.type = BSON_UNDEFINED;
/* read and discard document size */
if (read_int32(decoder, &len)) {
CODER_KILL(decoder, "failed reading length");
}
if ((len > 0) && (len > (int)decoder->bufsize)) {
CODER_KILL(decoder, "document length larger than buffer");
}
/* ready for decoding */
return 0;
}
int
bson_decoder_next(bson_decoder_t decoder)
{
int8_t tbyte;
int32_t tint;
unsigned nlen;
CODER_CHECK(decoder);
/* if the previous node was EOO, pop a nesting level */
if (decoder->node.type == BSON_EOO) {
if (decoder->nesting > 0) {
decoder->nesting--;
}
/* if the nesting level is now zero, the top-level document is done */
if (decoder->nesting == 0) {
/* like kill but not an error */
debug("nesting is zero, document is done");
decoder->fd = -1;
/* return end-of-file to the caller */
return 0;
}
}
/* if there are unread bytes pending in the stream, discard them */
while (decoder->pending > 0) {
if (read_int8(decoder, &tbyte)) {
CODER_KILL(decoder, "read error discarding pending bytes");
}
decoder->pending--;
}
/* get the type byte */
if (read_int8(decoder, &tbyte)) {
CODER_KILL(decoder, "read error on type byte");
}
decoder->node.type = tbyte;
decoder->pending = 0;
debug("got type byte 0x%02x", decoder->node.type);
/* EOO is special; it has no name/data following */
if (decoder->node.type == BSON_EOO) {
decoder->node.name[0] = '\0';
} else {
/* get the node name */
nlen = 0;
for (;;) {
if (nlen >= BSON_MAXNAME) {
CODER_KILL(decoder, "node name overflow");
}
if (read_int8(decoder, (int8_t *)&decoder->node.name[nlen])) {
CODER_KILL(decoder, "read error on node name");
}
if (decoder->node.name[nlen] == '\0') {
break;
}
nlen++;
}
debug("got name '%s'", decoder->node.name);
switch (decoder->node.type) {
case BSON_BOOL:
if (read_int8(decoder, &tbyte)) {
CODER_KILL(decoder, "read error on BSON_BOOL");
}
decoder->node.b = (tbyte != 0);
break;
case BSON_INT32:
if (read_int32(decoder, &tint)) {
CODER_KILL(decoder, "read error on BSON_INT");
}
decoder->node.i = tint;
break;
case BSON_INT64:
if (read_int64(decoder, &decoder->node.i)) {
CODER_KILL(decoder, "read error on BSON_INT");
}
break;
case BSON_DOUBLE:
if (read_double(decoder, &decoder->node.d)) {
CODER_KILL(decoder, "read error on BSON_DOUBLE");
}
break;
case BSON_STRING:
if (read_int32(decoder, &decoder->pending)) {
CODER_KILL(decoder, "read error on BSON_STRING length");
}
break;
case BSON_BINDATA:
if (read_int32(decoder, &decoder->pending)) {
CODER_KILL(decoder, "read error on BSON_BINDATA size");
}
if (read_int8(decoder, &tbyte)) {
CODER_KILL(decoder, "read error on BSON_BINDATA subtype");
}
decoder->node.subtype = tbyte;
break;
/* XXX currently not supporting other types */
default:
CODER_KILL(decoder, "unsupported node type");
}
}
/* call the callback and pass its results back */
return decoder->callback(decoder, decoder->priv, &decoder->node);
}
int
bson_decoder_copy_data(bson_decoder_t decoder, void *buf)
{
int result;
CODER_CHECK(decoder);
/* copy data */
result = read_x(decoder, buf, decoder->pending);
if (result != 0) {
CODER_KILL(decoder, "read error on copy_data");
}
/* pending count is discharged */
decoder->pending = 0;
return 0;
}
size_t
bson_decoder_data_pending(bson_decoder_t decoder)
{
return decoder->pending;
}
static int
write_x(bson_encoder_t encoder, const void *p, size_t s)
{
CODER_CHECK(encoder);
/* bson file encoder (non-buffered) */
if (encoder->fd > -1 && encoder->buf == NULL) {
return (BSON_WRITE(encoder->fd, p, s) == (int)s) ? 0 : -1;
}
/* do we need to extend the buffer? */
while ((encoder->bufpos + s) > encoder->bufsize) {
/* bson buffered file encoder */
if (encoder->fd > -1) {
// write to disk
debug("writing buffer (%d) to disk", encoder->bufpos);
int ret = BSON_WRITE(encoder->fd, encoder->buf, encoder->bufpos);
if (ret == encoder->bufpos) {
// reset buffer to beginning and continue
encoder->bufpos = 0;
if ((encoder->bufpos + s) > encoder->bufsize) {
CODER_KILL(encoder, "fixed-size buffer overflow");
}
break;
} else {
CODER_KILL(encoder, "file write error");
}
}
if (!encoder->realloc_ok) {
CODER_KILL(encoder, "fixed-size buffer overflow");
}
uint8_t *newbuf = realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT);
if (newbuf == NULL) {
CODER_KILL(encoder, "could not grow buffer");
}
encoder->buf = newbuf;
encoder->bufsize += BSON_BUF_INCREMENT;
debug("allocated %d bytes", BSON_BUF_INCREMENT);
}
memcpy(encoder->buf + encoder->bufpos, p, s);
encoder->bufpos += s;
debug("appended %d bytes", s);
return 0;
}
static int
write_int8(bson_encoder_t encoder, int8_t b)
{
return write_x(encoder, &b, sizeof(b));
}
static int
write_int32(bson_encoder_t encoder, int32_t i)
{
return write_x(encoder, &i, sizeof(i));
}
static int
write_int64(bson_encoder_t encoder, int64_t i)
{
return write_x(encoder, &i, sizeof(i));
}
static int
write_double(bson_encoder_t encoder, double d)
{
return write_x(encoder, &d, sizeof(d));
}
static int
write_name(bson_encoder_t encoder, const char *name)
{
size_t len = strlen(name);
if (len > BSON_MAXNAME) {
CODER_KILL(encoder, "node name too long");
}
return write_x(encoder, name, len + 1);
}
int
bson_encoder_init_file(bson_encoder_t encoder, int fd)
{
encoder->fd = fd;
encoder->buf = NULL;
encoder->dead = false;
if (write_int32(encoder, 0)) {
CODER_KILL(encoder, "write error on document length");
}
return 0;
}
int
bson_encoder_init_buf_file(bson_encoder_t encoder, int fd, void *buf, unsigned bufsize)
{
encoder->fd = fd;
encoder->buf = (uint8_t *)buf;
encoder->bufpos = 0;
encoder->bufsize = bufsize;
encoder->dead = false;
encoder->realloc_ok = false;
if (write_int32(encoder, 0)) {
CODER_KILL(encoder, "write error on document length");
}
return 0;
}
int
bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize)
{
encoder->fd = -1;
encoder->buf = (uint8_t *)buf;
encoder->bufpos = 0;
encoder->dead = false;
if (encoder->buf == NULL) {
encoder->bufsize = 0;
encoder->realloc_ok = true;
} else {
encoder->bufsize = bufsize;
encoder->realloc_ok = false;
}
if (write_int32(encoder, 0)) {
CODER_KILL(encoder, "write error on document length");
}
return 0;
}
int
bson_encoder_fini(bson_encoder_t encoder)
{
CODER_CHECK(encoder);
if (write_int8(encoder, BSON_EOO)) {
CODER_KILL(encoder, "write error on document terminator");
}
if (encoder->fd > -1 && encoder->buf != NULL) {
/* write final buffer to disk */
int ret = BSON_WRITE(encoder->fd, encoder->buf, encoder->bufpos);
if (ret != encoder->bufpos) {
CODER_KILL(encoder, "write error");
}
} else if (encoder->buf != NULL) {
/* update buffer length */
int32_t len = bson_encoder_buf_size(encoder);
memcpy(encoder->buf, &len, sizeof(len));
}
/* sync file */
if (encoder->fd > -1) {
BSON_FSYNC(encoder->fd);
}
return 0;
}
int
bson_encoder_buf_size(bson_encoder_t encoder)
{
CODER_CHECK(encoder);
if (encoder->fd > -1) {
return -1;
}
return encoder->bufpos;
}
void *
bson_encoder_buf_data(bson_encoder_t encoder)
{
/* note, no CODER_CHECK here as the caller has to clean up dead buffers */
if (encoder->fd > -1) {
return NULL;
}
return encoder->buf;
}
int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value)
{
CODER_CHECK(encoder);
if (write_int8(encoder, BSON_BOOL) ||
write_name(encoder, name) ||
write_int8(encoder, value ? 1 : 0)) {
CODER_KILL(encoder, "write error on BSON_BOOL");
}
return 0;
}
int
bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value)
{
bool result;
CODER_CHECK(encoder);
/* use the smallest encoding that will hold the value */
if (value == (int32_t)value) {
debug("encoding %lld as int32", value);
result = write_int8(encoder, BSON_INT32) ||
write_name(encoder, name) ||
write_int32(encoder, value);
} else {
debug("encoding %lld as int64", value);
result = write_int8(encoder, BSON_INT64) ||
write_name(encoder, name) ||
write_int64(encoder, value);
}
if (result) {
CODER_KILL(encoder, "write error on BSON_INT");
}
return 0;
}
int
bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value)
{
CODER_CHECK(encoder);
if (write_int8(encoder, BSON_DOUBLE) ||
write_name(encoder, name) ||
write_double(encoder, value)) {
CODER_KILL(encoder, "write error on BSON_DOUBLE");
}
return 0;
}
int
bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string)
{
size_t len;
CODER_CHECK(encoder);
len = strlen(string) + 1; /* include trailing nul */
if (write_int8(encoder, BSON_STRING) ||
write_name(encoder, name) ||
write_int32(encoder, len) ||
write_x(encoder, string, len)) {
CODER_KILL(encoder, "write error on BSON_STRING");
}
return 0;
}
int
bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size,
const void *data)
{
CODER_CHECK(encoder);
if (write_int8(encoder, BSON_BINDATA) ||
write_name(encoder, name) ||
write_int32(encoder, size) ||
write_int8(encoder, subtype) ||
write_x(encoder, data, size)) {
CODER_KILL(encoder, "write error on BSON_BINDATA");
}
return 0;
}
-288
View File
@@ -1,288 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file tinybson.h
*
* A simple subset SAX-style BSON parser and generator. See http://bsonspec.org
*
* Some types and defines taken from the standalone BSON parser/generator
* in the Mongo C connector.
*/
#ifndef _TINYBSON_H
#define _TINYBSON_H
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
/** subset of the BSON node types we might care about */
typedef enum {
BSON_EOO = 0,
BSON_DOUBLE = 1,
BSON_STRING = 2,
BSON_OBJECT = 3,
BSON_ARRAY = 4,
BSON_BINDATA = 5,
BSON_UNDEFINED = 6,
BSON_BOOL = 8,
BSON_DATE = 9,
BSON_NULL = 10,
BSON_INT32 = 16,
BSON_INT64 = 18
} bson_type_t;
typedef enum bson_binary_subtype {
BSON_BIN_BINARY = 0,
BSON_BIN_USER = 128
} bson_binary_subtype_t;
/**
* Maximum node name length.
*/
#define BSON_MAXNAME 32
/**
* Buffer growth increment when writing to a buffer.
*/
#define BSON_BUF_INCREMENT 128
/**
* Node structure passed to the callback.
*/
typedef struct bson_node_s {
char name[BSON_MAXNAME];
bson_type_t type;
bson_binary_subtype_t subtype;
union {
int64_t i;
double d;
bool b;
};
} *bson_node_t;
typedef struct bson_decoder_s *bson_decoder_t;
/**
* Node callback.
*
* The node callback function's return value is returned by bson_decoder_next.
*/
typedef int (* bson_decoder_callback)(bson_decoder_t decoder, void *priv, bson_node_t node);
struct bson_decoder_s {
/* file reader state */
int fd;
/* buffer reader state */
uint8_t *buf;
size_t bufsize;
unsigned bufpos;
bool dead;
bson_decoder_callback callback;
void *priv;
unsigned nesting;
struct bson_node_s node;
int32_t pending;
};
/**
* Initialise the decoder to read from a file.
*
* @param decoder Decoder state structure to be initialised.
* @param fd File to read BSON data from.
* @param callback Callback to be invoked by bson_decoder_next
* @param priv Callback private data, stored in node.
* @return Zero on success.
*/
__EXPORT int bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *priv);
/**
* Initialise the decoder to read from a buffer in memory.
*
* @param decoder Decoder state structure to be initialised.
* @param buf Buffer to read from.
* @param bufsize Size of the buffer (BSON object may be smaller). May be
* passed as zero if the buffer size should be extracted from the
* BSON header only.
* @param callback Callback to be invoked by bson_decoder_next
* @param priv Callback private data, stored in node.
* @return Zero on success.
*/
__EXPORT int bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback,
void *priv);
/**
* Process the next node from the stream and invoke the callback.
*
* @param decoder Decoder state, must have been initialised with bson_decoder_init.
* @return -1 if parsing encountered an error, 0 if the BSON stream has ended,
* otherwise the return value from the callback.
*/
__EXPORT int bson_decoder_next(bson_decoder_t decoder);
/**
* Copy node data.
*
* @param decoder Decoder state, must have been initialised with bson_decoder_init.
*/
__EXPORT int bson_decoder_copy_data(bson_decoder_t decoder, void *buf);
/**
* Report copyable data size.
*
* @param decoder Decoder state, must have been initialised with bson_decoder_init.
*/
__EXPORT size_t bson_decoder_data_pending(bson_decoder_t decoder);
/**
* Encoder state structure.
*/
typedef struct bson_encoder_s {
/* file writer state */
int fd;
/* buffer writer state */
uint8_t *buf;
unsigned bufsize;
unsigned bufpos;
bool realloc_ok;
bool dead;
} *bson_encoder_t;
/**
* Initialze the encoder for writing to a file.
*
* @param encoder Encoder state structure to be initialised.
* @param fd File to write to.
* @return Zero on success.
*/
__EXPORT int bson_encoder_init_file(bson_encoder_t encoder, int fd);
/**
* Initialze the encoder for writing to a file.
*
* @param encoder Encoder state structure to be initialised.
* @param fd File to write to.
* @param buf Buffer pointer to use, can't be NULL
* @param bufsize Supplied buffer size
* @return Zero on success.
*/
__EXPORT int bson_encoder_init_buf_file(bson_encoder_t encoder, int fd, void *buf, unsigned bufsize);
/**
* Initialze the encoder for writing to a buffer.
*
* @param encoder Encoder state structure to be initialised.
* @param buf Buffer pointer to use, or NULL if the buffer
* should be allocated by the encoder.
* @param bufsize Maximum buffer size, or zero for no limit. If
* the buffer is supplied, the size of the supplied buffer.
* @return Zero on success.
*/
__EXPORT int bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize);
/**
* Finalise the encoded stream.
*
* @param encoder The encoder to finalise.
*/
__EXPORT int bson_encoder_fini(bson_encoder_t encoder);
/**
* Fetch the size of the encoded object; only valid for buffer operations.
*/
__EXPORT int bson_encoder_buf_size(bson_encoder_t encoder);
/**
* Get a pointer to the encoded object buffer.
*
* Note that if the buffer was allocated by the encoder, it is the caller's responsibility
* to free this buffer.
*/
__EXPORT void *bson_encoder_buf_data(bson_encoder_t encoder);
/**
* Append a boolean to the encoded stream.
*
* @param encoder Encoder state.
* @param name Node name.
* @param value Value to be encoded.
*/
__EXPORT int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value);
/**
* Append an integer to the encoded stream.
*
* @param encoder Encoder state.
* @param name Node name.
* @param value Value to be encoded.
*/
__EXPORT int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value);
/**
* Append a double to the encoded stream
*
* @param encoder Encoder state.
* @param name Node name.
* @param value Value to be encoded.
*/
__EXPORT int bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value);
/**
* Append a string to the encoded stream.
*
* @param encoder Encoder state.
* @param name Node name.
* @param string Nul-terminated C string.
*/
__EXPORT int bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string);
/**
* Append a binary blob to the encoded stream.
*
* @param encoder Encoder state.
* @param name Node name.
* @param subtype Binary data subtype.
* @param size Data size.
* @param data Buffer containing data to be encoded.
*/
__EXPORT int bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype,
size_t size, const void *data);
#endif
File diff suppressed because it is too large Load Diff
-231
View File
@@ -1,231 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file param.h
*
* Global flash based parameter store.
*
* This provides the mechanisms to interface to the PX4
* parameter system but replace the IO with non file based flash
* i/o routines. So that the code my be implemented on a SMALL memory
* foot print device.
*
*/
#ifndef _SYSTEMLIB_FLASHPARAMS_NUTTX_PARAM_H
#define _SYSTEMLIB_FLASHPARAMS_NUTTX_PARAM_H
#include <stdint.h>
#include <stdbool.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/*
* PARAMETER_BUFFER_SIZE must be defined larger then the maximum parameter
* memory needed to commit the recored + ~20 bytes. For the syslib's parameter
* this would be the size of the bson representations of the data
*/
#if !defined(PARAMETER_BUFFER_SIZE)
#define PARAMETER_BUFFER_SIZE 512
#endif
__BEGIN_DECLS
/*
* Define the interface data a flash_file_token_t
* is like a file name
*
*/
typedef uint32_t flash_file_tokens_t;
typedef struct flash_file_token_t {
union {
flash_file_tokens_t t;
uint8_t n[sizeof(flash_file_tokens_t)];
};
} flash_file_token_t;
/*
* Define the parameter "file name" Currently there is only
* and it is hard coded. If more are added the
* parameter_flashfs_write would need to support a backing buffer
* for when a sector is erased.
*/
__EXPORT extern const flash_file_token_t parameters_token;
/* Define the elements of the array passed to the
* parameter_flashfs_init function
*
* For example
* static sector_descriptor_t sector_map[] = {
* {1, 16 * 1024, 0x08004000},
* {2, 16 * 1024, 0x08008000},
* {0, 0, 0},
*
*/
typedef struct sector_descriptor_t {
uint8_t page;
uint32_t size;
uint32_t address;
} sector_descriptor_t;
/****************************************************************************
* Name: parameter_flashfs_init
*
* Description:
* This helper function advances the flash entry header pointer to the
* locations of the next entry.
*
* Input Parameters:
* fconfig - A pointer to an null entry terminated array of
* flash_file_sector_t
* buffer - A pointer to a memory to make available to callers
* for write operations. When allocated to the caller
* space is reserved in the front for the
* flash_entry_header_t.
* If this is passes as NULL. The buffer will be
* allocated from the heap on calls to
* parameter_flashfs_alloc and fread on calls
* to parameter_flashfs_free
*
* size - The size of the buffer in bytes. Should be be 0 if buffer
* is NULL
*
* Returned value:
* - A pointer to the next file header location
*
*
****************************************************************************/
__EXPORT int parameter_flashfs_init(sector_descriptor_t *fconfig, uint8_t *buffer, uint16_t size);
/****************************************************************************
* Name: parameter_flashfs_read
*
* Description:
* This function returns a pointer to the locations of the data associated
* with the file token. On successful return *buffer will be set to Flash
* location and *buf_size the length of the user data.
*
* Input Parameters:
* token - File Token File to read
* buffer - A pointer to a pointer that will receive the address
* in flash of the data of this "files" data
* buf_size - A pointer to receive the number of bytes in the "file"
*
* Returned value:
* On success number of bytes read or a negative errno value,
*
*
****************************************************************************/
__EXPORT int parameter_flashfs_read(flash_file_token_t ft, uint8_t **buffer, size_t *buf_size);
/****************************************************************************
* Name: parameter_flashfs_write
*
* Description:
* This function writes user data from the buffer allocated with a previous call
* to parameter_flashfs_alloc. flash starting at the given address
*
* Input Parameters:
* token - File Token File to read
* buffer - A pointer to a buffer with buf_size bytes to be written
* to the flash. This buffer must be allocated
* with a previous call to parameter_flashfs_alloc
* buf_size - Number of bytes to write
*
* Returned value:
* On success the number of bytes written On Error a negative value of errno
*
****************************************************************************/
__EXPORT int parameter_flashfs_write(flash_file_token_t ft, uint8_t *buffer, size_t buf_size);
/****************************************************************************
* Name: parameter_flashfs_erase
*
* Description:
* This function erases the sectors that were passed to parameter_flashfs_init
*
* Input Parameters:
*
* Returned value:
* On success the number of bytes erased
* On Error a negative value of errno
*
****************************************************************************/
__EXPORT int parameter_flashfs_erase(void);
/****************************************************************************
* Name: parameter_flashfs_alloc
*
* Description:
* This function is called to get a buffer to use in a subsequent call
* to parameter_flashfs_write. The address returned is advanced into the
* buffer to reserve space for the flash entry header.
*
* Input Parameters:
* token - File Token File to read (not used)
* buffer - Memory of buf_size length suitable for calling
* parameter_flashfs_write
* buf_size - The maximum number of bytes that can be written to
* the buffer
*
* Returned value:
* On success the number of bytes written On Error a negative value of errno
*
****************************************************************************/
__EXPORT int parameter_flashfs_alloc(flash_file_token_t ft, uint8_t **buffer, size_t *buf_size);
/****************************************************************************
* Name: parameter_flashfs_free
*
* Description:
* Frees dynamically allocated memory
*
*
****************************************************************************/
__EXPORT void parameter_flashfs_free(void);
__END_DECLS
#endif /* _SYSTEMLIB_FLASHPARAMS_NUTTX_PARAM_H */
@@ -1,369 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file flashparam.c
*
* Global flash based parameter store.
*
* This provides the mechanisms to interface to the PX4
* parameter system but replace the IO with non file based flash
* i/o routines. So that the code my be implemented on a SMALL memory
* foot print device.
*/
#include <px4_defines.h>
#include <px4_posix.h>
#include <px4_shutdown.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "systemlib/param/param.h"
#include "systemlib/uthash/utarray.h"
#include "systemlib/bson/tinybson.h"
#include "flashparams.h"
#include "flashfs.h"
#if 0
# define debug(fmt, args...) do { warnx(fmt, ##args); } while(0)
#else
# define debug(fmt, args...) do { } while(0)
#endif
/**
* Storage for modified parameters.
*/
struct param_wbuf_s {
union param_value_u val;
param_t param;
bool unsaved;
};
static int
param_export_internal(bool only_unsaved)
{
struct param_wbuf_s *s = NULL;
struct bson_encoder_s encoder;
int result = -1;
/* Use realloc */
bson_encoder_init_buf(&encoder, NULL, 0);
/* no modified parameters -> we are done */
if (param_values == NULL) {
result = 0;
goto out;
}
while ((s = (struct param_wbuf_s *)utarray_next(param_values, s)) != NULL) {
int32_t i;
float f;
/*
* If we are only saving values changed since last save, and this
* one hasn't, then skip it
*/
if (only_unsaved && !s->unsaved) {
continue;
}
s->unsaved = false;
/* append the appropriate BSON type object */
switch (param_type(s->param)) {
case PARAM_TYPE_INT32:
i = s->val.i;
if (bson_encoder_append_int(&encoder, param_name(s->param), i)) {
debug("BSON append failed for '%s'", param_name(s->param));
goto out;
}
break;
case PARAM_TYPE_FLOAT:
f = s->val.f;
if (bson_encoder_append_double(&encoder, param_name(s->param), f)) {
debug("BSON append failed for '%s'", param_name(s->param));
goto out;
}
break;
case PARAM_TYPE_STRUCT ... PARAM_TYPE_STRUCT_MAX:
if (bson_encoder_append_binary(&encoder,
param_name(s->param),
BSON_BIN_BINARY,
param_size(s->param),
param_get_value_ptr_external(s->param))) {
debug("BSON append failed for '%s'", param_name(s->param));
goto out;
}
break;
default:
debug("unrecognized parameter type");
goto out;
}
}
result = 0;
out:
if (result == 0) {
/* Finalize the bison encoding*/
bson_encoder_fini(&encoder);
/* Get requiered space */
size_t buf_size = bson_encoder_buf_size(&encoder);
int shutdown_lock_ret = px4_shutdown_lock();
if (shutdown_lock_ret) {
PX4_ERR("px4_shutdown_lock() failed (%i)", shutdown_lock_ret);
}
/* Get a buffer from the flash driver with enough space */
uint8_t *buffer;
result = parameter_flashfs_alloc(parameters_token, &buffer, &buf_size);
if (result == OK) {
/* Check for a write that has no changes */
uint8_t *was_buffer;
size_t was_buf_size;
int was_result = parameter_flashfs_read(parameters_token, &was_buffer, &was_buf_size);
void *enc_buff = bson_encoder_buf_data(&encoder);
bool commit = was_result < OK || was_buf_size != buf_size || 0 != memcmp(was_buffer, enc_buff, was_buf_size);
if (commit) {
memcpy(buffer, enc_buff, buf_size);
result = parameter_flashfs_write(parameters_token, buffer, buf_size);
result = result == buf_size ? OK : -EFBIG;
}
free(enc_buff);
parameter_flashfs_free();
}
if (shutdown_lock_ret == 0) {
px4_shutdown_unlock();
}
}
return result;
}
struct param_import_state {
bool mark_saved;
};
static int
param_import_callback(bson_decoder_t decoder, void *private, bson_node_t node)
{
float f;
int32_t i;
void *v, *tmp = NULL;
int result = -1;
struct param_import_state *state = (struct param_import_state *)private;
/*
* EOO means the end of the parameter object. (Currently not supporting
* nested BSON objects).
*/
if (node->type == BSON_EOO) {
debug("end of parameters");
return 0;
}
/*
* Find the parameter this node represents. If we don't know it,
* ignore the node.
*/
param_t param = param_find_no_notification(node->name);
if (param == PARAM_INVALID) {
debug("ignoring unrecognised parameter '%s'", node->name);
return 1;
}
/*
* Handle setting the parameter from the node
*/
switch (node->type) {
case BSON_INT32:
if (param_type(param) != PARAM_TYPE_INT32) {
PX4_WARN("unexpected type for %s", node->name);
result = 1; // just skip this entry
goto out;
}
i = node->i;
v = &i;
break;
case BSON_DOUBLE:
if (param_type(param) != PARAM_TYPE_FLOAT) {
PX4_WARN("unexpected type for %s", node->name);
result = 1; // just skip this entry
goto out;
}
f = node->d;
v = &f;
break;
case BSON_BINDATA:
if (node->subtype != BSON_BIN_BINARY) {
PX4_WARN("unexpected type for %s", node->name);
result = 1; // just skip this entry
goto out;
}
if (bson_decoder_data_pending(decoder) != param_size(param)) {
PX4_WARN("bad size for '%s'", node->name);
result = 1; // just skip this entry
goto out;
}
/* XXX check actual file data size? */
tmp = malloc(param_size(param));
if (tmp == NULL) {
debug("failed allocating for '%s'", node->name);
goto out;
}
if (bson_decoder_copy_data(decoder, tmp)) {
debug("failed copying data for '%s'", node->name);
goto out;
}
v = tmp;
break;
default:
debug("unrecognised node type");
goto out;
}
if (param_set_external(param, v, state->mark_saved, true)) {
debug("error setting value for '%s'", node->name);
goto out;
}
if (tmp != NULL) {
free(tmp);
tmp = NULL;
}
/* don't return zero, that means EOF */
result = 1;
out:
if (tmp != NULL) {
free(tmp);
}
return result;
}
static int
param_import_internal(bool mark_saved)
{
struct bson_decoder_s decoder;
int result = -1;
struct param_import_state state;
uint8_t *buffer = 0;
size_t buf_size;
parameter_flashfs_read(parameters_token, &buffer, &buf_size);
if (bson_decoder_init_buf(&decoder, buffer, buf_size, param_import_callback, &state)) {
debug("decoder init failed");
goto out;
}
state.mark_saved = mark_saved;
do {
result = bson_decoder_next(&decoder);
} while (result > 0);
out:
if (result < 0) {
debug("BSON error decoding parameters");
}
return result;
}
int flash_param_save(void)
{
return param_export_internal(false);
}
int flash_param_load(void)
{
param_reset_all();
return param_import_internal(true);
}
int flash_param_import(void)
{
return -1;
}
@@ -1,72 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file param.h
*
* Global flash based parameter store.
*
* This provides the mechanisms to interface to the PX4
* parameter system but replace the IO with non file based flash
* i/o routines. So that the code my be implemented on a SMALL memory
* foot print device.
*
*/
#ifndef _SYSTEMLIB_FLASHPARAMS_FLASHPARAMS_H
#define _SYSTEMLIB_FLASHPARAMS_FLASHPARAMS_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include "systemlib/uthash/utarray.h"
__BEGIN_DECLS
/*
* When using the flash based parameter store we have to force
* the param_values and 2 functions to be global
*/
#define FLASH_PARAMS_EXPOSE __EXPORT
__EXPORT extern UT_array *param_values;
__EXPORT int param_set_external(param_t param, const void *val, bool mark_saved, bool notify_changes);
__EXPORT const void *param_get_value_ptr_external(param_t param);
/* The interface hooks to the Flash based storage. The caller is responsible for locking */
__EXPORT int flash_param_save(void);
__EXPORT int flash_param_load(void);
__EXPORT int flash_param_import(void);
__END_DECLS
#endif /* _SYSTEMLIB_FLASHPARAMS_FLASHPARAMS_H */
-322
View File
@@ -1,322 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file hx_stream.c
*
* A simple serial line framing protocol based on HDLC
* with 32-bit CRC protection.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <crc32.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "perf_counter.h"
#include "hx_stream.h"
struct hx_stream {
/* RX state */
uint8_t rx_buf[HX_STREAM_MAX_FRAME + 4];
unsigned rx_frame_bytes;
bool rx_escaped;
hx_stream_rx_callback rx_callback;
void *rx_callback_arg;
/* TX state */
int fd;
bool tx_error;
const uint8_t *tx_buf;
unsigned tx_resid;
uint32_t tx_crc;
enum {
TX_IDLE = 0,
TX_SEND_START,
TX_SEND_DATA,
TX_SENT_ESCAPE,
TX_SEND_END
} tx_state;
perf_counter_t pc_tx_frames;
perf_counter_t pc_rx_frames;
perf_counter_t pc_rx_errors;
};
/*
* Protocol magic numbers, straight out of HDLC.
*/
#define FBO 0x7e /**< Frame Boundary Octet */
#define CEO 0x7c /**< Control Escape Octet */
static void hx_tx_raw(hx_stream_t stream, uint8_t c);
static void hx_tx_raw(hx_stream_t stream, uint8_t c);
static int hx_rx_frame(hx_stream_t stream);
static void
hx_tx_raw(hx_stream_t stream, uint8_t c)
{
if (write(stream->fd, &c, 1) != 1) {
stream->tx_error = true;
}
}
static int
hx_rx_frame(hx_stream_t stream)
{
union {
uint8_t b[4];
uint32_t w;
} u;
unsigned length = stream->rx_frame_bytes;
/* reset the stream */
stream->rx_frame_bytes = 0;
stream->rx_escaped = false;
/* not a real frame - too short */
if (length < 4) {
if (length > 1) {
perf_count(stream->pc_rx_errors);
}
return 0;
}
length -= 4;
/* compute expected CRC */
u.w = crc32(&stream->rx_buf[0], length);
/* compare computed and actual CRC */
for (unsigned i = 0; i < 4; i++) {
if (u.b[i] != stream->rx_buf[length + i]) {
perf_count(stream->pc_rx_errors);
return 0;
}
}
/* frame is good */
perf_count(stream->pc_rx_frames);
stream->rx_callback(stream->rx_callback_arg, &stream->rx_buf[0], length);
return 1;
}
hx_stream_t
hx_stream_init(int fd,
hx_stream_rx_callback callback,
void *arg)
{
hx_stream_t stream;
stream = (hx_stream_t)malloc(sizeof(struct hx_stream));
if (stream != NULL) {
memset(stream, 0, sizeof(struct hx_stream));
stream->fd = fd;
stream->rx_callback = callback;
stream->rx_callback_arg = arg;
}
return stream;
}
void
hx_stream_free(hx_stream_t stream)
{
/* free perf counters (OK if they are NULL) */
perf_free(stream->pc_tx_frames);
perf_free(stream->pc_rx_frames);
perf_free(stream->pc_rx_errors);
free(stream);
}
void
hx_stream_set_counters(hx_stream_t stream,
perf_counter_t tx_frames,
perf_counter_t rx_frames,
perf_counter_t rx_errors)
{
stream->pc_tx_frames = tx_frames;
stream->pc_rx_frames = rx_frames;
stream->pc_rx_errors = rx_errors;
}
void
hx_stream_reset(hx_stream_t stream)
{
stream->rx_frame_bytes = 0;
stream->rx_escaped = false;
stream->tx_buf = NULL;
stream->tx_resid = 0;
stream->tx_state = TX_IDLE;
}
int
hx_stream_start(hx_stream_t stream,
const void *data,
size_t count)
{
if (count > HX_STREAM_MAX_FRAME) {
return -EINVAL;
}
stream->tx_buf = data;
stream->tx_resid = count;
stream->tx_state = TX_SEND_START;
stream->tx_crc = crc32(data, count);
return OK;
}
int
hx_stream_send_next(hx_stream_t stream)
{
int c;
/* sort out what we're going to send */
switch (stream->tx_state) {
case TX_SEND_START:
stream->tx_state = TX_SEND_DATA;
return FBO;
case TX_SEND_DATA:
c = *stream->tx_buf;
switch (c) {
case FBO:
case CEO:
stream->tx_state = TX_SENT_ESCAPE;
return CEO;
}
break;
case TX_SENT_ESCAPE:
c = *stream->tx_buf ^ 0x20;
stream->tx_state = TX_SEND_DATA;
break;
case TX_SEND_END:
stream->tx_state = TX_IDLE;
return FBO;
case TX_IDLE:
default:
return -1;
}
/* if we are here, we have consumed a byte from the buffer */
stream->tx_resid--;
stream->tx_buf++;
/* buffer exhausted */
if (stream->tx_resid == 0) {
uint8_t *pcrc = (uint8_t *)&stream->tx_crc;
/* was the buffer the frame CRC? */
if (stream->tx_buf == (pcrc + sizeof(stream->tx_crc))) {
stream->tx_state = TX_SEND_END;
} else {
/* no, it was the payload - switch to sending the CRC */
stream->tx_buf = pcrc;
stream->tx_resid = sizeof(stream->tx_crc);
}
}
return c;
}
int
hx_stream_send(hx_stream_t stream,
const void *data,
size_t count)
{
int result;
result = hx_stream_start(stream, data, count);
if (result != OK) {
return result;
}
int c;
while ((c = hx_stream_send_next(stream)) >= 0) {
hx_tx_raw(stream, c);
}
/* check for transmit error */
if (stream->tx_error) {
stream->tx_error = false;
return -EIO;
}
perf_count(stream->pc_tx_frames);
return OK;
}
void
hx_stream_rx(hx_stream_t stream, uint8_t c)
{
/* frame end? */
if (c == FBO) {
hx_rx_frame(stream);
return;
}
/* escaped? */
if (stream->rx_escaped) {
stream->rx_escaped = false;
c ^= 0x20;
} else if (c == CEO) {
/* now rx_escaped, ignore the byte */
stream->rx_escaped = true;
return;
}
/* save for later */
if (stream->rx_frame_bytes < sizeof(stream->rx_buf)) {
stream->rx_buf[stream->rx_frame_bytes++] = c;
}
}
-162
View File
@@ -1,162 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file hx_stream.h
*
* A simple serial line framing protocol based on HDLC
* with 32-bit CRC protection.
*/
#ifndef _SYSTEMLIB_HX_STREAM_H
#define _SYSTEMLIB_HX_STREAM_H
#include <sys/types.h>
#include "perf_counter.h"
struct hx_stream;
typedef struct hx_stream *hx_stream_t;
#define HX_STREAM_MAX_FRAME 64
typedef void (* hx_stream_rx_callback)(void *arg, const void *data, size_t length);
__BEGIN_DECLS
/**
* Allocate a new hx_stream object.
*
* @param fd The file handle over which the protocol will
* communicate, or -1 if the protocol will use
* hx_stream_start/hx_stream_send_next.
* @param callback Called when a frame is received.
* @param callback_arg Passed to the callback.
* @return A handle to the stream, or NULL if memory could
* not be allocated.
*/
__EXPORT extern hx_stream_t hx_stream_init(int fd,
hx_stream_rx_callback callback,
void *arg);
/**
* Free a hx_stream object.
*
* @param stream A handle returned from hx_stream_init.
*/
__EXPORT extern void hx_stream_free(hx_stream_t stream);
/**
* Set performance counters for the stream.
*
* Any counter may be set to NULL to disable counting that datum.
*
* @param stream A handle returned from hx_stream_init.
* @param tx_frames Counter for transmitted frames.
* @param rx_frames Counter for received frames.
* @param rx_errors Counter for short and corrupt received frames.
*/
__EXPORT extern void hx_stream_set_counters(hx_stream_t stream,
perf_counter_t tx_frames,
perf_counter_t rx_frames,
perf_counter_t rx_errors);
/**
* Reset a stream.
*
* Forces the local stream state to idle.
*
* @param stream A handle returned from hx_stream_init.
*/
__EXPORT extern void hx_stream_reset(hx_stream_t stream);
/**
* Prepare to send a frame.
*
* Use this in conjunction with hx_stream_send_next to
* set the frame to be transmitted.
*
* Use hx_stream_send() to write to the stream fd directly.
*
* @param stream A handle returned from hx_stream_init.
* @param data Pointer to the data to send.
* @param count The number of bytes to send.
* @return Zero on success, -errno on error.
*/
__EXPORT extern int hx_stream_start(hx_stream_t stream,
const void *data,
size_t count);
/**
* Get the next byte to send for a stream.
*
* This requires that the stream be prepared for sending by
* calling hx_stream_start first.
*
* @param stream A handle returned from hx_stream_init.
* @return The byte to send, or -1 if there is
* nothing left to send.
*/
__EXPORT extern int hx_stream_send_next(hx_stream_t stream);
/**
* Send a frame.
*
* This function will block until all frame bytes are sent if
* the descriptor passed to hx_stream_init is marked blocking,
* otherwise it will return -1 (but may transmit a
* runt frame at the same time).
*
* @todo Handling of non-blocking streams needs to be better.
*
* @param stream A handle returned from hx_stream_init.
* @param data Pointer to the data to send.
* @param count The number of bytes to send.
* @return Zero on success, -errno on error.
*/
__EXPORT extern int hx_stream_send(hx_stream_t stream,
const void *data,
size_t count);
/**
* Handle a byte from the stream.
*
* @param stream A handle returned from hx_stream_init.
* @param c The character to process.
*/
__EXPORT extern void hx_stream_rx(hx_stream_t stream,
uint8_t c);
__END_DECLS
#endif
-129
View File
@@ -1,129 +0,0 @@
############################################################################
#
# Copyright (c) 2017 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
set(SRCS)
if ("${CONFIG_SHMEM}" STREQUAL "1")
message(STATUS "parameters shared memory enabled")
list(APPEND SRCS
param_shmem.c
)
else()
list(APPEND SRCS
param.c
)
endif()
if (NOT PARAM_DEFAULT_OVERRIDES)
set(PARAM_DEFAULT_OVERRIDES "{}")
endif()
# get full path for each module
set(module_list)
if (DISABLE_PARAMS_MODULE_SCOPING)
# search all directories with .c files (potentially containing parameters)
file(GLOB_RECURSE new_list
${PX4_SOURCE_DIR}/src/*.c
${external_module_paths}
)
foreach(file_path ${new_list})
get_filename_component(dir_path ${file_path} PATH)
list(APPEND module_list "${dir_path}")
endforeach()
list(REMOVE_DUPLICATES module_list)
else()
foreach(module ${config_module_list})
# include all subdirectories as well
file(GLOB children RELATIVE ${PX4_SOURCE_DIR}/src/${module} ${PX4_SOURCE_DIR}/src/${module}/*)
foreach(child ${children})
if(IS_DIRECTORY ${PX4_SOURCE_DIR}/src/${module}/${child})
list(APPEND module_list ${PX4_SOURCE_DIR}/src/${module}/${child})
endif()
endforeach()
list(APPEND module_list ${PX4_SOURCE_DIR}/src/${module})
endforeach()
list(APPEND module_list ${external_module_paths})
endif()
list(REMOVE_DUPLICATES module_list)
set(parameters_xml ${PX4_BINARY_DIR}/parameters.xml)
file(GLOB_RECURSE param_src_files ${PX4_SOURCE_DIR}/src/*params.c)
add_custom_command(OUTPUT ${parameters_xml}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/px_process_params.py
--src-path ${module_list}
--xml ${parameters_xml}
--inject-xml ${CMAKE_CURRENT_SOURCE_DIR}/parameters_injected.xml
--overrides ${PARAM_DEFAULT_OVERRIDES}
--board ${BOARD}
#--verbose
DEPENDS
${param_src_files}
parameters_injected.xml
px4params/srcparser.py
px4params/srcscanner.py
px4params/xmlout.py
px_process_params.py
COMMENT "Generating parameters.xml"
)
add_custom_target(parameters_xml DEPENDS ${parameters_xml})
# generate px4_parameters.c and px4_parameters{,_public}.h
add_custom_command(OUTPUT px4_parameters.c px4_parameters.h px4_parameters_public.h
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/px_generate_params.py
--xml ${parameters_xml} --dest ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${PX4_BINARY_DIR}/parameters.xml
px_generate_params.py
templates/px4_parameters.c.jinja
templates/px4_parameters.h.jinja
templates/px4_parameters_public.h.jinja
)
add_custom_target(parameter_headers DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/px4_parameters_public.h)
add_dependencies(prebuild_targets parameter_headers)
px4_add_module(
MODULE modules__systemlib__param
COMPILE_FLAGS
-Wno-sign-compare # TODO: fix all sign-compare
INCLUDES
${CMAKE_CURRENT_BINARY_DIR}
SRCS
${SRCS}
px4_parameters.c
px4_parameters.h
DEPENDS
platforms__common
)
File diff suppressed because it is too large Load Diff
-502
View File
@@ -1,502 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file param.h
*
* Global parameter store.
*
* Note that a number of API members are marked const or pure; these
* assume that the set of parameters cannot change, or that a parameter
* cannot change type or size over its lifetime. If any of these assumptions
* are invalidated, the attributes should be re-evaluated.
*/
#ifndef _SYSTEMLIB_PARAM_PARAM_H
#define _SYSTEMLIB_PARAM_PARAM_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
/** Maximum size of the parameter backing file */
#define PARAM_FILE_MAXSIZE 4096
__BEGIN_DECLS
/**
* Parameter types.
*/
#define PARAM_TYPE_INT32 0
#define PARAM_TYPE_FLOAT 1
#define PARAM_TYPE_STRUCT 100
#define PARAM_TYPE_STRUCT_MAX (16384 + PARAM_TYPE_STRUCT)
#define PARAM_TYPE_UNKNOWN (0xffff)
typedef uint16_t param_type_t;
#ifdef __PX4_NUTTX // on NuttX use 16 bits to save RAM
/**
* Parameter handle.
*
* Parameters are represented by parameter handles, which can
* be obtained by looking up parameters. They are an offset into a global
* constant parameter array.
*/
typedef uint16_t param_t;
/**
* Handle returned when a parameter cannot be found.
*/
#define PARAM_INVALID ((uint16_t)0xffff)
/**
* Magic handle for hash check param
*/
#define PARAM_HASH ((uint16_t)INT16_MAX)
#else // on other platforms use 32 bits for better performance
/**
* Parameter handle.
*
* Parameters are represented by parameter handles, which can
* be obtained by looking up parameters. They are an offset into a global
* constant parameter array.
*/
typedef uint32_t param_t;
/**
* Handle returned when a parameter cannot be found.
*/
#define PARAM_INVALID ((uint32_t)0xffffffff)
/**
* Magic handle for hash check param
*/
#define PARAM_HASH ((uint32_t)INT32_MAX)
#endif /* __PX4_NUTTX */
/**
* Initialize the param backend. Call this on startup before calling any other methods.
*/
__EXPORT void param_init(void);
/**
* Look up a parameter by name.
*
* @param name The canonical name of the parameter being looked up.
* @return A handle to the parameter, or PARAM_INVALID if the parameter does not exist.
* This call will also set the parameter as "used" in the system, which is used
* to e.g. show the parameter via the RC interface
*/
__EXPORT param_t param_find(const char *name);
/**
* Look up a parameter by name.
*
* @param name The canonical name of the parameter being looked up.
* @return A handle to the parameter, or PARAM_INVALID if the parameter does not exist.
*/
__EXPORT param_t param_find_no_notification(const char *name);
/**
* Return the total number of parameters.
*
* @return The number of parameters.
*/
__EXPORT unsigned param_count(void);
/**
* Return the actually used number of parameters.
*
* @return The number of parameters.
*/
__EXPORT unsigned param_count_used(void);
/**
* Wether a parameter is in use in the system.
*
* @return True if it has been written or read
*/
__EXPORT bool param_used(param_t param);
/**
* Look up a parameter by index.
*
* @param index An index from 0 to n, where n is param_count()-1.
* @return A handle to the parameter, or PARAM_INVALID if the index is out of range.
*/
__EXPORT param_t param_for_index(unsigned index);
/**
* Look up an used parameter by index.
*
* @param index The parameter to obtain the index for.
* @return The index of the parameter in use, or -1 if the parameter does not exist.
*/
__EXPORT param_t param_for_used_index(unsigned index);
/**
* Look up the index of a parameter.
*
* @param param The parameter to obtain the index for.
* @return The index, or -1 if the parameter does not exist.
*/
__EXPORT int param_get_index(param_t param);
/**
* Look up the index of an used parameter.
*
* @param param The parameter to obtain the index for.
* @return The index of the parameter in use, or -1 if the parameter does not exist.
*/
__EXPORT int param_get_used_index(param_t param);
/**
* Obtain the name of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @return The name assigned to the parameter, or NULL if the handle is invalid.
*/
__EXPORT const char *param_name(param_t param);
/**
* Obtain the volatile state of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @return true if the parameter is volatile
*/
__EXPORT bool param_is_volatile(param_t param);
/**
* Test whether a parameter's value has changed from the default.
*
* @return If true, the parameter's value has not been changed from the default.
*/
__EXPORT bool param_value_is_default(param_t param);
/**
* Test whether a parameter's value has been changed but not saved.
*
* @return If true, the parameter's value has not been saved.
*/
__EXPORT bool param_value_unsaved(param_t param);
/**
* Obtain the type of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @return The type assigned to the parameter.
*/
__EXPORT param_type_t param_type(param_t param);
/**
* Determine the size of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @return The size of the parameter's value.
*/
__EXPORT size_t param_size(param_t param);
/**
* Copy the value of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @param val Where to return the value, assumed to point to suitable storage for the parameter type.
* For structures, a bitwise copy of the structure is performed to this address.
* @return Zero if the parameter's value could be returned, nonzero otherwise.
*/
__EXPORT int param_get(param_t param, void *val);
/**
* Set the value of a parameter.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @param val The value to set; assumed to point to a variable of the parameter type.
* For structures, the pointer is assumed to point to a structure to be copied.
* @return Zero if the parameter's value could be set from a scalar, nonzero otherwise.
*/
__EXPORT int param_set(param_t param, const void *val);
/**
* Mark a parameter as used. Only marked parameters will be sent to a GCS.
* A call to param_find() will mark a param as used as well.
*
* @param param A handle returned by param_find or passed by param_foreach.
*/
__EXPORT void param_set_used(param_t param);
/**
* Set the value of a parameter, but do not notify the system about the change.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @param val The value to set; assumed to point to a variable of the parameter type.
* For structures, the pointer is assumed to point to a structure to be copied.
* @return Zero if the parameter's value could be set from a scalar, nonzero otherwise.
*/
__EXPORT int param_set_no_notification(param_t param, const void *val);
/**
* Notify the system about parameter changes. Can be used for example after several calls to
* param_set_no_notification() to avoid unnecessary system notifications.
*/
__EXPORT void param_notify_changes(void);
/**
* Reset a parameter to its default value.
*
* This function frees any storage used by struct parameters, and returns the parameter
* to its default value.
*
* @param param A handle returned by param_find or passed by param_foreach.
* @return Zero on success, nonzero on failure
*/
__EXPORT int param_reset(param_t param);
/**
* Reset all parameters to their default values.
*
* This function also releases the storage used by struct parameters.
*/
__EXPORT void param_reset_all(void);
/**
* Reset all parameters to their default values except for excluded parameters.
*
* This function also releases the storage used by struct parameters.
*
* @param excludes Array of param names to exclude from resetting. Use a wildcard
* at the end to exclude parameters with a certain prefix.
* @param num_excludes The number of excludes provided.
*/
__EXPORT void param_reset_excludes(const char *excludes[], int num_excludes);
/**
* Export changed parameters to a file.
* Note: this method requires a large amount of stack size!
*
* @param fd File descriptor to export to.
* @param only_unsaved Only export changed parameters that have not yet been exported.
* @return Zero on success, nonzero on failure.
*/
__EXPORT int param_export(int fd, bool only_unsaved);
/**
* Import parameters from a file, discarding any unrecognized parameters.
*
* This function merges the imported parameters with the current parameter set.
*
* @param fd File descriptor to import from. (Currently expected to be a file.)
* @return Zero on success, nonzero if an error occurred during import.
* Note that in the failure case, parameters may be inconsistent.
*/
__EXPORT int param_import(int fd);
/**
* Load parameters from a file.
*
* This function resets all parameters to their default values, then loads new
* values from a file.
*
* @param fd File descriptor to import from. (Currently expected to be a file.)
* @return Zero on success, nonzero if an error occurred during import.
* Note that in the failure case, parameters may be inconsistent.
*/
__EXPORT int param_load(int fd);
/**
* Apply a function to each parameter.
*
* Note that the parameter set is not locked during the traversal. It also does
* not hold an internal state, so the callback function can block or sleep between
* parameter callbacks.
*
* @param func The function to invoke for each parameter.
* @param arg Argument passed to the function.
* @param only_changed If true, the function is only called for parameters whose values have
* been changed from the default.
* @param only_changed If true, the function is only called for parameters which have been
* used in one of the running applications.
*/
__EXPORT void param_foreach(void (*func)(void *arg, param_t param), void *arg, bool only_changed, bool only_used);
/**
* Set the default parameter file name.
*
* @param filename Path to the default parameter file. The file is not require to
* exist.
* @return Zero on success.
*/
__EXPORT int param_set_default_file(const char *filename);
/**
* Get the default parameter file name.
*
* @return The path to the current default parameter file; either as
* a result of a call to param_set_default_file, or the
* built-in default.
*/
__EXPORT const char *param_get_default_file(void);
/**
* Save parameters to the default file.
* Note: this method requires a large amount of stack size!
*
* This function saves all parameters with non-default values.
*
* @return Zero on success.
*/
__EXPORT int param_save_default(void);
/**
* Load parameters from the default parameter file.
*
* @return Zero on success.
*/
__EXPORT int param_load_default(void);
/**
* Generate the hash of all parameters and their values
*
* @return CRC32 hash of all param_ids and values
*/
__EXPORT uint32_t param_hash_check(void);
/**
* Enable/disable the param autosaving.
* Re-enabling with changed params will not cause an autosave.
* @param enable true: enable autosaving, false: disable autosaving
*/
__EXPORT void param_control_autosave(bool enable);
/*
* Macros creating static parameter definitions.
*
* Note that these structures are not known by name; they are
* collected into a section that is iterated by the parameter
* code.
*
* Note that these macros cannot be used in C++ code due to
* their use of designated initializers. They should probably
* be refactored to avoid the use of a union for param_value_u.
*/
/** define an int32 parameter */
#define PARAM_DEFINE_INT32(_name, _default)
/** define a float parameter */
#define PARAM_DEFINE_FLOAT(_name, _default)
/** define a parameter that points to a structure */
#define PARAM_DEFINE_STRUCT(_name, _default)
/**
* Parameter value union.
*/
union param_value_u {
void *p;
int32_t i;
float f;
};
/**
* Static parameter definition structure.
*
* This is normally not used by user code; see the PARAM_DEFINE macros
* instead.
*/
struct param_info_s {
const char *name
// GCC 4.8 and higher don't implement proper alignment of static data on
// 64-bit. This means that the 24-byte param_info_s variables are
// 16 byte aligned by GCC and that messes up the assumption that
// sequential items in the __param segment can be addressed as an array.
// The assumption is that the address of the second parameter is at
// &param[0]+sizeof(param[0]). When compiled with clang it is
// true, with gcc is is not true.
// See https://llvm.org/bugs/show_bug.cgi?format=multiple&id=18006
// The following hack is for GCC >=4.8 only. Clang works fine without
// this.
#ifdef __PX4_POSIX
__attribute__((aligned(16)));
#else
;
#endif
param_type_t type;
uint16_t volatile_param: 1;
union param_value_u val;
};
__END_DECLS
#ifdef __cplusplus
#if 0 // set to 1 to debug param type mismatches
#include <cstdio>
#define CHECK_PARAM_TYPE(param, type) \
if (param_type(param) != type) { \
/* use printf() to avoid having to use more includes */ \
printf("wrong type passed to param_get() for param %s\n", param_name(param)); \
}
#else
#define CHECK_PARAM_TYPE(param, type)
#endif
// param is a C-interface. This means there is no overloading, and thus no type-safety for param_get().
// So for C++ code we redefine param_get() to inlined overloaded versions, which gives us type-safety
// w/o having to use a different interface
static inline int param_get_cplusplus(param_t param, float *val)
{
CHECK_PARAM_TYPE(param, PARAM_TYPE_FLOAT);
return param_get(param, val);
}
static inline int param_get_cplusplus(param_t param, int32_t *val)
{
CHECK_PARAM_TYPE(param, PARAM_TYPE_INT32);
return param_get(param, val);
}
#undef CHECK_PARAM_TYPE
#define param_get(param, val) param_get_cplusplus(param, val)
#endif /* __cplusplus */
#endif
File diff suppressed because it is too large Load Diff
@@ -1,138 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<parameters>
<version>3</version>
<group name="UAVCAN Motor Parameters" no_code_generation="true">
<parameter default="75" name="ctl_bw" type="INT32">
<short_desc>Speed controller bandwidth</short_desc>
<long_desc>Speed controller bandwidth, in Hz. Higher values result in faster speed and current rise times, but may result in overshoot and higher current consumption. For fixed-wing aircraft, this value should be less than 50 Hz; for multirotors, values up to 100 Hz may provide improvements in responsiveness.</long_desc>
<unit>Hertz</unit>
<min>10</min>
<max>250</max>
</parameter>
<parameter default="1" name="ctl_dir" type="INT32">
<short_desc>Reverse direction</short_desc>
<long_desc>Motor spin direction as detected during initial enumeration. Use 0 or 1 to reverse direction.</long_desc>
<min>0</min>
<max>1</max>
</parameter>
<parameter default="1" name="ctl_gain" type="FLOAT">
<short_desc>Speed (RPM) controller gain</short_desc>
<long_desc>Speed (RPM) controller gain. Determines controller
aggressiveness; units are amp-seconds per radian. Systems with
higher rotational inertia (large props) will need gain increased;
systems with low rotational inertia (small props) may need gain
decreased. Higher values result in faster response, but may result
in oscillation and excessive overshoot. Lower values result in a
slower, smoother response.</long_desc>
<unit>amp-seconds per radian</unit>
<decimal>3</decimal>
<min>0.00</min>
<max>1.00</max>
</parameter>
<parameter default="3.5" name="ctl_hz_idle" type="FLOAT">
<short_desc>Idle speed (e Hz)</short_desc>
<long_desc>Idle speed (e Hz)</long_desc>
<unit>Hertz</unit>
<decimal>3</decimal>
<min>0.0</min>
<max>100.0</max>
</parameter>
<parameter default="25" name="ctl_start_rate" type="INT32">
<short_desc>Spin-up rate (e Hz/s)</short_desc>
<long_desc>Spin-up rate (e Hz/s)</long_desc>
<unit>Hz/s</unit>
<min>5</min>
<max>1000</max>
</parameter>
<parameter default="0" name="esc_index" type="INT32">
<short_desc>Index of this ESC in throttle command messages.</short_desc>
<long_desc>Index of this ESC in throttle command messages.</long_desc>
<unit>Index</unit>
<min>0</min>
<max>15</max>
</parameter>
<parameter default="20034" name="id_ext_status" type="INT32">
<short_desc>Extended status ID</short_desc>
<long_desc>Extended status ID</long_desc>
<min>1</min>
<max>1000000</max>
</parameter>
<parameter default="50000" name="int_ext_status" type="INT32">
<short_desc>Extended status interval (µs)</short_desc>
<long_desc>Extended status interval (µs)</long_desc>
<unit>µs</unit>
<min>0</min>
<max>1000000</max>
</parameter>
<parameter default="50000" name="int_status" type="INT32">
<short_desc>ESC status interval (µs)</short_desc>
<long_desc>ESC status interval (µs)</long_desc>
<unit>µs</unit>
<max>1000000</max>
</parameter>
<parameter default="12" name="mot_i_max" type="FLOAT">
<short_desc>Motor current limit in amps</short_desc>
<long_desc>Motor current limit in amps. This determines the maximum
current controller setpoint, as well as the maximum allowable
current setpoint slew rate. This value should generally be set to
the continuous current rating listed in the motors specification
sheet, or set equal to the motors specified continuous power
divided by the motor voltage limit.</long_desc>
<unit>Amps</unit>
<decimal>3</decimal>
<min>1</min>
<max>80</max>
</parameter>
<parameter default="2300" name="mot_kv" type="INT32">
<short_desc>Motor Kv in RPM per volt</short_desc>
<long_desc>Motor Kv in RPM per volt. This can be taken from the motors
specification sheet; accuracy will help control performance but
some deviation from the specified value is acceptable.</long_desc>
<unit>RPM/v</unit>
<min>0</min>
<max>4000</max>
</parameter>
<parameter default="0.0" name="mot_ls" type="FLOAT">
<short_desc>READ ONLY: Motor inductance in henries.</short_desc>
<long_desc>READ ONLY: Motor inductance in henries. This is measured on start-up.</long_desc>
<unit>henries</unit>
<decimal>3</decimal>
</parameter>
<parameter default="14" name="mot_num_poles" type="INT32">
<short_desc>Number of motor poles.</short_desc>
<long_desc>Number of motor poles. Used to convert mechanical speeds to
electrical speeds. This number should be taken from the motors
specification sheet.</long_desc>
<unit>Poles</unit>
<min>2</min>
<max>40</max>
</parameter>
<parameter default="0.0" name="mot_rs" type="FLOAT">
<short_desc>READ ONLY: Motor resistance in ohms</short_desc>
<long_desc>READ ONLY: Motor resistance in ohms. This is measured on start-up. When
tuning a new motor, check that this value is approximately equal
to the value shown in the motors specification sheet.</long_desc>
<unit>Ohms</unit>
<decimal>3</decimal>
</parameter>
<parameter default="0.5" name="mot_v_accel" type="FLOAT">
<short_desc>Acceleration limit (V)</short_desc>
<long_desc>Acceleration limit (V)</long_desc>
<unit>Volts</unit>
<decimal>3</decimal>
<min>0.01</min>
<max>1.00</max>
</parameter>
<parameter default="14.8" name="mot_v_max" type="FLOAT">
<short_desc>Motor voltage limit in volts</short_desc>
<long_desc>Motor voltage limit in volts. The current controllers
commanded voltage will never exceed this value. Note that this may
safely be above the nominal voltage of the motor; to determine the
actual motor voltage limit, divide the motors rated power by the
motor current limit.</long_desc>
<unit>Volts</unit>
<decimal>3</decimal>
<min>0</min>
</parameter>
</group>
</parameters>
@@ -1 +0,0 @@
This folder contains a python library used by px_process_params.py
@@ -1 +0,0 @@
__all__ = ["srcscanner", "srcparser", "xmlout", "dokuwikiout", "dokuwikirpc", "scope"]
@@ -1,44 +0,0 @@
from xml.sax.saxutils import escape
import codecs
class DokuWikiTablesOutput():
def __init__(self, groups):
result = ("====== Parameter Reference ======\n"
"<note>**This list is auto-generated from the source code** and contains the most recent parameter documentation.</note>\n"
"\n")
for group in groups:
result += "==== %s ====\n\n" % group.GetName()
result += "|< 100% 25% 45% 10% 10% 10% >|\n"
result += "^ Name ^ Description ^ Min ^ Max ^ Default ^\n"
result += "^ ::: ^ Comment ^^^^\n"
for param in group.GetParams():
code = param.GetName()
def_val = param.GetDefault()
name = param.GetFieldValue("short_desc")
min_val = param.GetFieldValue("min")
max_val = param.GetFieldValue("max")
long_desc = param.GetFieldValue("long_desc")
if name == code:
name = ""
else:
name = name.replace("\n", " ")
name = name.replace("|", "%%|%%")
name = name.replace("^", "%%^%%")
result += "| **%s** |" % code
result += " %s |" % name
result += " %s |" % (min_val or "")
result += " %s |" % (max_val or "")
result += " %s |" % (def_val or "")
result += "\n"
if long_desc is not None:
result += "| ::: | <div>%s</div> ||||\n" % long_desc
result += "\n"
self.output = result;
def Save(self, filename):
with codecs.open(filename, 'w', 'utf-8') as f:
f.write(self.output)
@@ -1,16 +0,0 @@
try:
import xmlrpclib
except ImportError:
import xmlrpc.client as xmlrpclib
# See https://www.dokuwiki.org/devel:xmlrpc for a list of available functions!
# Usage example:
# xmlrpc = dokuwikirpc.get_xmlrpc(url, username, password)
# print(xmlrpc.dokuwiki.getVersion())
def get_xmlrpc(url, username, password):
#proto, url = url.split("://")
#url = proto + "://" + username + ":" + password + "@" + url + "/lib/exe/xmlrpc.php"
url += "/lib/exe/xmlrpc.php?u=" + username + "&p=" + password
return xmlrpclib.ServerProxy(url)
@@ -1,105 +0,0 @@
from xml.sax.saxutils import escape
import codecs
class MarkdownTablesOutput():
def __init__(self, groups):
result = ("# Parameter Reference\n"
"> **Note** **This list is auto-generated from the source code** and contains the most recent parameter documentation.\n"
"\n")
for group in groups:
result += '## %s\n\n' % group.GetName()
#Check if scope (module where parameter is defined) is the same for all parameters in the group.
# If so then display just once about the table.
scope_set = set()
for param in group.GetParams():
scope_set.add(param.GetFieldValue("scope"))
if len(scope_set)==1:
result+='\nThe module where these parameters are defined is: *%s*.\n\n' % list(scope_set)[0]
result += '<table style="width: 100%; table-layout:fixed; font-size:1.5rem; overflow: auto; display:block;">\n'
result += ' <colgroup><col style="width: 23%"><col style="width: 46%"><col style="width: 11%"><col style="width: 11%"><col style="width: 9%"></colgroup>\n'
result += ' <thead>\n'
result += ' <tr><th>Name</th><th>Description</th><th>Min > Max (Incr.)</th><th>Default</th><th>Units</th></tr>\n'
result += ' </thead>\n'
result += '<tbody>\n'
for param in group.GetParams():
code = param.GetName()
name = param.GetFieldValue("short_desc") or ''
long_desc = param.GetFieldValue("long_desc") or ''
min_val = param.GetFieldValue("min") or ''
max_val = param.GetFieldValue("max") or ''
increment = param.GetFieldValue("increment") or ''
def_val = param.GetDefault() or ''
unit = param.GetFieldValue("unit") or ''
type = param.GetType()
reboot_required = param.GetFieldValue("reboot_required") or ''
#board = param.GetFieldValue("board") or '' ## Disabled as no board values are defined in any parameters!
#decimal = param.GetFieldValue("decimal") or '' #Disabled as is intended for GCS not people
#field_codes = param.GetFieldCodes() ## Disabled as not needed for display.
#boolean = param.GetFieldValue("boolean") # or '' # Disabled - does not appear useful.
# Format values for display.
# Display min/max/increment value based on what values are defined.
max_min_combined = ''
if min_val or max_val:
if not min_val:
min_val='?'
if not max_val:
max_val='?'
max_min_combined+='%s > %s ' % (min_val, max_val)
if increment:
max_min_combined+='(%s)' % increment
if long_desc is not '':
long_desc = '<p><strong>Comment:</strong> %s</p>' % long_desc
if name == code:
name = ""
code='<strong id="%s">%s</strong>' % (code, code)
if reboot_required:
reboot_required='<p><b>Reboot required:</b> %s</p>\n' % reboot_required
scope=''
if not len(scope_set)==1 or len(scope_set)==0:
scope = param.GetFieldValue("scope") or ''
if scope:
scope='<p><b>Module:</b> %s</p>\n' % scope
enum_codes=param.GetEnumCodes() or '' # Gets numerical values for parameter.
enum_output=''
# Format codes and their descriptions for display.
if enum_codes:
enum_output+='<strong>Values:</strong><ul>'
enum_codes=sorted(enum_codes,key=float)
for item in enum_codes:
enum_output+='\n<li><strong>%s:</strong> %s</li> \n' % (item, param.GetEnumValue(item))
enum_output+='</ul>\n'
bitmask_list=param.GetBitmaskList() #Gets bitmask values for parameter
bitmask_output=''
#Format bitmask values
if bitmask_list:
bitmask_output+='<strong>Bitmask:</strong><ul>'
for bit in bitmask_list:
bit_text = param.GetBitmaskBit(bit)
bitmask_output+=' <li><strong>%s:</strong> %s</li> \n' % (bit, bit_text)
bitmask_output+='</ul>\n'
result += '<tr>\n <td style="vertical-align: top;">%s (%s)</td>\n <td style="vertical-align: top;"><p>%s</p>%s %s %s %s %s</td>\n <td style="vertical-align: top;">%s</td>\n <td style="vertical-align: top;">%s </td>\n <td style="vertical-align: top;">%s</td>\n</tr>\n' % (code,type,name, long_desc, enum_output, bitmask_output, reboot_required, scope, max_min_combined,def_val,unit)
#Close the table.
result += '</tbody></table>\n\n'
self.output = result
def Save(self, filename):
with codecs.open(filename, 'w', 'utf-8') as f:
f.write(self.output)
@@ -1,32 +0,0 @@
import os
import re
class Scope(object):
"""
Single parameter group
"""
re_deep_lines = re.compile(r'.*\/.*\/')
def __init__(self,):
self.scope = set()
def __str__(self):
return self.scope.__str__()
def Add(self, scope):
"""
Add Scope to set
"""
self.scope.add(scope)
def Has(self, scope):
"""
Check for existance
"""
if len(self.scope) == 0:
return True
# Anything in the form xxxxx/yyyyy/zzzzz....
# is treated as xxxxx/yyyyy
while (self.re_deep_lines.match(scope)):
scope = os.path.dirname(scope)
return scope in self.scope
@@ -1,404 +0,0 @@
import sys
import re
import math
global default_var
default_var = {}
class ParameterGroup(object):
"""
Single parameter group
"""
def __init__(self, name):
self.name = name
self.params = []
def AddParameter(self, param):
"""
Add parameter to the group
"""
self.params.append(param)
def GetName(self):
"""
Get parameter group name
"""
return self.name
def GetParams(self):
"""
Returns the parsed list of parameters. Every parameter is a Parameter
object. Note that returned object is not a copy. Modifications affect
state of the parser.
"""
return sorted(self.params, key=lambda param: param.name)
class Parameter(object):
"""
Single parameter
"""
# Define sorting order of the fields
priority = {
"board": 9,
"short_desc": 8,
"long_desc": 7,
"min": 5,
"max": 4,
"unit": 3,
"decimal": 2,
# all others == 0 (sorted alphabetically)
}
def __init__(self, name, type, default = ""):
self.fields = {}
self.values = {}
self.bitmask = {}
self.name = name
self.type = type
self.default = default
self.volatile = "false"
self.category = ""
def GetName(self):
return self.name
def GetType(self):
return self.type
def GetDefault(self):
return self.default
def GetCategory(self):
return self.category.title()
def GetVolatile(self):
return self.volatile
def SetField(self, code, value):
"""
Set named field value
"""
self.fields[code] = value
def SetEnumValue(self, code, value):
"""
Set named enum value
"""
self.values[code] = value
def SetBitmaskBit(self, index, bit):
"""
Set named enum value
"""
self.bitmask[index] = bit
def SetVolatile(self):
"""
Set volatile flag
"""
self.volatile = "true"
def SetCategory(self, category):
"""
Set param category
"""
self.category = category
def GetFieldCodes(self):
"""
Return list of existing field codes in convenient order
"""
keys = self.fields.keys()
keys = sorted(keys)
keys = sorted(keys, key=lambda x: self.priority.get(x, 0), reverse=True)
return keys
def GetFieldValue(self, code):
"""
Return value of the given field code or None if not found.
"""
fv = self.fields.get(code)
if not fv:
# required because python 3 sorted does not accept None
return ""
return fv
def GetEnumCodes(self):
"""
Return list of existing value codes in convenient order
"""
return sorted(self.values.keys(), key=float)
def GetEnumValue(self, code):
"""
Return value of the given enum code or None if not found.
"""
fv = self.values.get(code)
if not fv:
# required because python 3 sorted does not accept None
return ""
return fv
def GetBitmaskList(self):
"""
Return list of existing bitmask codes in convenient order
"""
keys = self.bitmask.keys()
return sorted(keys, key=float)
def GetBitmaskBit(self, index):
"""
Return value of the given bitmask code or None if not found.
"""
fv = self.bitmask.get(index)
if not fv:
# required because python 3 sorted does not accept None
return ""
return fv
class SourceParser(object):
"""
Parses provided data and stores all found parameters internally.
"""
re_split_lines = re.compile(r'[\r\n]+')
re_comment_start = re.compile(r'^\/\*\*')
re_comment_content = re.compile(r'^\*\s*(.*)')
re_comment_tag = re.compile(r'@([a-zA-Z][a-zA-Z0-9_]*)\s*(.*)')
re_comment_end = re.compile(r'(.*?)\s*\*\/')
re_parameter_definition = re.compile(r'PARAM_DEFINE_([A-Z_][A-Z0-9_]*)\s*\(([A-Z_][A-Z0-9_]*)\s*,\s*([^ ,\)]+)\s*\)\s*;')
re_px4_parameter_definition = re.compile(r'PX4_PARAM_DEFINE_([A-Z_][A-Z0-9_]*)\s*\(([A-Z_][A-Z0-9_]*)\s*\)\s*;')
re_px4_param_default_definition = re.compile(r'#define\s*PARAM_([A-Z_][A-Z0-9_]*)\s*([^ ,\)]+)\s*')
re_cut_type_specifier = re.compile(r'[a-z]+$')
re_is_a_number = re.compile(r'^-?[0-9\.]')
re_remove_dots = re.compile(r'\.+$')
re_remove_carriage_return = re.compile('\n+')
valid_tags = set(["group", "board", "min", "max", "unit", "decimal", "increment", "reboot_required", "value", "boolean", "bit", "category", "volatile"])
# Order of parameter groups
priority = {
# All other groups = 0 (sort alphabetically)
"Miscellaneous": -10
}
def __init__(self):
self.param_groups = {}
def Parse(self, scope, contents):
"""
Incrementally parse program contents and append all found parameters
to the list.
"""
# This code is essentially a comment-parsing grammar. "state"
# represents parser state. It contains human-readable state
# names.
state = None
for line in self.re_split_lines.split(contents):
line = line.strip()
# Ignore empty lines
if line == "":
continue
if self.re_comment_start.match(line):
state = "wait-short"
short_desc = None
long_desc = None
tags = {}
def_values = {}
def_bitmask = {}
elif state is not None and state != "comment-processed":
m = self.re_comment_end.search(line)
if m:
line = m.group(1)
last_comment_line = True
else:
last_comment_line = False
m = self.re_comment_content.match(line)
if m:
comment_content = m.group(1)
if comment_content == "":
# When short comment ends with empty comment line,
# start waiting for the next part - long comment.
if state == "wait-short-end":
state = "wait-long"
else:
m = self.re_comment_tag.match(comment_content)
if m:
tag, desc = m.group(1, 2)
if (tag == "value"):
# Take the meta info string and split the code and description
metainfo = desc.split(" ", 1)
def_values[metainfo[0]] = metainfo[1]
elif (tag == "bit"):
# Take the meta info string and split the code and description
metainfo = desc.split(" ", 1)
def_bitmask[metainfo[0]] = metainfo[1]
else:
tags[tag] = desc
current_tag = tag
state = "wait-tag-end"
elif state == "wait-short":
# Store first line of the short description
short_desc = comment_content
state = "wait-short-end"
elif state == "wait-short-end":
# Append comment line to the short description
short_desc += "\n" + comment_content
elif state == "wait-long":
# Store first line of the long description
long_desc = comment_content
state = "wait-long-end"
elif state == "wait-long-end":
# Append comment line to the long description
long_desc += "\n" + comment_content
elif state == "wait-tag-end":
# Append comment line to the tag text
tags[current_tag] += "\n" + comment_content
else:
raise AssertionError(
"Invalid parser state: %s" % state)
elif not last_comment_line:
# Invalid comment line (inside comment, but not starting with
# "*" or "*/". Reset parsed content.
state = None
if last_comment_line:
state = "comment-processed"
else:
tp = None
name = None
defval = ""
# Non-empty line outside the comment
m = self.re_px4_param_default_definition.match(line)
# Default value handling
if m:
name_m, defval_m = m.group(1,2)
default_var[name_m] = defval_m
m = self.re_parameter_definition.match(line)
if m:
tp, name, defval = m.group(1, 2, 3)
else:
m = self.re_px4_parameter_definition.match(line)
if m:
tp, name = m.group(1, 2)
if (name+'_DEFAULT') in default_var:
defval = default_var[name+'_DEFAULT']
if tp is not None:
# Remove trailing type specifier from numbers: 0.1f => 0.1
if defval != "" and self.re_is_a_number.match(defval):
defval = self.re_cut_type_specifier.sub('', defval)
param = Parameter(name, tp, defval)
param.SetField("scope", scope)
param.SetField("short_desc", name)
# If comment was found before the parameter declaration,
# inject its data into the newly created parameter.
group = "Miscellaneous"
if state == "comment-processed":
if short_desc is not None:
param.SetField("short_desc", self.re_remove_dots.sub('', short_desc))
if long_desc is not None:
long_desc = self.re_remove_carriage_return.sub(' ', long_desc)
param.SetField("long_desc", long_desc)
for tag in tags:
if tag == "group":
group = tags[tag]
elif tag == "volatile":
param.SetVolatile()
elif tag == "category":
param.SetCategory(tags[tag])
elif tag not in self.valid_tags:
sys.stderr.write("Skipping invalid documentation tag: '%s'\n" % tag)
return False
else:
param.SetField(tag, tags[tag])
for def_value in def_values:
param.SetEnumValue(def_value, def_values[def_value])
for def_bit in def_bitmask:
param.SetBitmaskBit(def_bit, def_bitmask[def_bit])
# Store the parameter
if group not in self.param_groups:
self.param_groups[group] = ParameterGroup(group)
self.param_groups[group].AddParameter(param)
state = None
return True
def IsNumber(self, numberString):
try:
float(numberString)
return True
except ValueError:
return False
def Validate(self):
"""
Validates the parameter meta data.
"""
seenParamNames = []
for group in self.GetParamGroups():
for param in group.GetParams():
name = param.GetName()
if len(name) > 16:
sys.stderr.write("Parameter Name {0} is too long (Limit is 16)\n".format(name))
return False
board = param.GetFieldValue("board")
# Check for duplicates
name_plus_board = name + "+" + board
for seenParamName in seenParamNames:
if seenParamName == name_plus_board:
sys.stderr.write("Duplicate parameter definition: {0}\n".format(name_plus_board))
return False
seenParamNames.append(name_plus_board)
# Validate values
default = param.GetDefault()
min = param.GetFieldValue("min")
max = param.GetFieldValue("max")
#sys.stderr.write("{0} default:{1} min:{2} max:{3}\n".format(name, default, min, max))
if default != "" and not self.IsNumber(default):
sys.stderr.write("Default value not number: {0} {1}\n".format(name, default))
return False
# if default != "" and "." not in default:
# sys.stderr.write("Default value does not contain dot (e.g. 10 needs to be written as 10.0): {0} {1}\n".format(name, default))
# return False
if min != "":
if not self.IsNumber(min):
sys.stderr.write("Min value not number: {0} {1}\n".format(name, min))
return False
if default != "" and float(default) < float(min):
sys.stderr.write("Default value is smaller than min: {0} default:{1} min:{2}\n".format(name, default, min))
return False
if max != "":
if not self.IsNumber(max):
sys.stderr.write("Max value not number: {0} {1}\n".format(name, max))
return False
if default != "" and float(default) > float(max):
sys.stderr.write("Default value is larger than max: {0} default:{1} max:{2}\n".format(name, default, max))
return False
for code in param.GetEnumCodes():
if not self.IsNumber(code):
sys.stderr.write("Min value not number: {0} {1}\n".format(name, code))
return False
if param.GetEnumValue(code) == "":
sys.stderr.write("Description for enum value is empty: {0} {1}\n".format(name, code))
return False
for index in param.GetBitmaskList():
if not self.IsNumber(index):
sys.stderr.write("bit value not number: {0} {1}\n".format(name, index))
return False
if not int(min) <= math.pow(2, int(index)) <= int(max):
sys.stderr.write("Bitmask bit must be between {0} and {1}: {2} {3}\n".format(min, max, name, math.pow(2, int(index))))
return False
if param.GetBitmaskBit(index) == "":
sys.stderr.write("Description for bitmask bit is empty: {0} {1}\n".format(name, index))
return False
return True
def GetParamGroups(self):
"""
Returns the parsed list of parameters. Every parameter is a Parameter
object. Note that returned object is not a copy. Modifications affect
state of the parser.
"""
groups = self.param_groups.values()
groups = sorted(groups, key=lambda x: x.GetName())
groups = sorted(groups, key=lambda x: self.priority.get(x.GetName(), 0), reverse=True)
return groups
@@ -1,50 +0,0 @@
import os
import re
import codecs
import sys
class SourceScanner(object):
"""
Traverses directory tree, reads all source files, and passes their contents
to the Parser.
"""
def ScanDir(self, srcdirs, parser):
"""
Scans provided path and passes all found contents to the parser using
parser.Parse method.
"""
extensions1 = tuple([".h"])
extensions2 = tuple([".c"])
for srcdir in srcdirs:
for filename in os.listdir(srcdir):
if filename.endswith(extensions1):
path = os.path.join(srcdir, filename)
if not self.ScanFile(path, parser):
return False
for filename in os.listdir(srcdir):
if filename.endswith(extensions2):
path = os.path.join(srcdir, filename)
if not self.ScanFile(path, parser):
return False
return True
def ScanFile(self, path, parser):
"""
Scans provided file and passes its contents to the parser using
parser.Parse method.
"""
# Extract the scope: it is the directory within the repo. Either it
# starts directly with 'src/module/abc', or it has the form 'x/y/z/src/module/abc'.
# The output is 'module/abc' in both cases.
prefix = "^(|.*" + os.path.sep + ")src" + os.path.sep
scope = re.sub(prefix.replace("\\", "/"), "", os.path.dirname(os.path.relpath(path)).replace("\\", "/"))
with codecs.open(path, 'r', 'utf-8') as f:
try:
contents = f.read()
except:
contents = ''
print('Failed reading file: %s, skipping content.' % path)
pass
return parser.Parse(scope, contents)
@@ -1,82 +0,0 @@
import xml.etree.ElementTree as ET
import codecs
def indent(elem, level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
indent(elem, level+1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
class XMLOutput():
def __init__(self, groups, board, inject_xml_file_name):
xml_parameters = ET.Element("parameters")
xml_version = ET.SubElement(xml_parameters, "version")
xml_version.text = "3"
xml_version = ET.SubElement(xml_parameters, "parameter_version_major")
xml_version.text = "1"
xml_version = ET.SubElement(xml_parameters, "parameter_version_minor")
xml_version.text = "15"
importtree = ET.parse(inject_xml_file_name)
injectgroups = importtree.getroot().findall("group")
for igroup in injectgroups:
xml_parameters.append(igroup)
last_param_name = ""
board_specific_param_set = False
for group in groups:
xml_group = ET.SubElement(xml_parameters, "group")
xml_group.attrib["name"] = group.GetName()
for param in group.GetParams():
if (last_param_name == param.GetName() and not board_specific_param_set) or last_param_name != param.GetName():
xml_param = ET.SubElement(xml_group, "parameter")
xml_param.attrib["name"] = param.GetName()
xml_param.attrib["default"] = param.GetDefault()
xml_param.attrib["type"] = param.GetType()
if (param.GetVolatile() == "true"):
xml_param.attrib["volatile"] = param.GetVolatile()
if (param.GetCategory()):
xml_param.attrib["category"] = param.GetCategory()
last_param_name = param.GetName()
for code in param.GetFieldCodes():
value = param.GetFieldValue(code)
if code == "board":
if value == board:
board_specific_param_set = True
xml_field = ET.SubElement(xml_param, code)
xml_field.text = value
else:
xml_group.remove(xml_param)
else:
xml_field = ET.SubElement(xml_param, code)
xml_field.text = value
if last_param_name != param.GetName():
board_specific_param_set = False
if len(param.GetEnumCodes()) > 0:
xml_values = ET.SubElement(xml_param, "values")
for code in param.GetEnumCodes():
xml_value = ET.SubElement(xml_values, "value")
xml_value.attrib["code"] = code;
xml_value.text = param.GetEnumValue(code)
if len(param.GetBitmaskList()) > 0:
xml_values = ET.SubElement(xml_param, "bitmask")
for index in param.GetBitmaskList():
xml_value = ET.SubElement(xml_values, "bit")
xml_value.attrib["index"] = index;
xml_value.text = param.GetBitmaskBit(index)
indent(xml_parameters)
self.xml_document = ET.ElementTree(xml_parameters)
def Save(self, filename):
self.xml_document.write(filename, encoding="UTF-8")
@@ -1,59 +0,0 @@
#!/usr/bin/env python
"""
Param source code generation script.
"""
from __future__ import print_function
import xml.etree.ElementTree as ET
import codecs
import argparse
from jinja2 import Environment, FileSystemLoader
import os
def generate(xml_file, dest='.'):
"""
Generate px4 param source from xml.
@param xml_file: input parameter xml file
@param dest: Destination directory for generated files
None means to scan everything.
"""
# pylint: disable=broad-except
tree = ET.parse(xml_file)
root = tree.getroot()
params = []
for group in root:
if group.tag == "group" and "no_code_generation" not in group.attrib:
for param in group:
params.append(param)
params = sorted(params, key=lambda name: name.attrib["name"])
script_path = os.path.dirname(os.path.realpath(__file__))
# for jinja docs see: http://jinja.pocoo.org/docs/2.9/api/
env = Environment(
loader=FileSystemLoader(os.path.join(script_path, 'templates')))
if not os.path.isdir(dest):
os.path.mkdir(dest)
template_files = [
'px4_parameters.h.jinja',
'px4_parameters_public.h.jinja',
'px4_parameters.c.jinja',
]
for template_file in template_files:
template = env.get_template(template_file)
with open(os.path.join(
dest, template_file.replace('.jinja','')), 'w') as fid:
fid.write(template.render(params=params))
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("--xml", help="parameter xml file")
arg_parser.add_argument("--dest", help="destination path", default=os.path.curdir)
args = arg_parser.parse_args()
generate(xml_file=args.xml, dest=args.dest)
# vim: set et fenc=utf-8 ff=unix sts=4 sw=4 ts=4 :
@@ -1,200 +0,0 @@
#!/usr/bin/env python
############################################################################
#
# Copyright (C) 2013-2017 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
#
# PX4 paramers processor (main executable file)
#
# This tool scans the PX4 source code for declarations of tunable parameters
# and outputs the list in various formats.
#
# Currently supported formats are:
# * XML for the parametric UI generator
# * Human-readable description in DokuWiki page format
# * Human-readable description in Markdown page format for the PX4 dev guide
#
# This tool also allows to automatically upload the human-readable version
# to the DokuWiki installation via XML-RPC.
#
from __future__ import print_function
import sys
import os
import argparse
from px4params import srcscanner, srcparser, xmlout, dokuwikiout, dokuwikirpc, markdownout
import re
import json
import codecs
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description="Process parameter documentation.")
parser.add_argument("-s", "--src-path",
default=["../src"],
metavar="PATH",
nargs='*',
help="one or more paths to source files to scan for parameters")
parser.add_argument("-x", "--xml",
nargs='?',
const="parameters.xml",
metavar="FILENAME",
help="Create XML file"
" (default FILENAME: parameters.xml)")
parser.add_argument("-i", "--inject-xml",
nargs='?',
const="../Tools/parameters_injected.xml",
metavar="FILENAME",
help="Inject additional param XML file"
" (default FILENAME: ../Tools/parameters_injected.xml)")
parser.add_argument("-b", "--board",
nargs='?',
const="",
metavar="BOARD",
help="Board to create xml parameter xml for")
parser.add_argument("-m", "--markdown",
nargs='?',
const="parameters.md",
metavar="FILENAME",
help="Create Markdown file"
" (default FILENAME: parameters.md)")
parser.add_argument("-w", "--wiki",
nargs='?',
const="parameters.wiki",
metavar="FILENAME",
help="Create DokuWiki file"
" (default FILENAME: parameters.wiki)")
parser.add_argument("-u", "--wiki-update",
nargs='?',
const="firmware:parameters",
metavar="PAGENAME",
help="Update DokuWiki page"
" (default PAGENAME: firmware:parameters)")
parser.add_argument("--wiki-url",
default="https://pixhawk.org",
metavar="URL",
help="DokuWiki URL"
" (default: https://pixhawk.org)")
parser.add_argument("--wiki-user",
default=os.environ.get('XMLRPCUSER', None),
metavar="USERNAME",
help="DokuWiki XML-RPC user name"
" (default: $XMLRPCUSER environment variable)")
parser.add_argument("--wiki-pass",
default=os.environ.get('XMLRPCPASS', None),
metavar="PASSWORD",
help="DokuWiki XML-RPC user password"
" (default: $XMLRPCUSER environment variable)")
parser.add_argument("--wiki-summary",
metavar="SUMMARY",
default="Automagically updated parameter documentation from code.",
help="DokuWiki page edit summary")
parser.add_argument('-v', '--verbose',
action='store_true',
help="verbose output")
parser.add_argument("-o", "--overrides",
default="{}",
metavar="OVERRIDES",
help="a dict of overrides in the form of a json string")
args = parser.parse_args()
# Check for valid command
if not (args.xml or args.wiki or args.wiki_update or args.markdown):
print("Error: You need to specify at least one output method!\n")
parser.print_usage()
sys.exit(1)
# Initialize source scanner and parser
scanner = srcscanner.SourceScanner()
parser = srcparser.SourceParser()
# Scan directories, and parse the files
if (args.verbose):
print("Scanning source path " + str(args.src_path))
if not scanner.ScanDir(args.src_path, parser):
sys.exit(1)
if not parser.Validate():
sys.exit(1)
param_groups = parser.GetParamGroups()
if len(param_groups) == 0:
print("Warning: no parameters found")
override_dict = json.loads(args.overrides)
if len(override_dict.keys()) > 0:
for group in param_groups:
for param in group.GetParams():
name = param.GetName()
if name in override_dict.keys():
val = str(override_dict[param.GetName()])
param.default = val
print("OVERRIDING {:s} to {:s}!!!!!".format(name, val))
# Output to XML file
if args.xml:
if args.verbose:
print("Creating XML file " + args.xml)
cur_dir = os.path.dirname(os.path.realpath(__file__))
out = xmlout.XMLOutput(param_groups, args.board,
os.path.join(cur_dir, args.inject_xml))
out.Save(args.xml)
# Output to DokuWiki tables
if args.wiki or args.wiki_update:
out = dokuwikiout.DokuWikiTablesOutput(param_groups)
if args.wiki:
print("Creating wiki file " + args.wiki)
out.Save(args.wiki)
if args.wiki_update:
if args.wiki_user and args.wiki_pass:
print("Updating wiki page " + args.wiki_update)
xmlrpc = dokuwikirpc.get_xmlrpc(args.wiki_url, args.wiki_user, args.wiki_pass)
xmlrpc.wiki.putPage(args.wiki_update, out.output, {'sum': args.wiki_summary})
else:
print("Error: You need to specify DokuWiki XML-RPC username and password!")
# Output to Markdown/HTML tables
if args.markdown:
out = markdownout.MarkdownTablesOutput(param_groups)
if args.markdown:
print("Creating markdown file " + args.markdown)
out.Save(args.markdown)
#print("All done!")
if __name__ == "__main__":
main()
@@ -1,38 +0,0 @@
{# jinja syntax: http://jinja.pocoo.org/docs/2.9/templates/ #}
#include <px4_parameters.h>
// DO NOT EDIT
// This file is autogenerated from paramaters.xml
__BEGIN_DECLS
const
#ifndef __PX4_DARWIN
__attribute__((used, section("__param")))
#endif
struct px4_parameters_t px4_parameters = {
{% for param in params %}
{
"{{ param.attrib["name"] }}",
PARAM_TYPE_{{ param.attrib["type"] }},
{%- if param.attrib["volatile"] == "true" %}
.volatile_param = 1,
{%- else %}
.volatile_param = 0,
{%- endif %}
{%- if param.attrib["type"] == "FLOAT" %}
.val.f = {{ param.attrib["default"] }}
{%- elif param.attrib["type"] == "INT32" %}
.val.i = {{ param.attrib["default"] }}
{%- endif %}
},
{% endfor %}
{{ params | length }}
};
//extern const struct px4_parameters_t px4_parameters;
__END_DECLS
{# vim: set noet ft=jinja fenc=utf-8 ff=unix sts=4 sw=4 ts=4 : #}
@@ -1,21 +0,0 @@
{# jinja syntax: http://jinja.pocoo.org/docs/2.9/templates/ #}
#include <stdint.h>
#include <systemlib/param/param.h>
// DO NOT EDIT
// This file is autogenerated from parameters.xml
__BEGIN_DECLS
struct px4_parameters_t {
{%- for param in params %}
const struct param_info_s __param__{{ param.attrib["name"] }};
{%- endfor %}
const unsigned int param_count;
};
extern const struct px4_parameters_t px4_parameters;
__END_DECLS
{# vim: set noet ft=jinja fenc=utf-8 ff=unix sts=4 sw=4 ts=4 : #}
@@ -1,37 +0,0 @@
{# jinja syntax: http://jinja.pocoo.org/docs/2.9/templates/ #}
#include <stdint.h>
#include <systemlib/param/param.h>
// DO NOT EDIT
// This file is autogenerated from parameters.xml
#ifdef __cplusplus
namespace px4 { {# wrap the enum in a namespace, otherwise we get shadowing errors for MAV_TYPE #}
/// Enum with all parameters
enum class params {
{# enums are guaranteed to start with 0 (if the value for the first is not
specified), and then incremented by 1 (the implementation depends on that!) #}
{%- for param in params %}
{{ param.attrib["name"] }},
{%- endfor %}
_COUNT
};
// All parameter types
{# (px4_parameters is marked as extern, so we cannot use it as constexpr) #}
static const constexpr int param_types_array[] = {
{%- for param in params %}
PARAM_TYPE_{{ param.attrib["type"] }}, // {{ param.attrib["name"] }}
{%- endfor %}
};
} // namespace px4
#endif /* __cplusplus */
-634
View File
@@ -1,634 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2012-2016 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file perf_counter.c
*
* @brief Performance measuring tools.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/queue.h>
#include <drivers/drv_hrt.h>
#include <math.h>
#include <pthread.h>
#include <systemlib/err.h>
#include "perf_counter.h"
#ifdef __PX4_QURT
// There is presumably no dprintf on QURT. Therefore use the usual output to mini-dm.
#define dprintf(_fd, _text, ...) ((_fd) == 1 ? PX4_INFO((_text), ##__VA_ARGS__) : (void)(_fd))
#endif
/**
* Header common to all counters.
*/
struct perf_ctr_header {
sq_entry_t link; /**< list linkage */
enum perf_counter_type type; /**< counter type */
const char *name; /**< counter name */
};
/**
* PC_EVENT counter.
*/
struct perf_ctr_count {
struct perf_ctr_header hdr;
uint64_t event_count;
};
/**
* PC_ELAPSED counter.
*/
struct perf_ctr_elapsed {
struct perf_ctr_header hdr;
uint64_t event_count;
uint64_t time_start;
uint64_t time_total;
uint32_t time_least;
uint32_t time_most;
float mean;
float M2;
};
/**
* PC_INTERVAL counter.
*/
struct perf_ctr_interval {
struct perf_ctr_header hdr;
uint64_t event_count;
uint64_t time_event;
uint64_t time_first;
uint64_t time_last;
uint32_t time_least;
uint32_t time_most;
float mean;
float M2;
};
/**
* List of all known counters.
*/
static sq_queue_t perf_counters = { NULL, NULL };
/**
* mutex protecting access to the perf_counters linked list (which is read from & written to by different threads)
*/
pthread_mutex_t perf_counters_mutex = PTHREAD_MUTEX_INITIALIZER;
// FIXME: the mutex does **not** protect against access to/from the perf
// counter's data. It can still happen that a counter is updated while it is
// printed. This can lead to inconsistent output, or completely bogus values
// (especially the 64bit values which are in general not atomically updated).
// The same holds for shared perf counters (perf_alloc_once), that can be updated
// concurrently (this affects the 'ctrl_latency' counter).
perf_counter_t
perf_alloc(enum perf_counter_type type, const char *name)
{
perf_counter_t ctr = NULL;
switch (type) {
case PC_COUNT:
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_count), 1);
break;
case PC_ELAPSED:
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_elapsed), 1);
break;
case PC_INTERVAL:
ctr = (perf_counter_t)calloc(sizeof(struct perf_ctr_interval), 1);
break;
default:
break;
}
if (ctr != NULL) {
ctr->type = type;
ctr->name = name;
pthread_mutex_lock(&perf_counters_mutex);
sq_addfirst(&ctr->link, &perf_counters);
pthread_mutex_unlock(&perf_counters_mutex);
}
return ctr;
}
perf_counter_t
perf_alloc_once(enum perf_counter_type type, const char *name)
{
pthread_mutex_lock(&perf_counters_mutex);
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
while (handle != NULL) {
if (!strcmp(handle->name, name)) {
if (type == handle->type) {
/* they are the same counter */
pthread_mutex_unlock(&perf_counters_mutex);
return handle;
} else {
/* same name but different type, assuming this is an error and not intended */
pthread_mutex_unlock(&perf_counters_mutex);
return NULL;
}
}
handle = (perf_counter_t)sq_next(&handle->link);
}
pthread_mutex_unlock(&perf_counters_mutex);
/* if the execution reaches here, no existing counter of that name was found */
return perf_alloc(type, name);
}
void
perf_free(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
pthread_mutex_lock(&perf_counters_mutex);
sq_rem(&handle->link, &perf_counters);
pthread_mutex_unlock(&perf_counters_mutex);
free(handle);
}
void
perf_count(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_COUNT:
((struct perf_ctr_count *)handle)->event_count++;
break;
case PC_INTERVAL: {
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
hrt_abstime now = hrt_absolute_time();
switch (pci->event_count) {
case 0:
pci->time_first = now;
break;
case 1:
pci->time_least = (uint32_t)(now - pci->time_last);
pci->time_most = (uint32_t)(now - pci->time_last);
pci->mean = pci->time_least / 1e6f;
pci->M2 = 0;
break;
default: {
hrt_abstime interval = now - pci->time_last;
if ((uint32_t)interval < pci->time_least) {
pci->time_least = (uint32_t)interval;
}
if ((uint32_t)interval > pci->time_most) {
pci->time_most = (uint32_t)interval;
}
// maintain mean and variance of interval in seconds
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
float dt = interval / 1e6f;
float delta_intvl = dt - pci->mean;
pci->mean += delta_intvl / pci->event_count;
pci->M2 += delta_intvl * (dt - pci->mean);
break;
}
}
pci->time_last = now;
pci->event_count++;
break;
}
default:
break;
}
}
void
perf_begin(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_ELAPSED:
((struct perf_ctr_elapsed *)handle)->time_start = hrt_absolute_time();
break;
default:
break;
}
}
void
perf_end(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
if (pce->time_start != 0) {
int64_t elapsed = hrt_absolute_time() - pce->time_start;
if (elapsed >= 0) {
pce->event_count++;
pce->time_total += elapsed;
if ((pce->time_least > (uint32_t)elapsed) || (pce->time_least == 0)) {
pce->time_least = elapsed;
}
if (pce->time_most < (uint32_t)elapsed) {
pce->time_most = elapsed;
}
// maintain mean and variance of the elapsed time in seconds
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
float dt = elapsed / 1e6f;
float delta_intvl = dt - pce->mean;
pce->mean += delta_intvl / pce->event_count;
pce->M2 += delta_intvl * (dt - pce->mean);
pce->time_start = 0;
}
}
}
break;
default:
break;
}
}
void
perf_set_elapsed(perf_counter_t handle, int64_t elapsed)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
if (elapsed >= 0) {
pce->event_count++;
pce->time_total += elapsed;
if ((pce->time_least > (uint32_t)elapsed) || (pce->time_least == 0)) {
pce->time_least = elapsed;
}
if (pce->time_most < (uint32_t)elapsed) {
pce->time_most = elapsed;
}
// maintain mean and variance of the elapsed time in seconds
// Knuth/Welford recursive mean and variance of update intervals (via Wikipedia)
float dt = elapsed / 1e6f;
float delta_intvl = dt - pce->mean;
pce->mean += delta_intvl / pce->event_count;
pce->M2 += delta_intvl * (dt - pce->mean);
pce->time_start = 0;
}
}
break;
default:
break;
}
}
void
perf_set_count(perf_counter_t handle, uint64_t count)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_COUNT: {
((struct perf_ctr_count *)handle)->event_count = count;
}
break;
default:
break;
}
}
void
perf_cancel(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
pce->time_start = 0;
}
break;
default:
break;
}
}
void
perf_reset(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_COUNT:
((struct perf_ctr_count *)handle)->event_count = 0;
break;
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
pce->event_count = 0;
pce->time_start = 0;
pce->time_total = 0;
pce->time_least = 0;
pce->time_most = 0;
break;
}
case PC_INTERVAL: {
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
pci->event_count = 0;
pci->time_event = 0;
pci->time_first = 0;
pci->time_last = 0;
pci->time_least = 0;
pci->time_most = 0;
break;
}
}
}
void
perf_print_counter(perf_counter_t handle)
{
if (handle == NULL) {
return;
}
perf_print_counter_fd(1, handle);
}
void
perf_print_counter_fd(int fd, perf_counter_t handle)
{
if (handle == NULL) {
return;
}
switch (handle->type) {
case PC_COUNT:
dprintf(fd, "%s: %llu events\n",
handle->name,
(unsigned long long)((struct perf_ctr_count *)handle)->event_count);
break;
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
float rms = sqrtf(pce->M2 / (pce->event_count - 1));
dprintf(fd, "%s: %llu events, %lluus elapsed, %lluus avg, min %lluus max %lluus %5.3fus rms\n",
handle->name,
(unsigned long long)pce->event_count,
(unsigned long long)pce->time_total,
(pce->event_count == 0) ? 0 : (unsigned long long)pce->time_total / pce->event_count,
(unsigned long long)pce->time_least,
(unsigned long long)pce->time_most,
(double)(1e6f * rms));
break;
}
case PC_INTERVAL: {
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
float rms = sqrtf(pci->M2 / (pci->event_count - 1));
dprintf(fd, "%s: %llu events, %lluus avg, min %lluus max %lluus %5.3fus rms\n",
handle->name,
(unsigned long long)pci->event_count,
(pci->event_count == 0) ? 0 : (unsigned long long)(pci->time_last - pci->time_first) / pci->event_count,
(unsigned long long)pci->time_least,
(unsigned long long)pci->time_most,
(double)(1e6f * rms));
break;
}
default:
break;
}
}
int
perf_print_counter_buffer(char *buffer, int length, perf_counter_t handle)
{
int num_written = 0;
if (handle == NULL) {
return 0;
}
switch (handle->type) {
case PC_COUNT:
num_written = snprintf(buffer, length, "%s: %llu events",
handle->name,
(unsigned long long)((struct perf_ctr_count *)handle)->event_count);
break;
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
float rms = sqrtf(pce->M2 / (pce->event_count - 1));
num_written = snprintf(buffer, length, "%s: %llu events, %lluus elapsed, %lluus avg, min %lluus max %lluus %5.3fus rms",
handle->name,
(unsigned long long)pce->event_count,
(unsigned long long)pce->time_total,
(pce->event_count == 0) ? 0 : (unsigned long long)pce->time_total / pce->event_count,
(unsigned long long)pce->time_least,
(unsigned long long)pce->time_most,
(double)(1e6f * rms));
break;
}
case PC_INTERVAL: {
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
float rms = sqrtf(pci->M2 / (pci->event_count - 1));
num_written = snprintf(buffer, length, "%s: %llu events, %lluus avg, min %lluus max %lluus %5.3fus rms",
handle->name,
(unsigned long long)pci->event_count,
(pci->event_count == 0) ? 0 : (unsigned long long)(pci->time_last - pci->time_first) / pci->event_count,
(unsigned long long)pci->time_least,
(unsigned long long)pci->time_most,
(double)(1e6f * rms));
break;
}
default:
break;
}
buffer[length - 1] = 0; // ensure 0-termination
return num_written;
}
uint64_t
perf_event_count(perf_counter_t handle)
{
if (handle == NULL) {
return 0;
}
switch (handle->type) {
case PC_COUNT:
return ((struct perf_ctr_count *)handle)->event_count;
case PC_ELAPSED: {
struct perf_ctr_elapsed *pce = (struct perf_ctr_elapsed *)handle;
return pce->event_count;
}
case PC_INTERVAL: {
struct perf_ctr_interval *pci = (struct perf_ctr_interval *)handle;
return pci->event_count;
}
default:
break;
}
return 0;
}
void
perf_iterate_all(perf_callback cb, void *user)
{
pthread_mutex_lock(&perf_counters_mutex);
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
while (handle != NULL) {
cb(handle, user);
handle = (perf_counter_t)sq_next(&handle->link);
}
pthread_mutex_unlock(&perf_counters_mutex);
}
void
perf_print_all(int fd)
{
pthread_mutex_lock(&perf_counters_mutex);
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
while (handle != NULL) {
perf_print_counter_fd(fd, handle);
handle = (perf_counter_t)sq_next(&handle->link);
}
pthread_mutex_unlock(&perf_counters_mutex);
}
// these are defined in drv_hrt.c
extern const uint16_t latency_bucket_count;
extern uint32_t latency_counters[];
extern const uint16_t latency_buckets[];
void
perf_print_latency(int fd)
{
dprintf(fd, "bucket [us] : events\n");
for (int i = 0; i < latency_bucket_count; i++) {
printf(" %4i : %li\n", latency_buckets[i], (long int)latency_counters[i]);
}
// print the overflow bucket value
dprintf(fd, " >%4i : %i\n", latency_buckets[latency_bucket_count - 1], latency_counters[latency_bucket_count]);
}
void
perf_reset_all(void)
{
pthread_mutex_lock(&perf_counters_mutex);
perf_counter_t handle = (perf_counter_t)sq_peek(&perf_counters);
while (handle != NULL) {
perf_reset(handle);
handle = (perf_counter_t)sq_next(&handle->link);
}
pthread_mutex_unlock(&perf_counters_mutex);
for (int i = 0; i <= latency_bucket_count; i++) {
latency_counters[i] = 0;
}
}
-227
View File
@@ -1,227 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012-2016 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file perf_counter.h
* Performance measuring tools.
*/
#ifndef _SYSTEMLIB_PERF_COUNTER_H
#define _SYSTEMLIB_PERF_COUNTER_H value
#include <stdint.h>
#include <px4_defines.h>
/**
* Counter types.
*/
enum perf_counter_type {
PC_COUNT, /**< count the number of times an event occurs */
PC_ELAPSED, /**< measure the time elapsed performing an event */
PC_INTERVAL /**< measure the interval between instances of an event */
};
struct perf_ctr_header;
typedef struct perf_ctr_header *perf_counter_t;
__BEGIN_DECLS
/**
* Create a new local counter.
*
* @param type The type of the new counter.
* @param name The counter name.
* @return Handle for the new counter, or NULL if a counter
* could not be allocated.
*/
#ifndef perf_alloc // perf_alloc might be defined to be NULL in src/modules/px4iofirmware/px4io.h
__EXPORT extern perf_counter_t perf_alloc(enum perf_counter_type type, const char *name);
#endif
/**
* Get the reference to an existing counter or create a new one if it does not exist.
*
* @param type The type of the counter.
* @param name The counter name.
* @return Handle for the counter, or NULL if a counter
* could not be allocated.
*/
__EXPORT extern perf_counter_t perf_alloc_once(enum perf_counter_type type, const char *name);
/**
* Free a counter.
*
* @param handle The performance counter's handle.
*/
__EXPORT extern void perf_free(perf_counter_t handle);
/**
* Count a performance event.
*
* This call only affects counters that take single events; PC_COUNT, PC_INTERVAL etc.
*
* @param handle The handle returned from perf_alloc.
*/
__EXPORT extern void perf_count(perf_counter_t handle);
/**
* Begin a performance event.
*
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
*
* @param handle The handle returned from perf_alloc.
*/
__EXPORT extern void perf_begin(perf_counter_t handle);
/**
* End a performance event.
*
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
* If a call is made without a corresponding perf_begin call, or if perf_cancel
* has been called subsequently, no change is made to the counter.
*
* @param handle The handle returned from perf_alloc.
*/
__EXPORT extern void perf_end(perf_counter_t handle);
/**
* Register a measurement
*
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
* If a call is made without a corresponding perf_begin call. It sets the
* value provided as argument as a new measurement.
*
* @param handle The handle returned from perf_alloc.
* @param elapsed The time elapsed. Negative values lead to incrementing the overrun counter.
*/
__EXPORT extern void perf_set_elapsed(perf_counter_t handle, int64_t elapsed);
/**
* Set a counter
*
* This call applies to counters of type PC_COUNT. It (re-)sets the count.
*
* @param handle The handle returned from perf_alloc.
* @param count The counter value to be set.
*/
__EXPORT extern void perf_set_count(perf_counter_t handle, uint64_t count);
/**
* Cancel a performance event.
*
* This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
* It reverts the effect of a previous perf_begin.
*
* @param handle The handle returned from perf_alloc.
*/
__EXPORT extern void perf_cancel(perf_counter_t handle);
/**
* Reset a performance counter.
*
* This call resets performance counter to initial state
*
* @param handle The handle returned from perf_alloc.
*/
__EXPORT extern void perf_reset(perf_counter_t handle);
/**
* Print one performance counter to stdout
*
* @param handle The counter to print.
*/
__EXPORT extern void perf_print_counter(perf_counter_t handle);
/**
* Print one performance counter to a fd.
*
* @param fd File descriptor to print to - e.g. 0 for stdout
* @param handle The counter to print.
*/
__EXPORT extern void perf_print_counter_fd(int fd, perf_counter_t handle);
/**
* Print one performance counter to a buffer.
*
* @param buffer buffer to write to
* @param length buffer length
* @param handle The counter to print.
* @param return number of bytes written
*/
__EXPORT extern int perf_print_counter_buffer(char *buffer, int length, perf_counter_t handle);
/**
* Print all of the performance counters.
*
* @param fd File descriptor to print to - e.g. 0 for stdout
*/
__EXPORT extern void perf_print_all(int fd);
typedef void (*perf_callback)(perf_counter_t handle, void *user);
/**
* Iterate over all performance counters using a callback.
*
* Caution: This will aquire the mutex, so do not call any other perf_* method
* that aquire the mutex as well from the callback (If this is needed, configure
* the mutex to be reentrant).
*
* @param cb callback method
* @param user custom argument for the callback
*/
__EXPORT extern void perf_iterate_all(perf_callback cb, void *user);
/**
* Print hrt latency counters.
*
* @param fd File descriptor to print to - e.g. 0 for stdout
*/
__EXPORT extern void perf_print_latency(int fd);
/**
* Reset all of the performance counters.
*/
__EXPORT extern void perf_reset_all(void);
/**
* Return current event_count
*
* @param handle The counter returned from perf_alloc.
* @return event_count
*/
__EXPORT extern uint64_t perf_event_count(perf_counter_t handle);
__END_DECLS
#endif
+1 -1
View File
@@ -46,7 +46,7 @@
#include <systemlib/err.h>
#include <systemlib/rc_check.h>
#include <systemlib/param/param.h>
#include <parameters/param.h>
#include <systemlib/mavlink_log.h>
#include <drivers/drv_rc_input.h>