/* Copyright (c) 2013 Arduino. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _CAN_LIBRARY_ #define _CAN_LIBRARY_ #include //add some extra stuff that is needed for Arduino 1.5.2 #ifndef PINS_CAN0 static const uint8_t CAN1RX = 88; static const uint8_t CAN1TX = 89; // CAN0 #define PINS_CAN0 (90u) // CAN1 #define PINS_CAN1 (91u) #define ARDUINO152 #endif #define CAN Can0 #define CAN2 Can1 #define CAN0_EN 50 //these enable pins match most all recent EVTV boards (EVTVDue, CAN Due 2.0) #define CAN1_EN 48 //they're only defaults, you can set whichever pin you need when calling begin() /** Define the Mailbox mask for eight mailboxes. */ #define GLOBAL_MAILBOX_MASK 0x000000ff /** Disable all interrupt mask */ #define CAN_DISABLE_ALL_INTERRUPT_MASK 0xffffffff /** Define the typical baudrate for CAN communication. */ #ifdef CAN_BPS_500K #undef CAN_BPS_1000K #undef CAN_BPS_800K #undef CAN_BPS_500K #undef CAN_BPS_250K #undef CAN_BPS_125K #undef CAN_BPS_50K #undef CAN_BPS_33333 #undef CAN_BPS_25K #undef CAN_BPS_10K #undef CAN_BPS_5K #endif #define CAN_BPS_1000K 1000000 #define CAN_BPS_800K 800000 #define CAN_BPS_500K 500000 #define CAN_BPS_250K 250000 #define CAN_BPS_125K 125000 #define CAN_BPS_50K 50000 #define CAN_BPS_33333 33333 #define CAN_BPS_25K 25000 #define CAN_BPS_10K 10000 #define CAN_BPS_5K 5000 #define CAN_DEFAULT_BAUD CAN_BPS_250K /** Define the mailbox mode. */ #define CAN_MB_DISABLE_MODE 0 #define CAN_MB_RX_MODE 1 #define CAN_MB_RX_OVER_WR_MODE 2 #define CAN_MB_TX_MODE 3 #define CAN_MB_CONSUMER_MODE 4 #define CAN_MB_PRODUCER_MODE 5 /** Define CAN mailbox transfer status code. */ #define CAN_MAILBOX_TRANSFER_OK 0 //! Read from or write into mailbox successfully. #define CAN_MAILBOX_NOT_READY 0x01 //! Receiver is empty or transmitter is busy. #define CAN_MAILBOX_RX_OVER 0x02 //! Message overwriting happens or there're messages lost in different receive modes. #define CAN_MAILBOX_RX_NEED_RD_AGAIN 0x04 //! Application needs to re-read the data register in Receive with Overwrite mode. #define SIZE_RX_BUFFER 32 //RX incoming ring buffer is this big #define SIZE_TX_BUFFER 16 //TX ring buffer is this big #define SIZE_LISTENERS 4 //number of classes that can register as listeners with this class /** Define the timemark mask. */ #define TIMEMARK_MASK 0x0000ffff /* CAN timeout for synchronization. */ #define CAN_TIMEOUT 100000 /** The max value for CAN baudrate prescale. */ #define CAN_BAUDRATE_MAX_DIV 128 /** Define the scope for TQ. */ #define CAN_MIN_TQ_NUM 8 #define CAN_MAX_TQ_NUM 25 /** Define the fixed bit time value. */ #define CAN_BIT_SYNC 1 #define CAN_BIT_IPT 2 typedef struct { uint8_t uc_tq; //! CAN_BIT_SYNC + uc_prog + uc_phase1 + uc_phase2 = uc_tq, 8 <= uc_tq <= 25. uint8_t uc_prog; //! Propagation segment, (3-bits + 1), 1~8; uint8_t uc_phase1; //! Phase segment 1, (3-bits + 1), 1~8; uint8_t uc_phase2; //! Phase segment 2, (3-bits + 1), 1~8, CAN_BIT_IPT <= uc_phase2; uint8_t uc_sjw; //! Resynchronization jump width, (2-bits + 1), min(uc_phase1, 4); uint8_t uc_sp; //! Sample point value, 0~100 in percent. } can_bit_timing_t; /** Values of bit time register for different baudrates, Sample point = ((1 + uc_prog + uc_phase1) / uc_tq) * 100%. */ const can_bit_timing_t can_bit_time[] = { {8, (2 + 1), (1 + 1), (1 + 1), (2 + 1), 75}, {9, (1 + 1), (2 + 1), (2 + 1), (1 + 1), 67}, {10, (2 + 1), (2 + 1), (2 + 1), (2 + 1), 70}, {11, (3 + 1), (2 + 1), (2 + 1), (3 + 1), 72}, {12, (2 + 1), (3 + 1), (3 + 1), (3 + 1), 67}, {13, (3 + 1), (3 + 1), (3 + 1), (3 + 1), 77}, {14, (3 + 1), (3 + 1), (4 + 1), (3 + 1), 64}, {15, (3 + 1), (4 + 1), (4 + 1), (3 + 1), 67}, {16, (4 + 1), (4 + 1), (4 + 1), (3 + 1), 69}, {17, (5 + 1), (4 + 1), (4 + 1), (3 + 1), 71}, {18, (4 + 1), (5 + 1), (5 + 1), (3 + 1), 67}, {19, (5 + 1), (5 + 1), (5 + 1), (3 + 1), 68}, {20, (6 + 1), (5 + 1), (5 + 1), (3 + 1), 70}, {21, (7 + 1), (5 + 1), (5 + 1), (3 + 1), 71}, {22, (6 + 1), (6 + 1), (6 + 1), (3 + 1), 68}, {23, (7 + 1), (7 + 1), (6 + 1), (3 + 1), 70}, {24, (6 + 1), (7 + 1), (7 + 1), (3 + 1), 67}, {25, (7 + 1), (7 + 1), (7 + 1), (3 + 1), 68} }; //This is architecture specific. DO NOT USE THIS UNION ON ANYTHING OTHER THAN THE CORTEX M3 / Arduino Due //UNLESS YOU DOUBLE CHECK THINGS! typedef union { uint64_t value; struct { uint32_t low; uint32_t high; }; struct { uint16_t s0; uint16_t s1; uint16_t s2; uint16_t s3; }; uint8_t bytes[8]; uint8_t byte[8]; //alternate name so you can omit the s if you feel it makes more sense } BytesUnion; typedef struct { uint32_t id; // EID if ide set, SID otherwise uint32_t fid; // family ID uint8_t rtr; // Remote Transmission Request uint8_t priority; // Priority but only important for TX frames and then only for special uses. uint8_t extended; // Extended ID flag uint8_t length; // Number of data bytes BytesUnion data; // 64 bits - lots of ways to access it. } CAN_FRAME; class CANListener { public: CANListener(); virtual void gotFrame(CAN_FRAME *frame, int mailbox); void attachMBHandler(uint8_t mailBox); void detachMBHandler(uint8_t mailBox); void attachGeneralHandler(); void detachGeneralHandler(); private: int callbacksActive; //bitfield letting the code know which callbacks to actually try to use (for object oriented callbacks only) friend class CANRaw; //class has to have access to the the guts of this one }; class CANRaw { protected: int numTXBoxes; //There are 8 mailboxes, anything not TX will be set RX private: /* CAN peripheral, set by constructor */ Can* m_pCan ; volatile CAN_FRAME rx_frame_buff[SIZE_RX_BUFFER]; volatile CAN_FRAME tx_frame_buff[SIZE_TX_BUFFER]; volatile uint16_t rx_buffer_head, rx_buffer_tail; volatile uint16_t tx_buffer_head, tx_buffer_tail; void mailbox_int_handler(uint8_t mb, uint32_t ul_status); uint8_t enablePin; uint32_t busSpeed; //what speed is the bus currently initialized at? 0 if it is off right now uint32_t write_id; //public storage for an id. Will be used by the write function to set which ID to send to. bool bigEndian; void (*cbCANFrame[9])(CAN_FRAME *); //8 mailboxes plus an optional catch all CANListener *listener[SIZE_LISTENERS]; public: // Constructor CANRaw( Can* pCan, uint32_t En); int setRXFilter(uint32_t id, uint32_t mask, bool extended); int setRXFilter(uint8_t mailbox, uint32_t id, uint32_t mask, bool extended); 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 void setNumTXBoxes(int txboxes); int findFreeRXMailbox(); uint8_t mailbox_get_mode(uint8_t uc_index); uint32_t mailbox_get_id(uint8_t uc_index); uint32_t getMailboxIer(int8_t mailbox); uint32_t set_baudrate(uint32_t ul_baudrate); uint32_t init(uint32_t ul_baudrate); uint32_t begin(); uint32_t begin(uint32_t baudrate); uint32_t begin(uint32_t baudrate, uint8_t enablePin); uint32_t getBusSpeed(); void enable(); void disable(); bool sendFrame(CAN_FRAME& txFrame); void setWriteID(uint32_t id); template void write(t inputValue); //write a variable # of bytes out in a frame. Uses id as the ID. void setBigEndian(bool); void setCallback(int mailbox, void (*cb)(CAN_FRAME *)); void setGeneralCallback(void (*cb)(CAN_FRAME *)); //note that these below versions still use mailbox number. There isn't a good way around this. void attachCANInterrupt(void (*cb)(CAN_FRAME *)); //alternative callname for setGeneralCallback void attachCANInterrupt(uint8_t mailBox, void (*cb)(CAN_FRAME *)); void detachCANInterrupt(uint8_t mailBox); //now, object oriented versions to make OO projects easier boolean attachObj(CANListener *listener); boolean detachObj(CANListener *listener); void reset_all_mailbox(); void interruptHandler(); bool rx_avail(); int available(); //like rx_avail but returns the number of waiting frames uint32_t get_rx_buff(CAN_FRAME &); uint32_t read(CAN_FRAME &); //misc old cruft kept around just in case anyone actually used any of it in older code. //some are used within the functions above. Unless you really know of a good reason to use //any of these you probably should steer clear of them. void disable_low_power_mode(); void enable_low_power_mode(); void disable_autobaud_listen_mode(); void enable_autobaud_listen_mode(); void disable_overload_frame(); void enable_overload_frame(); void set_timestamp_capture_point(uint32_t ul_flag); void disable_time_triggered_mode(); void enable_time_triggered_mode(); void disable_timer_freeze(); void enable_timer_freeze(); void disable_tx_repeat(); void enable_tx_repeat(); void set_rx_sync_stage(uint32_t ul_stage); void enable_interrupt(uint32_t dw_mask); void disable_interrupt(uint32_t dw_mask); uint32_t get_interrupt_mask(); uint32_t get_status(); uint32_t get_internal_timer_value(); uint32_t get_timestamp_value(); uint8_t get_tx_error_cnt(); uint8_t get_rx_error_cnt(); void reset_internal_timer(); void global_send_transfer_cmd(uint8_t uc_mask); void global_send_abort_cmd(uint8_t uc_mask); void mailbox_set_timemark(uint8_t uc_index, uint16_t us_cnt); uint32_t mailbox_get_status(uint8_t uc_index); void mailbox_send_transfer_cmd(uint8_t uc_index); void mailbox_send_abort_cmd(uint8_t uc_index); void mailbox_init(uint8_t uc_index); uint32_t mailbox_read(uint8_t uc_index, volatile CAN_FRAME *rxframe); uint32_t mailbox_tx_frame(uint8_t uc_index); void mailbox_set_id(uint8_t uc_index, uint32_t id, bool extended); void mailbox_set_priority(uint8_t uc_index, uint8_t pri); void mailbox_set_accept_mask(uint8_t uc_index, uint32_t mask, bool ext); void mailbox_set_mode(uint8_t uc_index, uint8_t mode); void mailbox_set_databyte(uint8_t uc_index, uint8_t bytepos, uint8_t val); void mailbox_set_datalen(uint8_t uc_index, uint8_t dlen); void mailbox_set_datal(uint8_t uc_index, uint32_t val); void mailbox_set_datah(uint8_t uc_index, uint32_t val); }; extern CANRaw Can0; extern CANRaw Can1; #endif // _CAN_LIBRARY_