diff --git a/libuavcan_drivers/linux/include/uavcan_linux/clock.hpp b/libuavcan_drivers/linux/include/uavcan_linux/clock.hpp index 29fb75fe46..3098d14982 100644 --- a/libuavcan_drivers/linux/include/uavcan_linux/clock.hpp +++ b/libuavcan_drivers/linux/include/uavcan_linux/clock.hpp @@ -17,14 +17,19 @@ namespace uavcan_linux { - +/** + * Different adjustment modes can be used for time synchronization + */ enum class ClockAdjustmentMode { - SystemWide, - PerDriverPrivate + SystemWide, ///< Adjust the clock globally for the whole system; requires root privileges + PerDriverPrivate ///< Adjust the clock only for the current driver instance }; - +/** + * Linux system clock driver. + * Requires librt. + */ class SystemClock : public uavcan::ISystemClock { uavcan::UtcDuration private_adj_; @@ -61,6 +66,9 @@ class SystemClock : public uavcan::ISystemClock } public: + /** + * By default, the clock adjustment mode will be selected automatically - global if root, private otherwise. + */ explicit SystemClock(ClockAdjustmentMode adj_mode = detectPreferredClockAdjustmentMode()) : gradual_adj_limit_(uavcan::UtcDuration::fromMSec(4000)) , adj_mode_(adj_mode) @@ -68,6 +76,10 @@ public: , gradual_adj_cnt_(0) { } + /** + * Returns monotonic timestamp from librt. + * @throws uavcan_linux::Exception. + */ virtual uavcan::MonotonicTime getMonotonic() const { timespec ts; @@ -78,6 +90,10 @@ public: return uavcan::MonotonicTime::fromUSec(std::uint64_t(ts.tv_sec) * UInt1e6 + ts.tv_nsec / 1000); } + /** + * Returns wall time from gettimeofday(). + * @throws uavcan_linux::Exception. + */ virtual uavcan::UtcTime getUtc() const { timeval tv; @@ -93,6 +109,18 @@ public: return utc; } + /** + * Adjusts the wall clock. + * Behavior depends on the selected clock adjustment mode - @ref ClockAdjustmentMode. + * Clock adjustment mode can be set only once via constructor. + * + * If the system wide adjustment mode is selected, two ways for performing adjustment exist: + * - Gradual adjustment using adjtime(), if the phase error is less than gradual adjustment limit. + * - Step adjustment using settimeofday(), if the phase error is above gradual adjustment limit. + * The gradual adjustment limit can be configured at any time via the setter method. + * + * @throws uavcan_linux::Exception. + */ virtual void adjustUtc(const uavcan::UtcDuration adjustment) { if (adj_mode_ == ClockAdjustmentMode::PerDriverPrivate) @@ -120,6 +148,10 @@ public: } } + /** + * Sets the maximum phase error to use adjtime(). + * If the phase error exceeds this value, settimeofday() will be used instead. + */ void setGradualAdjustmentLimit(uavcan::UtcDuration limit) { if (limit.isNegative()) @@ -133,8 +165,15 @@ public: ClockAdjustmentMode getAdjustmentMode() const { return adj_mode_; } + /** + * This is only applicable if the selected clock adjustment mode is private. + * In system wide mode this method will always return zero duration. + */ uavcan::UtcDuration getPrivateAdjustment() const { return private_adj_; } + /** + * Statistics that allows to evaluate clock sync preformance. + */ std::uint64_t getStepAdjustmentCount() const { return step_adj_cnt_; } std::uint64_t getGradualAdjustmentCount() const { return gradual_adj_cnt_; } std::uint64_t getAdjustmentCount() const @@ -142,6 +181,11 @@ public: return getStepAdjustmentCount() + getGradualAdjustmentCount(); } + /** + * This static method decides what is the optimal clock sync adjustment mode for the current configuration. + * It selects system wide mode if the application is running as root; otherwise it prefers + * the private adjustment mode because the system wide mode requires root privileges. + */ static ClockAdjustmentMode detectPreferredClockAdjustmentMode() { const bool godmode = geteuid() == 0; diff --git a/libuavcan_drivers/linux/include/uavcan_linux/exception.hpp b/libuavcan_drivers/linux/include/uavcan_linux/exception.hpp index c639f62ae0..a04b4ddb8c 100644 --- a/libuavcan_drivers/linux/include/uavcan_linux/exception.hpp +++ b/libuavcan_drivers/linux/include/uavcan_linux/exception.hpp @@ -9,7 +9,9 @@ namespace uavcan_linux { - +/** + * This is the root exception class for all exceptions that can be thrown from the libuavcan Linux driver. + */ class Exception : public std::runtime_error { const int errno_; @@ -20,6 +22,10 @@ public: , errno_(errno) { } + /** + * Returns standard UNIX errno value captured at the moment + * when this exception object was constructed. + */ int getErrno() const { return errno_; } }; diff --git a/libuavcan_drivers/linux/include/uavcan_linux/helpers.hpp b/libuavcan_drivers/linux/include/uavcan_linux/helpers.hpp index b8fd563183..c5ead370dd 100644 --- a/libuavcan_drivers/linux/include/uavcan_linux/helpers.hpp +++ b/libuavcan_drivers/linux/include/uavcan_linux/helpers.hpp @@ -15,7 +15,8 @@ namespace uavcan_linux { /** - * Default log sink will dump everything into stderr + * Default log sink will dump everything into stderr. + * It is installed by default. */ class DefaultLogSink : public uavcan::ILogSink { @@ -29,7 +30,7 @@ class DefaultLogSink : public uavcan::ILogSink /** * Wrapper over uavcan::ServiceClient<> for blocking calls. - * Calls spin() internally. + * Blocks on uavcan::Node::spin() internally until the call is complete. */ template class BlockingServiceClient : public uavcan::ServiceClient @@ -60,6 +61,11 @@ public: setup(); } + /** + * Performs a blocking service call using default timeout (see the specs). + * Use @ref getResponse() to get the actual response. + * Returns negative error code. + */ int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request) { const auto SpinDuration = uavcan::MonotonicDuration::fromMSec(2); @@ -79,6 +85,11 @@ public: return call_res; } + /** + * Performs a blocking service call using the specified timeout. Please consider using default timeout instead. + * Use @ref getResponse() to get the actual response. + * Returns negative error code. + */ int blockingCall(uavcan::NodeID server_node_id, const typename DataType::Request& request, uavcan::MonotonicDuration timeout) { @@ -86,8 +97,15 @@ public: return blockingCall(server_node_id, request); } + /** + * Whether the last blocking call was successful. + */ bool wasSuccessful() const { return call_was_successful_; } + /** + * Use this to retrieve the response on the last blocking service call. + * This method returns default constructed response object if the last service call was unsuccessful. + */ const typename DataType::Response& getResponse() const { return response_; } }; @@ -109,10 +127,11 @@ typedef std::shared_ptr DriverPackPtr; typedef std::shared_ptr TimerPtr; -static constexpr std::size_t NodeMemPoolSize = 1024 * 512; // One size fits all +static constexpr std::size_t NodeMemPoolSize = 1024 * 512; ///< This shall be enough for any possible use case /** * Wrapper for uavcan::Node with some additional convenience functions. + * Note that this wrapper adds stderr log sink to @ref uavcan::Logger, which can be removed if needed. */ class Node : public uavcan::Node { @@ -137,7 +156,7 @@ class Node : public uavcan::Node public: /** - * Simple forwarding constructor, compatible with uavcan::Node + * Simple forwarding constructor, compatible with uavcan::Node. */ Node(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) : uavcan::Node(can_driver, clock) @@ -146,7 +165,7 @@ public: } /** - * Takes ownership of the driver container. + * Takes ownership of the driver container via the shared pointer. */ explicit Node(DriverPackPtr driver_pack) : uavcan::Node(driver_pack->can, driver_pack->clock) @@ -155,6 +174,11 @@ public: getLogger().setExternalSink(&log_sink_); } + /** + * Allocates @ref uavcan::Subscriber in the heap using shared pointer. + * The subscriber will be started immediately. + * @throws uavcan_linux::Exception. + */ template std::shared_ptr> makeSubscriber(const typename uavcan::Subscriber::Callback& cb) @@ -164,6 +188,11 @@ public: return p; } + /** + * Allocates @ref uavcan::Publisher in the heap using shared pointer. + * The publisher will be initialized immediately. + * @throws uavcan_linux::Exception. + */ template std::shared_ptr> makePublisher(uavcan::MonotonicDuration tx_timeout = uavcan::Publisher::getDefaultTxTimeout()) @@ -174,6 +203,11 @@ public: return p; } + /** + * Allocates @ref uavcan::ServiceServer in the heap using shared pointer. + * The server will be started immediately. + * @throws uavcan_linux::Exception. + */ template std::shared_ptr> makeServiceServer(const typename uavcan::ServiceServer::Callback& cb) @@ -183,6 +217,11 @@ public: return p; } + /** + * Allocates @ref uavcan::ServiceClient in the heap using shared pointer. + * The service client will be initialized immediately. + * @throws uavcan_linux::Exception. + */ template std::shared_ptr> makeServiceClient(const typename uavcan::ServiceClient::Callback& cb) @@ -193,6 +232,11 @@ public: return p; } + /** + * Allocates @ref uavcan_linux::BlockingServiceClient in the heap using shared pointer. + * The service client will be initialized immediately. + * @throws uavcan_linux::Exception. + */ template std::shared_ptr> makeBlockingServiceClient() @@ -202,6 +246,10 @@ public: return p; } + /** + * Allocates @ref uavcan::Timer in the heap using shared pointer. + * The timer will be started immediately in one-shot mode. + */ TimerPtr makeTimer(uavcan::MonotonicTime deadline, const typename uavcan::Timer::Callback& cb) { TimerPtr p(new uavcan::Timer(*this)); @@ -210,6 +258,10 @@ public: return p; } + /** + * Allocates @ref uavcan::Timer in the heap using shared pointer. + * The timer will be started immediately in periodic mode. + */ TimerPtr makeTimer(uavcan::MonotonicDuration period, const typename uavcan::Timer::Callback& cb) { TimerPtr p(new uavcan::Timer(*this)); @@ -226,6 +278,8 @@ typedef std::shared_ptr NodePtr; /** * Constructs Node with explicitly specified ClockAdjustmentMode. + * Please consider using the overload with fewer parameters instead. + * @throws uavcan_linux::Exception. */ static inline NodePtr makeNode(const std::vector& iface_names, ClockAdjustmentMode clock_adjustment_mode) { @@ -241,7 +295,10 @@ static inline NodePtr makeNode(const std::vector& iface_names, Cloc } /** - * This is the preferred way to make Node. + * Use this function to create a node instance. + * It accepts the list of interface names to use for the new node, e.g. "can1", "vcan2", "slcan0". + * Clock adjustment mode will be detected automatically. + * @throws uavcan_linux::Exception. */ static inline NodePtr makeNode(const std::vector& iface_names) { diff --git a/libuavcan_drivers/linux/include/uavcan_linux/socketcan.hpp b/libuavcan_drivers/linux/include/uavcan_linux/socketcan.hpp index 3906cc3683..bd30a55707 100644 --- a/libuavcan_drivers/linux/include/uavcan_linux/socketcan.hpp +++ b/libuavcan_drivers/linux/include/uavcan_linux/socketcan.hpp @@ -26,7 +26,9 @@ namespace uavcan_linux { - +/** + * SocketCan driver class keeps number of each kind of errors occurred since the object was created. + */ enum class SocketCanError { SocketReadFailure, @@ -35,6 +37,8 @@ enum class SocketCanError }; /** + * Single SocketCAN socket interface. + * * SocketCAN socket adapter maintains TX and RX queues in user space. At any moment socket's buffer contains * no more than 'max_frames_in_socket_tx_queue_' TX frames, rest is waiting in the user space TX queue; when the * socket produces loopback for the previously sent TX frame the next frame from the user space TX queue will @@ -308,6 +312,9 @@ public: assert(fd_ >= 0); } + /** + * Socket file descriptor will be closed. + */ virtual ~SocketCanIface() { (void)::close(fd_); @@ -406,8 +413,15 @@ public: return (ret < 0) ? -1 : 0; } + /** + * SocketCAN emulates the CAN filters in software, so the number of filters is virtually unlimited. + * This method returns a constant value. + */ virtual std::uint16_t getNumFilters() const { return 255; } + /** + * Returns total number of errors of each kind detected since the object was created. + */ virtual std::uint64_t getErrorCount() const { std::uint64_t ec = 0; @@ -415,6 +429,9 @@ public: return ec; } + /** + * Returns number of errors of each kind in a map. + */ const decltype(errors_)& getErrors() const { return errors_; } int getFileDescriptor() const { return fd_; } @@ -479,9 +496,9 @@ public: } }; - /** - * Multiplexing container for multiple SocketCAN sockets + * Multiplexing container for multiple SocketCAN sockets. + * Uses ppoll() for multiplexing. */ class SocketCanDriver : public uavcan::ICanDriver { @@ -495,6 +512,9 @@ private: std::uint8_t num_ifaces_; public: + /** + * Reference to the clock object shall remain valid. + */ explicit SocketCanDriver(const SystemClock& clock) : clock_(clock) , num_ifaces_(0) @@ -588,6 +608,7 @@ public: * Adds one iface by name. Will fail if there are @ref MaxIfaces ifaces registered already. * @param iface_name E.g. "can0", "vcan1" * @return Negative on error, zero on success. + * @throws uavcan_linux::Exception. */ int addIface(const std::string& iface_name) {