Merge branch 'dsdl_review'

This commit is contained in:
Pavel Kirienko
2015-03-27 00:05:46 +03:00
96 changed files with 636 additions and 392 deletions
@@ -5,9 +5,12 @@
uint8 actuator_id
float16 position # Position feedback; same units as command
float16 power # Watt
float16 force # Newton (sign depends on the direction of the force)
#
# Whether the units are linear or angular depends on the actuator type (refer to the Command data type).
#
float16 position # meter or radian
float16 force # Newton or Newton metre
float16 speed # meter per second or radian per second
uint7 POWER_RATING_PCT_UNKNOWN = 127
uint7 power_rating_pct # 0 - unloaded, 100 - full load/overload
uint7 power_rating_pct # 0 - unloaded, 100 - full load
+11 -6
View File
@@ -6,10 +6,15 @@
uint8 actuator_id
#
# Recommended units are, either:
# - Unitless [-1; 1]
# - Angular position in radians
# - Linear position in meters
# Status report should normally use the same units.
# Whether the units are linear or angular depends on the actuator type.
#
float16 command
uint4 COMMAND_TYPE_UNITLESS = 0 # [-1, 1]
uint4 COMMAND_TYPE_POSITION = 1 # meter or radian
uint4 COMMAND_TYPE_FORCE = 2 # Newton or Newton metre
uint4 COMMAND_TYPE_SPEED = 3 # meter per second or radian per second
uint4 command_type
#
# Value of the above type
#
float16 command_value
@@ -1,6 +0,0 @@
#
# True airspeed in meters per second.
#
float16 true_airspeed
float16 true_airspeed_variance
@@ -1,12 +0,0 @@
#
# Pressure altitude in meters and barometric climb rate in meters per second.
#
uavcan.Timestamp timestamp
float32 pressure_altitude # m
float16 pressure_altitude_variance # m^2
# Positive if climbing up
float16 climb_rate # m/s
float16 climb_rate_variance # m^2/s^2
@@ -1,9 +0,0 @@
#
# Static air data for barometric altitude and altitude rate measurements.
#
float32 static_pressure # Pascal
float16 static_pressure_variance # Pascal^2
float16 static_temperature # Kelvin
float16 static_temperature_variance # Kelvin^2
@@ -0,0 +1,6 @@
#
# TAS.
#
float16 true_airspeed # m/s
float16 true_airspeed_variance # (m/s)^2
@@ -0,0 +1,6 @@
#
# IAS.
#
float16 indicated_airspeed # m/s
float16 indicated_airspeed_variance # (m/s)^2
@@ -1,5 +1,5 @@
#
# Angle of attack in radians.
# Angle of attack.
#
uint8 SENSOR_ID_LEFT = 254
@@ -0,0 +1,6 @@
#
# Static pressure.
#
float32 static_pressure # Pascal
float16 static_pressure_variance # Pascal^2
@@ -0,0 +1,6 @@
#
# Static temperature.
#
float16 static_temperature # Kelvin
float16 static_temperature_variance # Kelvin^2
@@ -1,31 +1,20 @@
#
# Generic camera gimbal control.
#
# This message can only be used in the following modes:
# - COMMAND_MODE_ANGULAR_VELOCITY
# - COMMAND_MODE_ORIENTATION_FIXED_FRAME
# - COMMAND_MODE_ORIENTATION_BODY_FRAME
#
#
# Target operation mode - how to handle this message.
# See the list of acceptable modes above.
#
Mode mode
#
# This field is only used in the following modes:
# - COMMAND_MODE_ANGULAR_VELOCITY
# - COMMAND_MODE_ORIENTATION_FIXED_FRAME
# - COMMAND_MODE_ORIENTATION_BODY_FRAME
#
# In the angular velocity mode, this field contains a rate quaternion.
# In the orientation mode, this field contains orientation either in fixed frame or in body frame.
#
float16[4] quaternion_xyzw
#
# These fields are only used in the following modes:
# - COMMAND_MODE_GEO_POI
#
int32 longitude_deg_1e7 # 1 LSB = 1e-7 deg
int32 latitude_deg_1e7
int22 height_cm # 1 LSB = 10 mm
uint2 HEIGHT_REFERENCE_ELLIPSOID = 0
uint2 HEIGHT_REFERENCE_MEAN_SEA_LEVEL = 1
uint2 height_reference
@@ -0,0 +1,23 @@
#
# Generic camera gimbal control.
#
# This message can only be used in the following modes:
# - COMMAND_MODE_GEO_POI
#
#
# Target operation mode - how to handle this message.
# See the list of acceptable modes above.
#
Mode mode
#
# Coordinates of the POI (point of interest).
#
int32 longitude_deg_1e7 # 1 LSB = 1e-7 deg
int32 latitude_deg_1e7
int22 height_cm # 1 LSB = 10 mm
uint2 HEIGHT_REFERENCE_ELLIPSOID = 0
uint2 HEIGHT_REFERENCE_MEAN_SEA_LEVEL = 1
uint2 height_reference
@@ -2,8 +2,8 @@
# Gimbal operating mode
#
uint4 COMMAND_MODE_ANGULAR_VELOCITY = 0
uint4 COMMAND_MODE_ORIENTATION_FIXED_FRAME = 1
uint4 COMMAND_MODE_ORIENTATION_BODY_FRAME = 2
uint4 COMMAND_MODE_GEO_POI = 3
uint4 command_mode
uint8 COMMAND_MODE_ANGULAR_VELOCITY = 0
uint8 COMMAND_MODE_ORIENTATION_FIXED_FRAME = 1
uint8 COMMAND_MODE_ORIENTATION_BODY_FRAME = 2
uint8 COMMAND_MODE_GEO_POI = 3
uint8 command_mode
-27
View File
@@ -1,27 +0,0 @@
#
# GNSS navigation solution with uncertainty.
#
uavcan.Timestamp timestamp # Global network-synchronized time, if available, otherwise zero
uavcan.Timestamp gnss_timestamp # GNSS timestamp (UTC is preferred), if available, otherwise zero
int37 longitude_deg_1e8 # Longitude degrees multiplied by 1e8 (approx. 1 mm per LSB)
int37 latitude_deg_1e8 # Latitude degrees multiplied by 1e8 (approx. 1 mm per LSB on equator)
int27 height_ellipsoid_mm # Height above ellipsoid in millimeters
int27 height_msl_mm # Height above mean sea level in millimeters
float16[3] ned_velocity # NED frame (north-east-down) in meters per second
uint6 sats_used
uint2 STATUS_NO_FIX = 0
uint2 STATUS_TIME_ONLY = 1
uint2 STATUS_2D_FIX = 2
uint2 STATUS_3D_FIX = 3
uint2 status
float16 pdop
float16[<=9] position_covariance # m^2
float16[<=9] velocity_covariance # (m/s)^2
+52
View File
@@ -0,0 +1,52 @@
#
# GNSS navigation solution with uncertainty.
#
uavcan.Timestamp timestamp # Global network-synchronized time, if available, otherwise zero
#
# Time solution
#
# The following rules apply:
# - if num_leap_seconds = 0, it is assumed that its value is unknown, and that gnss_timestamp contains UTC time.
# - if num_leap_seconds = 1, it is assumed that its value is unknown, and that gnss_timestamp contains GPS time.
# - if num_leap_seconds = 2, it is assumed that its value is unknown, and that gnss_timestamp contains TAI time.
# - if num_leap_seconds > 2, it is assumed that its value is KNOWN, and that gnss_timestamp contains UTC time.
#
# At the time of February 2015, the number of leap seconds is 26.
#
uavcan.Timestamp gnss_timestamp # GNSS timestamp, if available, otherwise zero
uint8 NUM_LEAP_SECONDS_UNKNOWN_GNSS_TIME_UTC = 0 # num_leap_seconds is unknown, gnss_timestamp contains UTC time
uint8 NUM_LEAP_SECONDS_UNKNOWN_GNSS_TIME_GPS = 1 # num_leap_seconds is unknown, gnss_timestamp contains GPS time
uint8 NUM_LEAP_SECONDS_UNKNOWN_GNSS_TIME_TAI = 2 # num_leap_seconds is unknown, gnss_timestamp contains TAI time
uint8 num_leap_seconds
#
# Position and velocity solution
#
int37 longitude_deg_1e8 # Longitude degrees multiplied by 1e8 (approx. 1 mm per LSB)
int37 latitude_deg_1e8 # Latitude degrees multiplied by 1e8 (approx. 1 mm per LSB on equator)
int27 height_ellipsoid_mm # Height above ellipsoid in millimeters
int27 height_msl_mm # Height above mean sea level in millimeters
float16[3] ned_velocity # NED frame (north-east-down) in meters per second
#
# Fix status
#
uint6 sats_used
uint2 STATUS_NO_FIX = 0
uint2 STATUS_TIME_ONLY = 1
uint2 STATUS_2D_FIX = 2
uint2 STATUS_3D_FIX = 3
uint2 status
#
# Precision
#
float16 pdop
float16[<=9] position_covariance # m^2
float16[<=9] velocity_covariance # (m/s)^2
@@ -13,5 +13,3 @@ float16 edop
uint7 sats_visible # All visible sats of all available GNSS (e.g. GPS, GLONASS, etc)
uint6 sats_used # All used sats of all available GNSS
bool differential_corrections_applied
@@ -1,9 +0,0 @@
#
# X/Y velocities estimated by a simple downward looking optical flow sensor.
#
uavcan.Timestamp timestamp
float16 linear_velocity_x
float16 linear_velocity_y
float16 linear_velocity_variance
@@ -33,8 +33,8 @@ uint11 STATUS_MASK_OVERLOAD = 32 # Safe operating area violation
uint11 STATUS_MASK_BAD_BATTERY = 64 # This battery should not be used anymore (e.g. low SOH)
uint11 STATUS_MASK_NEED_SERVICE = 128 # This battery requires maintenance (e.g. balancing, full recharge)
uint11 STATUS_MASK_BMS_ERROR = 256 # Battery management system/controller error, smart battery interface error
uint11 STATUS_MASK_VENDOR_A = 512 # Vendor-specific flag
uint11 STATUS_MASK_VENDOR_B = 1024 # Vendor-specific flag
uint11 STATUS_MASK_RESERVED_A = 512 # Keep zero
uint11 STATUS_MASK_RESERVED_B = 1024 # Keep zero
uint11 status_mask
#
@@ -53,11 +53,10 @@ uint7 state_of_charge_pct_stdev # SOC error standard deviation; use best
#
# Battery identification.
# Instance ID must be unique within the same battery model name.
# Model instance ID must be unique within the same battery model name.
# Model name is a human-readable string that normally should include the vendor name, model name, and chemistry
# type of this battery. This field should be assumed case-insensitive. Example: "Zubax Smart Battery v1.1 LiPo".
#
uint32 instance_id # Set to zero if not applicable
uint6 battery_index # Identifies the battery within this vehicle, e.g. 0 - primary battery
uint2 group_id # Not used, set zero
uint8 battery_id # Identifies the battery within this vehicle, e.g. 0 - primary battery
uint32 model_instance_id # Set to zero if not applicable
uint8[<32] model_name # Battery model name
@@ -1,19 +0,0 @@
#
# Altitude above ground level.
# A single node can publish measurements from different sensors concurrently.
#
uavcan.Timestamp timestamp
float16 altitude_agl # +inf - too far, -inf - too close
float16 altitude_agl_variance # +inf if too close or too far
float16 sensor_max_range
float16 sensor_min_range
uint8 SENSOR_UNKNOWN = 0
uint8 SENSOR_SONAR = 1
uint8 SENSOR_LASER = 2
uint8 SENSOR_RADAR = 3
uint8 SENSOR_CV = 4
uint8 sensor_type
@@ -1,25 +0,0 @@
#
# Generic narrow-beam range sensor data.
#
uavcan.Timestamp timestamp
uint8 sensor_id
uavcan.equipment.CoarseOrientation beam_orientation # In body frame
float16 field_of_view # Radians
uint4 SENSOR_TYPE_UNDEFINED = 0
uint4 SENSOR_TYPE_SONAR = 1
uint4 SENSOR_TYPE_LIDAR = 2
uint4 SENSOR_TYPE_RADAR = 3
uint4 sensor_type
uint4 READING_TYPE_UNDEFINED = 0 # Range is unknown
uint4 READING_TYPE_VALID_RANGE = 1 # Range field contains valid distance
uint4 READING_TYPE_TOO_CLOSE = 2 # Range field contains min range for the sensor
uint4 READING_TYPE_TOO_FAR = 3 # Range field contains max range for the sensor
uint4 reading_type
float16 range # Meters
@@ -0,0 +1,25 @@
#
# Generic narrow-beam range sensor data.
#
uavcan.Timestamp timestamp
uint8 sensor_id
uavcan.equipment.CoarseOrientation beam_orientation # In body frame
float16 field_of_view # Radians
uint5 SENSOR_TYPE_UNDEFINED = 0
uint5 SENSOR_TYPE_SONAR = 1
uint5 SENSOR_TYPE_LIDAR = 2
uint5 SENSOR_TYPE_RADAR = 3
uint5 sensor_type
uint3 READING_TYPE_UNDEFINED = 0 # Range is unknown
uint3 READING_TYPE_VALID_RANGE = 1 # Range field contains valid distance
uint3 READING_TYPE_TOO_CLOSE = 2 # Range field contains min range for the sensor
uint3 READING_TYPE_TOO_FAR = 3 # Range field contains max range for the sensor
uint3 reading_type
float16 range # Meters
@@ -1,6 +0,0 @@
#
# Orientation and thrust setpoint for VTOL crafts.
#
float16[4] orientation_xyzw
float16 thrust # Normal range [0, 1]; or [-1, 1] if thrust can be reversed
+8 -6
View File
@@ -1,15 +1,17 @@
#
# Global time synchronization.
# Should be UTC time, not GPS time nor local time.
# Preferred time is UTC.
# Any node that publishes timestamped data must use this time reference.
# This message is not intended for unicast transfers.
#
# Please refer to the specification to learn about time synchronization algorithm.
#
uint16 MAX_PUBLICATION_PERIOD_MS = 1100
uint16 MIN_PUBLICATION_PERIOD_MS = 350
uint16 MAX_PUBLICATION_PERIOD_MS = 1100 # Milliseconds
uint16 MIN_PUBLICATION_PERIOD_MS = 350 # Milliseconds
uint16 PUBLISHER_TIMEOUT_MS = 10000
uint16 PUBLISHER_TIMEOUT_MS = 10000 # Milliseconds
# UTC time in microseconds when the PREVIOUS GlobalTimeSync message was transmitted.
# Time in microseconds when the PREVIOUS GlobalTimeSync message was transmitted.
# If this message is the first one, this field must be zero.
uint64 prev_utc_usec
uint64 previous_transmission_timestamp_usec # Microseconds
+7 -4
View File
@@ -1,10 +1,13 @@
#
# Abstract node status information.
# Any UAVCAN node is required to publish this message periodically.
# It is NOT recommended to change its publication rate at run time.
#
# See http://uavcan.org/Standard_data_types_and_application_level_functions
#
uint16 MAX_PUBLICATION_PERIOD_MS = 1000
uint16 MIN_PUBLICATION_PERIOD_MS = 20
uint16 MIN_PUBLICATION_PERIOD_MS = 2
# If a node fails to publish this message in this amount of time, it should be considered offline.
uint16 OFFLINE_TIMEOUT_MS = 3000
@@ -13,9 +16,6 @@ uint16 OFFLINE_TIMEOUT_MS = 3000
uint28 uptime_sec
# Status code should be used to reflect the node status in the most abstract way.
# Use cases: top-level onboard computer should not allow the UAV to begin normal operation
# unless all nodes report OK. If a mission critical node reports CRITICAL status, current
# mission should be immediately yet safely aborted (e.g. RTL).
# OFFLINE status can be actually reported by the node to explicitly inform other network
# participants that the sending node is about to shutdown. In this case other nodes will not
# have to wait OFFLINE_TIMEOUT_MS before they detect that the node is no longer available.
@@ -25,3 +25,6 @@ uint4 STATUS_WARNING = 2
uint4 STATUS_CRITICAL = 3
uint4 STATUS_OFFLINE = 15
uint4 status_code
# Optional, vendor-specific node status code, e.g. a fault code or a status bitmask.
uint16 vendor_specific_status_code
+1 -1
View File
@@ -16,4 +16,4 @@ HardwareVersion hardware_version
# Empty string is not a valid node name.
# Node name shall not be changed while the node is running.
# The naming convention is like of Java packages (reversed internet domain names), e.g. "com.example.project.product".
uint8[<64] name
uint8[<=80] name
@@ -1,6 +1,7 @@
#
# Restart the node.
# Some nodes may require restart before the new configuration will be applied.
# The request should be rejected if magic_number does not equal MAGIC_NUMBER.
#
uint40 MAGIC_NUMBER = 0xACCE551B1E
@@ -2,14 +2,6 @@
# Generic named parameter (key/value pair).
#
uint3 TYPE_UNDEF = 0
uint3 TYPE_INTEGER = 1
uint3 TYPE_FLOAT = 2
uint3 TYPE_STRING = 3
uint3 TYPE_BYTES = 4
uint3 type
uint8[<=92] key
uint8[<64] key
float64[<=1] numeric_value # For type = INTEGER, FLOAT
uint8[<256] binary_value # For type = STRING, BYTES
uavcan.protocol.param.Value value
@@ -1,5 +1,6 @@
#
# Start HIL simulation for the specified components.
# The request should be rejected if magic_number does not equal MAGIC_NUMBER.
#
uint40 MAGIC_NUMBER = 0xACCE551B1E
+2 -2
View File
@@ -1,7 +1,7 @@
#
# Nested type.
# File system path in ASCII or UTF8.
# The only valid separator is forward flash.
# File system path in UTF8.
# The only valid separator is forward slash.
#
uint8 SEPARATOR = '/'
@@ -0,0 +1,29 @@
#
# Service to control the node configuration.
#
# SAVE operation instructs the remote node to save the current configuration parameters to the non-volatile
# storage. The node may require a restart in order for some changes to take effect.
#
# ERASE operation instructs the remote node to clear its configuration storage and reinitialize the parameters
# with their default values. The node may require a restart in order for some changes to take effect.
#
# Other opcodes may be added in the future (for example, an opcode for switching between multiple configurations).
#
uint8 OPCODE_SAVE = 0 # Save all parameters to non-volatile storage.
uint8 OPCODE_ERASE = 1 # Clear the non-volatile storage; some changes may take effect only after reboot.
uint8 opcode
#
# Reserved, keep zero.
#
int48 argument
---
#
# Reserved, keep zero.
#
int48 argument
bool ok
@@ -1,11 +0,0 @@
#
# Service to control non-volatile parameter storage.
#
uint2 OPCODE_SAVE = 0 # Save all parameters to non-volatile storage
uint2 OPCODE_ERASE = 1 # Clear the non-volatile storage; actual parameter values may or may not be affected
uint2 opcode
---
bool ok
+18 -10
View File
@@ -1,26 +1,34 @@
#
# Get or set a parameter by name or by index.
# Note that access by index should only be used to retreive the list of parameters; it is higly
# discouraged to use it for anything else, because persistent ordering is not guaranteed.
#
# If set - parameter will be assigned this value, then the new value will be returned
# If not set - current parameter value will be returned
# If set - parameter will be assigned this value, then the new value will be returned.
# If not set - current parameter value will be returned.
# Refer to the definition of Value for details.
Value value
# Index of the parameter starting from 0; ignored if name is nonempty
# Index of the parameter starting from 0; ignored if name is nonempty.
# Use index only to retrieve the list of parameters.
uint8 index
# Name of the parameter; always preferred over index if nonempty
uint8[<=40] name
# Name of the parameter; always preferred over index if nonempty.
uint8[<=92] name
---
# Actual parameter value. For write requests it must contain the newly assigned parameter value.
# Actual parameter value.
# For set requests, it should contain the actual parameter value after the set request was
# executed. The objective is to let the client know if the value could not be updated, e.g.
# due to its range violation, etc.
# Empty value indicates that there is no such parameter.
Value value
Value default_value # Optional
Value max_value # Optional
Value min_value # Optional
Value default_value # Optional
NumericValue max_value # Optional, not applicable for bool/string
NumericValue min_value # Optional, not applicable for bool/string
# Empty name in response indicates that there is no such parameter
uint8[<=40] name
uint8[<=92] name
@@ -0,0 +1,8 @@
#
# Numeric-only value.
# The actual type should be inferred from the available values, as described below.
# If none of the values below are present, the value is considered empty.
#
int64[<=1] value_int # Preferred over float if ambiguous
float32[<=1] value_float # Only if int is empty
+5
View File
@@ -0,0 +1,5 @@
#
# This type is nested in Value.
#
uint8[<=127] value
+6 -4
View File
@@ -1,8 +1,10 @@
#
# Single parameter value.
# The actual type should be detected from the available values, as described below.
# The actual type should be inferred from the available values, as described below.
# If none of the values below are present, the value is considered empty.
#
bool[<=1] value_bool # Preferred over int and float if ambiguous
int64[<=1] value_int # Preferred over float if ambiguous
float32[<=1] value_float
bool[<=1] value_bool # Preferred over int, float and string if ambiguous
int64[<=1] value_int # Preferred over float and string if ambiguous
float32[<=1] value_float # Preferred over string if ambiguous
String[<=1] value_string # This one will be used only if all above are empty
+2 -5
View File
@@ -1,12 +1,9 @@
All the unallocated space can be claimed later.
256..399 - high priority equipment
540..549 - high priority nav
256..449 - high priority equipment
550..599 - protocol
600..749 - low priority eqipment
760..766 - low priority nav
767 - MAVLink
+8 -1
View File
@@ -123,7 +123,6 @@
#if UAVCAN_TOSTRING
# include <string>
# include <cstdio>
#endif
/**
@@ -135,6 +134,14 @@
# define UAVCAN_IMPLEMENT_PLACEMENT_NEW 0
#endif
/**
* Allows the user's application to provide custom implementation of uavcan::snprintf(),
* which is often useful on deeply embedded systems.
*/
#ifndef UAVCAN_USE_EXTERNAL_SNPRINTF
# define UAVCAN_USE_EXTERNAL_SNPRINTF 0
#endif
/**
* Run time checks.
* Resolves to the standard assert() by default.
+1 -1
View File
@@ -7,7 +7,7 @@
#include <cassert>
#include <cstring>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/transport/transfer.hpp>
+1 -1
View File
@@ -7,7 +7,7 @@
#define UAVCAN_DRIVER_CAN_HPP_INCLUDED
#include <cassert>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/driver/system_clock.hpp>
@@ -6,7 +6,7 @@
#ifndef UAVCAN_DRIVER_SYSTEM_CLOCK_HPP_INCLUDED
#define UAVCAN_DRIVER_SYSTEM_CLOCK_HPP_INCLUDED
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/time.hpp>
+1 -2
View File
@@ -8,7 +8,7 @@
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/util/placement_new.hpp>
#include <uavcan/build_config.hpp>
@@ -157,7 +157,6 @@ bool PoolManager<MaxPools>::addPool(IPoolAllocator* pool)
}
}
// We need to keep the pools in order, so that smallest blocks go first
using namespace std; // for qsort()
qsort(pools_, MaxPools, sizeof(IPoolAllocator*), &PoolManager::qsortComparePoolAllocators);
return retval;
}
+1 -1
View File
@@ -6,7 +6,7 @@
#define UAVCAN_ERROR_HPP_INCLUDED
#include <uavcan/build_config.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
namespace uavcan
{
@@ -6,7 +6,7 @@
#define UAVCAN_HELPERS_COMPONENT_STATUS_MANAGER_HPP_INCLUDED
#include <uavcan/build_config.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/protocol/NodeStatus.hpp>
namespace uavcan
+35 -2
View File
@@ -15,6 +15,7 @@
#include <uavcan/build_config.hpp>
#include <uavcan/marshal/type_util.hpp>
#include <uavcan/marshal/integer_spec.hpp>
#include <uavcan/std.hpp>
#ifndef UAVCAN_CPP_VERSION
# error UAVCAN_CPP_VERSION
@@ -714,7 +715,8 @@ public:
StaticAssert<IsDynamic>::check();
StaticAssert<sizeof(A() >= A(0))>::check(); // This check allows to weed out most compound types
StaticAssert<sizeof(A) <= sizeof(long double)>::check(); // Another stupid check to catch non-primitive types
StaticAssert<(sizeof(A) <= sizeof(long double)) ||
(sizeof(A) <= sizeof(long long))>::check(); // Another stupid check to catch non-primitive types
if (!format)
{
@@ -728,7 +730,6 @@ public:
const SizeType max_size = SizeType(capacity() - size());
// We have one extra byte for the null terminator, hence +1
using namespace std; // For snprintf()
const int ret = snprintf(reinterpret_cast<char*>(ptr), SizeType(max_size + 1U), format, value);
for (int i = 0; i < min(ret, int(max_size)); i++)
@@ -742,6 +743,38 @@ public:
}
}
/**
* Converts the string to upper/lower case in place, assuming that encoding is ASCII.
* These methods can only be used with string-like arrays; otherwise compilation will fail.
*/
void convertToUpperCaseASCII()
{
StaticAssert<Base::IsStringLike>::check();
for (SizeType i = 0; i < size(); i++)
{
const int x = Base::at(i);
if ((x <= 'z') && (x >= 'a'))
{
Base::at(i) = static_cast<ValueType>(x + ('Z' - 'z'));
}
}
}
void convertToLowerCaseASCII()
{
StaticAssert<Base::IsStringLike>::check();
for (SizeType i = 0; i < size(); i++)
{
const int x = Base::at(i);
if ((x <= 'Z') && (x >= 'A'))
{
Base::at(i) = static_cast<ValueType>(x - ('Z' - 'z'));
}
}
}
/**
* Fills this array as a packed square matrix from a static array.
* Please refer to the specification to learn more about matrix packing.
@@ -6,7 +6,7 @@
#define UAVCAN_MARSHAL_BIT_STREAM_HPP_INCLUDED
#include <cassert>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/transport/abstract_transfer_buffer.hpp>
#include <uavcan/build_config.hpp>
@@ -6,7 +6,7 @@
#define UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED
#include <cmath>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/data_type.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/build_config.hpp>
@@ -16,9 +16,7 @@
#ifndef UAVCAN_CPP_VERSION
# error UAVCAN_CPP_VERSION
#endif
#if UAVCAN_CPP_VERSION < UAVCAN_CPP11
# include <math.h> // Needed for isfinite()
#else
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
# include <limits> // Assuming that in C++11 mode all standard headers are available
#endif
@@ -169,8 +167,7 @@ public:
private:
static inline void saturate(StorageType& value)
{
using namespace std;
if ((IsExactRepresentation == 0) && isfinite(value))
if ((IsExactRepresentation == 0) && isFinite(value))
{
if (value > max())
{
@@ -189,8 +186,7 @@ private:
static inline void truncate(StorageType& value)
{
using namespace std;
if ((IsExactRepresentation == 0) && isfinite(value))
if ((IsExactRepresentation == 0) && isFinite(value))
{
if (value > max())
{
@@ -5,7 +5,7 @@
#ifndef UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED
#define UAVCAN_MARSHAL_INTEGER_SPEC_HPP_INCLUDED
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/data_type.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/marshal/scalar_codec.hpp>
@@ -6,7 +6,7 @@
#define UAVCAN_MARSHAL_SCALAR_CODEC_HPP_INCLUDED
#include <cassert>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/marshal/bit_stream.hpp>
@@ -7,7 +7,7 @@
#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/data_type.hpp>
#include <uavcan/util/bitset.hpp>
#include <uavcan/util/templates.hpp>
+8
View File
@@ -180,6 +180,14 @@ public:
(void)proto_nsp_.forcePublish();
}
/**
* Updates the vendor-specific status code.
*/
void setVendorSpecificStatusCode(NodeStatusProvider::VendorSpecificStatusCode code)
{
proto_nsp_.setVendorSpecificStatusCode(code);
}
/**
* Sets the node version information.
*/
+1 -1
View File
@@ -5,7 +5,7 @@
#ifndef UAVCAN_NODE_TIMER_HPP_INCLUDED
#define UAVCAN_NODE_TIMER_HPP_INCLUDED
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/error.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/util/linked_list.hpp>
@@ -46,7 +46,12 @@ private:
void (NodeStatusMonitor::*)(const ReceivedDataStructure<protocol::NodeStatus>&)>
NodeStatusCallback;
Subscriber<protocol::NodeStatus, NodeStatusCallback> sub_;
/*
* We'll be able to handle this many nodes in the network without any dynamic memory.
*/
enum { NumStaticReceivers = 64 };
Subscriber<protocol::NodeStatus, NodeStatusCallback, NumStaticReceivers, 0> sub_;
struct Entry
{
@@ -49,6 +49,9 @@ class UAVCAN_EXPORT NodeStatusProvider : private TimerBase
void handleGetNodeInfoRequest(const protocol::GetNodeInfo::Request&, protocol::GetNodeInfo::Response& rsp);
public:
typedef typename StorageType<typename protocol::NodeStatus::FieldTypes::vendor_specific_status_code>::Type
VendorSpecificStatusCode;
explicit NodeStatusProvider(INode& node)
: TimerBase(node)
, creation_timestamp_(node.getMonotonicTime())
@@ -78,8 +81,8 @@ public:
* Refer to the DSDL definition of uavcan.protocol.NodeStatus to see what is the default rate.
* Doesn't fail; if the value is outside of acceptable range, a closest valid value will be used instead.
*/
void setStatusPublishingPeriod(uavcan::MonotonicDuration period);
uavcan::MonotonicDuration getStatusPublishingPeriod() const;
void setStatusPublicationPeriod(uavcan::MonotonicDuration period);
uavcan::MonotonicDuration getStatusPublicationPeriod() const;
/**
* Local node status code control.
@@ -92,6 +95,15 @@ public:
void setStatusCritical() { setStatusCode(protocol::NodeStatus::STATUS_CRITICAL); }
void setStatusOffline() { setStatusCode(protocol::NodeStatus::STATUS_OFFLINE); }
/**
* Local node vendor-specific status code control.
*/
void setVendorSpecificStatusCode(VendorSpecificStatusCode code);
VendorSpecificStatusCode getVendorSpecificStatusCode() const
{
return node_info_.status.vendor_specific_status_code;
}
/**
* Local node name control.
* Can be set only once before the provider is started.
@@ -6,7 +6,7 @@
#define UAVCAN_PROTOCOL_PARAM_SERVER_HPP_INCLUDED
#include <uavcan/protocol/param/GetSet.hpp>
#include <uavcan/protocol/param/SaveErase.hpp>
#include <uavcan/protocol/param/ExecuteOpcode.hpp>
#include <uavcan/node/service_server.hpp>
#include <uavcan/util/method_binder.hpp>
@@ -19,33 +19,35 @@ namespace uavcan
class UAVCAN_EXPORT IParamManager
{
public:
typedef typename StorageType<typename protocol::param::GetSet::Response::FieldTypes::name>::Type ParamName;
typedef typename StorageType<typename protocol::param::GetSet::Request::FieldTypes::index>::Type ParamIndex;
typedef protocol::param::Value ParamValue;
typedef typename StorageType<typename protocol::param::GetSet::Response::FieldTypes::name>::Type Name;
typedef typename StorageType<typename protocol::param::GetSet::Request::FieldTypes::index>::Type Index;
typedef protocol::param::Value Value;
typedef protocol::param::NumericValue NumericValue;
virtual ~IParamManager() { }
/**
* Copy the parameter name to @ref out_name if it exists, otherwise do nothing.
*/
virtual void getParamNameByIndex(ParamIndex index, ParamName& out_name) const = 0;
virtual void getParamNameByIndex(Index index, Name& out_name) const = 0;
/**
* Assign by name if exists.
*/
virtual void assignParamValue(const ParamName& name, const ParamValue& value) = 0;
virtual void assignParamValue(const Name& name, const Value& value) = 0;
/**
* Read by name if exists, otherwise do nothing.
*/
virtual void readParamValue(const ParamName& name, ParamValue& out_value) const = 0;
virtual void readParamValue(const Name& name, Value& out_value) const = 0;
/**
* Read param's default/max/min if available.
* Note that min/max are only applicable to numeric params.
* Implementation is optional.
*/
virtual void readParamDefaultMaxMin(const ParamName& name, ParamValue& out_default,
ParamValue& out_max, ParamValue& out_min) const
virtual void readParamDefaultMaxMin(const Name& name, Value& out_default,
NumericValue& out_max, NumericValue& out_min) const
{
(void)name;
(void)out_default;
@@ -64,6 +66,22 @@ public:
* @return Negative if failed.
*/
virtual int eraseAllParams() = 0;
/**
* Convenience methods that can be used to check if a param value is empty.
*/
static bool isValueEmpty(const Value& val)
{
return val.value_bool.empty() &&
val.value_int.empty() &&
val.value_float.empty() &&
val.value_string.empty();
}
static bool isValueEmpty(const NumericValue& val)
{
return val.value_int.empty() &&
val.value_float.empty();
}
};
/**
@@ -75,19 +93,18 @@ class UAVCAN_EXPORT ParamServer
typedef MethodBinder<ParamServer*, void (ParamServer::*)(const protocol::param::GetSet::Request&,
protocol::param::GetSet::Response&)> GetSetCallback;
typedef MethodBinder<ParamServer*, void (ParamServer::*)(const protocol::param::SaveErase::Request&,
protocol::param::SaveErase::Response&)> SaveEraseCallback;
typedef MethodBinder<ParamServer*,
void (ParamServer::*)(const protocol::param::ExecuteOpcode::Request&,
protocol::param::ExecuteOpcode::Response&)> ExecuteOpcodeCallback;
ServiceServer<protocol::param::GetSet, GetSetCallback> get_set_srv_;
ServiceServer<protocol::param::SaveErase, SaveEraseCallback> save_erase_srv_;
ServiceServer<protocol::param::ExecuteOpcode, ExecuteOpcodeCallback> save_erase_srv_;
IParamManager* manager_;
static bool isValueNonEmpty(const protocol::param::Value& value);
void handleGetSet(const protocol::param::GetSet::Request& request, protocol::param::GetSet::Response& response);
void handleSaveErase(const protocol::param::SaveErase::Request& request,
protocol::param::SaveErase::Response& response);
void handleExecuteOpcode(const protocol::param::ExecuteOpcode::Request& request,
protocol::param::ExecuteOpcode::Response& response);
public:
explicit ParamServer(INode& node)
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#ifndef UAVCAN_STD_HPP_INCLUDED
#define UAVCAN_STD_HPP_INCLUDED
#include <uavcan/build_config.hpp>
#include <cstdarg>
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
# error UAVCAN_CPP_VERSION
#endif
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
# include <cstdint>
# include <cstdio>
namespace uavcan
{
typedef std::uint8_t uint8_t;
typedef std::uint16_t uint16_t;
typedef std::uint32_t uint32_t;
typedef std::uint64_t uint64_t;
typedef std::int8_t int8_t;
typedef std::int16_t int16_t;
typedef std::int32_t int32_t;
typedef std::int64_t int64_t;
}
#else
# include <stdint.h> // Standard integer types from C library
# include <stdio.h> // vsnprintf() from the C library
namespace uavcan
{
typedef ::uint8_t uint8_t;
typedef ::uint16_t uint16_t;
typedef ::uint32_t uint32_t;
typedef ::uint64_t uint64_t;
typedef ::int8_t int8_t;
typedef ::int16_t int16_t;
typedef ::int32_t int32_t;
typedef ::int64_t int64_t;
}
#endif
namespace uavcan
{
/**
* Wrapper over the standard snprintf(). This wrapper is needed because different standards and different
* implementations of C++ do not agree whether snprintf() should be defined in std:: or in ::. The solution
* is to use 'using namespace std' hack inside the wrapper, so the compiler will be able to pick whatever
* definition is available in the standard library. Alternatively, the user's application can provide a
* custom implementation of uavcan::snprintf().
*/
#if __GNUC__
__attribute__ ((format(printf, 3, 4)))
#endif
extern int snprintf(char* out, std::size_t maxlen, const char* format, ...);
#if !UAVCAN_USE_EXTERNAL_SNPRINTF
inline int snprintf(char* out, std::size_t maxlen, const char* format, ...)
{
using namespace std; // This way we can pull vsnprintf() either from std:: or from ::.
va_list args;
va_start(args, format);
const int return_value = vsnprintf(out, maxlen, format, args);
va_end(args);
return return_value;
}
#endif
}
#endif // UAVCAN_STD_HPP_INCLUDED
-57
View File
@@ -1,57 +0,0 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#ifndef UAVCAN_STDINT_HPP_INCLUDED
#define UAVCAN_STDINT_HPP_INCLUDED
#include <uavcan/build_config.hpp>
#if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
# error UAVCAN_CPP_VERSION
#endif
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
# include <cstdint>
namespace uavcan
{
typedef std::uint8_t uint8_t;
typedef std::uint16_t uint16_t;
typedef std::uint32_t uint32_t;
typedef std::uint64_t uint64_t;
typedef std::int8_t int8_t;
typedef std::int16_t int16_t;
typedef std::int32_t int32_t;
typedef std::int64_t int64_t;
}
#else
/*
* C++03 doesn't define standard integer types, so we pull it from the C library as a workaround.
*/
# include <stdint.h>
namespace uavcan
{
typedef ::uint8_t uint8_t;
typedef ::uint16_t uint16_t;
typedef ::uint32_t uint32_t;
typedef ::uint64_t uint64_t;
typedef ::int8_t int8_t;
typedef ::int16_t int16_t;
typedef ::int32_t int32_t;
typedef ::int64_t int64_t;
}
#endif
#endif // UAVCAN_STDINT_HPP_INCLUDED
+1 -3
View File
@@ -6,7 +6,7 @@
#define UAVCAN_TIME_HPP_INCLUDED
#include <cstdio>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/util/templates.hpp>
#include <uavcan/Timestamp.hpp>
@@ -223,7 +223,6 @@ const unsigned TimeBase<T, D>::StringBufSize;
template <typename D>
void DurationBase<D>::toString(char buf[StringBufSize]) const
{
using namespace std; // For snprintf()
char* ptr = buf;
if (isNegative())
{
@@ -238,7 +237,6 @@ void DurationBase<D>::toString(char buf[StringBufSize]) const
template <typename T, typename D>
void TimeBase<T, D>::toString(char buf[StringBufSize]) const
{
using namespace std; // For snprintf()
(void)snprintf(buf, StringBufSize, "%llu.%06lu",
static_cast<unsigned long long>(toUSec() / 1000000UL),
static_cast<unsigned long>(toUSec() % 1000000UL));
@@ -6,7 +6,7 @@
#define UAVCAN_TRANSPORT_ABSTRACT_TRANSFER_BUFFER_HPP_INCLUDED
#include <uavcan/build_config.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
namespace uavcan
{
@@ -8,7 +8,7 @@
#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/util/linked_list.hpp>
#include <uavcan/dynamic_memory.hpp>
#include <uavcan/build_config.hpp>
+1 -1
View File
@@ -6,7 +6,7 @@
#define UAVCAN_TRANSPORT_CRC_HPP_INCLUDED
#include <cassert>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
namespace uavcan
@@ -7,7 +7,7 @@
#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/transport/perf_counter.hpp>
#include <uavcan/transport/transfer_listener.hpp>
@@ -6,7 +6,7 @@
#define UAVCAN_TRANSPORT_OUTGOING_TRANSFER_REGISTRY_HPP_INCLUDED
#include <cassert>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
#include <uavcan/util/map.hpp>
#include <uavcan/debug.hpp>
@@ -5,7 +5,7 @@
#ifndef UAVCAN_TRANSPORT_PERF_COUNTER_HPP_INCLUDED
#define UAVCAN_TRANSPORT_PERF_COUNTER_HPP_INCLUDED
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/build_config.hpp>
namespace uavcan
@@ -7,7 +7,7 @@
#include <cassert>
#include <uavcan/build_config.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
namespace uavcan
{
@@ -5,7 +5,7 @@
#ifndef UAVCAN_TRANSPORT_TRANSFER_BUFFER_HPP_INCLUDED
#define UAVCAN_TRANSPORT_TRANSFER_BUFFER_HPP_INCLUDED
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/error.hpp>
#include <uavcan/transport/frame.hpp>
#include <uavcan/transport/abstract_transfer_buffer.hpp>
@@ -7,7 +7,7 @@
#include <cassert>
#include <uavcan/error.hpp>
#include <uavcan/stdint.hpp>
#include <uavcan/std.hpp>
#include <uavcan/transport/transfer_receiver.hpp>
#include <uavcan/transport/perf_counter.hpp>
#include <uavcan/util/linked_list.hpp>
@@ -470,6 +470,20 @@ inline bool isInfinity(T arg)
#endif
}
/**
* Replacement for std::isfinite().
* Note that direct float comparison (==, !=) is intentionally avoided.
*/
template <typename T>
inline bool isFinite(T arg)
{
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
return std::isfinite(arg);
#else
return !isNaN(arg) && !isInfinity(arg);
#endif
}
/**
* Replacement for std::signbit().
* Note that direct float comparison (==, !=) is intentionally avoided.
-2
View File
@@ -59,8 +59,6 @@ bool CanFrame::priorityHigherThan(const CanFrame& rhs) const
#if UAVCAN_TOSTRING
std::string CanFrame::toString(StringRepresentation mode) const
{
using namespace std; // For snprintf()
UAVCAN_ASSERT(mode == StrTight || mode == StrAligned);
static const unsigned AsciiColumnOffset = 36U;
@@ -56,11 +56,12 @@ int GlobalTimeSyncMaster::IfaceMaster::publish(TransferID tid, MonotonicTime cur
const bool long_period = since_prev_pub.toMSec() >= protocol::GlobalTimeSync::MAX_PUBLICATION_PERIOD_MS;
protocol::GlobalTimeSync msg;
msg.prev_utc_usec = long_period ? 0 : prev_tx_utc_.toUSec();
msg.previous_transmission_timestamp_usec = long_period ? 0 : prev_tx_utc_.toUSec();
prev_tx_utc_ = UtcTime();
UAVCAN_TRACE("GlobalTimeSyncMaster", "Publishing %llu iface=%i tid=%i",
static_cast<unsigned long long>(msg.prev_utc_usec), int(iface_index_), int(tid.get()));
static_cast<unsigned long long>(msg.previous_transmission_timestamp_usec),
int(iface_index_), int(tid.get()));
return pub_.broadcast(msg, tid);
}
@@ -11,8 +11,8 @@ namespace uavcan
void GlobalTimeSyncSlave::adjustFromMsg(const ReceivedDataStructure<protocol::GlobalTimeSync>& msg)
{
UAVCAN_ASSERT(msg.prev_utc_usec > 0);
const UtcDuration adjustment = UtcTime::fromUSec(msg.prev_utc_usec) - prev_ts_utc_;
UAVCAN_ASSERT(msg.previous_transmission_timestamp_usec > 0);
const UtcDuration adjustment = UtcTime::fromUSec(msg.previous_transmission_timestamp_usec) - prev_ts_utc_;
UAVCAN_TRACE("GlobalTimeSyncSlave", "Adjustment: usec=%lli snid=%i iface=%i suppress=%i",
static_cast<long long>(adjustment.toUSec()),
@@ -58,7 +58,7 @@ void GlobalTimeSyncSlave::processMsg(const ReceivedDataStructure<protocol::Globa
{
if (state_ == Adjust)
{
const bool msg_invalid = msg.prev_utc_usec == 0;
const bool msg_invalid = msg.previous_transmission_timestamp_usec == 0;
const bool wrong_tid = prev_tid_.computeForwardDistance(msg.getTransferID()) != 1;
const bool wrong_timing = since_prev_msg.toMSec() > protocol::GlobalTimeSync::MAX_PUBLICATION_PERIOD_MS;
if (msg_invalid || wrong_tid || wrong_timing)
@@ -92,7 +92,7 @@ int NodeStatusProvider::startAndPublish()
goto fail;
}
setStatusPublishingPeriod(MonotonicDuration::fromMSec(protocol::NodeStatus::MAX_PUBLICATION_PERIOD_MS));
setStatusPublicationPeriod(MonotonicDuration::fromMSec(protocol::NodeStatus::MAX_PUBLICATION_PERIOD_MS));
return res;
@@ -104,7 +104,7 @@ fail:
return res;
}
void NodeStatusProvider::setStatusPublishingPeriod(uavcan::MonotonicDuration period)
void NodeStatusProvider::setStatusPublicationPeriod(uavcan::MonotonicDuration period)
{
const MonotonicDuration maximum = MonotonicDuration::fromMSec(protocol::NodeStatus::MAX_PUBLICATION_PERIOD_MS);
const MonotonicDuration minimum = MonotonicDuration::fromMSec(protocol::NodeStatus::MIN_PUBLICATION_PERIOD_MS);
@@ -120,7 +120,7 @@ void NodeStatusProvider::setStatusPublishingPeriod(uavcan::MonotonicDuration per
period.toString().c_str(), node_status_pub_.getTxTimeout().toString().c_str());
}
uavcan::MonotonicDuration NodeStatusProvider::getStatusPublishingPeriod() const
uavcan::MonotonicDuration NodeStatusProvider::getStatusPublicationPeriod() const
{
return TimerBase::getPeriod();
}
@@ -130,6 +130,11 @@ void NodeStatusProvider::setStatusCode(uint8_t code)
node_info_.status.status_code = code;
}
void NodeStatusProvider::setVendorSpecificStatusCode(VendorSpecificStatusCode code)
{
node_info_.status.vendor_specific_status_code = code;
}
void NodeStatusProvider::setName(const char* name)
{
if ((name != NULL) && (*name != '\0') && (node_info_.name.empty()))
+14 -13
View File
@@ -10,11 +10,6 @@
namespace uavcan
{
bool ParamServer::isValueNonEmpty(const protocol::param::Value& value)
{
return !value.value_bool.empty() || !value.value_int.empty() || !value.value_float.empty();
}
void ParamServer::handleGetSet(const protocol::param::GetSet::Request& in, protocol::param::GetSet::Response& out)
{
UAVCAN_ASSERT(manager_ != NULL);
@@ -30,15 +25,21 @@ void ParamServer::handleGetSet(const protocol::param::GetSet::Request& in, proto
out.name = in.name;
}
if (out.name.empty())
{
UAVCAN_TRACE("ParamServer", "GetSet: Can't resolve parameter name, index=%i", int(in.index));
return;
}
// Assign if needed, read back
if (isValueNonEmpty(in.value))
if (!IParamManager::isValueEmpty(in.value))
{
manager_->assignParamValue(out.name, in.value);
}
manager_->readParamValue(out.name, out.value);
// Check if the value is OK, otherwise reset the name to indicate that we have no idea what is it all about
if (isValueNonEmpty(out.value))
if (!IParamManager::isValueEmpty(out.value))
{
manager_->readParamDefaultMaxMin(out.name, out.default_value, out.max_value, out.min_value);
}
@@ -49,22 +50,22 @@ void ParamServer::handleGetSet(const protocol::param::GetSet::Request& in, proto
}
}
void ParamServer::handleSaveErase(const protocol::param::SaveErase::Request& in,
protocol::param::SaveErase::Response& out)
void ParamServer::handleExecuteOpcode(const protocol::param::ExecuteOpcode::Request& in,
protocol::param::ExecuteOpcode::Response& out)
{
UAVCAN_ASSERT(manager_ != NULL);
if (in.opcode == protocol::param::SaveErase::Request::OPCODE_SAVE)
if (in.opcode == protocol::param::ExecuteOpcode::Request::OPCODE_SAVE)
{
out.ok = manager_->saveAllParams() >= 0;
}
else if (in.opcode == protocol::param::SaveErase::Request::OPCODE_ERASE)
else if (in.opcode == protocol::param::ExecuteOpcode::Request::OPCODE_ERASE)
{
out.ok = manager_->eraseAllParams() >= 0;
}
else
{
UAVCAN_TRACE("ParamServer", "SaveErase: invalid opcode %i", int(in.opcode));
UAVCAN_TRACE("ParamServer", "ExecuteOpcode: invalid opcode %i", int(in.opcode));
out.ok = false;
}
}
@@ -83,7 +84,7 @@ int ParamServer::start(IParamManager* manager)
return res;
}
res = save_erase_srv_.start(SaveEraseCallback(this, &ParamServer::handleSaveErase));
res = save_erase_srv_.start(ExecuteOpcodeCallback(this, &ParamServer::handleExecuteOpcode));
if (res < 0)
{
get_set_srv_.stop();
-1
View File
@@ -198,7 +198,6 @@ bool Frame::operator==(const Frame& rhs) const
#if UAVCAN_TOSTRING
std::string Frame::toString() const
{
using namespace std; // For snprintf()
/*
* Frame ID fields, according to UAVCAN specs:
* - Data Type ID
@@ -12,7 +12,6 @@ namespace uavcan
#if UAVCAN_TOSTRING
std::string OutgoingTransferRegistryKey::toString() const
{
using namespace std;
char buf[40];
(void)snprintf(buf, sizeof(buf), "dtid=%u tt=%u dnid=%u",
int(data_type_id_.get()), int(transfer_type_), int(destination_node_id_.get()));
@@ -14,7 +14,6 @@ namespace uavcan
#if UAVCAN_TOSTRING
std::string TransferBufferManagerKey::toString() const
{
using namespace std; // For snprintf()
char buf[24];
(void)snprintf(buf, sizeof(buf), "nid=%i tt=%i", int(node_id_.get()), int(transfer_type_));
return std::string(buf);
+1 -2
View File
@@ -111,8 +111,7 @@ std::string DataTypeDescriptor::toString() const
}
}
using namespace std; // For snprintf()
char buf[80];
char buf[128];
(void)snprintf(buf, sizeof(buf), "%s:%u%c:%016llx",
full_name_, static_cast<unsigned>(id_.get()), kindch,
static_cast<unsigned long long>(signature_.get()));
+6
View File
@@ -105,6 +105,12 @@ TEST(DataTypeDescriptor, ToString)
desc = uavcan::DataTypeDescriptor(uavcan::DataTypeKindMessage, 123,
uavcan::DataTypeSignature(0xdeadbeef1234), "Bar");
ASSERT_EQ("Bar:123m:0000deadbeef1234", desc.toString());
// Max length - 80 chars
desc = uavcan::DataTypeDescriptor(uavcan::DataTypeKindMessage, 1023, uavcan::DataTypeSignature(0xdeadbeef12345678),
"sirius_cybernetics_corporation.marvin.model_a.LongDataTypeName123456789abcdefghi");
ASSERT_EQ("sirius_cybernetics_corporation.marvin.model_a.LongDataTypeName123456789abcdefghi:1023m:deadbeef12345678",
desc.toString());
}
+1 -1
View File
@@ -57,7 +57,7 @@ TEST(Dsdl, Signature)
ASSERT_EQ("root_ns_a.EmptyService", root_ns_a::EmptyService::getDataTypeFullName());
ASSERT_EQ(uavcan::DataTypeKindService, root_ns_a::EmptyService::DataTypeKind);
ASSERT_EQ(0x41a2582ee72be419, root_ns_a::NestedMessage::getDataTypeSignature().get()); // Computed manually
ASSERT_EQ(0x99604d7066e0d713, root_ns_a::NestedMessage::getDataTypeSignature().get()); // Computed manually
ASSERT_EQ("root_ns_a.NestedMessage", root_ns_a::NestedMessage::getDataTypeFullName());
ASSERT_EQ(uavcan::DataTypeKindMessage, root_ns_a::NestedMessage::DataTypeKind);
}
@@ -60,6 +60,7 @@ TEST(Dsdl, Streaming)
"status: \n"
" uptime_sec: 0\n"
" status_code: 0\n"
" vendor_specific_status_code: 0\n"
"software_version: \n"
" major: 0\n"
" minor: 0\n"
+18
View File
@@ -1278,3 +1278,21 @@ TEST(Array, FuzzyComparison)
uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
std::cout << std::endl;
}
TEST(Array, CaseConversion)
{
Array<IntegerSpec<8, SignednessUnsigned, CastModeTruncate>, ArrayModeDynamic, 30> str;
str.convertToLowerCaseASCII();
str.convertToUpperCaseASCII();
ASSERT_STREQ("", str.c_str());
str = "Hello World!";
ASSERT_STREQ("Hello World!", str.c_str());
str.convertToLowerCaseASCII();
ASSERT_STREQ("hello world!", str.c_str());
str.convertToUpperCaseASCII();
ASSERT_STREQ("HELLO WORLD!", str.c_str());
}
@@ -37,9 +37,9 @@ TEST(GlobalTimeSyncSlave, Basic)
* The slave must only register the timestamp and adjust nothing
*/
uavcan::protocol::GlobalTimeSync gts;
gts.prev_utc_usec = 0;
gts.previous_transmission_timestamp_usec = 0;
gts_pub.broadcast(gts);
gts.prev_utc_usec = master_clock.utc;
gts.previous_transmission_timestamp_usec = master_clock.utc;
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
ASSERT_EQ(0, slave_clock.utc);
ASSERT_EQ(1000000, master_clock.utc);
@@ -54,7 +54,7 @@ TEST(GlobalTimeSyncSlave, Basic)
* Slave must adjust now
*/
gts_pub.broadcast(gts);
gts.prev_utc_usec = master_clock.utc;
gts.previous_transmission_timestamp_usec = master_clock.utc;
nodes.spinBoth(uavcan::MonotonicDuration());
ASSERT_EQ(1000000, slave_clock.utc);
ASSERT_EQ(1000000, master_clock.utc);
@@ -72,7 +72,7 @@ TEST(GlobalTimeSyncSlave, Basic)
* Will update
*/
gts_pub.broadcast(gts);
gts.prev_utc_usec = master_clock.utc;
gts.previous_transmission_timestamp_usec = master_clock.utc;
nodes.spinBoth(uavcan::MonotonicDuration());
ASSERT_EQ(2000000, slave_clock.utc);
ASSERT_EQ(2000000, master_clock.utc);
@@ -88,7 +88,7 @@ TEST(GlobalTimeSyncSlave, Basic)
* Will adjust
*/
gts_pub.broadcast(gts);
gts.prev_utc_usec = master_clock.utc;
gts.previous_transmission_timestamp_usec = master_clock.utc;
nodes.spinBoth(uavcan::MonotonicDuration());
ASSERT_EQ(3000000, slave_clock.utc);
ASSERT_EQ(3000000, master_clock.utc);
@@ -117,9 +117,9 @@ TEST(GlobalTimeSyncSlave, Basic)
/*
* Update step, no adjustment yet
*/
gts.prev_utc_usec = 0;
gts.previous_transmission_timestamp_usec = 0;
gts_pub2.broadcast(gts);
gts.prev_utc_usec = master2_clock.utc;
gts.previous_transmission_timestamp_usec = master2_clock.utc;
nodes.spinBoth(uavcan::MonotonicDuration());
ASSERT_EQ(4000000, slave_clock.utc);
ASSERT_EQ(100, master2_clock.utc);
@@ -142,7 +142,7 @@ TEST(GlobalTimeSyncSlave, Basic)
/*
* Another master will be ignored now
*/
gts.prev_utc_usec = 99999999;
gts.previous_transmission_timestamp_usec = 99999999;
// Update
gts_pub.broadcast(gts);
nodes.spinBoth(uavcan::MonotonicDuration());
@@ -20,7 +20,7 @@ static void publishNodeStatus(CanDriverMock& can, uavcan::NodeID node_id, uavcan
// Manual message publication
ASSERT_LT(0, uavcan::protocol::NodeStatus::encode(msg, codec));
ASSERT_GE(7, buffer.getMaxWritePos());
ASSERT_GE(8, buffer.getMaxWritePos());
// DataTypeID data_type_id, TransferType transfer_type, NodeID src_node_id, NodeID dst_node_id,
// uint_fast8_t frame_index, TransferID transfer_id, bool last_frame
@@ -48,15 +48,15 @@ TEST(NodeStatusProvider, Basic)
// Checking the publishing rate settings
ASSERT_EQ(uavcan::MonotonicDuration::fromMSec(uavcan::protocol::NodeStatus::MAX_PUBLICATION_PERIOD_MS),
nsp.getStatusPublishingPeriod());
nsp.getStatusPublicationPeriod());
nsp.setStatusPublishingPeriod(uavcan::MonotonicDuration());
nsp.setStatusPublicationPeriod(uavcan::MonotonicDuration());
ASSERT_EQ(uavcan::MonotonicDuration::fromMSec(uavcan::protocol::NodeStatus::MIN_PUBLICATION_PERIOD_MS),
nsp.getStatusPublishingPeriod());
nsp.getStatusPublicationPeriod());
nsp.setStatusPublishingPeriod(uavcan::MonotonicDuration::fromMSec(3600 * 1000 * 24));
nsp.setStatusPublicationPeriod(uavcan::MonotonicDuration::fromMSec(3600 * 1000 * 24));
ASSERT_EQ(uavcan::MonotonicDuration::fromMSec(uavcan::protocol::NodeStatus::MAX_PUBLICATION_PERIOD_MS),
nsp.getStatusPublishingPeriod());
nsp.getStatusPublicationPeriod());
/*
* Initial status publication
@@ -70,6 +70,22 @@ TEST(NodeStatusProvider, Basic)
ASSERT_TRUE(status_sub.collector.msg.get()); // Was published at startup
ASSERT_EQ(uavcan::protocol::NodeStatus::STATUS_OK, status_sub.collector.msg->status_code);
ASSERT_EQ(0, status_sub.collector.msg->vendor_specific_status_code);
ASSERT_GE(1, status_sub.collector.msg->uptime_sec);
/*
* Altering the vendor-specific status code, forcePublish()-ing it and checking the result
*/
ASSERT_EQ(0, nsp.getVendorSpecificStatusCode());
nsp.setVendorSpecificStatusCode(1234);
ASSERT_EQ(1234, nsp.getVendorSpecificStatusCode());
ASSERT_LE(0, nsp.forcePublish());
nodes.spinBoth(uavcan::MonotonicDuration::fromMSec(10));
ASSERT_EQ(uavcan::protocol::NodeStatus::STATUS_OK, status_sub.collector.msg->status_code);
ASSERT_EQ(1234, status_sub.collector.msg->vendor_specific_status_code);
ASSERT_GE(1, status_sub.collector.msg->uptime_sec);
/*
+20 -10
View File
@@ -12,9 +12,9 @@ struct ParamServerTestManager : public uavcan::IParamManager
typedef std::map<std::string, double> KeyValue;
KeyValue kv;
virtual void getParamNameByIndex(ParamIndex index, ParamName& out_name) const
virtual void getParamNameByIndex(Index index, Name& out_name) const
{
ParamIndex current_idx = 0;
Index current_idx = 0;
for (KeyValue::const_iterator it = kv.begin(); it != kv.end(); ++it, ++current_idx)
{
if (current_idx == index)
@@ -25,8 +25,9 @@ struct ParamServerTestManager : public uavcan::IParamManager
}
}
virtual void assignParamValue(const ParamName& name, const ParamValue& value)
virtual void assignParamValue(const Name& name, const Value& value)
{
assert(!name.empty());
std::cout << "ASSIGN [" << name.c_str() << "]\n" << value << "\n---" << std::endl;
KeyValue::iterator it = kv.find(name.c_str());
if (it != kv.end())
@@ -43,6 +44,10 @@ struct ParamServerTestManager : public uavcan::IParamManager
{
it->second = double(value.value_float[0]);
}
else if (!value.value_string.empty())
{
it->second = std::atof(value.value_string[0].value.c_str());
}
else
{
assert(0);
@@ -50,8 +55,9 @@ struct ParamServerTestManager : public uavcan::IParamManager
}
}
virtual void readParamValue(const ParamName& name, ParamValue& out_value) const
virtual void readParamValue(const Name& name, Value& out_value) const
{
assert(!name.empty());
KeyValue::const_iterator it = kv.find(name.c_str());
if (it != kv.end())
{
@@ -93,23 +99,23 @@ TEST(ParamServer, Basic)
uavcan::GlobalDataTypeRegistry::instance().reset();
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::GetSet> _reg1;
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::SaveErase> _reg2;
uavcan::DefaultDataTypeRegistrator<uavcan::protocol::param::ExecuteOpcode> _reg2;
ASSERT_LE(0, server.start(&mgr));
ServiceClientWithCollector<uavcan::protocol::param::GetSet> get_set_cln(nodes.b);
ServiceClientWithCollector<uavcan::protocol::param::SaveErase> save_erase_cln(nodes.b);
ServiceClientWithCollector<uavcan::protocol::param::ExecuteOpcode> save_erase_cln(nodes.b);
/*
* Save/erase
*/
uavcan::protocol::param::SaveErase::Request save_erase_rq;
save_erase_rq.opcode = uavcan::protocol::param::SaveErase::Request::OPCODE_SAVE;
uavcan::protocol::param::ExecuteOpcode::Request save_erase_rq;
save_erase_rq.opcode = uavcan::protocol::param::ExecuteOpcode::Request::OPCODE_SAVE;
doCall(save_erase_cln, save_erase_rq, nodes);
ASSERT_TRUE(save_erase_cln.collector.result.get());
ASSERT_TRUE(save_erase_cln.collector.result->response.ok);
save_erase_rq.opcode = uavcan::protocol::param::SaveErase::Request::OPCODE_ERASE;
save_erase_rq.opcode = uavcan::protocol::param::ExecuteOpcode::Request::OPCODE_ERASE;
doCall(save_erase_cln, save_erase_rq, nodes);
ASSERT_TRUE(save_erase_cln.collector.result->response.ok);
@@ -151,7 +157,11 @@ TEST(ParamServer, Basic)
// Set by index
get_set_rq = uavcan::protocol::param::GetSet::Request();
get_set_rq.index = 0;
get_set_rq.value.value_int.push_back(424242);
{
uavcan::protocol::param::String str;
str.value = "424242";
get_set_rq.value.value_string.push_back(str);
}
doCall(get_set_cln, get_set_rq, nodes);
ASSERT_STREQ("foobar", get_set_cln.collector.result->response.name.c_str());
ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->response.value.value_float[0]);
@@ -84,6 +84,7 @@ static void runForever(const uavcan_linux::NodePtr& node)
auto do_nothing_once_a_minute = [&node](const uavcan::TimerEvent&)
{
node->logInfo("timer", "Another minute passed...");
node->setVendorSpecificStatusCode(static_cast<std::uint16_t>(std::rand())); // Setting to an arbitrary value
};
auto timer = node->makeTimer(uavcan::MonotonicDuration::fromMSec(60000), do_nothing_once_a_minute);
@@ -14,7 +14,7 @@
#include "debug.hpp"
#include <uavcan/protocol/param/GetSet.hpp>
#include <uavcan/protocol/param/SaveErase.hpp>
#include <uavcan/protocol/param/ExecuteOpcode.hpp>
#include <uavcan/protocol/EnumerationRequest.hpp>
#include <uavcan/equipment/hardpoint/Command.hpp>
@@ -88,9 +88,29 @@ std::string paramValueToString(const uavcan::protocol::param::Value& value)
{
return std::to_string(value.value_float[0]);
}
else if (!value.value_string.empty())
{
return std::string(value.value_string[0].value.c_str()) + " ";
}
else
{
return "?";
return "";
}
}
std::string paramValueToString(const uavcan::protocol::param::NumericValue& value)
{
if (!value.value_int.empty())
{
return std::to_string(value.value_int[0]);
}
else if (!value.value_float.empty())
{
return std::to_string(value.value_float[0]);
}
else
{
return "";
}
}
@@ -176,6 +196,7 @@ const std::map<std::string,
else
{
request.name = args.at(0).c_str();
// TODO: add support for string parameters
request.value.value_float.push_back(std::stof(args.at(1)));
printGetSetResponse(call(*client, node_id, request));
}
@@ -185,11 +206,11 @@ const std::map<std::string,
{
"param_save",
{
"Calls uavcan.protocol.param.SaveErase on a remote node with OPCODE_SAVE",
"Calls uavcan.protocol.param.ExecuteOpcode on a remote node with OPCODE_SAVE",
[](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
{
auto client = node->makeBlockingServiceClient<uavcan::protocol::param::SaveErase>();
uavcan::protocol::param::SaveErase::Request request;
auto client = node->makeBlockingServiceClient<uavcan::protocol::param::ExecuteOpcode>();
uavcan::protocol::param::ExecuteOpcode::Request request;
request.opcode = request.OPCODE_SAVE;
std::cout << call(*client, node_id, request) << std::endl;
}
@@ -198,11 +219,11 @@ const std::map<std::string,
{
"param_erase",
{
"Calls uavcan.protocol.param.SaveErase on a remote node with OPCODE_ERASE",
"Calls uavcan.protocol.param.ExecuteOpcode on a remote node with OPCODE_ERASE",
[](const uavcan_linux::NodePtr& node, const uavcan::NodeID node_id, const std::vector<std::string>&)
{
auto client = node->makeBlockingServiceClient<uavcan::protocol::param::SaveErase>();
uavcan::protocol::param::SaveErase::Request request;
auto client = node->makeBlockingServiceClient<uavcan::protocol::param::ExecuteOpcode>();
uavcan::protocol::param::ExecuteOpcode::Request request;
request.opcode = request.OPCODE_ERASE;
std::cout << call(*client, node_id, request) << std::endl;
}
@@ -4,6 +4,7 @@
#include <iostream>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <uavcan_linux/uavcan_linux.hpp>
#include <uavcan/protocol/node_status_monitor.hpp>
@@ -18,6 +19,7 @@ struct OstreamColorizer
Yellow = 33,
Blue = 34,
Magenta = 35,
Cyan = 36,
Default = 39
};
explicit OstreamColorizer(Color color = Default) : color_(color) { }
@@ -33,11 +35,11 @@ private:
class Monitor : public uavcan::NodeStatusMonitor
{
uavcan_linux::TimerPtr timer_;
std::unordered_map<int, std::uint64_t> uptimes_;
std::unordered_map<int, uavcan::protocol::NodeStatus> status_registry_;
virtual void handleNodeStatusMessage(const uavcan::ReceivedDataStructure<uavcan::protocol::NodeStatus>& msg)
{
uptimes_[msg.getSrcNodeID().get()] = msg.uptime_sec;
status_registry_[msg.getSrcNodeID().get()] = msg;
}
static std::pair<OstreamColorizer, std::string>
@@ -49,7 +51,7 @@ class Monitor : public uavcan::NodeStatusMonitor
}
if (status_code == uavcan::protocol::NodeStatus::STATUS_INITIALIZING)
{
return { OstreamColorizer(OstreamColorizer::Blue), "INITIALIZING" };
return { OstreamColorizer(OstreamColorizer::Cyan), "INITIALIZING" };
}
if (status_code == uavcan::protocol::NodeStatus::STATUS_WARNING)
{
@@ -68,20 +70,33 @@ class Monitor : public uavcan::NodeStatusMonitor
void printStatusLine(uavcan::NodeID nid, const uavcan::NodeStatusMonitor::NodeStatus& status)
{
const auto original_flags = std::cout.flags();
const auto color_and_string = statusCodeToColoredString(status.status_code);
const int nid_int = nid.get();
const auto uptime = status_registry_[nid_int].uptime_sec;
const int vendor_code = status_registry_[nid_int].vendor_specific_status_code;
std::cout << color_and_string.first;
std::cout << " " << std::setw(3) << std::left << nid_int << " | "
<< std::setw(13) << std::left << color_and_string.second << " | "
<< uptimes_[nid_int];
std::cout << OstreamColorizer() << "\n";
std::cout << " " << std::setw(3) << std::left << nid_int << " | " // Node ID
<< std::setw(13) << std::left << color_and_string.second << " | " // Status name
<< std::setw(12) << uptime << " | " // Uptime
<< "0x" << std::hex << std::setw(4) << std::setfill('0') << vendor_code // Vendor, hex
<< " 0b" << std::dec << std::bitset<8>((vendor_code >> 8) & 0xFF) // Vendor, bin, high
<< "'" << std::bitset<8>(vendor_code & 0xFF) // Vendor, bin, low
<< " " << vendor_code; // Vendor, dec
std::cout << OstreamColorizer() << std::setfill(' ') << "\n";
std::cout.width(0);
std::cout.flags(original_flags);
}
void redraw(const uavcan::TimerEvent&)
{
std::cout << "\x1b\x5b\x48" << "\x1b\x5b\x32\x4a"
<< " NID | Status | Uptime\n"
<< "-----+---------------+--------\n";
<< " NID | Status | Uptime (sec) | Vendor-specific status (hex/bin/dec)\n"
<< "-----+---------------+--------------+--------------------------------------\n";
for (unsigned i = 1; i <= uavcan::NodeID::Max; i++)
{
const auto s = getNodeStatus(i);
-4
View File
@@ -183,16 +183,12 @@ class CompoundType(Type):
txt = StringIO()
txt.write(self.full_name + '\n')
adjoin = lambda attrs: txt.write('\n'.join(x.get_normalized_definition() for x in attrs) + '\n')
const_sort_key = lambda x: x.get_normalized_definition()
if self.kind == CompoundType.KIND_SERVICE:
adjoin(self.request_fields)
adjoin(sorted(self.request_constants, key=const_sort_key))
txt.write('\n---\n')
adjoin(self.response_fields)
adjoin(sorted(self.response_constants, key=const_sort_key))
elif self.kind == CompoundType.KIND_MESSAGE:
adjoin(self.fields)
adjoin(sorted(self.constants, key=const_sort_key))
else:
error('Compound type of unknown kind [%s]', self.kind)
return txt.getvalue().strip().replace('\n\n\n', '\n').replace('\n\n', '\n')