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 f2696eab9bea51d6f2ee1a5c99e680a7f5987198 Author: Peter van der Perk <peter.vanderp...@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 3f69fb0..8f961e0 100644 --- a/arch/arm/src/s32k1xx/Make.defs +++ b/arch/arm/src/s32k1xx/Make.defs @@ -90,6 +90,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 <a...@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 a6250c1..02f7ac2 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -152,7 +152,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 <a...@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 3b00ee6..6b3e5b8 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -53,6 +53,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" @@ -71,6 +72,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 @@ -82,6 +84,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 @@ -290,6 +294,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 */ dev->d_llhdrlen = BLUETOOTH_MAX_HDRLEN; /* Determined at runtime */