Skip to content

Commit

Permalink
Merge pull request #14336 from AGlass0fMilk/polymorphic-can
Browse files Browse the repository at this point in the history
Implement polymorphism for CAN driver
  • Loading branch information
0xc0170 authored May 12, 2021
2 parents a104dac + d39a416 commit c02e101
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 108 deletions.
116 changes: 10 additions & 106 deletions drivers/include/drivers/CAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,91 +21,12 @@

#if DEVICE_CAN || defined(DOXYGEN_ONLY)

#include "interfaces/InterfaceCAN.h"
#include "hal/can_api.h"
#include "platform/Callback.h"
#include "platform/PlatformMutex.h"
#include "platform/NonCopyable.h"

namespace mbed {
/** \defgroup drivers-public-api-can CAN
* \ingroup drivers-public-api
*/

/**
* \defgroup drivers_CANMessage CANMessage class
* \ingroup drivers-public-api-can
* @{
*/

/** CANMessage class
*
* @note Synchronization level: Thread safe
*/
class CANMessage : public CAN_Message {

public:
/** Creates empty CAN message.
*/
CANMessage() : CAN_Message()
{
len = 8U;
type = CANData;
format = CANStandard;
id = 0U;
memset(data, 0, 8);
}

/** Creates CAN message with specific content.
*
* @param _id Message ID
* @param _data Mesaage Data
* @param _len Message Data length
* @param _type Type of Data: Use enum CANType for valid parameter values
* @param _format Data Format: Use enum CANFormat for valid parameter values
*/
CANMessage(unsigned int _id, const unsigned char *_data, unsigned char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard)
{
len = (_len > 8) ? 8 : _len;
type = _type;
format = _format;
id = _id;
memcpy(data, _data, len);
}


/** Creates CAN message with specific content.
*
* @param _id Message ID
* @param _data Mesaage Data
* @param _len Message Data length
* @param _type Type of Data: Use enum CANType for valid parameter values
* @param _format Data Format: Use enum CANFormat for valid parameter values
*/
CANMessage(unsigned int _id, const char *_data, unsigned char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard)
{
len = (_len > 8) ? 8 : _len;
type = _type;
format = _format;
id = _id;
memcpy(data, _data, len);
}

/** Creates CAN remote message.
*
* @param _id Message ID
* @param _format Data Format: Use enum CANType for valid parameter values
*/
CANMessage(unsigned int _id, CANFormat _format = CANStandard)
{
len = 0;
type = CANRemote;
format = _format;
id = _id;
memset(data, 0, 8);
}
};

/** @}*/

/**
* \defgroup drivers_CAN CAN class
Expand All @@ -115,7 +36,13 @@ class CANMessage : public CAN_Message {

/** A can bus client, used for communicating with can devices
*/
class CAN : private NonCopyable<CAN> {
class CAN
#ifdef FEATURE_EXPERIMENTAL_API
final : public interface::CAN
#else
: public interface::can
#endif
{

public:
/** Creates a CAN interface connected to specific pins.
Expand Down Expand Up @@ -233,15 +160,6 @@ class CAN : private NonCopyable<CAN> {
*/
void monitor(bool silent);

enum Mode {
Reset = 0,
Normal,
Silent,
LocalTest,
GlobalTest,
SilentTest
};

/** Change CAN operation to the specified mode
*
* @param mode The new operation mode (CAN::Normal, CAN::Silent, CAN::LocalTest, CAN::GlobalTest, CAN::SilentTest)
Expand Down Expand Up @@ -277,20 +195,6 @@ class CAN : private NonCopyable<CAN> {
*/
unsigned char tderror();

enum IrqType {
RxIrq = 0,
TxIrq,
EwIrq,
DoIrq,
WuIrq,
EpIrq,
AlIrq,
BeIrq,
IdIrq,

IrqCnt
};

/** Attach a function to call whenever a CAN frame received interrupt is
* generated.
*
Expand All @@ -299,7 +203,7 @@ class CAN : private NonCopyable<CAN> {
* @param func A pointer to a void function, or 0 to set as none
* @param type Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, CAN::TxIrq for transmitted or aborted, CAN::EwIrq for error warning, CAN::DoIrq for data overrun, CAN::WuIrq for wake-up, CAN::EpIrq for error passive, CAN::AlIrq for arbitration lost, CAN::BeIrq for bus error)
*/
void attach(Callback<void()> func, IrqType type = RxIrq);
void attach(Callback<void()> func, IrqType type = IrqType::RxIrq);

static void _irq_handler(uint32_t id, CanIrqType type);

Expand All @@ -309,7 +213,7 @@ class CAN : private NonCopyable<CAN> {
virtual void unlock();

can_t _can;
Callback<void()> _irq[IrqCnt];
Callback<void()> _irq[IrqType::IrqCnt];
PlatformMutex _mutex;
#endif
};
Expand Down
187 changes: 187 additions & 0 deletions drivers/include/drivers/interfaces/InterfaceCAN.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Mbed-OS Microcontroller Library
* Copyright (c) 2021 Embedded Planet
* Copyright (c) 2021 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

#ifndef MBED_INTERFACE_CAN_H_
#define MBED_INTERFACE_CAN_H_

#include "hal/can_helper.h"

#include <cstring>

#include "platform/Callback.h"

namespace mbed {

#ifndef FEATURE_EXPERIMENTAL_API
// Forward declare CAN
class CAN;
#endif

/** \defgroup drivers-public-api-can CAN
* \ingroup drivers-public-api
*/

/**
* \defgroup drivers_CANMessage CANMessage class
* \ingroup drivers-public-api-can
* @{
*/

/** CANMessage class
*
* @note Synchronization level: Thread safe
*/
class CANMessage : public CAN_Message {

public:
/** Creates empty CAN message.
*/
CANMessage() : CAN_Message()
{
len = 8U;
type = CANData;
format = CANStandard;
id = 0U;
memset(data, 0, 8);
}

/** Creates CAN message with specific content.
*
* @param _id Message ID
* @param _data Mesaage Data
* @param _len Message Data length
* @param _type Type of Data: Use enum CANType for valid parameter values
* @param _format Data Format: Use enum CANFormat for valid parameter values
*/
CANMessage(unsigned int _id, const unsigned char *_data, unsigned char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard)
{
len = (_len > 8) ? 8 : _len;
type = _type;
format = _format;
id = _id;
memcpy(data, _data, len);
}


/** Creates CAN message with specific content.
*
* @param _id Message ID
* @param _data Mesaage Data
* @param _len Message Data length
* @param _type Type of Data: Use enum CANType for valid parameter values
* @param _format Data Format: Use enum CANFormat for valid parameter values
*/
CANMessage(unsigned int _id, const char *_data, unsigned char _len = 8, CANType _type = CANData, CANFormat _format = CANStandard)
{
len = (_len > 8) ? 8 : _len;
type = _type;
format = _format;
id = _id;
memcpy(data, _data, len);
}

/** Creates CAN remote message.
*
* @param _id Message ID
* @param _format Data Format: Use enum CANType for valid parameter values
*/
CANMessage(unsigned int _id, CANFormat _format = CANStandard)
{
len = 0;
type = CANRemote;
format = _format;
id = _id;
memset(data, 0, 8);
}
};

/** @}*/

namespace interface {

/* Having this as a struct allows interface::CAN and/or mbed::CAN to inherit the enums */
struct can {

enum Mode {
Reset = 0,
Normal,
Silent,
LocalTest,
GlobalTest,
SilentTest
};

enum IrqType {
RxIrq = 0,
TxIrq,
EwIrq,
DoIrq,
WuIrq,
EpIrq,
AlIrq,
BeIrq,
IdIrq,

IrqCnt
};

// Prevent slicing and user creation of base class.
protected:
can() = default;
~can() = default;

public:

/* Copy constructor and copy assignment operators will be deleted in subclasses as well */
can(const can &) = delete;
can &operator=(const can &) = delete;

};

#ifdef FEATURE_EXPERIMENTAL_API

// Pure virtual interface for CAN
struct CAN : public interface::can {

virtual ~CAN() = default;
virtual int frequency(int hz) = 0;
virtual int write(CANMessage msg) = 0;
virtual int read(CANMessage &msg, int handle = 0) = 0;
virtual void reset() = 0;
virtual void monitor(bool silent) = 0;
virtual int mode(Mode mode) = 0;
virtual int filter(unsigned int id, unsigned int mask, CANFormat format = CANAny, int handle = 0) = 0;
virtual unsigned char rderror() = 0;
virtual unsigned char tderror() = 0;
virtual void attach(Callback<void()> func, IrqType type = IrqType::RxIrq) = 0;
};

#else
using CAN = ::mbed::CAN;
#endif

} // namespace interface

#if defined(FEATURE_EXPERIMENTAL_API) && !DEVICE_CAN
using CAN = interface::CAN;
#endif

} // namespace mbed

#endif /* MBED_INTERFACE_CAN_H_ */
2 changes: 1 addition & 1 deletion drivers/source/CAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ CAN::~CAN()
// No lock needed in destructor

// Detaching interrupts releases the sleep lock if it was locked
for (int irq = 0; irq < IrqCnt; irq++) {
for (int irq = 0; irq < IrqType::IrqCnt; irq++) {
attach(nullptr, (IrqType)irq);
}
can_irq_free(&_can);
Expand Down
2 changes: 1 addition & 1 deletion hal/include/hal/can_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#ifndef MBED_CAN_HELPER_H
#define MBED_CAN_HELPER_H

#if DEVICE_CAN
#if DEVICE_CAN || FEATURE_EXPERIMENTAL_API

#ifdef __cplusplus
extern "C" {
Expand Down

0 comments on commit c02e101

Please sign in to comment.