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:
parent
63ca443b05
commit
ab5f8548f2
@ -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)))
|
||||
|
@ -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
|
||||
|
@ -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
3
sys/can/conn/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = conn_can
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
419
sys/can/conn/isotp.c
Normal file
419
sys/can/conn/isotp.c
Normal 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
279
sys/can/conn/raw.c
Normal 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;
|
||||
}
|
202
sys/include/can/conn/isotp.h
Normal file
202
sys/include/can/conn/isotp.h
Normal 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
138
sys/include/can/conn/raw.h
Normal 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 */
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user