diff --git a/drivers/include/drivers/CAN.h b/drivers/include/drivers/CAN.h index 66d6ad4..be404f8 100644 --- a/drivers/include/drivers/CAN.h +++ b/drivers/include/drivers/CAN.h @@ -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 @@ -115,7 +36,13 @@ /** A can bus client, used for communicating with can devices */ -class CAN : private NonCopyable { +class CAN +#ifdef FEATURE_EXPERIMENTAL_API + final : public interface::CAN +#else + : public interface::can +#endif +{ public: /** Creates a CAN interface connected to specific pins. @@ -233,15 +160,6 @@ */ 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) @@ -277,20 +195,6 @@ */ 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. * @@ -299,7 +203,7 @@ * @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 func, IrqType type = RxIrq); + void attach(Callback func, IrqType type = IrqType::RxIrq); static void _irq_handler(uint32_t id, CanIrqType type); @@ -309,7 +213,7 @@ virtual void unlock(); can_t _can; - Callback _irq[IrqCnt]; + Callback _irq[IrqType::IrqCnt]; PlatformMutex _mutex; #endif }; diff --git a/drivers/include/drivers/interfaces/InterfaceCAN.h b/drivers/include/drivers/interfaces/InterfaceCAN.h new file mode 100644 index 0000000..54cf0d2 --- /dev/null +++ b/drivers/include/drivers/interfaces/InterfaceCAN.h @@ -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 + +#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 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_ */ diff --git a/drivers/source/CAN.cpp b/drivers/source/CAN.cpp index 6688829..2767c07 100644 --- a/drivers/source/CAN.cpp +++ b/drivers/source/CAN.cpp @@ -55,7 +55,7 @@ // 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); diff --git a/hal/include/hal/can_helper.h b/hal/include/hal/can_helper.h index 3f56f16..c9a6698 100644 --- a/hal/include/hal/can_helper.h +++ b/hal/include/hal/can_helper.h @@ -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" {