|
- // -------------------------------------------------------------
- // a simple Arduino Teensy 3.1/3.2/3.6 CAN driver
- // by teachop
- // dual CAN support for MK66FX1M0 by Pawelsky
- //
- #ifndef __FLEXCAN_H__
- #define __FLEXCAN_H__
-
- #include <Arduino.h>
-
- #define FlexCAN_MAILBOX_TX_BUFFER_SUPPORT // helper definition for handling different FlexCAN revisions
- #define FlexCAN_DYNAMIC_BUFFER_SUPPORT // helper definition for handling different FlexCAN revisions
-
- #if !defined(SIZE_RX_BUFFER)
- #define SIZE_RX_BUFFER 32 // receive incoming ring buffer size
- #endif
-
- #if !defined(SIZE_TX_BUFFER)
- #define SIZE_TX_BUFFER 16 // transmit ring buffer size
- #endif
-
- #define SIZE_LISTENERS 4 // number of classes that can register as listeners on each CAN bus
- #define NUM_MAILBOXES 16 // architecture specific but all Teensy 3.x boards have 16 mailboxes
- #define IRQ_PRIORITY 64 // 0 = highest, 255 = lowest
-
- #define COLLECT_CAN_STATS
-
- typedef struct CAN_message_t {
- uint32_t id; // can identifier
- uint16_t timestamp; // FlexCAN time when message arrived
- struct {
- uint8_t extended:1; // identifier is extended (29-bit)
- uint8_t remote:1; // remote transmission request packet type
- uint8_t overrun:1; // message overrun
- uint8_t reserved:5;
- } flags;
- uint8_t len; // length of data
- uint8_t buf[8];
- } CAN_message_t;
-
- typedef struct CAN_filter_t {
- uint32_t id;
- struct {
- uint8_t extended:1; // identifier is extended (29-bit)
- uint8_t remote:1; // remote transmission request packet type
- uint8_t reserved:6;
- } flags;
- } CAN_filter_t;
-
- // statistics about the CAN interface
-
- typedef struct CAN_stats_t {
- bool enabled; // enable collecting statistics
- uint32_t ringRxMax; // number of entries in the ring buffer
- uint32_t ringRxHighWater; // maximum entries used in the ring buffer
- uint32_t ringRxFramesLost; // total number of frames lost
- uint32_t ringTxMax; // number of entries in the ring buffer
- uint32_t ringTxHighWater; // maximum entries used in the ring buffer
- struct {
- uint32_t refCount; // mailbox reference (use) count
- uint32_t overrunCount; // mailbox message overrun count
- } mb[NUM_MAILBOXES];
- } CAN_stats_t;
-
- // ring buffer data structure
-
- typedef struct ringbuffer_t {
- volatile uint16_t head;
- volatile uint16_t tail;
- uint16_t size;
- volatile CAN_message_t *buffer;
- } ringbuffer_t;
-
- // for backwards compatibility with previous structure members
-
- #define ext flags.extended
- #define rtr flags.remote
-
- class CANListener
- {
- public:
- CANListener ();
-
- virtual bool frameHandler (CAN_message_t &frame, int mailbox, uint8_t controller);
- virtual void txHandler (int mailbox, uint8_t controller);
-
- void attachMBHandler (uint8_t mailBox);
- void detachMBHandler (uint8_t mailBox);
- void attachGeneralHandler (void);
- void detachGeneralHandler (void);
-
- private:
- uint32_t callbacksActive; // bitfield indicating which callbacks are installed (for object oriented callbacks only)
-
- friend class FlexCAN; // class has to have access to the the guts of this one
- };
-
- // -------------------------------------------------------------
-
- class FlexCAN
- {
- private:
- uint32_t flexcanBase;
- struct CAN_filter_t MBFilters[NUM_MAILBOXES];
- static struct CAN_filter_t defaultMask;
- void mailbox_int_handler (uint8_t mb, uint32_t ul_status);
- CANListener *listener[SIZE_LISTENERS];
-
- ringbuffer_t txRing;
- volatile CAN_message_t *tx_buffer;
- ringbuffer_t rxRing;
- volatile CAN_message_t *rx_buffer;
- ringbuffer_t * txRings[NUM_MAILBOXES];
-
- bool IrqEnabled;
- uint32_t IrqMessage;
-
- void writeTxRegisters (const CAN_message_t &msg, uint8_t buffer);
- void readRxRegisters (CAN_message_t &msg, uint8_t buffer);
-
- void initRingBuffer (ringbuffer_t &ring, volatile CAN_message_t *buffer, uint32_t size);
- bool addToRingBuffer (ringbuffer_t &ring, const CAN_message_t &msg);
- bool removeFromRingBuffer (ringbuffer_t &ring, CAN_message_t &msg);
- bool isRingBufferEmpty (ringbuffer_t &ring);
- uint32_t ringBufferCount (ringbuffer_t &ring);
-
- void irqLock() { IrqEnabled=NVIC_IS_ENABLED(IrqMessage); NVIC_DISABLE_IRQ(IrqMessage); }
- void irqRelease() { if (IrqEnabled) NVIC_ENABLE_IRQ(IrqMessage); }
-
- void initializeBuffers();
- bool isInitialized() { return tx_buffer!=0; }
- void setPins(uint8_t txAlt, uint8_t rxAlt);
- void setBaudRate(uint32_t baud);
- void softReset();
- void halt();
- void exitHalt();
- void freeze();
- void waitFrozen();
- void waitNotFrozen();
- void waitReady();
- bool isFrozen();
-
- bool usesGlobalTxRing(uint8_t mbox) { return (mbox<getNumMailBoxes()?txRings[mbox]==0:true); }
- bool isTxBox(uint8_t mbox) { return (mbox>=getFirstTxBox() && mbox<getNumMailBoxes() ); }
-
- #ifdef COLLECT_CAN_STATS
- CAN_stats_t stats;
- #endif
-
- protected:
- uint8_t numTxMailboxes;
- uint16_t sizeRxBuffer;
- uint16_t sizeTxBuffer;
-
- public:
- FlexCAN (uint8_t id = 0);
-
- // Before begin, you can define rx buffer size. Default is SIZE_RX_BUFFER. This does not have effect after begin.
- void setRxBufferSize(uint16_t size) { if (!isInitialized() ) sizeRxBuffer=size; }
-
- // Before begin, you can define global tx buffer size. Default is SIZE_TX_BUFFER. This does not have effect after begin.
- void setTxBufferSize(uint16_t size) { if (!isInitialized() ) sizeTxBuffer=size; }
-
- // You can define mailbox specific tx buffer size. This can be defined only once per mailbox.
- // As default prioritized messages will not be buffered. If you define buffer size for mail box, the messages will be
- // buffered to own buffer, if necessary.
- void setMailBoxTxBufferSize(uint8_t mbox, uint16_t size);
-
- inline uint8_t getFirstTxBox() { return getNumMailBoxes()-numTxMailboxes; }
- inline uint8_t getLastTxBox() { return getNumMailBoxes()-1; }
- inline uint8_t getNumMailBoxes() { return NUM_MAILBOXES; }
- inline uint8_t getNumRxBoxes() { return getNumMailBoxes()-numTxMailboxes; }
-
- void begin (uint32_t baud = 250000, const CAN_filter_t &mask = defaultMask, uint8_t txAlt = 0, uint8_t rxAlt = 0);
-
- void setFilter (const CAN_filter_t &filter, uint8_t n);
- bool getFilter (CAN_filter_t &filter, uint8_t n);
- void setMask (uint32_t mask, uint8_t n);
- void end (void);
- uint32_t available (void);
- int write (const CAN_message_t &msg);
- int write (const CAN_message_t &msg, uint8_t n);
- int read (CAN_message_t &msg);
- uint32_t rxBufferOverruns (void)
- {
- return stats.ringRxFramesLost;
- };
-
- #ifdef COLLECT_CAN_STATS
- void startStats (void)
- {
- stats.enabled = true;
- };
- void stopStats (void)
- {
- stats.enabled = false;
- };
- void clearStats (void);
- CAN_stats_t getStats (void)
- {
- return stats;
- };
- #endif
-
- //new functionality added to header but not yet implemented. Fix me
- void setListenOnly (bool mode); //pass true to go into listen only mode, false to be in normal mode
-
- bool attachObj (CANListener *listener);
- bool detachObj (CANListener *listener);
-
- //int watchFor(); //allow anything through
- //int watchFor(uint32_t id); //allow just this ID through (automatic determination of extended status)
- //int watchFor(uint32_t id, uint32_t mask); //allow a range of ids through
- //int watchForRange(uint32_t id1, uint32_t id2); //try to allow the range from id1 to id2 - automatically determine base ID and mask
-
- uint8_t setNumTxBoxes (uint8_t txboxes);
- // Obsolete, for compatibility with version provided with Teensyduino
- uint8_t setNumTXBoxes (uint8_t txboxes) { return setNumTxBoxes(txboxes); }
-
- void message_isr (void);
- void bus_off_isr (void);
- void error_isr (void);
- void tx_warn_isr (void);
- void rx_warn_isr (void);
- void wakeup_isr (void);
- };
-
- extern FlexCAN Can0;
- #ifdef __MK66FX1M0__
- extern FlexCAN Can1;
- #endif
-
- #endif // __FLEXCAN_H__
|