mirror of
https://github.com/apache/nuttx.git
synced 2025-05-08 22:32:04 +08:00
arch/sim: add CAN support based on host SocketCAN
Add CAN support for sim target based on host SocketCAN interface. Tested with virtual CAN on Linux but should work also with hardware CAN cards supported by host. Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
parent
7ea8b59a59
commit
76e1b80076
@ -227,6 +227,29 @@ config SIM_NETUSRSOCK
|
||||
|
||||
endchoice
|
||||
|
||||
config SIM_CANDEV
|
||||
bool "Simulated CAN Device"
|
||||
default n
|
||||
---help---
|
||||
Build in support for a simulated CAN device.
|
||||
|
||||
if SIM_CANDEV
|
||||
|
||||
config SIM_CANDEV_CHAR
|
||||
bool "Simulated CAN Device as CAN character driver"
|
||||
default n
|
||||
depends on CAN
|
||||
select ARCH_HAVE_CAN_ERRORS
|
||||
|
||||
config SIM_CANDEV_SOCK
|
||||
bool "Simulated CAN Device as SocketCAN"
|
||||
default n
|
||||
depends on NET_CAN
|
||||
select NET_CAN_HAVE_ERRORS
|
||||
select NET_CAN_HAVE_CANFD
|
||||
|
||||
endif # SIM_CANDEV
|
||||
|
||||
if SIM_NETDEV
|
||||
|
||||
choice
|
||||
|
@ -261,6 +261,18 @@ ifeq ($(CONFIG_SIM_LIBUSB),y)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_CANDEV),y)
|
||||
HOSTSRCS += sim_hostcan.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_CANDEV_CHAR),y)
|
||||
CSRCS += sim_canchar.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_CANDEV_SOCK),y)
|
||||
CSRCS += sim_cansock.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RPMSG_VIRTIO_LITE),y)
|
||||
CSRCS += sim_rpmsg_virtio.c
|
||||
endif
|
||||
|
@ -264,6 +264,18 @@ if(CONFIG_SIM_USB_HOST)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_SIM_CANDEV)
|
||||
list(APPEND HOSTSRCS sim_hostcan.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SIM_CANDEV_CHAR)
|
||||
list(APPEND SRCS sim_canchar.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SIM_CANDEV_SOCK)
|
||||
list(APPEND SRCS sim_cansock.c)
|
||||
endif()
|
||||
|
||||
list(APPEND HOSTSRCS sim_hostfs.c)
|
||||
list(APPEND HOST_DEFINITIONS CONFIG_NAME_MAX=${CONFIG_NAME_MAX})
|
||||
|
||||
|
186
arch/sim/src/sim/posix/sim_hostcan.c
Normal file
186
arch/sim/src/sim/posix/sim_hostcan.c
Normal file
@ -0,0 +1,186 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/posix/sim_hostcan.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
#include "sim_hostcan.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_init
|
||||
****************************************************************************/
|
||||
|
||||
int host_can_init(struct sim_can_s *can, int devidx)
|
||||
{
|
||||
struct sockaddr_can addr;
|
||||
struct ifreq ifr;
|
||||
int enable_canfd = 1;
|
||||
int ret;
|
||||
|
||||
/* Get socket */
|
||||
|
||||
can->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (can->fd < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Get SocketCAN interface */
|
||||
|
||||
snprintf(ifr.ifr_name, IFNAMSIZ, "can%d", devidx);
|
||||
ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
|
||||
if (!ifr.ifr_ifindex)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
/* Switch to CAN FD mode */
|
||||
|
||||
ret = setsockopt(can->fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd,
|
||||
sizeof(enable_canfd));
|
||||
if (ret < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Bind socket */
|
||||
|
||||
ret = bind(can->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_read
|
||||
*
|
||||
* Description:
|
||||
* Read data from host CAN interface.
|
||||
*
|
||||
* Assumption:
|
||||
* NuttX canfd_frame is byte compatible with host canfd_frame
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int host_can_read(struct sim_can_s *can, void *frame)
|
||||
{
|
||||
if (!can->ifup || can->fd < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return read(can->fd, frame, sizeof(struct canfd_frame));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_send
|
||||
*
|
||||
* Description:
|
||||
* Send data on host CAN interface.
|
||||
*
|
||||
* Assumption:
|
||||
* NuttX canfd_frame is byte compatible with host canfd_frame
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int host_can_send(struct sim_can_s *can, void *frame, size_t len)
|
||||
{
|
||||
if (!can->ifup || can->fd < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (len != sizeof(struct canfd_frame) && len != sizeof(struct can_frame))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return write(can->fd, frame, len);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_ifup
|
||||
****************************************************************************/
|
||||
|
||||
int host_can_ifup(struct sim_can_s *can)
|
||||
{
|
||||
can->ifup = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_ifdown
|
||||
****************************************************************************/
|
||||
|
||||
int host_can_ifdown(struct sim_can_s *can)
|
||||
{
|
||||
can->ifup = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: host_can_avail
|
||||
****************************************************************************/
|
||||
|
||||
bool host_can_avail(struct sim_can_s *can)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fdset;
|
||||
|
||||
if (!can->ifup || can->fd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Wait for data on the user channel (or a timeout) */
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(can->fd, &fdset);
|
||||
|
||||
return select(can->fd + 1, &fdset, NULL, NULL, &tv) > 0;
|
||||
}
|
373
arch/sim/src/sim/sim_canchar.c
Normal file
373
arch/sim/src/sim/sim_canchar.c
Normal file
@ -0,0 +1,373 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/sim_canchar.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
|
||||
#include <nuttx/can/can.h>
|
||||
#include <nuttx/can.h>
|
||||
|
||||
#include "sim_hostcan.h"
|
||||
#include "sim_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SIM_CAN_WORK_DELAY USEC2TICK(1000)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sim_canchar_s
|
||||
{
|
||||
struct can_dev_s dev; /* CAN character device */
|
||||
struct sim_can_s host; /* Host CAN handler */
|
||||
struct work_s worker; /* Work queue for RX */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* CAN driver methods */
|
||||
|
||||
static void sim_can_reset(struct can_dev_s *dev);
|
||||
static int sim_can_setup(struct can_dev_s *dev);
|
||||
static void sim_can_shutdown(struct can_dev_s *dev);
|
||||
static void sim_can_rxint(struct can_dev_s *dev, bool enable);
|
||||
static void sim_can_txint(struct can_dev_s *dev, bool enable);
|
||||
static int sim_can_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg);
|
||||
static int sim_can_remoterequest(struct can_dev_s *dev, uint16_t id);
|
||||
static int sim_can_send(struct can_dev_s *dev, struct can_msg_s *msg);
|
||||
static bool sim_can_txready(struct can_dev_s *dev);
|
||||
static bool sim_can_txempty(struct can_dev_s *dev);
|
||||
static void sim_can_work(void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct can_ops_s g_sim_can_ops =
|
||||
{
|
||||
.co_reset = sim_can_reset,
|
||||
.co_setup = sim_can_setup,
|
||||
.co_shutdown = sim_can_shutdown,
|
||||
.co_rxint = sim_can_rxint,
|
||||
.co_txint = sim_can_txint,
|
||||
.co_ioctl = sim_can_ioctl,
|
||||
.co_remoterequest = sim_can_remoterequest,
|
||||
.co_send = sim_can_send,
|
||||
.co_txready = sim_can_txready,
|
||||
.co_txempty = sim_can_txempty,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_reset
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_reset(struct can_dev_s *dev)
|
||||
{
|
||||
/* Nothing is here */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_setup
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_setup(struct can_dev_s *dev)
|
||||
{
|
||||
struct sim_canchar_s *priv = dev->cd_priv;
|
||||
int ret;
|
||||
|
||||
ret = host_can_ifup(&priv->host);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start RX work */
|
||||
|
||||
return work_queue(HPWORK, &priv->worker, sim_can_work, priv, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_shutdown
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_shutdown(struct can_dev_s *dev)
|
||||
{
|
||||
struct sim_canchar_s *priv = dev->cd_priv;
|
||||
|
||||
/* Cancel work */
|
||||
|
||||
work_cancel(HPWORK, &priv->worker);
|
||||
|
||||
host_can_ifdown(&priv->host);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_rxint
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_rxint(struct can_dev_s *dev, bool enable)
|
||||
{
|
||||
/* Nothing is here */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_txint
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_txint(struct can_dev_s *dev, bool enable)
|
||||
{
|
||||
/* Nothing is here */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_ioctl
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_remoterequest
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_remoterequest(struct can_dev_s *dev, uint16_t id)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_send
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_send(struct can_dev_s *dev, struct can_msg_s *msg)
|
||||
{
|
||||
struct sim_canchar_s *priv = dev->cd_priv;
|
||||
|
||||
if (!msg->cm_hdr.ch_edl)
|
||||
{
|
||||
struct can_frame frame;
|
||||
|
||||
frame.can_id = msg->cm_hdr.ch_id;
|
||||
frame.can_dlc = msg->cm_hdr.ch_dlc;
|
||||
|
||||
if (msg->cm_hdr.ch_rtr)
|
||||
{
|
||||
frame.can_id |= CAN_RTR_FLAG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_EXTID
|
||||
/* Extended frame */
|
||||
|
||||
if (msg->cm_hdr.ch_extid)
|
||||
{
|
||||
frame.can_id |= CAN_EFF_FLAG;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(frame.data, msg->cm_data, frame.can_dlc);
|
||||
|
||||
return host_can_send(&priv->host, &frame, sizeof(struct can_frame));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct canfd_frame frame;
|
||||
|
||||
frame.can_id = msg->cm_hdr.ch_id;
|
||||
|
||||
if (msg->cm_hdr.ch_rtr)
|
||||
{
|
||||
frame.can_id |= CAN_RTR_FLAG;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CAN_EXTID
|
||||
if (msg->cm_hdr.ch_extid)
|
||||
{
|
||||
frame.can_id |= CAN_EFF_FLAG;
|
||||
}
|
||||
#endif
|
||||
|
||||
frame.flags = CANFD_FDF;
|
||||
|
||||
if (msg->cm_hdr.ch_brs)
|
||||
{
|
||||
frame.flags |= CANFD_BRS;
|
||||
}
|
||||
|
||||
if (msg->cm_hdr.ch_esi)
|
||||
{
|
||||
frame.flags |= CANFD_ESI;
|
||||
}
|
||||
|
||||
frame.len = can_dlc2bytes(msg->cm_hdr.ch_dlc);
|
||||
|
||||
memcpy(frame.data, msg->cm_data, frame.len);
|
||||
|
||||
return host_can_send(&priv->host, &frame, sizeof(struct canfd_frame));
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_txready
|
||||
****************************************************************************/
|
||||
|
||||
static bool sim_can_txready(struct can_dev_s *dev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_txempty
|
||||
****************************************************************************/
|
||||
|
||||
static bool sim_can_txempty(struct can_dev_s *dev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_work
|
||||
*
|
||||
* Description:
|
||||
* Feed pending packets on the host sockets into the CAN stack.
|
||||
*
|
||||
* Assumption:
|
||||
* NuttX canfd_frame is byte compatible with host canfd_frame
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_work(void *arg)
|
||||
{
|
||||
struct sim_canchar_s *priv = arg;
|
||||
struct canfd_frame frame;
|
||||
struct can_hdr_s hdr;
|
||||
int ret;
|
||||
|
||||
if (host_can_avail(&priv->host))
|
||||
{
|
||||
/* Wait for data from host stack */
|
||||
|
||||
ret = host_can_read(&priv->host, &frame);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("host_can_read failed %d\n", ret);
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
/* Get header */
|
||||
|
||||
hdr.ch_id = frame.can_id & CAN_ERR_MASK;
|
||||
hdr.ch_dlc = can_bytes2dlc(frame.len);
|
||||
hdr.ch_rtr = frame.can_id & CAN_RTR_FLAG;
|
||||
#ifdef CONFIG_CAN_ERRORS
|
||||
hdr.ch_error = frame.can_id & CAN_ERR_FLAG;
|
||||
#endif
|
||||
#ifdef CONFIG_CAN_EXTID
|
||||
hdr.ch_extid = frame.can_id & CAN_EFF_FLAG;
|
||||
#endif
|
||||
#ifdef CONFIG_CAN_FD
|
||||
hdr.ch_edl = frame.flags & CANFD_FDF;
|
||||
hdr.ch_brs = frame.flags & CANFD_BRS;
|
||||
hdr.ch_esi = frame.flags & CANFD_ESI;
|
||||
#endif
|
||||
hdr.ch_tcf = 0;
|
||||
#ifdef CONFIG_CAN_TIMESTAMP
|
||||
hdr.ch_ts = 0;
|
||||
#endif
|
||||
|
||||
/* Notify upper-half */
|
||||
|
||||
can_receive(&priv->dev, &hdr, frame.data);
|
||||
}
|
||||
|
||||
nodata:
|
||||
work_queue(HPWORK, &priv->worker, sim_can_work, priv, SIM_CAN_WORK_DELAY);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_canchar_initialize
|
||||
****************************************************************************/
|
||||
|
||||
int sim_canchar_initialize(int devidx, int devno)
|
||||
{
|
||||
struct sim_canchar_s *priv;
|
||||
char devpath[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
/* Allocate device */
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct sim_canchar_s));
|
||||
if (!priv)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Get host interface */
|
||||
|
||||
ret = host_can_init(&priv->host, devidx);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("host_can_init failed %d\n", ret);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialzie CAN character driver */
|
||||
|
||||
priv->dev.cd_ops = &g_sim_can_ops;
|
||||
priv->dev.cd_priv = priv;
|
||||
|
||||
/* Register CAN device */
|
||||
|
||||
snprintf(devpath, PATH_MAX, "/dev/can%d", devno);
|
||||
ret = can_register(devpath, &priv->dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("can_register failed %d\n", ret);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
258
arch/sim/src/sim/sim_cansock.c
Normal file
258
arch/sim/src/sim/sim_cansock.c
Normal file
@ -0,0 +1,258 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/sim_cansock.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/can.h>
|
||||
|
||||
#include "sim_hostcan.h"
|
||||
#include "sim_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SIM_CAN_WORK_DELAY USEC2TICK(1000)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sim_cansock_s
|
||||
{
|
||||
struct net_driver_s dev; /* Interface understood by the network */
|
||||
struct sim_can_s host; /* Host CAN handler */
|
||||
struct work_s worker; /* Work queue for RX */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_ifup(struct net_driver_s *dev);
|
||||
static int sim_can_ifdown(struct net_driver_s *dev);
|
||||
static int sim_can_txavail(struct net_driver_s *dev);
|
||||
#ifdef CONFIG_NETDEV_IOCTL
|
||||
static int sim_can_netdev_ioctl(struct net_driver_s *dev, int cmd,
|
||||
unsigned long arg);
|
||||
#endif
|
||||
static void sim_can_work(void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_ifup
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_ifup(struct net_driver_s *dev)
|
||||
{
|
||||
struct sim_cansock_s *priv = (struct sim_cansock_s *)dev;
|
||||
int ret;
|
||||
|
||||
ret = host_can_ifup(&priv->host);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start RX work */
|
||||
|
||||
return work_queue(HPWORK, &priv->worker, sim_can_work, priv, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_ifdown
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_ifdown(struct net_driver_s *dev)
|
||||
{
|
||||
struct sim_cansock_s *priv = (struct sim_cansock_s *)dev;
|
||||
|
||||
/* Cancel work */
|
||||
|
||||
work_cancel(HPWORK, &priv->worker);
|
||||
|
||||
return host_can_ifdown(&priv->host);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_txpoll
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_txpoll(FAR struct net_driver_s *dev)
|
||||
{
|
||||
struct sim_cansock_s *priv = (struct sim_cansock_s *)dev;
|
||||
|
||||
if (priv->dev.d_len > 0)
|
||||
{
|
||||
/* Send the packet */
|
||||
|
||||
return host_can_send(&priv->host, priv->dev.d_buf, priv->dev.d_len);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_txavail
|
||||
*
|
||||
* Assumption:
|
||||
* NuttX canfd_frame is byte compatible with host canfd_frame.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_txavail(struct net_driver_s *dev)
|
||||
{
|
||||
struct sim_cansock_s *priv = (struct sim_cansock_s *)dev;
|
||||
|
||||
/* Ignore the notification if the interface is not yet up */
|
||||
|
||||
net_lock();
|
||||
if (IFF_IS_UP(priv->dev.d_flags))
|
||||
{
|
||||
devif_poll(&priv->dev, sim_can_txpoll);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NETDEV_IOCTL
|
||||
/****************************************************************************
|
||||
* Name: sim_can_netdev_ioctl
|
||||
****************************************************************************/
|
||||
|
||||
static int sim_can_netdev_ioctl(struct net_driver_s *dev, int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_can_work
|
||||
*
|
||||
* Description:
|
||||
* Feed pending packets on the host sockets into the CAN stack.
|
||||
*
|
||||
* Assumption:
|
||||
* NuttX canfd_frame is byte compatible with host canfd_frame.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void sim_can_work(void *arg)
|
||||
{
|
||||
struct sim_cansock_s *priv = arg;
|
||||
struct canfd_frame hframe;
|
||||
int ret;
|
||||
|
||||
if (host_can_avail(&priv->host))
|
||||
{
|
||||
/* Wait for data from host stack */
|
||||
|
||||
ret = host_can_read(&priv->host, &hframe);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("host_can_read failed %d\n", ret);
|
||||
goto nodata;
|
||||
}
|
||||
|
||||
/* Copy the buffer pointer to priv->dev.. Set amount of data
|
||||
* in priv->dev.d_len
|
||||
*/
|
||||
|
||||
net_lock();
|
||||
priv->dev.d_len = ret;
|
||||
priv->dev.d_buf = (FAR uint8_t *)&hframe;
|
||||
|
||||
/* Send to socket interface */
|
||||
|
||||
NETDEV_RXPACKETS(&priv->dev);
|
||||
|
||||
can_input(&priv->dev);
|
||||
net_unlock();
|
||||
}
|
||||
|
||||
nodata:
|
||||
work_queue(HPWORK, &priv->worker, sim_can_work, priv, SIM_CAN_WORK_DELAY);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sim_cansock_initialize
|
||||
****************************************************************************/
|
||||
|
||||
int sim_cansock_initialize(int devidx)
|
||||
{
|
||||
struct sim_cansock_s *priv;
|
||||
int ret;
|
||||
|
||||
/* Allocate device */
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct sim_cansock_s));
|
||||
if (!priv)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initialize host interface */
|
||||
|
||||
ret = host_can_init(&priv->host, devidx);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("host_can_init failed %d\n", ret);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize the driver structure */
|
||||
|
||||
priv->dev.d_ifup = sim_can_ifup;
|
||||
priv->dev.d_ifdown = sim_can_ifdown;
|
||||
priv->dev.d_txavail = sim_can_txavail;
|
||||
#ifdef CONFIG_NETDEV_IOCTL
|
||||
priv->dev.d_ioctl = sim_can_netdev_ioctl;
|
||||
#endif
|
||||
priv->dev.d_private = priv;
|
||||
|
||||
ret = netdev_register(&priv->dev, NET_LL_CAN);
|
||||
if (ret < 0)
|
||||
{
|
||||
canerr("netdev_register failed %d\n", ret);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
66
arch/sim/src/sim/sim_hostcan.h
Normal file
66
arch/sim/src/sim/sim_hostcan.h
Normal file
@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/sim_hostcan.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_SIM_SRC_SIM_CAN_H
|
||||
#define __ARCH_SIM_SRC_SIM_CAN_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __SIM__
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Reserve data for maximum CANFD frame */
|
||||
|
||||
#define SIM_CAN_MAX_DLEN 64
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct sim_can_s
|
||||
{
|
||||
int fd;
|
||||
bool ifup;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Host CAN interface */
|
||||
|
||||
int host_can_init(struct sim_can_s *can, int devidx);
|
||||
int host_can_read(struct sim_can_s *can, void *frame);
|
||||
int host_can_send(struct sim_can_s *can, void *frame, size_t len);
|
||||
int host_can_ifup(struct sim_can_s *can);
|
||||
int host_can_ifdown(struct sim_can_s *can);
|
||||
bool host_can_avail(struct sim_can_s *can);
|
||||
|
||||
#endif /* __ARCH_SIM_SRC_SIM_CAN_H */
|
@ -484,6 +484,18 @@ int sim_usbhost_initialize(void);
|
||||
int sim_usbhost_loop(void);
|
||||
#endif
|
||||
|
||||
/* sim_canchar.c ************************************************************/
|
||||
|
||||
#ifdef CONFIG_SIM_CANDEV_CHAR
|
||||
int sim_canchar_initialize(int devidx, int devno);
|
||||
#endif
|
||||
|
||||
/* sim_cansock.c ************************************************************/
|
||||
|
||||
#ifdef CONFIG_SIM_CANDEV_SOCK
|
||||
int sim_cansock_initialize(int devidx);
|
||||
#endif
|
||||
|
||||
/* Debug ********************************************************************/
|
||||
|
||||
#ifdef CONFIG_STACK_COLORATION
|
||||
|
Loading…
x
Reference in New Issue
Block a user