You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/02 14:09:22 UTC
[incubator-nuttx] 04/31: PoC S32K1XX FlexCAN sends CAN msgs through
SocketCAN
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch SocketCAN
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit d600a3dca452519c129d04f03244dff048970428
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Wed Feb 19 11:24:31 2020 +0100
PoC S32K1XX FlexCAN sends CAN msgs through SocketCAN
---
arch/arm/src/s32k1xx/Kconfig | 4 +
arch/arm/src/s32k1xx/Make.defs | 4 +
arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h | 57 +-
arch/arm/src/s32k1xx/s32k1xx_flexcan.c | 1422 ++++++++++++++++++++
.../arm/src/s32k1xx/s32k1xx_flexcan.h | 120 +-
include/nuttx/can.h | 279 ++++
include/nuttx/net/can.h | 88 ++
include/nuttx/net/net.h | 3 +-
net/can/Make.defs | 6 +
net/can/can.h | 75 ++
net/{devif/devif_pktsend.c => can/can_callback.c} | 70 +-
net/can/can_poll.c | 107 ++
net/can/can_send.c | 264 ++++
net/can/can_sockif.c | 81 +-
net/devif/Make.defs | 2 +-
net/devif/devif.h | 4 +-
net/devif/devif_pktsend.c | 2 +-
net/devif/devif_poll.c | 49 +
net/local/local_sendpacket.c | 1 +
net/netdev/netdev_register.c | 12 +
20 files changed, 2487 insertions(+), 163 deletions(-)
diff --git a/arch/arm/src/s32k1xx/Kconfig b/arch/arm/src/s32k1xx/Kconfig
index 63e0cd9..68f9bb6 100644
--- a/arch/arm/src/s32k1xx/Kconfig
+++ b/arch/arm/src/s32k1xx/Kconfig
@@ -150,6 +150,10 @@ config S32K1XX_ENET
default n
depends on S32K1XX_HAVE_ENET
+config S32K1XX_FLEXCAN
+ bool "FLEXCAN"
+ default n
+
menuconfig S32K1XX_LPI2C0
bool "LPI2C0"
default n
diff --git a/arch/arm/src/s32k1xx/Make.defs b/arch/arm/src/s32k1xx/Make.defs
index a06fa86..940dc05 100644
--- a/arch/arm/src/s32k1xx/Make.defs
+++ b/arch/arm/src/s32k1xx/Make.defs
@@ -87,6 +87,10 @@ ifeq ($(CONFIG_S32K1XX_ENET),y)
CHIP_CSRCS += s32k1xx_enet.c
endif
+ifeq ($(CONFIG_S32K1XX_FLEXCAN),y)
+CHIP_CSRCS += s32k1xx_flexcan.c
+endif
+
ifeq ($(CONFIG_S32K1XX_RTC),y)
CHIP_CSRCS += s32k1xx_rtc.c
endif
diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
index fa9c36f..03d3d90 100644
--- a/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
+++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_flexcan.h
@@ -66,6 +66,9 @@
#define S32K1XX_CAN_CRCR_OFFSET 0x0044 /* CRC Register */
#define S32K1XX_CAN_RXFGMASK_OFFSET 0x0048 /* Rx FIFO Global Mask Register */
#define S32K1XX_CAN_RXFIR_OFFSET 0x004c /* Rx FIFO Information Register */
+#define S32K1XX_CAN_CBT_OFFSET 0x0050 /* CAN Bit Timing register */
+
+#define S32K1XX_CAN_MB_OFFSET 0x0080 /* CAN MB register */
#define S32K1XX_CAN_RXIMR_OFFSET(n) (0x0880 + ((n) << 2)) /* Rn Individual Mask Registers */
# define S32K1XX_CAN_RXIMR0_OFFSET 0x0880 /* R0 Individual Mask Registers */
@@ -162,6 +165,11 @@
#define S32K1XX_CAN0_CRCR (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_CRCR_OFFSET)
#define S32K1XX_CAN0_RXFGMASK (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXFGMASK_OFFSET)
#define S32K1XX_CAN0_RXFIR (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXFIR_OFFSET)
+#define S32K1XX_CAN0_CBT (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_CBT_OFFSET)
+#define S32K1XX_CAN0_MB (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_MB_OFFSET)
+#define S32K1XX_CAN0_FDCTRL (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCTRL_OFFSET)
+#define S32K1XX_CAN0_FDCBT (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCBT_OFFSET)
+#define S32K1XX_CAN0_FDCRC (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_FDCRC_OFFSET)
#define S32K1XX_CAN0_RXIMR(n) (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXIMR_OFFSET(n))
# define S32K1XX_CAN0_RXIMR0 (S32K1XX_FLEXCAN0_BASE + S32K1XX_CAN_RXIMR0_OFFSET)
@@ -340,7 +348,8 @@
# define CAN_MCR_IDAM_FMTB (1 << CAN_MCR_IDAM_SHIFT) /* Format B: Two full (or partial) IDs */
# define CAN_MCR_IDAM_FMTC (2 << CAN_MCR_IDAM_SHIFT) /* Format C: Four partial IDs */
# define CAN_MCR_IDAM_FMTD (3 << CAN_MCR_IDAM_SHIFT) /* Format D: All frames rejected */
- /* Bits 10-11: Reserved */
+ /* Bit 10: Reserved */
+#define CAN_MCR_FDEN (1 << 11) /* Bit 11: CAN FD operation enable */
#define CAN_MCR_AEN (1 << 12) /* Bit 12: Abort Enable */
#define CAN_MCR_LPRIOEN (1 << 13) /* Bit 13: Local Priority Enable */
/* Bits 14-15: Reserved */
@@ -454,7 +463,12 @@
#define CAN_IFLAG1(n) (1 << (n)) /* Bit n: Buffer MBn Interrupt, n=0..4,8..31 */
/* Control 2 Register */
- /* Bits 0-15: Reserved */
+ /* Bits 0-10: Reserved */
+#define CAN_CTRL2_EDFLTDIS (1 << 11) /* Bit 11: Edge Filter Disable */
+#define CAN_CTRL2_ISOCANFDEN (1 << 12) /* Bit 12: ISO CAN FD Enable */
+ /* Bit 13: Reserved */
+#define CAN_CTRL2_PREXCEN (1 << 14) /* Bit 14: Protocol Exception Enable */
+#define CAN_CTRL2_TIMER_SRC (1 << 15) /* Bit 15: Timer Source */
#define CAN_CTRL2_EACEN (1 << 16) /* Bit 16: Entire Frame Arbitration Field Comparison Enable (Rx) */
#define CAN_CTRL2_RRS (1 << 17) /* Bit 17: Remote Request Storing */
#define CAN_CTRL2_MRP (1 << 18) /* Bit 18: Mailboxes Reception Priority */
@@ -506,6 +520,45 @@
#define CAN_RXFIR_IDHIT_SHIFT (0) /* Bits 0-8: Identifier Acceptance Filter Hit Indicator */
#define CAN_RXFIR_IDHIT_MASK (0x1ff << CAN_RXFIR_IDHIT_SHIFT)
+/* CAN Bit Timing register (CBT) */
+
+/* CBT Bit Fields */
+#define CAN_CBT_EPSEG2(x) (((uint32_t)(((uint32_t)(x)) << 0)) & 0x1F)
+#define CAN_CBT_EPSEG1(x) (((uint32_t)(((uint32_t)(x)) << 5)) & 0x3E0)
+#define CAN_CBT_EPROPSEG(x) (((uint32_t)(((uint32_t)(x)) << 10)) & 0xFC00)
+#define CAN_CBT_ERJW(x) (((uint32_t)(((uint32_t)(x)) << 16)) & 0x1F0000)
+#define CAN_CBT_EPRESDIV(x) (((uint32_t)(((uint32_t)(x)) << 21)) & 0x7FE00000)
+#define CAN_CBT_BTF (1 << 31) /* Bit 31: Bit Timing Format Enable */
+
+/* CAN MB TX codes */
+#define CAN_TXMB_INACTIVE 0x8 /* MB is not active.*/
+#define CAN_TXMB_ABORT 0x9 /* MB is aborted.*/
+#define CAN_TXMB_DATAORREMOTE 0xC /* MB is a TX Data Frame(when MB RTR = 0) or */
+ /* MB is a TX Remote Request Frame (when MB RTR = 1).*/
+#define CAN_TXMB_TANSWER 0xE /* MB is a TX Response Request Frame from */
+ /* an incoming Remote Request Frame.*/
+#define CAN_TXMB_NOTUSED 0xF /* Not used.*/
+
+/* CAN FD Control register (FDCTRL) */
+#define CAN_FDCTRL_TDCVAL(x) (((uint32_t)(((uint32_t)(x)) << 0)) & 0x3F)
+#define CAN_FDCTRL_TDCOFF(x) (((uint32_t)(((uint32_t)(x)) << 8)) & 0x1F00)
+#define CAN_FDCTRL_TDCEN (1 << 14) /* Bit 14: TDC fail */
+#define CAN_FDCTRL_TDCEN (1 << 15) /* Bit 15: TDC enable */
+#define CAN_FDCTRL_MBDSR0(x) (((uint32_t)(((uint32_t)(x)) << 16)) & 0x30000)
+#define CAN_FDCTRL_FDRATE (1 << 31) /* Bit 31: FD rate */
+
+/* FDCBT Bit Fields */
+#define CAN_FDCBT_FPSEG2(x) (((uint32_t)(((uint32_t)(x)) << 0)) & 0x7)
+#define CAN_FDCBT_FPSEG1(x) (((uint32_t)(((uint32_t)(x)) << 5)) & 0xE0)
+#define CAN_FDCBT_FPROPSEG(x) (((uint32_t)(((uint32_t)(x)) << 10)) & 0x7C00)
+#define CAN_FDCBT_FRJW(x) (((uint32_t)(((uint32_t)(x)) << 16)) & 0x70000)
+#define CAN_FDCBT_FPRESDIV(x) (((uint32_t)(((uint32_t)(x)) << 20)) & 0x3FF00000)
+
+/* FDCRC Bit Fields */
+#define CAN_FDCRC_FD_TXCRC(x) (((uint32_t)(((uint32_t)(x)) << 0)) & 0x1FFFFF)
+#define CAN_FDCRC_FD_MBCRC(x) (((uint32_t)(((uint32_t)(x)) << 24)) & 0x7F000000)
+
+
/* Rn Individual Mask Registers */
#define CAN_RXIMR(n) (1 << (n)) /* Bit n: Individual Mask Bits */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
new file mode 100644
index 0000000..74a21b8
--- /dev/null
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
@@ -0,0 +1,1422 @@
+/****************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_flexcan.c
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/can.h>
+#include <nuttx/wdog.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/mii.h>
+#include <nuttx/net/arp.h>
+#include <nuttx/net/phy.h>
+#include <nuttx/net/netdev.h>
+
+#ifdef CONFIG_NET_PKT
+# include <nuttx/net/pkt.h>
+#endif
+
+#include "up_arch.h"
+#include "chip.h"
+#include "s32k1xx_config.h"
+#include "hardware/s32k1xx_flexcan.h"
+#include "hardware/s32k1xx_pinmux.h"
+#include "s32k1xx_periphclocks.h"
+#include "s32k1xx_pin.h"
+#include "s32k1xx_flexcan.h"
+
+#ifdef CONFIG_S32K1XX_FLEXCAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required
+#else
+
+ /* Select work queue. Always use the LP work queue if available. If not,
+ * then LPWORK will re-direct to the HP work queue.
+ *
+ * NOTE: However, the network should NEVER run on the high priority work
+ * queue! That queue is intended only to service short back end interrupt
+ * processing that never suspends. Suspending the high priority work queue
+ * may bring the system to its knees!
+ */
+
+# define ETHWORK LPWORK
+#endif
+
+/* CONFIG_S32K1XX_FLEXCAN_NETHIFS determines the number of physical interfaces
+ * that will be supported.
+ */
+/*
+#if CONFIG_S32K1XX_FLEXCAN_NETHIFS != 1
+# error "CONFIG_S32K1XX_FLEXCAN_NETHIFS must be one for now"
+#endif
+
+#if CONFIG_S32K1XX_FLEXCAN_NTXBUFFERS < 1
+# error "Need at least one TX buffer"
+#endif
+
+#if CONFIG_S32K1XX_FLEXCAN_NRXBUFFERS < 1
+# error "Need at least one RX buffer"
+#endif*/
+
+#define S32K1XX_FLEXCAN_FIRST_TX_MB 10
+
+#define MaskStdID 0x000007FF;
+#define MaskExtID 0x1FFFFFFF;
+
+//Fixme nice variables/constants
+#define NumMBinFiFoAndFilters 10 //FIXME
+#define NumTxMesgBuffers 6
+#define HWMaxMB 16
+#define TXMBMask (0b111111 << NumMBinFiFoAndFilters)
+
+#define CAN_FIFO_NE (1 << 5)
+#define CAN_FIFO_OV (1 << 6)
+#define CAN_FIFO_WARN (1 << 7)
+
+static int peak_tx_mailbox_index_ = 0;
+
+
+
+
+/* Normally you would clean the cache after writing new values to the DMA
+ * memory so assure that the dirty cache lines are flushed to memory
+ * before the DMA occurs. And you would invalid the cache after a data is
+ * received via DMA so that you fetch the actual content of the data from
+ * the cache.
+ *
+ * These conditions are not fully supported here. If the write-throuch
+ * D-Cache is enabled, however, then many of these issues go away: The
+ * cache clean operation does nothing (because there are not dirty cache
+ * lines) and the cache invalid operation is innocuous (because there are
+ * never dirty cache lines to be lost; valid data will always be reloaded).
+ *
+ * At present, we simply insist that write through cache be enabled.
+ */
+
+#if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
+# error Write back D-Cache not yet supported
+#endif
+
+/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
+ * second.
+ */
+
+#define S32K1XX_WDDELAY (1*CLK_TCK)
+
+/* Align assuming that the D-Cache is enabled (probably 32-bytes).
+ *
+ * REVISIT: The size of descriptors and buffers must also be in even units
+ * of the cache line size That is because the operations to clean and
+ * invalidate the cache will operate on a full 32-byte cache line. If
+ * CONFIG_FLEXCAN_ENHANCEDBD is selected, then the size of the descriptor is
+ * 32-bytes (and probably already the correct size for the cache line);
+ * otherwise, the size of the descriptors much smaller, only 8 bytes.
+ */
+
+#define FLEXCAN_ALIGN ARMV7M_DCACHE_LINESIZE
+#define FLEXCAN_ALIGN_MASK (FLEXCAN_ALIGN - 1)
+#define FLEXCAN_ALIGN_UP(n) (((n) + FLEXCAN_ALIGN_MASK) & ~FLEXCAN_ALIGN_MASK)
+
+/* TX timeout = 1 minute */
+
+#define S32K1XX_TXTIMEOUT (60*CLK_TCK)
+#define MII_MAXPOLLS (0x1ffff)
+#define LINK_WAITUS (500*1000)
+#define LINK_NLOOPS (10)
+
+/* Interrupt groups */
+
+#define RX_INTERRUPTS (FLEXCAN_INT_RXF | FLEXCAN_INT_RXB)
+#define TX_INTERRUPTS FLEXCAN_INT_TXF
+#define ERROR_INTERRUPTS (FLEXCAN_INT_UN | FLEXCAN_INT_RL | FLEXCAN_INT_LC | \
+ FLEXCAN_INT_EBERR | FLEXCAN_INT_BABT | FLEXCAN_INT_BABR)
+
+/* The subset of errors that require us to reset the hardware - this list
+ * may need to be revisited if it's found that some error above leads to a
+ * locking up of the Ethernet interface.
+ */
+
+#define CRITICAL_ERROR (FLEXCAN_INT_UN | FLEXCAN_INT_RL | FLEXCAN_INT_EBERR )
+
+/* This is a helper pointer for accessing the contents of the Ethernet header */
+
+#define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
+
+#define S32K1XX_BUF_SIZE FLEXCAN_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+
+union TXcsType
+{
+ volatile uint32_t w;
+ struct
+ {
+ volatile uint32_t time_stamp : 16;
+ volatile uint32_t dlc : 4;
+ volatile uint32_t rtr : 1;
+ volatile uint32_t ide : 1;
+ volatile uint32_t srr : 1;
+ volatile uint32_t res : 1;
+ volatile uint32_t code : 4;
+ volatile uint32_t res2 : 4;
+ };
+};
+
+union RXcsType
+{
+ volatile uint32_t cs;
+ struct
+ {
+ volatile uint32_t time_stamp : 16;
+ volatile uint32_t dlc : 4;
+ volatile uint32_t rtr : 1;
+ volatile uint32_t ide : 1;
+ volatile uint32_t srr : 1;
+ volatile uint32_t res : 9;
+ };
+};
+
+union IDType
+{
+ volatile uint32_t w;
+ struct
+ {
+ volatile uint32_t ext : 29;
+ volatile uint32_t resex : 3;
+ };
+ struct
+ {
+ volatile uint32_t res : 18;
+ volatile uint32_t std : 11;
+ volatile uint32_t resstd : 3;
+ };
+};
+
+union DataType
+{
+ volatile uint32_t l;
+ volatile uint32_t h;
+ struct
+ {
+ volatile uint32_t b3 : 8;
+ volatile uint32_t b2 : 8;
+ volatile uint32_t b1 : 8;
+ volatile uint32_t b0 : 8;
+ volatile uint32_t b7 : 8;
+ volatile uint32_t b6 : 8;
+ volatile uint32_t b5 : 8;
+ volatile uint32_t b4 : 8;
+ };
+};
+
+struct MbTx
+{
+ union TXcsType CS;
+ union IDType ID;
+ union DataType data;
+};
+
+struct MbRx
+{
+ union RXcsType CS;
+ union IDType ID;
+ union DataType data;
+};
+
+/* The s32k1xx_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct s32k1xx_driver_s
+{
+ bool bifup; /* true:ifup false:ifdown */
+ uint8_t txtail; /* The oldest busy TX descriptor */
+ uint8_t txhead; /* The next TX descriptor to use */
+ uint8_t rxtail; /* The next RX descriptor to use */
+ uint8_t phyaddr; /* Selected PHY address */
+ WDOG_ID txpoll; /* TX poll timer */
+ WDOG_ID txtimeout; /* TX timeout timer */
+ struct work_s irqwork; /* For deferring interrupt work to the work queue */
+ struct work_s pollwork; /* For deferring poll work to the work queue */
+ struct enet_desc_s *txdesc; /* A pointer to the list of TX descriptor */
+ struct enet_desc_s *rxdesc; /* A pointer to the list of RX descriptors */
+
+ /* This holds the information visible to the NuttX network */
+
+ struct net_driver_s dev; /* Interface understood by the network */
+
+ struct MbRx *rx;
+ struct MbTx *tx;
+
+};
+
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct s32k1xx_driver_s g_flexcan[CONFIG_S32K1XX_ENET_NETHIFS];
+
+static uint8_t g_desc_pool[2000]
+ __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Utility functions */
+
+#ifndef S32K1XX_BUFFERS_SWAP
+# define s32k1xx_swap32(value) (value)
+# define s32k1xx_swap16(value) (value)
+#else
+#if 0 /* Use builtins if the compiler supports them */
+static inline uint32_t s32k1xx_swap32(uint32_t value);
+static inline uint16_t s32k1xx_swap16(uint16_t value);
+#else
+# define s32k1xx_swap32 __builtin_bswap32
+# define s32k1xx_swap16 __builtin_bswap16
+#endif
+#endif
+
+/* Common TX logic */
+
+static bool s32k1xx_txringfull(FAR struct s32k1xx_driver_s *priv);
+static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv);
+static int s32k1xx_txpoll(struct net_driver_s *dev);
+
+/* Interrupt handling */
+
+static void s32k1xx_dispatch(FAR struct s32k1xx_driver_s *priv);
+static void s32k1xx_receive(FAR struct s32k1xx_driver_s *priv);
+static void s32k1xx_txdone(FAR struct s32k1xx_driver_s *priv);
+
+static void s32k1xx_flexcan_interrupt_work(FAR void *arg);
+static int s32k1xx_flexcan_interrupt(int irq, FAR void *context,
+ FAR void *arg);
+
+/* Watchdog timer expirations */
+
+static void s32k1xx_txtimeout_work(FAR void *arg);
+static void s32k1xx_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void s32k1xx_poll_work(FAR void *arg);
+static void s32k1xx_polltimer_expiry(int argc, uint32_t arg, ...);
+
+/* NuttX callback functions */
+
+static int s32k1xx_ifup(struct net_driver_s *dev);
+static int s32k1xx_ifdown(struct net_driver_s *dev);
+
+static void s32k1xx_txavail_work(FAR void *arg);
+static int s32k1xx_txavail(struct net_driver_s *dev);
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int s32k1xx_addmac(struct net_driver_s *dev,
+ FAR const uint8_t *mac);
+static int s32k1xx_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd,
+ unsigned long arg);
+#endif
+
+/* Initialization */
+
+static void s32k1xx_initbuffers(struct s32k1xx_driver_s *priv);
+static void s32k1xx_reset(struct s32k1xx_driver_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+
+/****************************************************************************
+ * Function: s32k1xx_txringfull
+ *
+ * Description:
+ * Check if all of the TX descriptors are in use.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * true is the TX ring is full; false if there are free slots at the
+ * head index.
+ *
+ ****************************************************************************/
+
+static bool s32k1xx_txringfull(FAR struct s32k1xx_driver_s *priv)
+{
+ uint8_t txnext;
+
+ /* Check if there is room in the hardware to hold another outgoing
+ * packet. The ring is full if incrementing the head pointer would
+ * collide with the tail pointer.
+ */
+
+ txnext = priv->txhead + 1;
+
+ return priv->txtail == txnext;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_transmit
+ *
+ * Description:
+ * Start hardware transmission. Called either from the txdone interrupt
+ * handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ * May or may not be called from an interrupt handler. In either case,
+ * global interrupts are disabled, either explicitly or indirectly through
+ * interrupt handling logic.
+ *
+ ****************************************************************************/
+
+
+static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
+{
+ #warning Missing logic
+
+ struct can_frame *frame = (struct can_frame*)priv->dev.d_buf;
+
+ /*printf("CAN id: %i dlc: %i", frame->can_id, frame->can_dlc);
+
+ for(int i = 0; i < frame->can_dlc; i++){
+ printf(" %02X", frame->data[i]);
+ }
+ printf("\r\n");*/
+
+ /* Attempt to write frame */
+ uint32_t mbi = 0;
+ if ((getreg32(S32K1XX_CAN0_ESR2) & (CAN_ESR2_IMB | CAN_ESR2_VPS)) == (CAN_ESR2_IMB | CAN_ESR2_VPS))
+ {
+ mbi = (getreg32(S32K1XX_CAN0_ESR2) & CAN_ESR2_LPTM_MASK) >> CAN_ESR2_LPTM_SHIFT;
+ }
+
+ uint32_t mb_bit = 1 << (NumMBinFiFoAndFilters + mbi);
+
+ while (mbi < NumTxMesgBuffers)
+ {
+
+ if (priv->tx[mbi].CS.code != CAN_TXMB_DATAORREMOTE)
+ {
+ putreg32(mb_bit, S32K1XX_CAN0_IFLAG1);
+ break;
+ }
+ mb_bit <<= 1;
+ mbi++;
+ }
+
+ if (mbi == NumTxMesgBuffers)
+ {
+ return 0; // No transmission for you!
+ }
+
+ peak_tx_mailbox_index_ = (peak_tx_mailbox_index_ > mbi ? peak_tx_mailbox_index_ : mbi );
+
+ union TXcsType cs;
+ cs.code = CAN_TXMB_DATAORREMOTE;
+ struct MbTx* mb = &priv->tx[mbi];
+ mb->CS.code = CAN_TXMB_INACTIVE;
+
+ if (0) //FIXME detect Std or Ext id
+ {
+ cs.ide = 1;
+ mb->ID.ext = frame->can_id & MaskExtID;
+ }
+ else
+ {
+ mb->ID.std = frame->can_id & MaskStdID;
+ }
+
+ //cs.rtr = frame.isRemoteTransmissionRequest();
+
+ cs.dlc = frame->can_dlc;
+ //FIXME endian swap instruction or somekind
+ mb->data.b0 = frame->data[0];
+ mb->data.b1 = frame->data[1];
+ mb->data.b2 = frame->data[2];
+ mb->data.b3 = frame->data[3];
+ mb->data.b4 = frame->data[4];
+ mb->data.b5 = frame->data[5];
+ mb->data.b6 = frame->data[6];
+ mb->data.b7 = frame->data[7];
+
+ /*
+ * Registering the pending transmission so we can track its deadline and loopback it as needed
+ */
+ /*TxItem& txi = pending_tx_[mbi];
+ txi.deadline = tx_deadline;
+ txi.frame = frame;
+ txi.loopback = (flags & uavcan::CanIOFlagLoopback) != 0;
+ txi.abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0;
+ txi.pending = TxItem::busy;*/
+
+ mb->CS = cs; // Go.
+
+ uint32_t regval;
+ regval = getreg32(S32K1XX_CAN0_IMASK1);
+ regval |= mb_bit;
+ putreg32(regval, S32K1XX_CAN0_IMASK1);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txpoll
+ *
+ * Description:
+ * The transmitter is available, check if the network has any outgoing
+ * packets ready to send. This is a callback from devif_poll().
+ * devif_poll() may be called:
+ *
+ * 1. When the preceding TX packet send is complete,
+ * 2. When the preceding TX packet send timesout and the interface is reset
+ * 3. During normal TX polling
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ * May or may not be called from an interrupt handler. In either case,
+ * global interrupts are disabled, either explicitly or indirectly through
+ * interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static int s32k1xx_txpoll(struct net_driver_s *dev)
+{
+ #warning Missing logic
+
+ FAR struct s32k1xx_driver_s *priv =
+ (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+ /* If the polling resulted in data that should be sent out on the network,
+ * the field d_len is set to a value > 0.
+ */
+
+ if (priv->dev.d_len > 0)
+ {
+
+ if (!devif_loopback(&priv->dev))
+ {
+ /* Send the packet */
+
+ s32k1xx_transmit(priv);
+ /*priv->dev.d_buf =
+ (uint8_t *)s32k1xx_swap32((uint32_t)priv->txdesc[priv->txhead].data);*/
+
+ /* Check if there is room in the device to hold another packet. If
+ * not, return a non-zero value to terminate the poll.
+ */
+
+ if (s32k1xx_txringfull(priv))
+ {
+ return -EBUSY;
+ }
+ }
+ }
+
+ /* If zero is returned, the polling will continue until all connections
+ * have been examined.
+ */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_dispatch
+ *
+ * Description:
+ * A new Rx packet was received; dispatch that packet to the network layer
+ * as necessary.
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static inline void s32k1xx_dispatch(FAR struct s32k1xx_driver_s *priv)
+{
+
+ #warning Missing logic
+}
+
+/****************************************************************************
+ * Function: s32k1xx_receive
+ *
+ * Description:
+ * An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by interrupt handling logic.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_receive(FAR struct s32k1xx_driver_s *priv)
+{
+ #warning Missing logic
+ printf("FLEXCAN: receive\r\n");
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txdone
+ *
+ * Description:
+ * An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txdone(FAR struct s32k1xx_driver_s *priv)
+{
+ #warning Missing logic
+
+ uint32_t tx_iflags;
+ tx_iflags = getreg32(S32K1XX_CAN0_IFLAG1) & TXMBMask;
+
+ //FIXME process aborts
+
+ /* Process TX completions */
+
+ uint32_t mb_bit = 1 << NumMBinFiFoAndFilters;
+ for(uint32_t mbi = 0; tx_iflags && mbi < NumTxMesgBuffers; mbi++)
+ {
+ if (tx_iflags & mb_bit)
+ {
+ putreg32(mb_bit, S32K1XX_CAN0_IFLAG1);
+ tx_iflags &= ~mb_bit;
+ const bool txok = priv->tx[mbi].CS.code != CAN_TXMB_ABORT;
+ //handleTxMailboxInterrupt(mbi, txok, utc_usec);
+ }
+ mb_bit <<= 1;
+ }
+}
+
+/****************************************************************************
+ * Function: s32k1xx_flexcan_interrupt_work
+ *
+ * Description:
+ * Perform interrupt related work from the worker thread
+ *
+ * Input Parameters:
+ * arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_flexcan_interrupt_work(FAR void *arg)
+{
+ #warning Missing logic
+}
+
+/****************************************************************************
+ * Function: s32k1xx_flexcan_interrupt
+ *
+ * Description:
+ * Three interrupt sources will vector this this function:
+ * 1. Ethernet MAC transmit interrupt handler
+ * 2. Ethernet MAC receive interrupt handler
+ * 3.
+ *
+ * Input Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+
+static int s32k1xx_flexcan_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+ #warning Missing logic
+
+ FAR struct s32k1xx_driver_s *priv = &g_flexcan[0];
+ uint32_t FIFO_IFLAG1 = CAN_FIFO_NE | CAN_FIFO_WARN | CAN_FIFO_OV;
+ uint32_t flags;
+ flags = getreg32(S32K1XX_CAN0_IFLAG1);
+ flags &= FIFO_IFLAG1;
+
+ if(flags)
+ {
+ s32k1xx_receive(priv);
+ }
+
+ flags = getreg32(S32K1XX_CAN0_IFLAG1);
+ flags &= TXMBMask;
+
+ if(flags)
+ {
+ s32k1xx_txdone(priv);
+ }
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Input Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txtimeout_work(FAR void *arg)
+{
+ #warning Missing logic
+ printf("FLEXCAN: tx timeout work\r\n");
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txtimeout_expiry
+ *
+ * Description:
+ * Our TX watchdog timed out. Called from the timer interrupt handler.
+ * The last TX never completed. Reset the hardware and start again.
+ *
+ * Input Parameters:
+ * argc - The number of available arguments
+ * arg - The first argument
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txtimeout_expiry(int argc, uint32_t arg, ...)
+{
+ #warning Missing logic
+ printf("FLEXCAN: tx timeout expiry\r\n");
+}
+
+/****************************************************************************
+ * Function: s32k1xx_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Input Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_poll_work(FAR void *arg)
+{
+ #warning Missing logic
+ //printf("FLEXCAN: poll work\r\n");
+
+ FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+ /* Check if there is there is a transmission in progress. We cannot
+ * perform the TX poll if he are unable to accept another packet for
+ * transmission.
+ */
+
+ net_lock();
+ if (1) //!s32k1xx_txringfull(priv))
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT
+ * data. Hmmm.. might be bug here. Does this mean if there is a
+ * transmit in progress, we will missing TCP time state updates?
+ */
+
+ devif_timer(&priv->dev, S32K1XX_WDDELAY, s32k1xx_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again in any case */
+
+ wd_start(priv->txpoll, S32K1XX_WDDELAY, s32k1xx_polltimer_expiry,
+ 1, (wdparm_t)priv);
+ net_unlock();
+
+}
+
+/****************************************************************************
+ * Function: s32k1xx_polltimer_expiry
+ *
+ * Description:
+ * Periodic timer handler. Called from the timer interrupt handler.
+ *
+ * Input Parameters:
+ * argc - The number of available arguments
+ * arg - The first argument
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_polltimer_expiry(int argc, uint32_t arg, ...)
+{
+ #warning Missing logic
+ FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+ /* Schedule to perform the poll processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pollwork, s32k1xx_poll_work, priv, 0);
+}
+
+static void s32k1xx_setfreeze(uint32_t freeze)
+{
+ uint32_t regval;
+ if(freeze)
+ {
+ /* Enter freeze mode */
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval |= (CAN_MCR_HALT | CAN_MCR_FRZ);
+ putreg32(regval, S32K1XX_CAN0_MCR);
+ }
+ else
+ {
+ /* Exit freeze mode */
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval &= ~(CAN_MCR_HALT | CAN_MCR_FRZ);
+ putreg32(regval, S32K1XX_CAN0_MCR);
+ }
+}
+
+static uint32_t s32k1xx_waitmcr_change(uint32_t mask, uint32_t target_state)
+{
+ const unsigned Timeout = 1000;
+ for (unsigned wait_ack = 0; wait_ack < Timeout; wait_ack++)
+ {
+ const bool state = (getreg32(S32K1XX_CAN0_MCR) & mask) != 0;
+ if (state == target_state)
+ {
+ return true;
+ }
+ up_udelay(10);
+ }
+ return false;
+}
+
+static uint32_t s32k1xx_waitfreezeack_change(uint32_t target_state)
+{
+ return s32k1xx_waitmcr_change(CAN_MCR_FRZACK, target_state);
+}
+
+
+/****************************************************************************
+ * Function: s32k1xx_ifup
+ *
+ * Description:
+ * NuttX Callback: Bring up the Ethernet interface when an IP address is
+ * provided
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_ifup(struct net_driver_s *dev)
+{
+ FAR struct s32k1xx_driver_s *priv =
+ (FAR struct s32k1xx_driver_s *)dev->d_private;
+ uint32_t regval;
+
+ #warning Missing logic
+ printf("FLEXCAN: test ifup\r\n");
+
+ /* initialize CAN device */
+ //FIXME we only support a single can device for now
+
+
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval |= CAN_MCR_MDIS;
+ putreg32(regval, S32K1XX_CAN0_MCR);
+
+ /* Set SYS_CLOCK src */
+ regval = getreg32(S32K1XX_CAN0_CTRL1);
+ regval |= CAN_CTRL1_CLKSRC;
+ putreg32(regval, S32K1XX_CAN0_CTRL1);
+
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval &= ~(CAN_MCR_MDIS);
+ putreg32(regval, S32K1XX_CAN0_MCR);
+
+
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval |= CAN_MCR_RFEN | CAN_MCR_SLFWAK | CAN_MCR_WRNEN | CAN_MCR_SRXDIS
+ | CAN_MCR_IRMQ | CAN_MCR_AEN |
+ (((HWMaxMB - 1) << CAN_MCR_MAXMB_SHIFT) & CAN_MCR_MAXMB_MASK);
+ putreg32(regval, S32K1XX_CAN0_MCR);
+
+ regval = CAN_CTRL2_RRS | CAN_CTRL2_EACEN | CAN_CTRL2_RFFN_16MB; //FIXME TASD
+ putreg32(regval, S32K1XX_CAN0_CTRL2);
+
+ /* Enter freeze mode */
+ s32k1xx_setfreeze(1);
+ if(!s32k1xx_waitfreezeack_change(1))
+ {
+ printf("FLEXCAN: freeze fail\r\n");
+ return -1;
+ }
+
+ /*regval = getreg32(S32K1XX_CAN0_CTRL1);
+ regval |= ((0 << CAN_CTRL1_PRESDIV_SHIFT) & CAN_CTRL1_PRESDIV_MASK)
+ | ((46 << CAN_CTRL1_ROPSEG_SHIFT) & CAN_CTRL1_ROPSEG_MASK)
+ | ((18 << CAN_CTRL1_PSEG1_SHIFT) & CAN_CTRL1_PSEG1_MASK)
+ | ((12 << CAN_CTRL1_PSEG2_SHIFT) & CAN_CTRL1_PSEG2_MASK)
+ | ((12 << CAN_CTRL1_RJW_SHIFT) & CAN_CTRL1_RJW_MASK)
+ | CAN_CTRL1_ERRMSK
+ | CAN_CTRL1_TWRNMSK
+ | CAN_CTRL1_RWRNMSK;
+
+ putreg32(regval, S32K1XX_CAN0_CTRL1);*/
+
+ /* CAN Bit Timing (CBT) configuration for a nominal phase of 1 Mbit/s
+ * with 80 time quantas,in accordance with Bosch 2012 specification,
+ * sample point at 83.75% */
+ regval = getreg32(S32K1XX_CAN0_CBT);
+ regval |= CAN_CBT_BTF | /* Enable extended bit timing configurations for CAN-FD
+ for setting up separetely nominal and data phase */
+ CAN_CBT_EPRESDIV(0) | /* Prescaler divisor factor of 1 */
+ CAN_CBT_EPROPSEG(46) | /* Propagation segment of 47 time quantas */
+ CAN_CBT_EPSEG1(18) | /* Phase buffer segment 1 of 19 time quantas */
+ CAN_CBT_EPSEG2(12) | /* Phase buffer segment 2 of 13 time quantas */
+ CAN_CBT_ERJW(12); /* Resynchronization jump width same as PSEG2 */
+ putreg32(regval, S32K1XX_CAN0_CBT);
+
+#ifdef CAN_FD
+
+ /* Enable CAN FD feature */
+ regval = getreg32(S32K1XX_CAN0_MCR);
+ regval |= CAN_MCR_FDEN;
+ putreg32(regval, S32K1XX_CAN0_MCR);
+
+ /* CAN-FD Bit Timing (FDCBT) for a data phase of 4 Mbit/s with 20 time quantas,
+ in accordance with Bosch 2012 specification, sample point at 75% */
+ regval = getreg32(S32K1XX_CAN0_FDCBT);
+ regval |= CAN_FDCBT_FPRESDIV(0) | /* Prescaler divisor factor of 1 */
+ CAN_FDCBT_FPROPSEG(7) | /* Propagation semgment of 7 time quantas
+ (only register that doesn't add 1) */
+ CAN_FDCBT_FPSEG1(6) | /* Phase buffer segment 1 of 7 time quantas */
+ CAN_FDCBT_FPSEG2(4) | /* Phase buffer segment 2 of 5 time quantas */
+ CAN_FDCBT_FRJW(4); /* Resynchorinzation jump width same as PSEG2 */
+ putreg32(regval, S32K1XX_CAN0_FDCBT);
+
+ /* Additional CAN-FD configurations */
+ regval = getreg32(S32K1XX_CAN0_FDCTRL);
+ regval |= CAN_FDCTRL_FDRATE | /* Enable bit rate switch in data phase of frame */
+ CAN_FDCTRL_TDCEN | /* Enable transceiver delay compensation */
+ CAN_FDCTRL_TDCOFF(5) | /* Setup 5 cycles for data phase sampling delay */
+ CAN_FDCTRL_MBDSR0(3); /* Setup 64 bytes per message buffer (7 MB's) */
+ putreg32(regval, S32K1XX_CAN0_FDCTRL);
+
+ regval = getreg32(S32K1XX_CAN0_CTRL2);
+ regval |= CAN_CTRL2_ISOCANFDEN;
+ putreg32(regval, S32K1XX_CAN0_CTRL2);
+#endif
+
+
+ /* Filtering catchall */
+ putreg32(0, S32K1XX_CAN0_RXFGMASK);
+
+ /* Iniatilize all MB rx and tx */
+ /*for(int i = 0; i < HWMaxMB; i++)
+ {
+ priv->rx[i].CS.cs = 0x0;
+ priv->rx[i].ID.w = 0x0;
+ priv->rx[i].data.l = 0x0;
+ priv->rx[i].data.h = 0x0;
+ }*/
+
+ //FIXME max mb
+ for(int i = 0; i < HWMaxMB; i++)
+ {
+ putreg32(0,S32K1XX_CAN0_RXIMR(i));
+ }
+
+ putreg32(0,S32K1XX_CAN0_RXIMR0);
+ putreg32(0,S32K1XX_CAN0_RXIMR1);
+ putreg32(0,S32K1XX_CAN0_RXIMR2);
+ putreg32(0,S32K1XX_CAN0_RXIMR3);
+ putreg32(0,S32K1XX_CAN0_RXIMR4);
+ putreg32(0,S32K1XX_CAN0_RXIMR5);
+ putreg32(0,S32K1XX_CAN0_RXIMR6);
+ putreg32(0,S32K1XX_CAN0_RXIMR7);
+ putreg32(0,S32K1XX_CAN0_RXIMR8);
+ putreg32(0,S32K1XX_CAN0_RXIMR9);
+ putreg32(0,S32K1XX_CAN0_RXIMR10);
+ putreg32(0,S32K1XX_CAN0_RXIMR11);
+ putreg32(0,S32K1XX_CAN0_RXIMR12);
+ putreg32(0,S32K1XX_CAN0_RXIMR13);
+ putreg32(0,S32K1XX_CAN0_RXIMR14);
+ putreg32(0,S32K1XX_CAN0_RXIMR15);
+
+ putreg32(CAN_IFLAG1(1) | TXMBMask, S32K1XX_CAN0_IFLAG1); //FIXME dynamic MXMB
+ putreg32(CAN_IFLAG1(1), S32K1XX_CAN0_IMASK1);
+
+
+ /* Exit freeze mode */
+ s32k1xx_setfreeze(0);
+ if(!s32k1xx_waitfreezeack_change(0))
+ {
+ printf("FLEXCAN: unfreeze fail\r\n");
+ return -1;
+ }
+
+
+ /* Set and activate a timer process */
+
+ wd_start(priv->txpoll, S32K1XX_WDDELAY, s32k1xx_polltimer_expiry, 1,
+ (wdparm_t)priv);
+
+ priv->bifup = true;
+
+ priv->dev.d_buf = &g_desc_pool;
+
+ /* Set interrupts */
+ up_enable_irq(S32K1XX_IRQ_CAN0_BUS);
+ up_enable_irq(S32K1XX_IRQ_CAN0_ERROR);
+ up_enable_irq(S32K1XX_IRQ_CAN0_LPRX);
+ up_enable_irq(S32K1XX_IRQ_CAN0_0_15);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_ifdown
+ *
+ * Description:
+ * NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int s32k1xx_ifdown(struct net_driver_s *dev)
+{
+ #warning Missing logic
+ return OK;
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Input Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void s32k1xx_txavail_work(FAR void *arg)
+{
+ FAR struct s32k1xx_driver_s *priv = (FAR struct s32k1xx_driver_s *)arg;
+
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->bifup)
+ {
+ /* Check if there is room in the hardware to hold another outgoing
+ * packet.
+ */
+
+ if (!s32k1xx_txringfull(priv))
+ {
+ /* No, there is space for another transfer. Poll the network for
+ * new XMIT data.
+ */
+
+ devif_poll(&priv->dev, s32k1xx_txpoll);
+ }
+ }
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: s32k1xx_txavail
+ *
+ * Description:
+ * Driver callback invoked when new TX data is available. This is a
+ * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ * latency.
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int s32k1xx_txavail(struct net_driver_s *dev)
+{
+ FAR struct s32k1xx_driver_s *priv =
+ (FAR struct s32k1xx_driver_s *)dev->d_private;
+
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&priv->pollwork))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pollwork, s32k1xx_txavail_work, priv, 0);
+ }
+
+ return OK;
+}
+
+
+/****************************************************************************
+ * Function: s32k1xx_ioctl
+ *
+ * Description:
+ * PHY ioctl command handler
+ *
+ * Input Parameters:
+ * dev - Reference to the NuttX driver state structure
+ * cmd - ioctl command
+ * arg - Argument accompanying the command
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NETDEV_IOCTL
+static int s32k1xx_ioctl(struct net_driver_s *dev, int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ switch (cmd)
+ {
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_NETDEV_IOCTL */
+
+
+/****************************************************************************
+ * Function: s32k1xx_initbuffers
+ *
+ * Description:
+ * Initialize FLEXCAN buffers and descriptors
+ *
+ * Input Parameters:
+ * priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void s32k1xx_initbuffers(struct s32k1xx_driver_s *priv)
+{
+ #warning Missing logic
+}
+
+/****************************************************************************
+ * Function: s32k1xx_reset
+ *
+ * Description:
+ * Put the EMAC in the non-operational, reset state
+ *
+ * Input Parameters:
+ * priv - Reference to the private FLEXCAN driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void s32k1xx_reset(struct s32k1xx_driver_s *priv)
+{
+ unsigned int i;
+
+ /* Set the reset bit and clear the enable bit */
+
+
+ #warning Missing logic
+
+ /* Wait at least 8 clock cycles */
+
+ for (i = 0; i < 10; i++)
+ {
+ asm volatile ("nop");
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: s32k1xx_netinitialize
+ *
+ * Description:
+ * Initialize the Ethernet controller and driver
+ *
+ * Input Parameters:
+ * intf - In the case where there are multiple EMACs, this value
+ * identifies which EMAC is to be initialized.
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int s32k1xx_netinitialize(int intf)
+{
+ struct s32k1xx_driver_s *priv;
+ int ret;
+
+ //FIXME dynamic board config
+ s32k1xx_pinconfig(PIN_CAN0_TX_4);
+ s32k1xx_pinconfig(PIN_CAN0_RX_4);
+
+ priv = &g_flexcan[intf];
+
+ ninfo("initialize\r\n");
+
+ /* Get the interface structure associated with this interface number. */
+
+ #warning Missing logic
+
+
+ /* Attach the flexcan interrupt handler */
+ if (irq_attach(S32K1XX_IRQ_CAN0_BUS, s32k1xx_flexcan_interrupt, NULL))
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ nerr("ERROR: Failed to attach CAN bus IRQ\n");
+ return -EAGAIN;
+ }
+ if (irq_attach(S32K1XX_IRQ_CAN0_ERROR, s32k1xx_flexcan_interrupt, NULL))
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ nerr("ERROR: Failed to attach CAN error IRQ\n");
+ return -EAGAIN;
+ }
+ if (irq_attach(S32K1XX_IRQ_CAN0_LPRX, s32k1xx_flexcan_interrupt, NULL))
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ nerr("ERROR: Failed to attach CAN LPRX IRQ\n");
+ return -EAGAIN;
+ }
+ if (irq_attach(S32K1XX_IRQ_CAN0_0_15, s32k1xx_flexcan_interrupt, NULL))
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ nerr("ERROR: Failed to attach CAN OR'ed Message buffer (0-15) IRQ\n");
+ return -EAGAIN;
+ }
+
+ /* Initialize the driver structure */
+
+ memset(priv, 0, sizeof(struct s32k1xx_driver_s));
+ priv->dev.d_ifup = s32k1xx_ifup; /* I/F up (new IP address) callback */
+ priv->dev.d_ifdown = s32k1xx_ifdown; /* I/F down callback */
+ priv->dev.d_txavail = s32k1xx_txavail; /* New TX data callback */
+#ifdef CONFIG_NETDEV_IOCTL
+ priv->dev.d_ioctl = s32k1xx_ioctl; /* Support PHY ioctl() calls */
+#endif
+ priv->dev.d_private = (void *)g_flexcan; /* Used to recover private state from dev */
+
+ /* Create a watchdog for timing polling for and timing of transmissions */
+ priv->txpoll = wd_create(); /* Create periodic poll timer */
+ priv->txtimeout = wd_create(); /* Create TX timeout timer */
+ priv->rx = (struct MbRx *)(S32K1XX_CAN0_MB);
+ priv->tx = (struct MbTx *)(S32K1XX_CAN0_MB + (sizeof(struct MbRx)
+ * S32K1XX_FLEXCAN_FIRST_TX_MB) );
+
+ /* Put the interface in the down state. This usually amounts to resetting
+ * the device and/or calling s32k1xx_ifdown().
+ */
+
+ ninfo("callbacks done\r\n");
+
+ s32k1xx_ifdown(&priv->dev);
+
+ /* Register the device with the OS so that socket IOCTLs can be performed */
+
+ netdev_register(&priv->dev, NET_LL_CAN);
+
+ UNUSED(ret);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: up_netinitialize
+ *
+ * Description:
+ * Initialize the first network interface. If there are more than one
+ * interface in the chip, then board-specific logic will have to provide
+ * this function to determine which, if any, Ethernet controllers should
+ * be initialized.
+ *
+ ****************************************************************************/
+
+//FIXME CONFIG_S32K1XX_FLEXCAN_NETHIFS == 1 &&
+
+#if !defined(CONFIG_NETDEV_LATEINIT)
+void up_netinitialize(void)
+{
+ s32k1xx_netinitialize(0);
+}
+#endif
+
+#endif /* CONFIG_S32K1XX_FLEXCAN */
diff --git a/net/devif/devif_pktsend.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.h
similarity index 54%
copy from net/devif/devif_pktsend.c
copy to arch/arm/src/s32k1xx/s32k1xx_flexcan.h
index b041b2f..9dfe681 100644
--- a/net/devif/devif_pktsend.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.h
@@ -1,7 +1,7 @@
-/****************************************************************************
- * net/devif/devif_pktsend.c
+/************************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_flexcan.h
*
- * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gn...@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -31,83 +31,87 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ****************************************************************************/
+ ************************************************************************************/
-/****************************************************************************
+#ifndef __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H
+#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H
+
+/************************************************************************************
* Included Files
- ****************************************************************************/
+ ************************************************************************************/
#include <nuttx/config.h>
-#include <string.h>
-#include <assert.h>
-#include <debug.h>
-
-#include <nuttx/net/netdev.h>
+#include "hardware/s32k1xx_flexcan.h"
-#ifdef CONFIG_NET_PKT
+#ifdef CONFIG_S32K1XX_FLEXCAN
-/****************************************************************************
+/************************************************************************************
* Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Type Declarations
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
+ ************************************************************************************/
-/****************************************************************************
- * Public Constant Data
- ****************************************************************************/
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Constant Data
- ****************************************************************************/
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
-/****************************************************************************
- * Private Data
- ****************************************************************************/
+#ifndef __ASSEMBLY__
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
-/****************************************************************************
- * Name: devif_pkt_send
+/************************************************************************************
+ * Function: up_netinitialize
*
* Description:
- * Called from socket logic in order to send a raw packet in response to
- * an xmit or poll request from the network interface driver.
+ * Initialize the first network interface. If there are more than one
+ * interface in the chip, then board-specific logic will have to provide
+ * this function to determine which, if any, Ethernet controllers should
+ * be initialized. Also prototyped in up_internal.h.
*
- * This is almost identical to calling devif_send() except that the data to
- * be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
- * no header on the data.
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
*
* Assumptions:
- * Called with the network locked.
+ * Called very early in the initialization sequence.
*
- ****************************************************************************/
-
-void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
- unsigned int len)
-{
- DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev));
+ ************************************************************************************/
- /* Copy the data into the device packet buffer */
+void up_netinitialize(void);
- memcpy(dev->d_buf, buf, len);
+/************************************************************************************
+ * Function: s32k1xx_phy_boardinitialize
+ *
+ * Description:
+ * Some boards require specialized initialization of the PHY before it can be
+ * used. This may include such things as configuring GPIOs, resetting the PHY,
+ * etc. If CONFIG_S32K1XX_FLEXCAN_PHYINIT is defined in the configuration then the
+ * board specific logic must provide s32k1xx_phyinitialize(); The i.MX RT Ethernet
+ * driver will call this function one time before it first uses the PHY.
+ *
+ * Input Parameters:
+ * intf - Always zero for now.
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ************************************************************************************/
- /* Set the number of bytes to send */
- dev->d_len = len;
- dev->d_sndlen = len;
+#undef EXTERN
+#if defined(__cplusplus)
}
+#endif
-#endif /* CONFIG_NET_PKT */
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_S32K1XX_FLEXCAN */
+#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXCAN_H */
diff --git a/include/nuttx/can.h b/include/nuttx/can.h
new file mode 100644
index 0000000..fd86b74
--- /dev/null
+++ b/include/nuttx/can.h
@@ -0,0 +1,279 @@
+/************************************************************************************
+ * include/nuttx/can/can.h
+ *
+ * Copyright (C) 2008, 2009, 2011-2012, 2015-2017, 2019 Gregory Nutt. All rights
+ * reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_CAN_CAN_H
+#define __INCLUDE_NUTTX_CAN_CAN_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#ifdef CONFIG_CAN_TXREADY
+# include <nuttx/wqueue.h>
+#endif
+
+#ifdef CONFIG_NET_CAN
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+
+/* Ioctl Commands *******************************************************************/
+
+/* Ioctl commands supported by the upper half CAN driver.
+ *
+ * CANIOC_RTR:
+ * Description: Send the remote transmission request and wait for the response.
+ * Argument: A reference to struct canioc_rtr_s
+ *
+ * Ioctl commands that may or may not be supported by the lower half CAN driver.
+ *
+ * CANIOC_ADD_STDFILTER:
+ * Description: Add an address filter for a standard 11 bit address.
+ * Argument: A reference to struct canioc_stdfilter_s
+ * Returned Value: A non-negative filter ID is returned on success.
+ * Otherwise -1 (ERROR) is returned with the errno
+ * variable set to indicate the nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_ADD_EXTFILTER:
+ * Description: Add an address filter for a extended 29 bit address.
+ * Argument: A reference to struct canioc_extfilter_s
+ * Returned Value: A non-negative filter ID is returned on success.
+ * Otherwise -1 (ERROR) is returned with the errno
+ * variable set to indicate the nature of the error.
+ * Dependencies: Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_DEL_STDFILTER:
+ * Description: Remove an address filter for a standard 11 bit address.
+ * Argument: The filter index previously returned by the
+ * CANIOC_ADD_STDFILTER command
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_DEL_EXTFILTER:
+ * Description: Remove an address filter for a standard 29 bit address.
+ * Argument: The filter index previously returned by the
+ * CANIOC_ADD_EXTFILTER command
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_GET_BITTIMING:
+ * Description: Return the current bit timing settings
+ * Argument: A pointer to a write-able instance of struct
+ * canioc_bittiming_s in which current bit timing values
+ * will be returned.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_SET_BITTIMING:
+ * Description: Set new current bit timing values
+ * Argument: A pointer to a read-able instance of struct
+ * canioc_bittiming_s in which the new bit timing values
+ * are provided.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_GET_CONNMODES:
+ * Description: Get the current bus connection modes
+ * Argument: A pointer to a write-able instance of struct
+ * canioc_connmodes_s in which the new bus modes will be returned.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_SET_CONNMODES:
+ * Description: Set new bus connection modes values
+ * Argument: A pointer to a read-able instance of struct
+ * canioc_connmodes_s in which the new bus modes are provided.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_BUSOFF_RECOVERY:
+ * Description: Initiates the BUS-OFF recovery sequence
+ * Argument: None
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ */
+
+#define CANIOC_RTR _CANIOC(1)
+#define CANIOC_GET_BITTIMING _CANIOC(2)
+#define CANIOC_SET_BITTIMING _CANIOC(3)
+#define CANIOC_ADD_STDFILTER _CANIOC(4)
+#define CANIOC_ADD_EXTFILTER _CANIOC(5)
+#define CANIOC_DEL_STDFILTER _CANIOC(6)
+#define CANIOC_DEL_EXTFILTER _CANIOC(7)
+#define CANIOC_GET_CONNMODES _CANIOC(8)
+#define CANIOC_SET_CONNMODES _CANIOC(9)
+#define CANIOC_BUSOFF_RECOVERY _CANIOC(10)
+
+#define CAN_FIRST 0x0001 /* First common command */
+#define CAN_NCMDS 10 /* Ten common commands */
+
+/* User defined ioctl commands are also supported. These will be forwarded
+ * by the upper-half CAN driver to the lower-half CAN driver via the co_ioctl()
+ * method fo the CAN lower-half interface. However, the lower-half driver
+ * must reserve a block of commands as follows in order prevent IOCTL
+ * command numbers from overlapping.
+ *
+ * This is generally done as follows. The first reservation for CAN driver A would
+ * look like:
+ *
+ * CAN_A_FIRST (CAN_FIRST + CAN_NCMDS) <- First command
+ * CAN_A_NCMDS 42 <- Number of commands
+ *
+ * IOCTL commands for CAN driver A would then be defined in a CAN A header file like:
+ *
+ * CANIOC_A_CMD1 _CANIOC(CAN_A_FIRST+0)
+ * CANIOC_A_CMD2 _CANIOC(CAN_A_FIRST+1)
+ * CANIOC_A_CMD3 _CANIOC(CAN_A_FIRST+2)
+ * ...
+ * CANIOC_A_CMD42 _CANIOC(CAN_A_FIRST+41)
+ *
+ * The next reservation would look like:
+ *
+ * CAN_B_FIRST (CAN_A_FIRST + CAN_A_NCMDS) <- Next command
+ * CAN_B_NCMDS 77 <- Number of commands
+ */
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+typedef uint32_t canid_t;
+
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
+#define CANFD_MAX_DLC 15
+#define CANFD_MAX_DLEN 64
+
+
+/**
+ * struct can_frame - basic CAN frame structure
+ * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @can_dlc: frame payload length in byte (0 .. 8) aka data length code
+ * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
+ * mapping of the 'data length code' to the real payload length
+ * @__pad: padding
+ * @__res0: reserved / padding
+ * @__res1: reserved / padding
+ * @data: CAN frame payload (up to 8 byte)
+ */
+struct can_frame {
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ uint8_t can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
+ uint8_t __pad; /* padding */
+ uint8_t __res0; /* reserved / padding */
+ uint8_t __res1; /* reserved / padding */
+ uint8_t data[CAN_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/*
+ * defined bits for canfd_frame.flags
+ *
+ * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
+ * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
+ * the CAN controllers bitstream processor into the CAN FD mode which creates
+ * two new options within the CAN FD frame specification:
+ *
+ * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
+ * Error State Indicator - represents the error state of the transmitting node
+ *
+ * As the CANFD_ESI bit is internally generated by the transmitting CAN
+ * controller only the CANFD_BRS bit is relevant for real CAN controllers when
+ * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
+ * sense for virtual CAN interfaces to test applications with echoed frames.
+ */
+#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
+#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
+
+/**
+ * struct canfd_frame - CAN flexible data rate frame structure
+ * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * @len: frame payload length in byte (0 .. CANFD_MAX_DLEN)
+ * @flags: additional flags for CAN FD
+ * @__res0: reserved / padding
+ * @__res1: reserved / padding
+ * @data: CAN FD frame payload (up to CANFD_MAX_DLEN byte)
+ */
+struct canfd_frame {
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ uint8_t len; /* frame payload length in byte */
+ uint8_t flags; /* additional flags for CAN FD */
+ uint8_t __res0; /* reserved / padding */
+ uint8_t __res1; /* reserved / padding */
+ uint8_t data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_CAN */
+#endif /* __INCLUDE_NUTTX_CAN_CAN_H */
diff --git a/include/nuttx/net/can.h b/include/nuttx/net/can.h
new file mode 100644
index 0000000..d426c7b
--- /dev/null
+++ b/include/nuttx/net/can.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * include/nuttx/net/ethernt.h
+ * Macros and definitions for the Ethernet link layer.
+ *
+ * Copyright (C) 2007, 2009-2012, 2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Derived from uIP with has a similar BSD-styple license:
+ *
+ * Author: Adam Dunkels <ad...@dunkels.com>
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_CAN_H
+#define __INCLUDE_NUTTX_NET_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/can.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CAN_HDRLEN 4 //FIXME standard id vs extended
+#define NET_CAN_PKTSIZE sizeof(struct canfd_frame) // max size we can send through socket
+//FIXME think about can & canfd support
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_CAN_H */
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 8218c0c..8c11db7 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -155,7 +155,8 @@ enum net_lltype_e
NET_LL_BLUETOOTH, /* Bluetooth */
NET_LL_IEEE80211, /* IEEE 802.11 */
NET_LL_IEEE802154, /* IEEE 802.15.4 MAC */
- NET_LL_PKTRADIO /* Non-standard packet radio */
+ NET_LL_PKTRADIO, /* Non-standard packet radio */
+ NET_LL_CAN /* CAN bus */
};
/* This defines a bitmap big enough for one bit for each socket option */
diff --git a/net/can/Make.defs b/net/can/Make.defs
index bb9ef9f..f8488c0 100644
--- a/net/can/Make.defs
+++ b/net/can/Make.defs
@@ -22,8 +22,14 @@
ifeq ($(CONFIG_NET_CAN),y)
+# Socket layer
+
SOCK_CSRCS += can_sockif.c
+SOCK_CSRCS += can_send.c
+
NET_CSRCS += can_conn.c
+NET_CSRCS += can_poll.c
+NET_CSRCS += can_callback.c
# Include can build support
diff --git a/net/can/can.h b/net/can/can.h
index 6f41ce9..3fed49b 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -32,6 +32,7 @@
#include <netpacket/can.h>
#include <nuttx/semaphore.h>
+#include <nuttx/net/netdev.h>
#include "devif/devif.h"
#include "socket/socket.h"
@@ -39,6 +40,17 @@
#ifdef CONFIG_NET_CAN
/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Allocate a new packet socket data callback */
+
+#define can_callback_alloc(dev,conn) \
+ devif_callback_alloc(dev, &conn->list)
+#define can_callback_free(dev,conn,cb) \
+ devif_conn_callback_free(dev, cb, &conn->list)
+
+/****************************************************************************
* Public Type Definitions
****************************************************************************/
@@ -57,6 +69,8 @@ struct can_conn_s
FAR struct devif_callback_s *list; /* NetLink callbacks */
+ FAR struct net_driver_s *dev; /* Reference to CAN device */
+
/* CAN-specific content follows */
uint8_t protocol; /* Selected CAN protocol */
@@ -135,6 +149,43 @@ void can_free(FAR struct can_conn_s *conn);
FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn);
/****************************************************************************
+ * Name: can_callback
+ *
+ * Description:
+ * Inform the application holding the packet socket of a change in state.
+ *
+ * Returned Value:
+ * OK if packet has been processed, otherwise ERROR.
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_callback(FAR struct net_driver_s *dev,
+ FAR struct can_conn_s *conn, uint16_t flags);
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ * Poll a CAN connection structure for availability of TX data
+ *
+ * Input Parameters:
+ * dev - The device driver structure to use in the send operation
+ * conn - The CAN "connection" to poll for TX data
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn);
+
+/****************************************************************************
* Name: can_active()
*
* Description:
@@ -145,6 +196,30 @@ FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn);
FAR struct can_conn_s *can_active(FAR struct sockaddr_can *addr);
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ * The psock_can_send() call may be used only when the packet socket is in
+ * a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * buf Data to send
+ * len Length of data to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is returned. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+struct socket;
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len);
+
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/net/devif/devif_pktsend.c b/net/can/can_callback.c
similarity index 53%
copy from net/devif/devif_pktsend.c
copy to net/can/can_callback.c
index b041b2f..2fad951 100644
--- a/net/devif/devif_pktsend.c
+++ b/net/can/can_callback.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * net/devif/devif_pktsend.c
+ * net/pkt/pkt_callback.c
*
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gn...@nuttx.org>
@@ -38,76 +38,48 @@
****************************************************************************/
#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
-#include <string.h>
-#include <assert.h>
+#include <stdint.h>
#include <debug.h>
+#include <nuttx/net/netconfig.h>
#include <nuttx/net/netdev.h>
-#ifdef CONFIG_NET_PKT
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Type Declarations
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Public Constant Data
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Constant Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
+#include "devif/devif.h"
+#include "can/can.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Name: devif_pkt_send
+ * Name: can_callback
*
* Description:
- * Called from socket logic in order to send a raw packet in response to
- * an xmit or poll request from the network interface driver.
+ * Inform the application holding the packet socket of a change in state.
*
- * This is almost identical to calling devif_send() except that the data to
- * be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
- * no header on the data.
+ * Returned Value:
+ * OK if packet has been processed, otherwise ERROR.
*
* Assumptions:
- * Called with the network locked.
+ * This function is called with the network locked.
*
****************************************************************************/
-void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
- unsigned int len)
+uint16_t can_callback(FAR struct net_driver_s *dev,
+ FAR struct can_conn_s *conn, uint16_t flags)
{
- DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev));
-
- /* Copy the data into the device packet buffer */
+ /* Some sanity checking */
- memcpy(dev->d_buf, buf, len);
+ if (conn)
+ {
+ /* Perform the callback */
- /* Set the number of bytes to send */
+ flags = devif_conn_event(dev, conn, flags, conn->list);
+ }
- dev->d_len = len;
- dev->d_sndlen = len;
+ return flags;
}
-#endif /* CONFIG_NET_PKT */
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_poll.c b/net/can/can_poll.c
new file mode 100644
index 0000000..84aeeab
--- /dev/null
+++ b/net/can/can_poll.c
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * net/pkt/pkt_poll.c
+ * Poll for the availability of packet TX data
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Adapted for NuttX from logic in uIP which also has a BSD-like license:
+ *
+ * Original author Adam Dunkels <ad...@dunkels.com>
+ * Copyright () 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <debug.h>
+
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/netdev.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ * Poll a packet "connection" structure for availability of TX data
+ *
+ * Input Parameters:
+ * dev - The device driver structure to use in the send operation
+ * conn - The packet "connection" to poll for TX data
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn)
+{
+ /* Verify that the packet connection is valid */
+
+ if (conn != NULL)
+ {
+ /* Setup for the application callback */
+
+ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)];
+ dev->d_len = 0;
+ dev->d_sndlen = 0;
+
+ /* Perform the application callback */
+
+ can_callback(dev, conn, CAN_POLL);
+
+ /* Check if the application has data to send */
+
+ if (dev->d_sndlen > 0)
+ {
+ return;
+ }
+ }
+
+ /* Make sure that d_len is zero meaning that there is nothing to be sent */
+
+ dev->d_len = 0;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_send.c b/net/can/can_send.c
new file mode 100644
index 0000000..6b7a609
--- /dev/null
+++ b/net/can/can_send.c
@@ -0,0 +1,264 @@
+/****************************************************************************
+ * net/can/can_send.c
+ *
+ * Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/semaphore.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/ip.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "socket/socket.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure holds the state of the send operation until it can be
+ * operated upon by the event handler.
+ */
+
+struct send_s
+{
+ FAR struct socket *snd_sock; /* Points to the parent socket structure */
+ FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
+ sem_t snd_sem; /* Used to wake up the waiting thread */
+ FAR const uint8_t *snd_buffer; /* Points to the buffer of data to send */
+ size_t snd_buflen; /* Number of bytes in the buffer to send */
+ ssize_t snd_sent; /* The number of bytes sent */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_send_eventhandler
+ ****************************************************************************/
+
+static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct send_s *pstate = (FAR struct send_s *)pvpriv;
+
+ if (pstate)
+ {
+ /* Check if the outgoing packet is available. It may have been claimed
+ * by a send event handler serving a different thread -OR- if the
+ * output buffer currently contains unprocessed incoming data. In
+ * these cases we will just have to wait for the next polling cycle.
+ */
+
+ if (dev->d_sndlen > 0 || (flags & CAN_NEWDATA) != 0)
+ {
+ /* Another thread has beat us sending data or the buffer is busy,
+ * Check for a timeout. If not timed out, wait for the next
+ * polling cycle and check again.
+ */
+
+ /* No timeout. Just wait for the next polling cycle */
+
+ return flags;
+ }
+
+ /* It looks like we are good to send the data */
+
+ else
+ {
+ /* Copy the packet data into the device packet buffer and send it */
+ //FIXME potentialy wrong function do we have a header??
+ devif_pkt_send(dev, pstate->snd_buffer, pstate->snd_buflen);
+ pstate->snd_sent = pstate->snd_buflen;
+ }
+
+ /* Don't allow any further call backs. */
+
+ pstate->snd_cb->flags = 0;
+ pstate->snd_cb->priv = NULL;
+ pstate->snd_cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ nxsem_post(&pstate->snd_sem);
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ * The psock_can_send() call may be used only when the packet socket is in
+ * a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * buf Data to send
+ * len Length of data to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is retruend. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len)
+{
+ FAR struct net_driver_s *dev;
+ FAR struct can_conn_s *conn;
+ struct send_s state;
+ int ret = OK;
+
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ /* Verify that the sockfd corresponds to valid, allocated socket */
+
+ if (!psock || psock->s_crefs <= 0)
+ {
+ return -EBADF;
+ }
+
+ /* Get the device driver that will service this transfer */
+
+ dev = conn->dev;
+ if (dev == NULL)
+ {
+ return -ENODEV;
+ }
+
+ /* Perform the send operation */
+
+ /* Initialize the state structure. This is done with the network locked
+ * because we don't want anything to happen until we are ready.
+ */
+
+ net_lock();
+ memset(&state, 0, sizeof(struct send_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
+ nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE);
+
+ state.snd_sock = psock; /* Socket descriptor to use */
+ state.snd_buflen = len; /* Number of bytes to send */
+ state.snd_buffer = buf; /* Buffer to send from */
+
+ if (len > 0)
+ {
+ /* Allocate resource to receive a callback */
+
+ state.snd_cb = can_callback_alloc(dev, conn);
+ if (state.snd_cb)
+ {
+ /* Set up the callback in the connection */
+
+ state.snd_cb->flags = CAN_POLL;
+ state.snd_cb->priv = (FAR void *)&state;
+ state.snd_cb->event = psock_send_eventhandler;
+
+ /* Notify the device driver that new TX data is available. */
+
+ netdev_txnotify_dev(dev);
+
+ /* Wait for the send to complete or an error to occur.
+ * net_lockedwait will also terminate if a signal is received.
+ */
+
+ ret = net_lockedwait(&state.snd_sem);
+
+ /* Make sure that no further events are processed */
+
+ can_callback_free(dev, conn, state.snd_cb);
+ }
+ }
+
+ nxsem_destroy(&state.snd_sem);
+ net_unlock();
+
+ /* Check for a errors, Errors are signalled by negative errno values
+ * for the send length
+ */
+
+ if (state.snd_sent < 0)
+ {
+ return state.snd_sent;
+ }
+
+ /* If net_lockedwait failed, then we were probably reawakened by a signal.
+ * In this case, net_lockedwait will have returned negated errno
+ * appropriately.
+ */
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Return the number of bytes actually sent */
+
+ return state.snd_sent;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c
index b7e3fe6..1de95d9 100644
--- a/net/can/can_sockif.c
+++ b/net/can/can_sockif.c
@@ -40,6 +40,7 @@
#include <nuttx/net/net.h>
#include "can/can.h"
+#include "netdev/netdev.h"
#ifdef CONFIG_NET_CAN
@@ -61,7 +62,7 @@ static int can_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock);
-static int can_poll(FAR struct socket *psock, FAR struct pollfd *fds,
+static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
bool setup);
static ssize_t can_send(FAR struct socket *psock,
FAR const void *buf, size_t len, int flags);
@@ -88,7 +89,7 @@ const struct sock_intf_s g_can_sockif =
can_listen, /* si_listen */
can_connect, /* si_connect */
can_accept, /* si_accept */
- can_poll, /* si_poll */
+ can_poll_local, /* si_poll */
can_send, /* si_send */
can_sendto, /* si_sendto */
#ifdef CONFIG_NET_SENDFILE
@@ -272,7 +273,15 @@ static int can_bind(FAR struct socket *psock,
canaddr = (FAR struct sockaddr_can *)addr;
conn = (FAR struct can_conn_s *)psock->s_conn;
-#warning Missing logic
+
+ /* Bind CAN device to socket */
+
+ //TODO better support for CONFIG_NETDEV_IFINDEX
+ char netdev_name[6];
+
+ sprintf(netdev_name, "can%i", canaddr->can_ifindex);
+
+ conn->dev = netdev_findbyname(&netdev_name);
return OK;
}
@@ -473,7 +482,7 @@ static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
}
/****************************************************************************
- * Name: can_poll
+ * Name: can_poll_local
*
* Description:
* The standard poll() operation redirects operations on socket descriptors
@@ -495,7 +504,7 @@ static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
*
****************************************************************************/
-static int can_poll(FAR struct socket *psock, FAR struct pollfd *fds,
+static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
bool setup)
{
FAR struct can_conn_s *conn;
@@ -621,36 +630,25 @@ static int can_poll(FAR struct socket *psock, FAR struct pollfd *fds,
static ssize_t can_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags)
{
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
-
- /* The socket must be connected in order to use send */
-
- if (_SS_ISBOUND(psock->s_flags))
- {
- FAR struct can_conn_s *conn;
- struct sockaddr_can canaddr;
-
- /* Get the underlying connection structure */
+ ssize_t ret;
- conn = (FAR struct can_conn_s *)psock->s_conn;
+ /* Only SOCK_RAW is supported */
- /* Format the address */
-
- canaddr.can_family = AF_CAN;
-#warning Missing logic
+ if (psock->s_type == SOCK_RAW)
+ {
+ /* Raw packet send */
+ ret = psock_can_send(psock, buf, len);
+ }
+ else
+ {
+ /* EDESTADDRREQ. Signifies that the socket is not connection-mode and
+ * no peer address is set.
+ */
- /* Then let sendto() perform the actual send operation */
-
- return can_sendto(psock, buf, len, flags,
- (FAR const struct sockaddr *)&canaddr,
- sizeof(struct sockaddr_can));
- }
-
- /* EDESTADDRREQ. Signifies that the socket is not connection-mode and no
- * peer address is set.
- */
+ ret = -EDESTADDRREQ;
+ }
- return -EDESTADDRREQ;
+ return ret;
}
/****************************************************************************
@@ -681,25 +679,8 @@ static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags,
FAR const struct sockaddr *to, socklen_t tolen)
{
- FAR struct can_conn_s *conn;
- int ret;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL &&
- to != NULL && tolen >= sizeof(struct sockaddr_can));
-
- conn = (FAR struct can_conn_s *)psock->s_conn;
-#warning Missing logic
-
- switch (conn->protocol)
- {
-#warning Missing logic
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
+ nerr("ERROR: sendto() not supported for raw packet sockets\n");
+ return -EAFNOSUPPORT;
}
/****************************************************************************
diff --git a/net/devif/Make.defs b/net/devif/Make.defs
index 714a0ce..b2dca4a 100644
--- a/net/devif/Make.defs
+++ b/net/devif/Make.defs
@@ -62,7 +62,7 @@ endif
# Raw packet socket support
-ifeq ($(CONFIG_NET_PKT),y)
+ifeq ($(filter y,$(CONFIG_NET_PKT) $(CONFIG_NET_CAN)),)
NET_CSRCS += devif_pktsend.c
endif
diff --git a/net/devif/devif.h b/net/devif/devif.h
index cbe1a00..c54a68d 100644
--- a/net/devif/devif.h
+++ b/net/devif/devif.h
@@ -168,6 +168,7 @@
#define BLUETOOTH_NEWDATA TCP_NEWDATA
#define IEEE802154_NEWDATA TCP_NEWDATA
#define PKT_NEWDATA TCP_NEWDATA
+#define CAN_NEWDATA TCP_NEWDATA
#define WPAN_NEWDATA TCP_NEWDATA
#define IPFWD_NEWDATA TCP_NEWDATA
#define TCP_SNDACK (1 << 2)
@@ -175,6 +176,7 @@
#define TCP_POLL (1 << 4)
#define UDP_POLL TCP_POLL
#define PKT_POLL TCP_POLL
+#define CAN_POLL TCP_POLL
#define BLUETOOTH_POLL TCP_POLL
#define IEEE802154_POLL TCP_POLL
#define WPAN_POLL TCP_POLL
@@ -492,7 +494,7 @@ void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
*
****************************************************************************/
-#ifdef CONFIG_NET_PKT
+#if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_CAN)
void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
unsigned int len);
#endif
diff --git a/net/devif/devif_pktsend.c b/net/devif/devif_pktsend.c
index b041b2f..a5d0515 100644
--- a/net/devif/devif_pktsend.c
+++ b/net/devif/devif_pktsend.c
@@ -45,7 +45,7 @@
#include <nuttx/net/netdev.h>
-#ifdef CONFIG_NET_PKT
+#if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_CAN)
/****************************************************************************
* Pre-processor Definitions
diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c
index 7c4fd04..e997a6f 100644
--- a/net/devif/devif_poll.c
+++ b/net/devif/devif_poll.c
@@ -50,6 +50,7 @@
#include "devif/devif.h"
#include "arp/arp.h"
+#include "can/can.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
@@ -233,6 +234,46 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
#endif /* CONFIG_NET_PKT */
/****************************************************************************
+ * Name: devif_poll_pkt_connections
+ *
+ * Description:
+ * Poll all packet connections for available packets to send.
+ *
+ * Assumptions:
+ * This function is called from the MAC device driver with the network
+ * locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN
+static int devif_poll_can_connections(FAR struct net_driver_s *dev,
+ devif_poll_callback_t callback)
+{
+ FAR struct can_conn_s *can_conn = NULL;
+ int bstop = 0;
+
+ /* Traverse all of the allocated packet connections and perform the poll action */
+
+ while (!bstop && (can_conn = can_nextconn(can_conn)))
+ {
+ /* Perform the packet TX poll */
+
+ can_poll(dev, can_conn);
+
+ /* Perform any necessary conversions on outgoing packets */
+
+ devif_packet_conversion(dev, DEVIF_CAN);
+
+ /* Call back into the driver */
+
+ bstop = callback(dev);
+ }
+
+ return bstop;
+}
+#endif /* CONFIG_NET_PKT */
+
+/****************************************************************************
* Name: devif_poll_bluetooth_connections
*
* Description:
@@ -646,6 +687,14 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
if (!bstop)
#endif
+#ifdef CONFIG_NET_CAN
+ {
+ /* Check for pending packet socket transfer */
+ bstop = devif_poll_can_connections(dev, callback);
+ }
+
+ if (!bstop)
+#endif
#ifdef CONFIG_NET_BLUETOOTH
{
/* Check for pending PF_BLUETOOTH socket transfer */
diff --git a/net/local/local_sendpacket.c b/net/local/local_sendpacket.c
index 68dfac6..644dd31 100644
--- a/net/local/local_sendpacket.c
+++ b/net/local/local_sendpacket.c
@@ -47,6 +47,7 @@
#include <debug.h>
#include <nuttx/fs/fs.h>
+#include "devif/devif.h"
#include "local/local.h"
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index 85483dc..fc4634b 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -37,6 +37,7 @@
#include <nuttx/net/netdev.h>
#include <nuttx/net/ethernet.h>
#include <nuttx/net/bluetooth.h>
+#include <nuttx/net/can.h>
#include "utils/utils.h"
#include "igmp/igmp.h"
@@ -55,6 +56,7 @@
#define NETDEV_PAN_FORMAT "pan%d"
#define NETDEV_WLAN_FORMAT "wlan%d"
#define NETDEV_WPAN_FORMAT "wpan%d"
+#define NETDEV_CAN_FORMAT "can%d"
#if defined(CONFIG_DRIVERS_IEEE80211) /* Usually also has CONFIG_NET_ETHERNET */
# define NETDEV_DEFAULT_FORMAT NETDEV_WLAN_FORMAT
@@ -66,6 +68,8 @@
# define NETDEV_DEFAULT_FORMAT NETDEV_SLIP_FORMAT
#elif defined(CONFIG_NET_TUN)
# define NETDEV_DEFAULT_FORMAT NETDEV_TUN_FORMAT
+#elif defined(CONFIG_NET_CAN)
+# define NETDEV_DEFAULT_FORMAT NETDEV_CAN_FORMAT
#else /* if defined(CONFIG_NET_LOOPBACK) */
# define NETDEV_DEFAULT_FORMAT NETDEV_LO_FORMAT
#endif
@@ -276,6 +280,14 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
break;
#endif
+#ifdef CONFIG_NET_CAN
+ case NET_LL_CAN: /* CAN bus */
+ dev->d_llhdrlen = 0;
+ dev->d_pktsize = NET_CAN_PKTSIZE;
+ devfmt = NETDEV_CAN_FORMAT;
+ break;
+#endif
+
#ifdef CONFIG_NET_BLUETOOTH
case NET_LL_BLUETOOTH: /* Bluetooth */
llhdrlen = BLUETOOTH_MAX_HDRLEN; /* Determined at runtime */