1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

can: add conn_can top layer interface

This module provide support for raw can and isotp
socket-like user interface.
This commit is contained in:
Vincent Dupont 2016-11-23 19:10:34 +01:00
parent 63ca443b05
commit ab5f8548f2
8 changed files with 1052 additions and 0 deletions

View File

@ -583,6 +583,12 @@ ifneq (,$(filter can_isotp,$(USEMODULE)))
USEMODULE += xtimer
endif
ifneq (,$(filter conn_can,$(USEMODULE)))
USEMODULE += can
USEMODULE += can_mbox
USEMODULE += xtimer
endif
ifneq (,$(filter random,$(USEMODULE)))
# select default prng
ifeq (,$(filter prng_%,$(USEMODULE)))

View File

@ -2,6 +2,7 @@ PSEUDOMODULES += auto_init_gnrc_rpl
PSEUDOMODULES += can_mbox
PSEUDOMODULES += can_pm
PSEUDOMODULES += can_raw
PSEUDOMODULES += conn_can_isotp_multi
PSEUDOMODULES += core_%
PSEUDOMODULES += emb6_router
PSEUDOMODULES += gnrc_ipv6_default

View File

@ -3,4 +3,8 @@ ifneq (,$(filter can_isotp,$(USEMODULE)))
DIRS += isotp
endif
ifneq (,$(filter conn_can,$(USEMODULE)))
DIRS += conn
endif
include $(RIOTBASE)/Makefile.base

3
sys/can/conn/Makefile Normal file
View File

@ -0,0 +1,3 @@
MODULE = conn_can
include $(RIOTBASE)/Makefile.base

419
sys/can/conn/isotp.c Normal file
View File

@ -0,0 +1,419 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @brief Implementation of isotp CAN connection
*
* @author Vincent Dupont <vincent@otakeys.com>
*/
#ifdef MODULE_CAN_ISOTP
#include <errno.h>
#include <string.h>
#include "can/conn/isotp.h"
#include "can/isotp.h"
#include "can/device.h"
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
#include "utlist.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "xtimer.h"
#define _TIMEOUT_TX_MSG_TYPE (0x8000)
#define _TIMEOUT_RX_MSG_TYPE (0x8001)
#define _CLOSE_CONN_MSG_TYPE (0x8002)
#define _TIMEOUT_MSG_VALUE (0xABCDEFAB)
#ifndef CONN_CAN_ISOTP_TIMEOUT_TX_CONF
#define CONN_CAN_ISOTP_TIMEOUT_TX_CONF (10 * US_PER_SEC)
#endif
static inline void put_msg(conn_can_isotp_t *conn, msg_t *msg)
{
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
mbox_put(&conn->master->mbox, msg);
#else
mbox_put(&conn->mbox, msg);
#endif
}
static inline void get_msg(conn_can_isotp_t *conn, msg_t *msg)
{
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
mbox_get(&conn->master->mbox, msg);
#else
mbox_get(&conn->mbox, msg);
#endif
}
int conn_can_isotp_create(conn_can_isotp_t *conn, struct isotp_options *options, int ifnum)
{
assert(conn != NULL);
assert(options != NULL);
assert(ifnum < CAN_DLL_NUMOF);
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
DEBUG("conn_can_isotp_create: conn=%p, conn->master=%p, ifnum=%d\n",
(void *)conn, (void *)conn->master, ifnum);
if (conn->master == conn || conn->master == NULL) {
conn->master = conn;
conn->master->next = NULL;
mutex_init(&conn->master->lock);
mutex_lock(&conn->master->lock);
DEBUG("conn_can_isotp_create: init master conn\n");
mbox_init(&conn->master->mbox, conn->master->mbox_queue, CONN_CAN_ISOTP_MBOX_SIZE);
mutex_unlock(&conn->master->lock);
}
#else
mbox_init(&conn->mbox, conn->mbox_queue, CONN_CAN_ISOTP_MBOX_SIZE);
#endif
conn->ifnum = ifnum;
memset(&conn->isotp, 0, sizeof(struct isotp));
conn->isotp.opt = *options;
return 0;
}
int conn_can_isotp_bind(conn_can_isotp_t *conn)
{
assert(conn != NULL);
assert(conn->isotp.opt.tx_id != 0 || conn->isotp.opt.rx_id != 0);
DEBUG("conn_can_isotp_bind: conn=%p, ifnum=%d\n",
(void *)conn, conn->ifnum);
if (conn->bound) {
return -EALREADY;
}
msg_t msg;
int ret;
can_reg_entry_t entry;
entry.ifnum = conn->ifnum;
entry.type = CAN_TYPE_MBOX;
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
assert(conn->master != NULL);
entry.target.mbox = &(conn->master->mbox);
if (conn != conn->master) {
mutex_lock(&conn->master->lock);
LL_APPEND(conn->master->next, (conn_can_isotp_slave_t *)conn);
mutex_unlock(&conn->master->lock);
}
ret = mbox_try_get(&conn->master->mbox, &msg);
#else
entry.target.mbox = &conn->mbox;
ret = mbox_try_get(&conn->mbox, &msg);
#endif
if ((ret == 1) && (msg.type != _CLOSE_CONN_MSG_TYPE)) {
DEBUG("conn_can_isotp_bind: msg in queue type=%x\n", msg.type);
put_msg(conn, &msg);
}
ret = isotp_bind(&conn->isotp, &entry, conn);
if (!ret) {
conn->bound = 1;
}
return ret;
}
static void _tx_conf_timeout(void *arg)
{
conn_can_isotp_t *conn = arg;
msg_t msg;
msg.type = _TIMEOUT_TX_MSG_TYPE;
msg.content.value = _TIMEOUT_MSG_VALUE;
put_msg(conn, &msg);
}
int conn_can_isotp_send(conn_can_isotp_t *conn, const void *buf, size_t size, int flags)
{
assert(conn != NULL);
assert(buf != NULL || size == 0);
int ret = 0;
if (!conn->bound) {
return -ENOTCONN;
}
if (flags & CAN_ISOTP_TX_DONT_WAIT) {
return isotp_send(&conn->isotp, buf, size, flags);
}
else {
xtimer_t timer;
timer.callback = _tx_conf_timeout;
timer.arg = conn;
xtimer_set(&timer, CONN_CAN_ISOTP_TIMEOUT_TX_CONF);
ret = isotp_send(&conn->isotp, buf, size, flags);
msg_t msg;
while (1) {
get_msg(conn, &msg);
switch (msg.type) {
case CAN_MSG_TX_ERROR:
if (msg.content.ptr == conn) {
ret = -EIO;
}
/* No break */
case CAN_MSG_TX_CONFIRMATION:
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
if (msg.content.ptr != conn) {
mbox_put(&conn->master->mbox, &msg);
break;
}
#endif
xtimer_remove(&timer);
return ret;
case _TIMEOUT_TX_MSG_TYPE:
return -ETIMEDOUT;
default:
DEBUG("conn_can_isotp_send: unexpected msg %x, requeing\n", msg.type);
put_msg(conn, &msg);
break;
}
}
}
return ret;
}
static void _rx_timeout(void *arg)
{
conn_can_isotp_t *conn = arg;
msg_t msg;
msg.type = _TIMEOUT_RX_MSG_TYPE;
msg.content.value = _TIMEOUT_MSG_VALUE;
put_msg(conn, &msg);
}
int conn_can_isotp_recv(conn_can_isotp_t *conn, void *buf, size_t size, uint32_t timeout)
{
assert(conn != NULL);
assert(buf != NULL);
int ret = 0;
gnrc_pktsnip_t *snip;
if (!conn->bound) {
return -ENOTCONN;
}
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
if (conn->rx) {
snip = conn->rx->data.iov_base;
if (snip->size <= size) {
memcpy(buf, snip->data, snip->size);
ret = snip->size;
}
else {
ret = -EOVERFLOW;
}
isotp_free_rx(conn->rx);
conn->rx = NULL;
return ret;
}
#endif
xtimer_t timer;
if (timeout != 0) {
timer.callback = _rx_timeout;
timer.arg = conn;
xtimer_set(&timer, timeout);
}
msg_t msg;
can_rx_data_t *rx;
while (1) {
get_msg(conn, &msg);
switch (msg.type) {
case CAN_MSG_RX_INDICATION:
DEBUG("conn_can_isotp_recv: CAN_MSG_RX_INDICATION\n");
rx = msg.content.ptr;
snip = rx->data.iov_base;
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
if (rx->arg != conn) {
mbox_put(&conn->master->mbox, &msg);
break;
}
#endif
if (timeout != 0) {
xtimer_remove(&timer);
}
if (snip->size <= size) {
memcpy(buf, snip->data, snip->size);
ret = snip->size;
}
else {
ret = -EOVERFLOW;
}
isotp_free_rx(rx);
return ret;
case _TIMEOUT_RX_MSG_TYPE:
DEBUG("conn_can_isotp_recv: _TIMEOUT_RX_MSG_TYPE\n");
if (msg.content.value == _TIMEOUT_MSG_VALUE) {
ret = -ETIMEDOUT;
}
else {
ret = -EINTR;
}
return ret;
case _CLOSE_CONN_MSG_TYPE:
DEBUG("conn_can_isotp_recv: _CLOSE_CONN_MSG_TYPE\n");
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
if ((msg.content.ptr == conn) || (msg.content.ptr == conn->master)) {
#endif
if (timeout != 0) {
xtimer_remove(&timer);
}
return -ECONNABORTED;
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
}
#endif
break;
default:
DEBUG("conn_can_isotp_recv: unexpected msg %x\n", msg.type);
if (timeout != 0) {
xtimer_remove(&timer);
}
ret = -EINTR;
return ret;
}
}
return ret;
}
int conn_can_isotp_close(conn_can_isotp_t *conn)
{
assert(conn != NULL);
msg_t msg;
DEBUG("conn_can_isotp_close: conn=%p, ifnum=%d\n",
(void *)conn, conn->ifnum);
if (!conn->bound) {
return -EALREADY;
}
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
assert(conn->master != NULL);
if (conn->master != conn) {
mutex_lock(&conn->master->lock);
LL_DELETE(conn->master->next, (conn_can_isotp_slave_t *)conn);
mutex_unlock(&conn->master->lock);
}
else {
if (conn->master->next) {
return -EBUSY;
}
}
#endif
isotp_release(&conn->isotp);
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
if (conn->rx) {
isotp_free_rx(conn->rx);
}
if (conn->master == conn) {
while (mbox_try_get(&conn->master->mbox, &msg)) {
if (msg.type == CAN_MSG_RX_INDICATION) {
DEBUG("conn_can_isotp_close: freeing %p\n", msg.content.ptr);
isotp_free_rx(msg.content.ptr);
}
}
}
#else
while (mbox_try_get(&conn->mbox, &msg)) {
if (msg.type == CAN_MSG_RX_INDICATION) {
DEBUG("conn_can_isotp_close: freeing %p\n", msg.content.ptr);
isotp_free_rx(msg.content.ptr);
}
}
#endif
msg.type = _CLOSE_CONN_MSG_TYPE;
msg.content.ptr = conn;
put_msg(conn, &msg);
conn->bound = 0;
return 0;
}
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
int conn_can_isotp_select(conn_can_isotp_slave_t **conn, conn_can_isotp_t *master, uint32_t timeout)
{
assert(master != NULL);
assert(conn != NULL);
int ret;
xtimer_t timer;
if (timeout != 0) {
timer.callback = _rx_timeout;
timer.arg = master;
xtimer_set(&timer, timeout);
}
msg_t msg;
can_rx_data_t *rx;
mbox_get(&master->mbox, &msg);
if (timeout != 0) {
xtimer_remove(&timer);
}
switch (msg.type) {
case CAN_MSG_RX_INDICATION:
DEBUG("conn_can_isotp_select: CAN_MSG_RX_INDICATION\n");
rx = msg.content.ptr;
*conn = rx->arg;
(*conn)->rx = rx;
ret = 0;
break;
case _TIMEOUT_RX_MSG_TYPE:
DEBUG("conn_can_isotp_select: _TIMEOUT_MSG_VALUE\n");
if (msg.content.value == _TIMEOUT_MSG_VALUE) {
ret = -ETIMEDOUT;
}
else {
ret = -EINTR;
}
*conn = NULL;
break;
default:
DEBUG("conn_can_isotp_select: %d\n", msg.type);
*conn = NULL;
ret = -EINTR;
break;
}
return ret;
}
#endif /* MODULE_CONN_CAN_ISOTP_MULTI */
#else
typedef int dont_be_pedantic;
#endif /* MODULE_CAN_ISOTP */

279
sys/can/conn/raw.c Normal file
View File

@ -0,0 +1,279 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @file
* @brief Implementation of raw CAN connection
*
* @author Vincent Dupont <vincent@otakeys.com>
*/
#include <errno.h>
#include <string.h>
#include "can/conn/raw.h"
#include "can/can.h"
#include "can/raw.h"
#include "timex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "xtimer.h"
#define _TIMEOUT_TX_MSG_TYPE (0x8000)
#define _TIMEOUT_RX_MSG_TYPE (0x8001)
#define _CLOSE_CONN_MSG_TYPE (0x8002)
#define _TIMEOUT_MSG_VALUE (0xABCDEFAB)
#ifndef CONN_CAN_RAW_TIMEOUT_TX_CONF
#define CONN_CAN_RAW_TIMEOUT_TX_CONF (1 * US_PER_SEC)
#endif
int conn_can_raw_create(conn_can_raw_t *conn, struct can_filter *filter, size_t count,
int ifnum, int flags)
{
assert(conn != NULL);
assert(ifnum < CAN_DLL_NUMOF);
DEBUG("conn_can_raw_create: create conn=%p, ifnum=%d flags=%d\n", (void *)conn, ifnum, flags);
mbox_init(&conn->mbox, conn->mbox_queue, CONN_CAN_RAW_MBOX_SIZE);
conn->flags = flags;
conn->count = 0;
conn->ifnum = ifnum;
if (flags & CONN_CAN_RECVONLY) {
can_opt_t opt;
opt.opt = CANOPT_STATE;
canopt_state_t state = CANOPT_STATE_LISTEN_ONLY;
opt.data = &state;
opt.data_len = sizeof(state);
int ret = raw_can_set_can_opt(ifnum, &opt);
if (ret < 0) {
return ret;
}
}
return conn_can_raw_set_filter(conn, filter, count);
}
int conn_can_raw_set_filter(conn_can_raw_t *conn, struct can_filter *filter, size_t count)
{
assert(conn != NULL);
assert(filter != NULL || count == 0);
DEBUG("conn_can_raw_set_filter: conn=%p, filter=%p, count=%d\n",
(void *)conn, (void *)filter, count);
DEBUG("conn_can_raw_set_filter: conn->filter=%p, conn->count=%d\n",
(void *)conn->filter, conn->count);
/* unset previous filters */
if (conn->count) {
for (size_t i = 0; i < conn->count; i++) {
DEBUG("conn_can_raw_set_filter: unsetting filter=0x%" PRIx32 ", mask=0x%" PRIx32 "\n",
conn->filter[i].can_id, conn->filter[i].can_mask);
raw_can_unsubscribe_rx_mbox(conn->ifnum, &conn->filter[i], &conn->mbox, conn);
}
}
for (size_t i = 0; i < count; i++) {
DEBUG("conn_can_raw_set_filter: setting filter=0x%" PRIx32 ", mask=0x%" PRIx32 "\n",
filter[i].can_id, filter[i].can_mask);
int ret = raw_can_subscribe_rx_mbox(conn->ifnum, &filter[i], &conn->mbox, conn);
if (ret < 0) {
DEBUG("conn_can_raw_set_filter: error setting filters %d\n", ret);
for (size_t j = 0; j < i; j++) {
DEBUG("conn_can_raw_set_filter: unsetting filter=0x%" PRIx32 ", mask=0x%" PRIx32 "\n",
filter[j].can_id, filter[j].can_mask);
raw_can_unsubscribe_rx_mbox(conn->ifnum, &filter[j], &conn->mbox, conn);
}
return ret;
}
}
conn->filter = filter;
conn->count = count;
return 0;
}
static void _tx_conf_timeout(void *arg)
{
conn_can_raw_t *conn = arg;
msg_t msg;
msg.type = _TIMEOUT_TX_MSG_TYPE;
msg.content.value = _TIMEOUT_MSG_VALUE;
mbox_put(&conn->mbox, &msg);
}
int conn_can_raw_send(conn_can_raw_t *conn, const struct can_frame *frame, int flags)
{
assert(conn != NULL);
assert(conn->ifnum < CAN_DLL_NUMOF);
assert((conn->flags & CONN_CAN_RECVONLY) == 0);
assert(frame != NULL);
int ret = 0;
int handle;
DEBUG("conn_can_raw_send: conn=%p, frame=%p, flags=%d\n",
(void *)conn, (void *)frame, flags);
if (flags & CONN_CAN_DONTWAIT) {
handle = ret = raw_can_send(conn->ifnum, frame, 0);
if (ret >= 0) {
ret = 0;
}
}
else {
xtimer_t timer;
timer.callback = _tx_conf_timeout;
timer.arg = conn;
xtimer_set(&timer, CONN_CAN_RAW_TIMEOUT_TX_CONF);
handle = raw_can_send_mbox(conn->ifnum, frame, &conn->mbox);
if (handle < 0) {
xtimer_remove(&timer);
return handle;
}
msg_t msg;
int timeout = 5;
while (1) {
mbox_get(&conn->mbox, &msg);
switch (msg.type) {
case CAN_MSG_TX_ERROR:
xtimer_remove(&timer);
return -EIO;
case CAN_MSG_TX_CONFIRMATION:
xtimer_remove(&timer);
if ((int)msg.content.value == handle) {
DEBUG("conn_can_raw_send: frame sent correctly\n");
return 0;
}
else {
raw_can_abort(conn->ifnum, handle);
return -EINTR;
}
break;
case _TIMEOUT_TX_MSG_TYPE:
DEBUG("conn_can_raw_send: timeout\n");
return -ETIMEDOUT;
break;
default:
DEBUG("conn_can_raw_send: unexpected msg=%x, requeing\n", msg.type);
mbox_put(&conn->mbox, &msg);
if (!timeout--) {
return -EINTR;
}
break;
}
}
}
return ret;
}
static void _rx_timeout(void *arg)
{
conn_can_raw_t *conn = arg;
msg_t msg;
msg.type = _TIMEOUT_RX_MSG_TYPE;
msg.content.value = _TIMEOUT_MSG_VALUE;
mbox_put(&conn->mbox, &msg);
}
int conn_can_raw_recv(conn_can_raw_t *conn, struct can_frame *frame, uint32_t timeout)
{
assert(conn != NULL);
assert(conn->ifnum < CAN_DLL_NUMOF);
assert(frame != NULL);
xtimer_t timer;
if (timeout != 0) {
timer.callback = _rx_timeout;
timer.arg = conn;
xtimer_set(&timer, timeout);
}
int ret;
msg_t msg;
can_rx_data_t *rx;
mbox_get(&conn->mbox, &msg);
if (timeout != 0) {
xtimer_remove(&timer);
}
switch (msg.type) {
case CAN_MSG_RX_INDICATION:
DEBUG("conn_can_raw_recv: CAN_MSG_RX_INDICATION\n");
rx = msg.content.ptr;
memcpy(frame, rx->data.iov_base, rx->data.iov_len);
ret = rx->data.iov_len;
raw_can_free_frame(rx);
break;
case _TIMEOUT_RX_MSG_TYPE:
if (msg.content.value == _TIMEOUT_MSG_VALUE) {
ret = -ETIMEDOUT;
}
else {
ret = -EINTR;
}
break;
case _CLOSE_CONN_MSG_TYPE:
if (msg.content.ptr == conn) {
ret = -ECONNABORTED;
}
else {
ret = -EINTR;
}
break;
default:
mbox_put(&conn->mbox, &msg);
ret = -EINTR;
break;
}
return ret;
}
int conn_can_raw_close(conn_can_raw_t *conn)
{
assert(conn != NULL);
assert(conn->ifnum < CAN_DLL_NUMOF);
DEBUG("conn_can_raw_close: conn=%p\n", (void *)conn);
if (conn->count) {
for (size_t i = 0; i < conn->count; i++) {
DEBUG("conn_can_raw_close: unsetting filter=0x%" PRIx32 ", mask=0x%" PRIx32 "\n",
conn->filter[i].can_id, conn->filter[i].can_mask);
raw_can_unsubscribe_rx_mbox(conn->ifnum, &conn->filter[i], &conn->mbox, conn);
}
conn->count = 0;
msg_t msg;
while (mbox_try_get(&conn->mbox, &msg)) {
if (msg.type == CAN_MSG_RX_INDICATION) {
DEBUG("conn_can_raw_close: incoming msg pending, freeing\n");
raw_can_free_frame(msg.content.ptr);
}
}
msg.type = _CLOSE_CONN_MSG_TYPE;
msg.content.ptr = conn;
mbox_try_put(&conn->mbox, &msg);
}
return 0;
}

View File

@ -0,0 +1,202 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup conn_can
* @{
*
*
* @file
* @brief Definitions of generic CAN interface
*
* @author Vincent Dupont <vincent@otakeys.com>
*
*/
#ifndef CAN_CONN_ISOTP_H
#define CAN_CONN_ISOTP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "can/can.h"
#include "can/isotp.h"
#include "mbox.h"
#if defined(MODULE_CONN_CAN_ISOTP_MULTI) || defined(DOXYGEN)
#include "mutex.h"
#ifndef CONN_CAN_ISOTP_MBOX_SIZE
/**
* @brief Mailbox size of a conn_can_isotp_t
*/
#define CONN_CAN_ISOTP_MBOX_SIZE (16)
#endif
/**
* @brief ISO-TP connection
*
* When conn_can_isotp_multi module is used, this is a 'master' connection
* which can be used to send and receive with multiple connections within
* a single thread.
*
* If conn_can_isotp_multi is not used, this is a simple ISO-TP connection
*/
typedef struct conn_can_isotp_master conn_can_isotp_t;
/**
* @brief ISO-TP salve connection
*
* This is a slave connection which exists only when conn_can_isotp_multi
* module is used.
*/
typedef struct conn_can_isotp_slave {
struct conn_can_isotp_slave *next; /**< Next slave in the list */
struct conn_can_isotp_master *master; /**< Master connection holding the mailbox */
struct isotp isotp; /**< ISO-TP parameters and status */
int ifnum; /**< interface number */
int bound; /**< 1 if connection is bound */
can_rx_data_t *rx; /**< Buffered rx data */
} conn_can_isotp_slave_t;
/**
* @brief ISO-TP master connection
*/
struct conn_can_isotp_master {
/* slave fields */
struct conn_can_isotp_slave *next; /**< First slave in the list */
struct conn_can_isotp_master *master; /**< Master connection */
struct isotp isotp; /**< ISO-TP parameters and status */
int ifnum; /**< interface number */
int bound; /**< 1 if connection is bound */
can_rx_data_t *rx; /**< Buffered rx data */
/* slave fields end */
mutex_t lock; /**< Master lock */
mbox_t mbox; /**< mailbox for the connection list */
/** Connection list message queue */
msg_t mbox_queue[CONN_CAN_ISOTP_MBOX_SIZE];
};
/**
* @brief Initialize a slave connection
*
* This initializes a slave connection.
*
* This must be called on slave connections when conn_can_isotp_multi is used.
* Does not exist otherwise.
*
* @param[in] master the master connection
* @param[inout] slave the slave connection to initialize
*/
static inline void conn_can_isotp_init_slave(conn_can_isotp_t *master, conn_can_isotp_slave_t *slave)
{
slave->next = NULL;
slave->master = master;
slave->rx = NULL;
}
#else
#ifndef CONN_CAN_ISOTP_MBOX_SIZE
/**
* @brief Mailbox size of a conn_can_isotp_t
*/
#define CONN_CAN_ISOTP_MBOX_SIZE (16)
#endif
/**
* @brief ISOTP connection
*/
typedef struct conn_can_isotp {
struct isotp isotp; /**< ISO-TP connection */
int ifnum; /**< interface number */
int bound; /**< 1 if connection is bound */
mbox_t mbox; /**< mbox */
/** message queue */
msg_t mbox_queue[CONN_CAN_ISOTP_MBOX_SIZE];
} conn_can_isotp_t;
#endif /* MODULE_CONN_CAN_ISOTP_MULTI */
/**
* @brief Create can isotp connection socket
*
* @param[inout] conn ISO-TP connection
* @param[in] options ISO-TP options
* @param[in] ifnum can device Interface
*
* @return 0 if socket was successfully connected
* @return any other negative number in case of an error
*/
int conn_can_isotp_create(conn_can_isotp_t *conn, struct isotp_options *options, int ifnum);
/**
* @brief Bind a can isotp connection
*
* @param[inout] conn ISO-TP connection
*
* @return 0 on success
* @return any other negative number in case of an error
*/
int conn_can_isotp_bind(conn_can_isotp_t *conn);
/**
* @brief Close can isotp connection socket
*
* @param[in] conn ISO-TP connection
*
* @return 0 if conn is closed correctly
* @return any other negative number in case of an error
*/
int conn_can_isotp_close(conn_can_isotp_t *conn);
/**
* @brief Receive isotp data
*
* @param[in] conn ISO-TP connection
* @param[out] buf buf to fill in with received data
* @param[in] size size of the buffer in bytes
* @param[in] timeout timeout in us, 0 for infinite
*
* @return the number of bytes received
* @return any other negative number in case of an error
*/
int conn_can_isotp_recv(conn_can_isotp_t *conn, void *buf, size_t size, uint32_t timeout);
/**
* @brief Generic can send
*
* @param[in] conn ISO-TP connection
* @param[in] buf data to send
* @param[in] size size of the buffer in bytes
* @param[in] flags make function blocked or not
* (CAN_ISOTP_TX_DONT_WAIT to ignore tx confirmation)
*
* @return the number of bytes sent
* @return any other negative number in case of an error
*/
int conn_can_isotp_send(conn_can_isotp_t *conn, const void *buf, size_t size, int flags);
#if defined(MODULE_CONN_CAN_ISOTP_MULTI) || defined(DOXYGEN)
/**
* @brief Wait for reception from multiple connections
*
* @param[out] conn ISO-TP connection which received data
* @param[in] master the master connection
* @param[in] timeout timeout in us, 0 for infinite wait
*
* @return 0 if OK, < 0 if error
*/
int conn_can_isotp_select(conn_can_isotp_slave_t **conn, conn_can_isotp_t *master, uint32_t timeout);
#endif
#ifdef __cplusplus
}
#endif
#endif /* CAN_CONN_ISOTP_H */
/** @} */

138
sys/include/can/conn/raw.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup can
* @defgroup conn_can Connection
* @brief conn interface for CAN stack
*
* This is the user interface to send and receive raw CAN frames or ISO-TP datagrams
*
* @{
*
*
* @file
* @brief Definitions of generic CAN interface
*
* @author Vincent Dupont <vincent@otakeys.com>
*
*/
#ifndef CAN_CONN_RAW_H
#define CAN_CONN_RAW_H
#ifdef __cplusplus
extern "C" {
#endif
#include "can/can.h"
#include "can/raw.h"
#include "mbox.h"
#ifndef CONN_CAN_RAW_MBOX_SIZE
/**
* @brief Mailbox size of a conn_can_raw_t
*/
#define CONN_CAN_RAW_MBOX_SIZE (16)
#endif
/**
* @name flags values
* @{
*/
#define CONN_CAN_DONTWAIT (1) /**< Do not wait for Tx confirmation when sending */
#define CONN_CAN_RECVONLY (2) /**< Do not send anything on the bus */
/** @} */
/**
* @brief RAW CAN connection
*/
typedef struct conn_can_raw {
int ifnum; /**< Interface number of the can device */
int flags; /**< Config flags for that conn object */
size_t count; /**< number of filters set */
struct can_filter *filter; /**< list of filter */
mbox_t mbox; /**< mbox */
/**
* message queue
*/
msg_t mbox_queue[CONN_CAN_RAW_MBOX_SIZE];
} conn_can_raw_t;
/**
* @brief Create can connection socket
*
* @param[inout] conn CAN connection
* @param[in] filter list of filters to set
* @param[in] count number of filters in @p filter
* @param[in] ifnum can device Interface
* @param[in] flags conn flags to set (CONN_CAN_RECVONLY)
*
* @return 0 if socket was successfully connected
* @return any other negative number in case of an error
*/
int conn_can_raw_create(conn_can_raw_t *conn, struct can_filter *filter, size_t count,
int ifnum, int flags);
/**
* @brief Close can connection socket
*
* @param[in] conn CAN connection
*
* @return 0 if conn is closed correctly
* @return any other negative number in case of an error.
*/
int conn_can_raw_close(conn_can_raw_t *conn);
/**
* @brief Generic can receive
*
* @param[in] conn CAN connection
* @param[out] frame CAN frame to receive
* @param[in] timeout timeout in us, 0 for infinite
*
* @return the number of bytes received
* @return any other negative number in case of an error
*/
int conn_can_raw_recv(conn_can_raw_t *conn, struct can_frame *frame, uint32_t timeout);
/**
* @brief Generic can send
*
* @param[in] conn CAN connection
* @param[in] frame frame to send
* @param[in] flags make function blocked or not
* (CONN_CAN_DONTWAIT to ignore tx confirmation)
*
* @return the number of bytes sent
* @return any other negative number in case of an error
*/
int conn_can_raw_send(conn_can_raw_t *conn, const struct can_frame *frame, int flags);
/**
* @brief Set raw CAN filters
*
* If filters were already set for this connection, it first unsets the previous filters
* and sets the new ones.
*
* @param[in] conn CAN connection
* @param[in] filter list of filters to set
* @param[in] count number of filters in @p filter
*
* @return 0 if can filters were successfully set
* @return any other negative number in case of an error
*/
int conn_can_raw_set_filter(conn_can_raw_t *conn, struct can_filter *filter, size_t count);
#ifdef __cplusplus
}
#endif
#endif /* CAN_CONN_RAW_H */
/** @} */