ardupilot/libraries/AP_UAVCAN/AP_UAVCAN_SLCAN.h

241 lines
6.2 KiB
C++

#pragma once
#include <AP_HAL/AP_HAL.h>
#if AP_UAVCAN_SLCAN_ENABLED
#include <AP_UAVCAN/AP_UAVCAN.h>
#include "AP_HAL/utility/RingBuffer.h"
#define SLCAN_BUFFER_SIZE 200
#define SLCAN_RX_QUEUE_SIZE 64
#define SLCAN_DRIVER_INDEX 2
class SLCANRouter;
namespace SLCAN {
/**
* Driver error codes.
* These values can be returned from driver functions negated.
*/
static const int16_t ErrUnknown = 1000; ///< Reserved for future use
static const int16_t ErrNotImplemented = 1001; ///< Feature not implemented
static const int16_t ErrInvalidBitRate = 1002; ///< Bit rate not supported
static const int16_t ErrLogic = 1003; ///< Internal logic error
static const int16_t ErrUnsupportedFrame = 1004; ///< Frame not supported (e.g. RTR, CAN FD, etc)
static const int16_t ErrMsrInakNotSet = 1005; ///< INAK bit of the MSR register is not 1
static const int16_t ErrMsrInakNotCleared = 1006; ///< INAK bit of the MSR register is not 0
static const int16_t ErrBitRateNotDetected = 1007; ///< Auto bit rate detection could not be finished
static const int16_t ErrFilterNumConfigs = 1008; ///< Auto bit rate detection could not be finished
class CANManager;
/**
* RX queue item.
* The application shall not use this directly.
*/
struct CanRxItem {
uint64_t utc_usec;
uavcan::CanFrame frame;
uavcan::CanIOFlags flags;
CanRxItem() :
utc_usec(0), flags(0)
{
}
};
class CAN: public AP_HAL::CANHal {
friend class CANManager;
friend class ::SLCANRouter;
struct TxItem {
uavcan::MonotonicTime deadline;
uavcan::CanFrame frame;
bool pending;
bool loopback;
bool abort_on_error;
TxItem() :
pending(false), loopback(false), abort_on_error(false)
{
}
};
enum {
NumTxMailboxes = 3
};
enum {
NumFilters = 14
};
uint32_t bitrate_;
virtual int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline,
uavcan::CanIOFlags flags) override;
virtual int16_t receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags) override;
int16_t reportFrame(const uavcan::CanFrame& frame, bool loopback, uint64_t timestamp_usec);
virtual int16_t configureFilters(const uavcan::CanFilterConfig* filter_configs, uint16_t num_configs) override
{
//TODO: possibly check at the first serial read
return 0;
}
virtual uint16_t getNumFilters() const override
{
return NumFilters;
}
/**
* Total number of hardware failures and other kinds of errors (e.g. queue overruns).
* May increase continuously if the interface is not connected to the bus.
*/
virtual uint64_t getErrorCount() const override
{
return 0;
}
const char* processCommand(char* cmd);
bool push_Frame(uavcan::CanFrame &frame);
bool handle_FrameRTRStd(const char* cmd);
bool handle_FrameRTRExt(const char* cmd);
bool handle_FrameDataStd(const char* cmd);
bool handle_FrameDataExt(const char* cmd);
void reader();
inline void addByte(const uint8_t byte);
bool initialized_;
bool _port_initialised;
char buf_[SLCAN_BUFFER_SIZE + 1];
int16_t pos_ = 0;
AP_HAL::UARTDriver *_port = nullptr;
ObjectBuffer<CanRxItem> rx_queue_;
uint8_t self_index_;
HAL_Semaphore rx_sem_;
unsigned _pending_frame_size = 0;
const uint32_t _serial_lock_key = 0x53494442;
bool _close = true;
public:
CAN(uint8_t self_index, uint8_t rx_queue_capacity):
self_index_(self_index), rx_queue_(rx_queue_capacity), _port_initialised(false)
{
UAVCAN_ASSERT(self_index_ < CAN_STM32_NUM_IFACES);
}
enum {
MaxRxQueueCapacity = 254
};
enum OperatingMode {
NormalMode, SilentMode
};
int init(const uint32_t bitrate, const OperatingMode mode, AP_HAL::UARTDriver* port);
bool begin(uint32_t bitrate) override
{
if (init(bitrate, OperatingMode::NormalMode, nullptr) == 0) {
bitrate_ = bitrate;
initialized_ = true;
}
else {
initialized_ = false;
}
return initialized_;
}
void end() override
{
}
void reset() override;
int32_t tx_pending() override
{
return _port->tx_pending() ? 0:-1;
}
int32_t available() override
{
return _port->available() ? 0:-1;
}
bool is_initialized() override
{
return initialized_;
}
bool closed()
{
return _close;
}
bool pending_frame_sent();
bool isRxBufferEmpty(void);
bool canAcceptNewTxFrame() const;
};
class CANManager: public AP_HAL::CANManager, public uavcan::ICanDriver {
bool initialized_;
CAN driver_;
uint8_t _ifaces_num = 1;
virtual int16_t select(uavcan::CanSelectMasks& inout_masks,
const uavcan::CanFrame* (&pending_tx)[uavcan::MaxCanIfaces], uavcan::MonotonicTime blocking_deadline) override;
uavcan::CanSelectMasks makeSelectMasks(const uavcan::CanFrame* (&pending_tx)[uavcan::MaxCanIfaces]);
thread_t *_irq_handler_ctx = nullptr;
public:
CANManager()
: AP_HAL::CANManager(this), initialized_(false), driver_(SLCAN_DRIVER_INDEX, SLCAN_RX_QUEUE_SIZE)
{ }
/**
* Whether at least one iface had at least one successful IO since previous call of this method.
* This is designed for use with iface activity LEDs.
*/
//bool hadActivity();
static CANManager *from(AP_HAL::CANManager *can)
{
return static_cast<CANManager*>(can);
}
bool begin(uint32_t bitrate, uint8_t can_number) override;
/*
Test if CAN manager is ready and initialized
return false - CAN manager not initialized
true - CAN manager is initialized
*/
bool is_initialized() override;
void initialized(bool val) override;
virtual CAN* getIface(uint8_t iface_index) override
{
return &driver_;
}
virtual uint8_t getNumIfaces() const override
{
return _ifaces_num;
}
void reader_trampoline(void);
};
}
#include <AP_HAL_ChibiOS/CANSerialRouter.h>
#endif // AP_UAVCAN_SLCAN_ENABLED