/* * Copyright (C) 2014 Pavel Kirienko */ #pragma once #include #include #include #include #include #include namespace uavcan_linux { /** * Default log sink will dump everything into stderr */ class DefaultLogSink : public uavcan::ILogSink { virtual void log(const uavcan::protocol::debug::LogMessage& message) { const auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); const auto tstr = std::ctime(&tt); std::cerr << "### UAVCAN " << tstr << message << std::endl; } }; /** * Contains all drivers needed for uavcan::Node. */ struct DriverPack { SocketCanDriver can; SystemClock clock; DriverPack(ClockAdjustmentMode clock_adjustment_mode) : can() , clock(clock_adjustment_mode) { } }; typedef std::shared_ptr DriverPackPtr; typedef std::shared_ptr TimerPtr; static constexpr std::size_t NodeMemPoolSize = 1024 * 512; // One size fits all /** * Wrapper for uavcan::Node with some additional convenience functions. */ class Node : public uavcan::Node { DriverPackPtr driver_pack_; DefaultLogSink log_sink_; static void enforce(int error, const char* msg) { if (error < 0) { throw Exception(msg); } } public: /** * Simple forwarding constructor, compatible with uavcan::Node */ Node(uavcan::ICanDriver& can_driver, uavcan::ISystemClock& clock) : uavcan::Node(can_driver, clock) { getLogger().setExternalSink(&log_sink_); } /** * Takes ownership of the driver container. */ Node(DriverPackPtr driver_pack) : uavcan::Node(driver_pack->can, driver_pack->clock) , driver_pack_(driver_pack) { getLogger().setExternalSink(&log_sink_); } template std::shared_ptr> makeSubscriber(const typename uavcan::Subscriber::Callback& cb) { std::shared_ptr> p(new uavcan::Subscriber(*this)); enforce(p->start(cb), "Subscriber start"); return p; } template std::shared_ptr> makePublisher(uavcan::MonotonicDuration tx_timeout = uavcan::Publisher::getDefaultTxTimeout()) { std::shared_ptr> p(new uavcan::Publisher(*this)); enforce(p->init(), "Publisher init"); p->setTxTimeout(tx_timeout); return p; } template std::shared_ptr> makeServiceServer(const typename uavcan::ServiceServer::Callback& cb) { std::shared_ptr> p(new uavcan::ServiceServer(*this)); enforce(p->start(cb), "ServiceServer start"); return p; } template std::shared_ptr> makeServiceClient(const typename uavcan::ServiceClient::Callback& cb) { std::shared_ptr> p(new uavcan::ServiceClient(*this)); enforce(p->init(), "ServiceClient init"); p->setCallback(cb); return p; } TimerPtr makeTimer(uavcan::MonotonicTime deadline, const typename uavcan::Timer::Callback& cb) { TimerPtr p(new uavcan::Timer(*this)); p->setCallback(cb); p->startOneShotWithDeadline(deadline); return p; } TimerPtr makeTimer(uavcan::MonotonicDuration period, const typename uavcan::Timer::Callback& cb) { TimerPtr p(new uavcan::Timer(*this)); p->setCallback(cb); p->startPeriodic(period); return p; } }; typedef std::shared_ptr NodePtr; /** * Constructs Node with explicitly specified ClockAdjustmentMode. */ static inline NodePtr makeNode(const std::vector& iface_names, ClockAdjustmentMode clock_adjustment_mode) { DriverPackPtr dp(new DriverPack(clock_adjustment_mode)); for (auto ifn : iface_names) { if (dp->can.addIface(ifn) < 0) { throw Exception("Failed to add iface " + ifn); } } return NodePtr(new Node(dp)); } /** * This is the preferred way to make Node. */ static inline NodePtr makeNode(const std::vector& iface_names) { return makeNode(iface_names, SystemClock::detectPreferredClockAdjustmentMode()); } }