Skip to content

Commit

Permalink
Merge pull request #185 from arduino/can-api
Browse files Browse the repository at this point in the history
Add HardwareCAN - a abstract base class for implementing CAN interfaces across Arduino cores.
  • Loading branch information
facchinm authored Apr 26, 2023
2 parents 844e4bf + 032a0fc commit becd6b5
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 0 deletions.
97 changes: 97 additions & 0 deletions api/CanMsg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/

#ifndef ARDUINOCORE_API_CAN_MSG_H_
#define ARDUINOCORE_API_CAN_MSG_H_

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include <cstdlib>
#include <cstdint>
#include <cstring>

#include <Arduino.h>

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

namespace arduino
{

/**************************************************************************************
* CLASS DECLARATION
**************************************************************************************/

class CanMsg : public Printable
{
public:
static size_t constexpr MAX_DATA_LENGTH = 8;

CanMsg(uint32_t const can_id, uint8_t const can_data_len, uint8_t const * can_data_ptr)
: id{can_id}
, data_length{can_data_len}
, data{0}
{
memcpy(data, can_data_ptr, min(can_data_len, MAX_DATA_LENGTH));
}

CanMsg() : CanMsg(0, 0, nullptr) { }

CanMsg(CanMsg const & other)
{
this->id = other.id;
this->data_length = other.data_length;
memcpy(this->data, other.data, this->data_length);
}

virtual ~CanMsg() { }

void operator = (CanMsg const & other)
{
if (this == &other)
return;

this->id = other.id;
this->data_length = other.data_length;
memcpy(this->data, other.data, this->data_length);
}

virtual size_t printTo(Print & p) const override
{
char buf[20] = {0};
size_t len = 0;

/* Print the header. */
len = snprintf(buf, sizeof(buf), "[%08X] (%d) : ", id, data_length);
size_t n = p.write(buf, len);

/* Print the data. */
for (size_t d = 0; d < data_length; d++)
{
len = snprintf(buf, sizeof(buf), "%02X", data[d]);
n += p.write(buf, len);
}

/* Wrap up. */
return n;
}

uint32_t id;
uint8_t data_length;
uint8_t data[MAX_DATA_LENGTH];
};

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

} /* arduino */

#endif /* ARDUINOCORE_API_CAN_MSG_H_ */
62 changes: 62 additions & 0 deletions api/CanMsgRingbuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include "CanMsgRingbuffer.h"

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

namespace arduino
{

/**************************************************************************************
* CTOR/DTOR
**************************************************************************************/

CanMsgRingbuffer::CanMsgRingbuffer()
: _head{0}
, _tail{0}
, _num_elems{0}
{
}

/**************************************************************************************
* PUBLIC MEMBER FUNCTIONS
**************************************************************************************/

void CanMsgRingbuffer::enqueue(CanMsg const & msg)
{
if (isFull())
return;

_buf[_head] = msg;
_head = next(_head);
_num_elems++;
}

CanMsg CanMsgRingbuffer::dequeue()
{
if (isEmpty())
return CanMsg();

CanMsg const msg = _buf[_tail];
_tail = next(_tail);
_num_elems--;

return msg;
}

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

} /* arduino */
60 changes: 60 additions & 0 deletions api/CanMsgRingbuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/

#ifndef ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_
#define ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include <cstdint>

#include "CanMsg.h"

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

namespace arduino
{

/**************************************************************************************
* CLASS DECLARATION
**************************************************************************************/

class CanMsgRingbuffer
{
public:
static size_t constexpr RING_BUFFER_SIZE = 32U;

CanMsgRingbuffer();

inline bool isFull() const { return (_num_elems == RING_BUFFER_SIZE); }
void enqueue(CanMsg const & msg);

inline bool isEmpty() const { return (_num_elems == 0); }
CanMsg dequeue();

inline size_t available() const { return _num_elems; }

private:
CanMsg _buf[RING_BUFFER_SIZE];
volatile size_t _head;
volatile size_t _tail;
volatile size_t _num_elems;

inline size_t next(size_t const idx) const { return ((idx + 1) % RING_BUFFER_SIZE); }
};

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

} /* arduino */

#endif /* ARDUINOCORE_API_CAN_MSG_RING_BUFFER_H_ */
62 changes: 62 additions & 0 deletions api/HardwareCAN.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/

#ifndef ARDUINOCORE_API_HARDWARECAN_H
#define ARDUINOCORE_API_HARDWARECAN_H

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include "CanMsg.h"
#include "CanMsgRingbuffer.h"

/**************************************************************************************
* TYPEDEF
**************************************************************************************/

enum class CanBitRate : int
{
BR_125k = 125000,
BR_250k = 250000,
BR_500k = 500000,
BR_1000k = 1000000,
};

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

namespace arduino
{

/**************************************************************************************
* CLASS DECLARATION
**************************************************************************************/

class HardwareCAN
{
public:
virtual ~HardwareCAN() {}


virtual bool begin(CanBitRate const can_bitrate) = 0;
virtual void end() = 0;


virtual int write(CanMsg const &msg) = 0;
virtual size_t available() = 0;
virtual CanMsg read() = 0;
};

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

} /* arduino */

#endif /* ARDUINOCORE_API_HARDWARECAN_H */

0 comments on commit becd6b5

Please sign in to comment.