steering-wheel/lib/due_can/due_can.h

315 lines
11 KiB
C
Raw Normal View History

/*
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 <Arduino.h>
//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 <typename t> 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_