mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-28 04:50:35 +08:00
cmake remove circular linking and reorganize
- px4_add_module now requires MAIN - px4_add_library doesn't automatically link
This commit is contained in:
@@ -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 :
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
// ¶m[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 motor’s specification
|
||||
sheet, or set equal to the motor’s 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 motor’s
|
||||
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 motor’s
|
||||
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 motor’s 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 controller’s
|
||||
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 motor’s 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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user