From 670d405172d52bcb4844a8b69a5b06fb05e83e2f Mon Sep 17 00:00:00 2001 From: "Thomas E. Horner" <> Date: Wed, 10 Apr 2019 15:30:20 +0200 Subject: [PATCH 1/3] rework CAN to use esp-idf functionality --- components/can/CAN.c | 283 ---------- components/can/component.mk | 14 - components/can/include/CAN.h | 115 ---- components/can/include/CAN_config.h | 60 --- components/can/include/can_bus.h | 2 - components/can/include/can_regdef.h | 249 --------- components/lua/modules/hw/can.c | 303 +++++------ components/sys/drivers/can.c | 778 +++++++++++++++------------- components/sys/drivers/can.h | 33 ++ 9 files changed, 620 insertions(+), 1217 deletions(-) delete mode 100644 components/can/CAN.c delete mode 100755 components/can/component.mk delete mode 100644 components/can/include/CAN.h delete mode 100644 components/can/include/CAN_config.h delete mode 100644 components/can/include/can_bus.h delete mode 100644 components/can/include/can_regdef.h mode change 100644 => 100755 components/lua/modules/hw/can.c mode change 100644 => 100755 components/sys/drivers/can.c diff --git a/components/can/CAN.c b/components/can/CAN.c deleted file mode 100644 index 67a40fa55..000000000 --- a/components/can/CAN.c +++ /dev/null @@ -1,283 +0,0 @@ -/** - * @section License - * - * The MIT License (MIT) - * - * Copyright (c) 2017, Thomas Barth, barth-dev.de - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "CAN.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" - -#include "esp_intr.h" -#include "soc/dport_reg.h" - -#include -#include - -#include "driver/gpio.h" - -#include "can_regdef.h" -#include "CAN_config.h" - - -static void CAN_read_frame(); -static void CAN_isr(void *arg_p); - -CAN_stats_t CAN_stat; - -static void CAN_isr(void *arg_p){ - - //Interrupt flag buffer - __CAN_IRQ_t interrupt; - - // Read interrupt status and clear flags - interrupt = MODULE_CAN->IR.U; - - // Handle TX complete interrupt - if ((interrupt & __CAN_IRQ_TX) != 0) { - /*handler*/ - } - - // Handle RX frame available interrupt - if ((interrupt & __CAN_IRQ_RX) != 0) - CAN_read_frame(); - - // Handle overrun - if ((interrupt & __CAN_IRQ_DATA_OVERRUN) != 0) - CAN_stat.hw_overruns++; - - // Handle bus errors - if ((interrupt & __CAN_IRQ_BUS_ERR) != 0) - CAN_stat.bus_errors++; - - // Handle arbitration lost - if ((interrupt & __CAN_IRQ_ARB_LOST) != 0) - CAN_stat.passive_errors++; - - // Handle arbitration lost - if ((interrupt & __CAN_IRQ_ERR) != 0) - CAN_stat.irq_errors++; - - // Handle irq wakeup - if ((interrupt & __CAN_IRQ_WAKEUP) != 0) { - } -} - -static void CAN_read_frame(){ - //byte iterator - uint8_t __byte_i; - - //frame read buffer - CAN_frame_t __frame; - - //check if we have a queue. If not, operation is aborted. - if (CAN_cfg.rx_queue == NULL){ - // Let the hardware know the frame has been read. - MODULE_CAN->CMR.B.RRB=1; - return; - } - - //get FIR - __frame.FIR.U=MODULE_CAN->MBX_CTRL.FCTRL.FIR.U; - - //check if this is a standard or extended CAN frame - //standard frame - if(__frame.FIR.B.FF==CAN_frame_std){ - - //Get Message ID - __frame.MsgID = _CAN_GET_STD_ID; - - //deep copy data bytes - for(__byte_i=0;__byte_i<__frame.FIR.B.DLC;__byte_i++) - __frame.data.u8[__byte_i]=MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i]; - - } - //extended frame - else{ - - //Get Message ID - __frame.MsgID = _CAN_GET_EXT_ID; - - //deep copy data bytes - for(__byte_i=0;__byte_i<__frame.FIR.B.DLC;__byte_i++) - __frame.data.u8[__byte_i]=MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[__byte_i]; - - } - - //Let the hardware know the frame has been read. - MODULE_CAN->CMR.B.RRB=1; - - CAN_stat.rx.packets++; - CAN_stat.rx.bytes += __frame.FIR.B.DLC; - - //send frame to input queue - if (xQueueSendFromISR(CAN_cfg.rx_queue,&__frame,0) == errQUEUE_FULL) { - CAN_stat.sw_overruns++; - } -} - -int CAN_write_frame(const CAN_frame_t* p_frame){ - CAN_stat.tx.packets++; - CAN_stat.tx.bytes += p_frame->FIR.B.DLC; - - //byte iterator - uint8_t __byte_i; - - //copy frame information record - MODULE_CAN->MBX_CTRL.FCTRL.FIR.U=p_frame->FIR.U; - - //standard frame - if(p_frame->FIR.B.FF==CAN_frame_std){ - - //Write message ID - _CAN_SET_STD_ID(p_frame->MsgID); - - // Copy the frame data to the hardware - for(__byte_i=0;__byte_iFIR.B.DLC;__byte_i++) - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i]=p_frame->data.u8[__byte_i]; - - } - //extended frame - else{ - - //Write message ID - _CAN_SET_EXT_ID(p_frame->MsgID); - - // Copy the frame data to the hardware - for(__byte_i=0;__byte_iFIR.B.DLC;__byte_i++) - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[__byte_i]=p_frame->data.u8[__byte_i]; - - } - - // Transmit frame - MODULE_CAN->CMR.B.TR=1; - - return 0; -} - -int CAN_init(){ - // Time quantum - double __tq; - - // reset stats - memset(&CAN_stat, 0, sizeof(CAN_stats_t)); - - //enable module - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST); - - //configure TX pin - gpio_set_direction(CAN_cfg.tx_pin_id,GPIO_MODE_OUTPUT); - gpio_matrix_out(CAN_cfg.tx_pin_id,CAN_TX_IDX,0,0); - gpio_pad_select_gpio(CAN_cfg.tx_pin_id); - - //configure RX pin - gpio_set_direction(CAN_cfg.rx_pin_id,GPIO_MODE_INPUT); - gpio_matrix_in(CAN_cfg.rx_pin_id,CAN_RX_IDX,0); - gpio_pad_select_gpio(CAN_cfg.rx_pin_id); - - //set to PELICAN mode - MODULE_CAN->CDR.B.CAN_M=0x1; - - //synchronization jump width is the same for all baud rates - MODULE_CAN->BTR0.B.SJW =0x1; - - //TSEG2 is the same for all baud rates - MODULE_CAN->BTR1.B.TSEG2 =0x1; - - //select time quantum and set TSEG1 - switch(CAN_cfg.speed){ - case CAN_SPEED_1000KBPS: - MODULE_CAN->BTR1.B.TSEG1 =0x4; - __tq = 0.125; - break; - - case CAN_SPEED_800KBPS: - MODULE_CAN->BTR1.B.TSEG1 =0x6; - __tq = 0.125; - break; - default: - MODULE_CAN->BTR1.B.TSEG1 =0xc; - __tq = (((float)1000/CAN_cfg.speed) / 16) * 1000; - } - - //set baud rate prescaler - MODULE_CAN->BTR0.B.BRP=(uint8_t)round((((APB_CLK_FREQ * __tq) / 2) - 1)/1000000)-1; - - /* Set sampling - * 1 -> triple; the bus is sampled three times; recommended for low/medium speed buses (class A and B) where filtering spikes on the bus line is beneficial - * 0 -> single; the bus is sampled once; recommended for high speed buses (SAE class C)*/ - MODULE_CAN->BTR1.B.SAM =0x1; - - //enable all interrupts - MODULE_CAN->IER.U = 0xff; - - //no acceptance filtering, as we want to fetch all messages - MODULE_CAN->MBX_CTRL.ACC.CODE[0] = 0; - MODULE_CAN->MBX_CTRL.ACC.CODE[1] = 0; - MODULE_CAN->MBX_CTRL.ACC.CODE[2] = 0; - MODULE_CAN->MBX_CTRL.ACC.CODE[3] = 0; - MODULE_CAN->MBX_CTRL.ACC.MASK[0] = 0xff; - MODULE_CAN->MBX_CTRL.ACC.MASK[1] = 0xff; - MODULE_CAN->MBX_CTRL.ACC.MASK[2] = 0xff; - MODULE_CAN->MBX_CTRL.ACC.MASK[3] = 0xff; - - //set to normal mode - MODULE_CAN->OCR.B.OCMODE=__CAN_OC_NOM; - - //clear error counters - MODULE_CAN->TXERR.U = 0; - MODULE_CAN->RXERR.U = 0; - (void)MODULE_CAN->ECC; - - //clear interrupt flags - (void)MODULE_CAN->IR.U; - - //install CAN ISR - esp_intr_alloc(ETS_CAN_INTR_SOURCE,0,CAN_isr,NULL,NULL); - - //Showtime. Release Reset Mode. - MODULE_CAN->MOD.B.RM = 0; - - return 0; -} - -int CAN_stop(){ - - //enter reset mode - MODULE_CAN->MOD.B.RM = 1; - - return 0; -} - -int CAN_start(){ - - //exit reset mode - MODULE_CAN->MOD.B.RM = 0; - - return 0; -} diff --git a/components/can/component.mk b/components/can/component.mk deleted file mode 100755 index 8b353ab5c..000000000 --- a/components/can/component.mk +++ /dev/null @@ -1,14 +0,0 @@ -# currently the only SoC supported; to be moved into Kconfig - -ifdef CONFIG_LUA_RTOS_LUA_USE_CAN - -COMPONENT_SRCDIRS := . cfg -COMPONENT_ADD_INCLUDEDIRS := include - -else - -# disable CAN support -COMPONENT_SRCDIRS := -COMPONENT_ADD_INCLUDEDIRS := - -endif diff --git a/components/can/include/CAN.h b/components/can/include/CAN.h deleted file mode 100644 index 2d90ec125..000000000 --- a/components/can/include/CAN.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @section License - * - * The MIT License (MIT) - * - * Copyright (c) 2017, Thomas Barth, barth-dev.de - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __DRIVERS_CAN_H__ -#define __DRIVERS_CAN_H__ - -#include -#include "CAN_config.h" - -/** - * \brief CAN frame type (standard/extended) - */ -typedef enum { - CAN_frame_std=0, /**< Standard frame, using 11 bit identifer. */ - CAN_frame_ext=1 /**< Extended frame, using 29 bit identifer. */ -}CAN_frame_format_t; - -/** - * \brief CAN RTR - */ -typedef enum { - CAN_no_RTR=0, /**< No RTR frame. */ - CAN_RTR=1 /**< RTR frame. */ -}CAN_RTR_t; - -/** \brief Frame information record type */ -typedef union{uint32_t U; /**< \brief Unsigned access */ - struct { - uint8_t DLC:4; /**< \brief [3:0] DLC, Data length container */ - unsigned int unknown_2:2; /**< \brief \internal unknown */ - CAN_RTR_t RTR:1; /**< \brief [6:6] RTR, Remote Transmission Request */ - CAN_frame_format_t FF:1; /**< \brief [7:7] Frame Format, see# CAN_frame_format_t*/ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; -} CAN_FIR_t; - - -/** \brief CAN Frame structure */ -typedef struct { - CAN_FIR_t FIR; /**< \brief Frame information record*/ - uint32_t MsgID; /**< \brief Message ID */ - union { - uint8_t u8[8]; /**< \brief Payload byte access*/ - uint32_t u32[2]; /**< \brief Payload u32 access*/ - } data; -}CAN_frame_t; - -typedef struct { - struct { - uint32_t packets; - uint32_t bytes; - } rx; - - struct { - uint32_t packets; - uint32_t bytes; - } tx; - - uint32_t hw_overruns; - uint32_t sw_overruns; - uint32_t bus_errors; - uint32_t arbitration_lost_errors; - uint32_t passive_errors; - uint32_t irq_errors; -} CAN_stats_t; - -/** - * \brief Initialize the CAN Module - * - * \return 0 CAN Module had been initialized - */ -int CAN_init(void); - -/** - * \brief Send a can frame - * - * \param p_frame Pointer to the frame to be send, see #CAN_frame_t - * \return 0 Frame has been written to the module - */ -int CAN_write_frame(const CAN_frame_t* p_frame); - -/** - * \brief Stops the CAN Module - * - * \return 0 CAN Module was stopped - */ -int CAN_stop(void); -int CAN_start(); - -#endif diff --git a/components/can/include/CAN_config.h b/components/can/include/CAN_config.h deleted file mode 100644 index cc521982d..000000000 --- a/components/can/include/CAN_config.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @section License - * - * The MIT License (MIT) - * - * Copyright (c) 2017, Thomas Barth, barth-dev.de - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __DRIVERS_CAN_CFG_H__ -#define __DRIVERS_CAN_CFG_H__ - -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "driver/gpio.h" - - -/** \brief CAN Node Bus speed */ -typedef enum { - CAN_SPEED_100KBPS=100, /**< \brief CAN Node runs at 100kBit/s. */ - CAN_SPEED_125KBPS=125, /**< \brief CAN Node runs at 125kBit/s. */ - CAN_SPEED_250KBPS=250, /**< \brief CAN Node runs at 250kBit/s. */ - CAN_SPEED_500KBPS=500, /**< \brief CAN Node runs at 500kBit/s. */ - CAN_SPEED_800KBPS=800, /**< \brief CAN Node runs at 800kBit/s. */ - CAN_SPEED_1000KBPS=1000, /**< \brief CAN Node runs at 1000kBit/s. */ - CAN_SPEED_500000KBPS=500000 /**< \brief CAN Node runs at 500000/s. */ -}CAN_speed_t; - -/** \brief CAN configuration structure */ -typedef struct { - CAN_speed_t speed; /**< \brief CAN speed. */ - gpio_num_t tx_pin_id; /**< \brief TX pin. */ - gpio_num_t rx_pin_id; /**< \brief RX pin. */ - QueueHandle_t rx_queue; /**< \brief Handler to FreeRTOS RX queue. */ -}CAN_device_t; - -/** \brief CAN configuration reference */ -extern CAN_device_t CAN_cfg; - - -#endif /* __DRIVERS_CAN_CFG_H__ */ diff --git a/components/can/include/can_bus.h b/components/can/include/can_bus.h deleted file mode 100644 index d80ef056f..000000000 --- a/components/can/include/can_bus.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "CAN.h" -#include "CAN_config.h" diff --git a/components/can/include/can_regdef.h b/components/can/include/can_regdef.h deleted file mode 100644 index 1f9d2cb4a..000000000 --- a/components/can/include/can_regdef.h +++ /dev/null @@ -1,249 +0,0 @@ -/** - * @section License - * - * The MIT License (MIT) - * - * Copyright (c) 2017, Thomas Barth, barth-dev.de - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __DRIVERS_CAN_REGDEF_H_ -#define __DRIVERS_CAN_REGDEF_H_ - -#include "CAN.h" //CAN_FIR_t - -/** \brief Start address of CAN registers */ -#define MODULE_CAN ((volatile CAN_Module_t *)0x3ff6b000) - -/** \brief Get standard message ID */ -#define _CAN_GET_STD_ID (((uint32_t)MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] << 3) | \ - (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] >> 5)) - -/** \brief Get extended message ID */ -#define _CAN_GET_EXT_ID (((uint32_t)MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] << 21) | \ - (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] << 13) | \ - (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] << 5) | \ - (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] >> 3 )) - -/** \brief Set standard message ID */ -#define _CAN_SET_STD_ID(x) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] = ((x) >> 3); \ - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] = ((x) << 5); - -/** \brief Set extended message ID */ -#define _CAN_SET_EXT_ID(x) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] = ((x) >> 21); \ - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] = ((x) >> 13); \ - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] = ((x) >> 5); \ - MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] = ((x) << 3); \ - -/** \brief Interrupt status register */ -typedef enum { - __CAN_IRQ_RX= BIT(0), /**< \brief RX Interrupt */ - __CAN_IRQ_TX= BIT(1), /**< \brief TX Interrupt */ - __CAN_IRQ_ERR= BIT(2), /**< \brief Error Interrupt */ - __CAN_IRQ_DATA_OVERRUN= BIT(3), /**< \brief Date Overrun Interrupt */ - __CAN_IRQ_WAKEUP= BIT(4), /**< \brief Wakeup Interrupt */ - __CAN_IRQ_ERR_PASSIVE= BIT(5), /**< \brief Passive Error Interrupt */ - __CAN_IRQ_ARB_LOST= BIT(6), /**< \brief Arbitration lost interrupt */ - __CAN_IRQ_BUS_ERR= BIT(7), /**< \brief Bus error Interrupt */ -}__CAN_IRQ_t; - - -/** \brief OCMODE options. */ -typedef enum { - __CAN_OC_BOM= 0b00, /**< \brief bi-phase output mode */ - __CAN_OC_TOM= 0b01, /**< \brief test output mode */ - __CAN_OC_NOM= 0b10, /**< \brief normal output mode */ - __CAN_OC_COM= 0b11, /**< \brief clock output mode */ -}__CAN_OCMODE_t; - - -/** - * CAN controller (SJA1000). - */ -typedef struct { - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RM:1; /**< \brief MOD.0 Reset Mode */ - unsigned int LOM:1; /**< \brief MOD.1 Listen Only Mode */ - unsigned int STM:1; /**< \brief MOD.2 Self Test Mode */ - unsigned int AFM:1; /**< \brief MOD.3 Acceptance Filter Mode */ - unsigned int SM:1; /**< \brief MOD.4 Sleep Mode */ - unsigned int reserved_27:27; /**< \brief \internal Reserved */ - } B; - } MOD; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int TR:1; /**< \brief CMR.0 Transmission Request */ - unsigned int AT:1; /**< \brief CMR.1 Abort Transmission */ - unsigned int RRB:1; /**< \brief CMR.2 Release Receive Buffer */ - unsigned int CDO:1; /**< \brief CMR.3 Clear Data Overrun */ - unsigned int GTS:1; /**< \brief CMR.4 Go To Sleep */ - unsigned int reserved_27:27; /**< \brief \internal Reserved */ - } B; - } CMR; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RBS:1; /**< \brief SR.0 Receive Buffer Status */ - unsigned int DOS:1; /**< \brief SR.1 Data Overrun Status */ - unsigned int TBS:1; /**< \brief SR.2 Transmit Buffer Status */ - unsigned int TCS:1; /**< \brief SR.3 Transmission Complete Status */ - unsigned int RS:1; /**< \brief SR.4 Receive Status */ - unsigned int TS:1; /**< \brief SR.5 Transmit Status */ - unsigned int ES:1; /**< \brief SR.6 Error Status */ - unsigned int BS:1; /**< \brief SR.7 Bus Status */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } SR; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RI:1; /**< \brief IR.0 Receive Interrupt */ - unsigned int TI:1; /**< \brief IR.1 Transmit Interrupt */ - unsigned int EI:1; /**< \brief IR.2 Error Interrupt */ - unsigned int DOI:1; /**< \brief IR.3 Data Overrun Interrupt */ - unsigned int WUI:1; /**< \brief IR.4 Wake-Up Interrupt */ - unsigned int EPI:1; /**< \brief IR.5 Error Passive Interrupt */ - unsigned int ALI:1; /**< \brief IR.6 Arbitration Lost Interrupt */ - unsigned int BEI:1; /**< \brief IR.7 Bus Error Interrupt */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } IR; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RIE:1; /**< \brief IER.0 Receive Interrupt Enable */ - unsigned int TIE:1; /**< \brief IER.1 Transmit Interrupt Enable */ - unsigned int EIE:1; /**< \brief IER.2 Error Interrupt Enable */ - unsigned int DOIE:1; /**< \brief IER.3 Data Overrun Interrupt Enable */ - unsigned int WUIE:1; /**< \brief IER.4 Wake-Up Interrupt Enable */ - unsigned int EPIE:1; /**< \brief IER.5 Error Passive Interrupt Enable */ - unsigned int ALIE:1; /**< \brief IER.6 Arbitration Lost Interrupt Enable */ - unsigned int BEIE:1; /**< \brief IER.7 Bus Error Interrupt Enable */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } IER; - uint32_t RESERVED0; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int BRP:6; /**< \brief BTR0[5:0] Baud Rate Prescaler */ - unsigned int SJW:2; /**< \brief BTR0[7:6] Synchronization Jump Width*/ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } BTR0; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int TSEG1:4; /**< \brief BTR1[3:0] Timing Segment 1 */ - unsigned int TSEG2:3; /**< \brief BTR1[6:4] Timing Segment 2*/ - unsigned int SAM:1; /**< \brief BTR1.7 Sampling*/ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } BTR1; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int OCMODE:2; /**< \brief OCR[1:0] Output Control Mode, see # */ - unsigned int OCPOL0:1; /**< \brief OCR.2 Output Control Polarity 0 */ - unsigned int OCTN0:1; /**< \brief OCR.3 Output Control Transistor N0 */ - unsigned int OCTP0:1; /**< \brief OCR.4 Output Control Transistor P0 */ - unsigned int OCPOL1:1; /**< \brief OCR.5 Output Control Polarity 1 */ - unsigned int OCTN1:1; /**< \brief OCR.6 Output Control Transistor N1 */ - unsigned int OCTP1:1; /**< \brief OCR.7 Output Control Transistor P1 */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } OCR; - uint32_t RESERVED1[2]; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int ALC:8; /**< \brief ALC[7:0] Arbitration Lost Capture */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } ALC; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int ECC:8; /**< \brief ECC[7:0] Error Code Capture */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } ECC; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int EWLR:8; /**< \brief EWLR[7:0] Error Warning Limit */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } EWLR; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RXERR:8; /**< \brief RXERR[7:0] Receive Error Counter */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } RXERR; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int TXERR:8; /**< \brief TXERR[7:0] Transmit Error Counter */ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } TXERR; - - union { - struct { - uint32_t CODE[4]; /**< \brief Acceptance Message ID */ - uint32_t MASK[4]; /**< \brief Acceptance Mask */ - uint32_t RESERVED2[5]; - } ACC; /**< \brief Acceptance filtering */ - struct { - CAN_FIR_t FIR; /**< \brief Frame information record */ - union{ - struct { - uint32_t ID[2]; /**< \brief Standard frame message-ID*/ - uint32_t data[8]; /**< \brief Standard frame payload */ - uint32_t reserved[2]; - } STD; /**< \brief Standard frame format */ - struct { - uint32_t ID[4]; /**< \brief Extended frame message-ID*/ - uint32_t data[8]; /**< \brief Extended frame payload */ - } EXT; /**< \brief Extended frame format */ - }TX_RX; /**< \brief RX/TX interface */ - }FCTRL; /**< \brief Function control regs */ - } MBX_CTRL; /**< \brief Mailbox control */ - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RMC:8; /**< \brief RMC[7:0] RX Message Counter */ - unsigned int reserved_24:24; /**< \brief \internal Reserved Enable */ - } B; - } RMC; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int RBSA:8; /**< \brief RBSA[7:0] RX Buffer Start Address */ - unsigned int reserved_24:24; /**< \brief \internal Reserved Enable */ - } B; - } RBSA; - union{uint32_t U; /**< \brief Unsigned access */ - struct { - unsigned int COD:3; /**< \brief CDR[2:0] CLKOUT frequency selector based of fOSC*/ - unsigned int COFF:1; /**< \brief CDR.3 CLKOUT off*/ - unsigned int reserved_1:1; /**< \brief \internal Reserved */ - unsigned int RXINTEN:1; /**< \brief CDR.5 This bit allows the TX1 output to be used as a dedicated receive interrupt output*/ - unsigned int CBP:1; /**< \brief CDR.6 allows to bypass the CAN input comparator and is only possible in reset mode.*/ - unsigned int CAN_M:1; /**< \brief CDR.7 If CDR.7 is at logic 0 the CAN controller operates in BasicCAN mode. If set to logic 1 the CAN controller operates in PeliCAN mode. Write access is only possible in reset mode*/ - unsigned int reserved_24:24; /**< \brief \internal Reserved */ - } B; - } CDR; - uint32_t IRAM[2]; -}CAN_Module_t; - -#endif /* __DRIVERS_CAN_REGDEF_H_ */ diff --git a/components/lua/modules/hw/can.c b/components/lua/modules/hw/can.c old mode 100644 new mode 100755 index 7a3d3032f..88196018a --- a/components/lua/modules/hw/can.c +++ b/components/lua/modules/hw/can.c @@ -56,207 +56,216 @@ #include -#include - +#include #include #include +#define MIN(a,b) ((a) < (b) ? (a) : (b)) static uint8_t dump_stop = 0; -extern CAN_stats_t CAN_stat; - static int lcan_attach(lua_State* L) { - driver_error_t *error; + driver_error_t *error; - int id = luaL_checkinteger(L, 1); - uint32_t speed = luaL_checkinteger(L, 2); - uint16_t rx_size = luaL_optinteger(L, 3, 200); + int id = luaL_checkinteger(L, 1); + uint32_t speed = luaL_checkinteger(L, 2); + uint16_t rx_size = luaL_optinteger(L, 3, 200); if ((error = can_setup(id, speed, rx_size))) { - return luaL_driver_error(L, error); + return luaL_driver_error(L, error); } return 0; } static int lcan_send(lua_State* L) { - driver_error_t *error; + driver_error_t *error; - int id = luaL_checkinteger(L, 1); - int msg_id = luaL_checkinteger(L, 2); - int msg_id_type = luaL_checkinteger(L, 3); - int len = luaL_checkinteger(L, 4); - const char *data = luaL_checkstring(L, 5); + int id = luaL_checkinteger(L, 1); + int msg_id = luaL_checkinteger(L, 2); + int msg_id_type = luaL_checkinteger(L, 3); + int len = luaL_checkinteger(L, 4); + size_t datalen; + const char *data = luaL_checklstring(L, 5, &datalen); - if ((error = can_tx(id, msg_id, msg_id_type, (uint8_t *)data, len))) { - return luaL_driver_error(L, error); + if ((error = can_tx(id, msg_id, msg_id_type, (uint8_t *)data, MIN(len, datalen)))) { + return luaL_driver_error(L, error); } - return 0; + return 0; } static int lcan_add_filter(lua_State* L) { - driver_error_t *error; + driver_error_t *error; - int id = luaL_checkinteger(L, 1); - int fromId = luaL_checkinteger(L, 2); - int toId = luaL_checkinteger(L, 3); + int id = luaL_checkinteger(L, 1); + int fromId = luaL_checkinteger(L, 2); + int toId = luaL_checkinteger(L, 3); if ((error = can_add_filter(id, fromId, toId))) { - return luaL_driver_error(L, error); + return luaL_driver_error(L, error); } - - return 0; + return 0; } static int lcan_remove_filter(lua_State* L) { - driver_error_t *error; + driver_error_t *error; - int id = luaL_checkinteger(L, 1); - int fromId = luaL_checkinteger(L, 2); - int toId = luaL_checkinteger(L, 3); + int id = luaL_checkinteger(L, 1); + int fromId = luaL_checkinteger(L, 2); + int toId = luaL_checkinteger(L, 3); if ((error = can_remove_filter(id, fromId, toId))) { - return luaL_driver_error(L, error); + return luaL_driver_error(L, error); } - - return 0; + return 0; } static int lcan_recv(lua_State* L) { - driver_error_t *error; - uint32_t msg_id; - uint8_t msg_id_type; - uint8_t len; - uint8_t data[9] = {0,0,0,0,0,0,0,0,0}; + driver_error_t *error; + uint32_t msg_id; + uint8_t msg_id_type; + uint8_t len; + uint8_t data[9] = {0,0,0,0,0,0,0,0,0}; - int id = luaL_checkinteger(L, 1); + int id = luaL_checkinteger(L, 1); if ((error = can_rx(id, &msg_id, &msg_id_type, data, &len))) { - return luaL_driver_error(L, error); + return luaL_driver_error(L, error); } - lua_pushinteger(L, msg_id); - lua_pushinteger(L, msg_id_type); - lua_pushinteger(L, len); - lua_pushlstring(L, (const char *) data, (size_t) len); + lua_pushinteger(L, msg_id); + lua_pushinteger(L, msg_id_type); + lua_pushinteger(L, len); + lua_pushlstring(L, (const char *) data, (size_t) len); - return 4; + return 4; } static void ldump_stop (int i) { - dump_stop = 1; + dump_stop = 1; } static int lcan_dump(lua_State* L) { - driver_error_t *error; - uint32_t msg_id; - uint8_t msg_id_type; - uint8_t len; - uint8_t data[9] = {0,0,0,0,0,0,0,0,0}; - int id = luaL_checkinteger(L, 1); - int i; + driver_error_t *error; + uint32_t msg_id; + uint8_t msg_id_type; + uint8_t len; + uint8_t data[9] = {0,0,0,0,0,0,0,0,0}; + int id = luaL_checkinteger(L, 1); + int i; - dump_stop = 0; - signal(SIGINT, ldump_stop); + dump_stop = 0; + signal(SIGINT, ldump_stop); - while (!dump_stop) { - if ((error = can_rx(id, &msg_id, &msg_id_type, data, &len))) { - return luaL_driver_error(L, error); - } + while (!dump_stop) { + if ((error = can_rx(id, &msg_id, &msg_id_type, data, &len))) { + return luaL_driver_error(L, error); + } - printf("can%d %08x [%d] ", id, msg_id, len); + printf("can%d %08x [%d] ", id, msg_id, len); - for(i = 0;i 0) { - printf(" "); - } + for(i = 0;i 0) { + printf(" "); + } - printf("%02x", data[i]); - } + printf("%02x", data[i]); + } - printf("\r\n"); - } + printf("\r\n"); + } - return 0; + return 0; } static int lcan_stats(lua_State* L) { - uint8_t table = 0; - - // Check if user wants result as a table, or wants scan's result - // on the console - if (lua_gettop(L) == 1) { - luaL_checktype(L, 1, LUA_TBOOLEAN); - if (lua_toboolean(L, 1)) { - table = 1; - } - } - - if (table) { - lua_createtable(L, 0, 12); - - lua_pushinteger(L, CAN_stat.rx.packets); - lua_setfield (L, -2, "rx_packets"); - - lua_pushinteger(L, CAN_stat.rx.bytes); - lua_setfield (L, -2, "rx_bytes"); - - lua_pushinteger(L, CAN_stat.tx.packets); - lua_setfield (L, -2, "tx_packets"); - - lua_pushinteger(L, CAN_stat.hw_overruns); - lua_setfield (L, -2, "hw_overruns"); - - lua_pushinteger(L, CAN_stat.sw_overruns); - lua_setfield (L, -2, "sw_overruns"); - - lua_pushinteger(L, CAN_stat.bus_errors); - lua_setfield (L, -2, "bus_error"); - - lua_pushinteger(L, CAN_stat.arbitration_lost_errors); - lua_setfield (L, -2, "arbitration_lost_errors"); - - lua_pushinteger(L, CAN_stat.passive_errors); - lua_setfield (L, -2, "passive_errors"); - - lua_pushinteger(L, CAN_stat.irq_errors); - lua_setfield (L, -2, "irq_errors"); - } else { - printf("RX packets:%d bytes:%d\r\n", CAN_stat.rx.packets, CAN_stat.rx.bytes); - printf("TX packets:%d bytes:%d\r\n", CAN_stat.tx.packets, CAN_stat.tx.bytes); - printf("hw overruns:%d\r\n",CAN_stat.hw_overruns); - printf("sw overruns:%d\r\n",CAN_stat.sw_overruns); - - printf("errors:\r\n"); - printf(" hw overruns:%d\r\n",CAN_stat.hw_overruns); - printf(" sw overruns:%d\r\n",CAN_stat.sw_overruns); - printf(" bus:%d arbitration lost:%d passive:%d irq:%d\r\n", - CAN_stat.bus_errors, - CAN_stat.arbitration_lost_errors, - CAN_stat.passive_errors, - CAN_stat.irq_errors - ); - } - - return table; + can_status_info_t status_info; + driver_error_t *error = can_check_error(can_get_status_info(&status_info)); + if (error) { + return luaL_driver_error(L, error); + } + + uint8_t table = 0; + + // Check if user wants result as a table, or wants scan's result + // on the console + if (lua_gettop(L) == 1) { + luaL_checktype(L, 1, LUA_TBOOLEAN); + if (lua_toboolean(L, 1)) { + table = 1; + } + } + + if (table) { + lua_createtable(L, 0, 12); + + lua_pushinteger(L, status_info.state); + lua_setfield (L, -2, "state"); + + lua_pushinteger(L, status_info.msgs_to_tx); + lua_setfield (L, -2, "msgs_to_tx"); + + lua_pushinteger(L, status_info.msgs_to_rx); + lua_setfield (L, -2, "msgs_to_rx"); + + lua_pushinteger(L, status_info.tx_error_counter); + lua_setfield (L, -2, "tx_error_counter"); + + lua_pushinteger(L, status_info.rx_error_counter); + lua_setfield (L, -2, "rx_error_counter"); + + lua_pushinteger(L, status_info.tx_failed_count); + lua_setfield (L, -2, "tx_failed_count"); + + lua_pushinteger(L, status_info.rx_missed_count); + lua_setfield (L, -2, "rx_missed_count"); + + lua_pushinteger(L, status_info.arb_lost_count); + lua_setfield (L, -2, "arb_lost_count"); + + lua_pushinteger(L, status_info.bus_error_count); + lua_setfield (L, -2, "bus_error_count"); + } else { + char *state = NULL; + switch(status_info.state) { + case CAN_STATE_STOPPED: state = "stopped"; break; + case CAN_STATE_RUNNING: state = "running"; break; + case CAN_STATE_BUS_OFF: state = "bus off"; break; + case CAN_STATE_RECOVERING: state = "recovering"; break; + } + if (state) printf("State: %s\r\n", state); + printf("TX packets waiting: %d\r\n", status_info.msgs_to_tx); + printf("RX packets waiting: %d\r\n", status_info.msgs_to_rx); + printf("TX failed counter: %d\r\n",status_info.tx_failed_count); + printf("RX missed counter: %d\r\n",status_info.rx_missed_count); + + printf("errors:\r\n"); + printf(" TX error counter: %d\r\n",status_info.tx_error_counter); + printf(" RX error counter: %d\r\n",status_info.rx_error_counter); + printf(" bus: %d arbitration lost: %d\r\n", + status_info.bus_error_count, + status_info.arb_lost_count + ); + } + + return table; } static const LUA_REG_TYPE lcan_map[] = { - { LSTRKEY( "attach" ), LFUNCVAL( lcan_attach ) }, - { LSTRKEY( "addfilter" ), LFUNCVAL( lcan_add_filter ) }, - { LSTRKEY( "removefilter" ), LFUNCVAL( lcan_remove_filter ) }, - { LSTRKEY( "send" ), LFUNCVAL( lcan_send ) }, - { LSTRKEY( "receive" ), LFUNCVAL( lcan_recv ) }, - { LSTRKEY( "dump" ), LFUNCVAL( lcan_dump ) }, - { LSTRKEY( "stats" ), LFUNCVAL( lcan_stats ) }, - CAN_CAN0 - CAN_CAN1 - DRIVER_REGISTER_LUA_ERRORS(can) - {LSTRKEY("STD"), LINTVAL(0)}, - {LSTRKEY("EXT"), LINTVAL(1)}, - - { LNILKEY, LNILVAL } + { LSTRKEY( "attach" ), LFUNCVAL( lcan_attach ) }, + { LSTRKEY( "addfilter" ), LFUNCVAL( lcan_add_filter ) }, + { LSTRKEY( "removefilter" ), LFUNCVAL( lcan_remove_filter ) }, + { LSTRKEY( "send" ), LFUNCVAL( lcan_send ) }, + { LSTRKEY( "receive" ), LFUNCVAL( lcan_recv ) }, + { LSTRKEY( "dump" ), LFUNCVAL( lcan_dump ) }, + { LSTRKEY( "stats" ), LFUNCVAL( lcan_stats ) }, + CAN_CAN0 + CAN_CAN1 + DRIVER_REGISTER_LUA_ERRORS(can) + {LSTRKEY("STD"), LINTVAL(0)}, + {LSTRKEY("EXT"), LINTVAL(1)}, + + { LNILKEY, LNILVAL } }; LUALIB_API int luaopen_can( lua_State *L ) { @@ -270,19 +279,19 @@ MODULE_REGISTER_ROM(CAN, can, lcan_map, luaopen_can, 1); /* -can.setup(can.CAN0, 1000) +can.attach(can.CAN0, 1000) while true do frame = string.pack( - "BBBBBBBB", - math.random(255), math.random(255), math.random(255), math.random(255), - math.random(255), math.random(255), math.random(255), math.random(255) + "BBBBBBBB", + math.random(255), math.random(255), math.random(255), math.random(255), + math.random(255), math.random(255), math.random(255), math.random(255) ) - can.send(can.CAN0, 100, can.STD, 8, frame) - tmr.delayms(50) + can.send(can.CAN0, 100, can.STD, 8, frame) + tmr.delayms(50) end -can.setup(can.CAN0, 1000) +can.attach(can.CAN0, 1000) can.dump(can.CAN0) */ diff --git a/components/sys/drivers/can.c b/components/sys/drivers/can.c old mode 100644 new mode 100755 index 754ec134f..8dfda29e5 --- a/components/sys/drivers/can.c +++ b/components/sys/drivers/can.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2015 - 2018, IBEROXARXA SERVICIOS INTEGRALES, S.L. - * Copyright (C) 2015 - 2018, Jaume Olivé Petrus (jolive@whitecatboard.org) + * Copyright (C) 2015 - 2019, Jaume Olivé Petrus (jolive@whitecatboard.org) + * Copyright (C) 2015 - 2019, Thomas E. Horner (whitecatboard.org@horner.it) * * All rights reserved. * @@ -57,7 +58,7 @@ #include #include -#include +#include #include #include @@ -67,12 +68,25 @@ #include #include +#include static uint8_t setup = 0; -static struct mtx mtx; -// CAN configuration -CAN_device_t CAN_cfg; +static can_timing_config_t t_config = CAN_TIMING_CONFIG_25KBITS(); +/* +//Filter all other IDs except MSG_ID +static const can_filter_config_t f_config = {.acceptance_code = (MSG_ID << 21), + .acceptance_mask = ~(CAN_STD_ID_MASK << 21), + .single_filter = true}; +*/ +static can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL(); +//Set to NO_ACK mode due to self testing with single module +static can_general_config_t g_config = CAN_GENERAL_CONFIG_DEFAULT(CONFIG_LUA_RTOS_CAN_TX, CONFIG_LUA_RTOS_CAN_RX, CAN_MODE_NORMAL); +/* {.mode = CAN_MODE_NO_ACK, .tx_io = CONFIG_LUA_RTOS_CAN_TX, .rx_io = CONFIG_LUA_RTOS_CAN_RX, \ + .clkout_io = CAN_IO_UNUSED, .bus_off_io = CAN_IO_UNUSED, \ + .tx_queue_len = 5, .rx_queue_len = 5, \ + .alerts_enabled = CAN_ALERT_NONE, .clkout_divider = 0, } +*/ // CAN gateway configuration can_gw_config_t *gw_config = NULL; @@ -83,171 +97,218 @@ static CAN_filter_t can_filter[CAN_NUM_FILTERS]; // Register driver and errors DRIVER_REGISTER_BEGIN(CAN,can,0,NULL,NULL); - DRIVER_REGISTER_ERROR(CAN, can, NotEnoughtMemory, "not enough memory", CAN_ERR_NOT_ENOUGH_MEMORY); - DRIVER_REGISTER_ERROR(CAN, can, InvalidFrameLength, "invalid frame length", CAN_ERR_INVALID_FRAME_LENGTH); - DRIVER_REGISTER_ERROR(CAN, can, InvalidUnit, "invalid unit", CAN_ERR_INVALID_UNIT); - DRIVER_REGISTER_ERROR(CAN, can, NoMoreFiltersAllowed, "no more filters allowed", CAN_ERR_NO_MORE_FILTERS_ALLOWED); - DRIVER_REGISTER_ERROR(CAN, can, InvalidFilter, "invalid filter", CAN_ERR_INVALID_FILTER); - DRIVER_REGISTER_ERROR(CAN, can, NotSetup, "is not setup", CAN_ERR_IS_NOT_SETUP); - DRIVER_REGISTER_ERROR(CAN, can, CannotStart, "can't start", CAN_ERR_CANT_START); - DRIVER_REGISTER_ERROR(CAN, can, GatewayNotStarted, "gateway not started", CAN_ERR_GW_NOT_STARTED); + DRIVER_REGISTER_ERROR(CAN, can, NotEnoughtMemory, "not enough memory", CAN_ERR_NOT_ENOUGH_MEMORY); + DRIVER_REGISTER_ERROR(CAN, can, InvalidFrameLength, "invalid frame length", CAN_ERR_INVALID_FRAME_LENGTH); + DRIVER_REGISTER_ERROR(CAN, can, InvalidUnit, "invalid unit", CAN_ERR_INVALID_UNIT); + DRIVER_REGISTER_ERROR(CAN, can, NoMoreFiltersAllowed, "no more filters allowed", CAN_ERR_NO_MORE_FILTERS_ALLOWED); + DRIVER_REGISTER_ERROR(CAN, can, InvalidFilter, "invalid filter", CAN_ERR_INVALID_FILTER); + DRIVER_REGISTER_ERROR(CAN, can, NotSetup, "is not setup", CAN_ERR_IS_NOT_SETUP); + DRIVER_REGISTER_ERROR(CAN, can, CannotStart, "can't start", CAN_ERR_CANT_START); + DRIVER_REGISTER_ERROR(CAN, can, GatewayNotStarted, "gateway not started", CAN_ERR_GW_NOT_STARTED); + DRIVER_REGISTER_ERROR(CAN, can, TransmitFail, "error transmitting message", CAN_ERR_TRANSMIT_FAIL); + DRIVER_REGISTER_ERROR(CAN, can, InvalidArg, "invalid argument", CAN_ERR_INVALID_ARGUMENT); + DRIVER_REGISTER_ERROR(CAN, can, InvalidState, "invalid state", CAN_ERR_INVALID_STATE); + DRIVER_REGISTER_ERROR(CAN, can, NotSupport, "can API is not supported yet", CAN_ERR_NOT_SUPPORT); DRIVER_REGISTER_END(CAN,can,0,NULL,NULL); +#define CAN_DRIVER driver_get_by_name("can") + +driver_error_t *can_check_error(esp_err_t error) { + if (error == ESP_OK) return NULL; + + switch (error) { + case ESP_FAIL: return driver_error(CAN_DRIVER, CAN_ERR_TRANSMIT_FAIL,NULL); + case ESP_ERR_NO_MEM: return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY,NULL); + case ESP_ERR_INVALID_ARG: return driver_error(CAN_DRIVER, CAN_ERR_INVALID_ARGUMENT,NULL); + case ESP_ERR_NOT_SUPPORTED: return driver_error(CAN_DRIVER, CAN_ERR_NOT_SUPPORT,NULL); + case ESP_ERR_INVALID_STATE: return driver_error(CAN_DRIVER, CAN_ERR_INVALID_STATE,NULL); + + default: { + char *buffer; + + buffer = malloc(40); + if (!buffer) { + panic("not enough memory"); + } + + snprintf(buffer, 40, "missing can error case %d", error); + + return driver_error(CAN_DRIVER, CAN_ERR_CANT_START, buffer); + } + } + + return NULL; +} + /* * Helper functions */ -static void can_ll_tx(CAN_frame_t *frame) { - mtx_lock(&mtx); - CAN_write_frame(frame); - mtx_unlock(&mtx); +static driver_error_t *can_ll_tx(can_message_t *frame) { + can_start(); //make sure can is running + can_initiate_recovery(); //make sure the bus is on + driver_error_t *error; + if ((error = can_check_error(can_transmit(frame, portMAX_DELAY)))) return error; + return 0; } -static void can_ll_rx(CAN_frame_t *frame) { - // Read next frame +static driver_error_t *can_ll_rx(can_message_t *frame) { + can_start(); //make sure can is running + can_initiate_recovery(); //make sure the bus is on + + // Read next frame // Check filter - uint8_t i; + uint8_t i; uint8_t pass = 0; + driver_error_t *error; while (!pass) { - xQueueReceive(CAN_cfg.rx_queue, frame, portMAX_DELAY); + if ((error = can_check_error(can_receive(frame, portMAX_DELAY)))) return error; + pass = 1; if (filters > 0) { + CAN_FIR_t FIR = (CAN_FIR_t)frame->flags; for(i=0;((i < CAN_NUM_FILTERS) && (!pass));i++) { - if ((can_filter[i].fromID >= 0) && (can_filter[i].toID >= 0) && (frame->FIR.B.DLC > 0) && (frame->FIR.B.DLC < 9)) { - pass = ((frame->MsgID >= can_filter[i].fromID) && (frame->MsgID <= can_filter[i].toID)); - } + if ((can_filter[i].fromID >= 0) && (can_filter[i].toID >= 0) && (FIR.B.DLC > 0) && (FIR.B.DLC < 9)) { + pass = ((frame->identifier >= can_filter[i].fromID) && (frame->identifier <= can_filter[i].toID)); + } } } else { - pass = 1; + pass = 1; } } + + return 0; } static void *gw_thread_up(void *arg) { - CAN_frame_t frame; - struct can_frame packet; + can_message_t frame; + struct can_frame packet; - // Set a timeout for send - struct timeval tout; - tout.tv_sec = 4; - tout.tv_usec = 0; - setsockopt(gw_config->client, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(tout)); + // Set a timeout for send + struct timeval tout; + tout.tv_sec = 4; + tout.tv_usec = 0; + setsockopt(gw_config->client, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(tout)); - while(!gw_config->stop) { - // Wait for a CAN packet - can_ll_rx(&frame); - if (frame.FIR.B.DLC != 0) { - // Fill packet - memset(&packet, 0, sizeof(packet)); + while(!gw_config->stop) { + // Wait for a CAN packet + can_ll_rx(&frame); + CAN_FIR_t FIR = (CAN_FIR_t)frame.flags; + if (FIR.B.DLC != 0) { + // Fill packet + memset(&packet, 0, sizeof(packet)); - packet.can_id = (frame.FIR.B.FF << 31) | (frame.FIR.B.RTR << 30) | frame.MsgID; - packet.can_dlc = frame.FIR.B.DLC; + packet.can_id = (FIR.B.FF << 31) | (FIR.B.RTR << 30) | frame.identifier; + packet.can_dlc = FIR.B.DLC; - memcpy(packet.data, frame.data.u8, sizeof(frame.data)); + memcpy(packet.data, frame.data, sizeof(frame.data)); - // Write frame to socket - if (write(gw_config->client, &packet, sizeof(packet)) != sizeof(packet)) { - close(gw_config->client); + // Write frame to socket + if (write(gw_config->client, &packet, sizeof(packet)) != sizeof(packet)) { + close(gw_config->client); - syslog(LOG_ERR, "can%d gateway: can't write to socket", gw_config->unit); + syslog(LOG_ERR, "can%d gateway: can't write to socket", gw_config->unit); - return NULL; - } - } - } + return NULL; + } + } + } - close(gw_config->client); + close(gw_config->client); - return NULL; + return NULL; } static void *gw_thread_down(void *arg) { - struct can_frame packet; - CAN_frame_t frame; + struct can_frame packet; + can_message_t frame; + + while(!gw_config->stop) { + if (read(gw_config->client, &packet, sizeof(packet)) == sizeof(packet)) { + // Fill frame + frame.identifier = (packet.can_id & 0b11111111111111111111111111111); + CAN_FIR_t FIR; + memset(&FIR, 0, sizeof(CAN_FIR_t)); + FIR.B.FF = (packet.can_id & 0b10000000000000000000000000000000?1:0); + FIR.B.RTR = (packet.can_id & 0b01000000000000000000000000000000?1:0); + FIR.B.DLC = packet.can_dlc; + memcpy(&frame.flags, &FIR, sizeof(CAN_FIR_t)); + + memcpy(frame.data, packet.data, sizeof(packet.data)); + + can_ll_tx(&frame); + } + } + + close(gw_config->client); + + return NULL; +} - while(!gw_config->stop) { - if (read(gw_config->client, &packet, sizeof(packet)) == sizeof(packet)) { - // Fill frame - frame.MsgID = (packet.can_id & 0b11111111111111111111111111111); - frame.FIR.B.FF = (packet.can_id & 0b10000000000000000000000000000000?1:0); - frame.FIR.B.RTR = (packet.can_id & 0b01000000000000000000000000000000?1:0); - frame.FIR.B.DLC = packet.can_dlc; +static void *gw_thread(void *arg) { + // Create an setup socket + struct sockaddr_in6 sin; - memcpy(frame.data.u8, packet.data, sizeof(packet.data)); + gw_config->socket = socket(AF_INET6, SOCK_STREAM, 0); + if (gw_config->socket < 0) { + syslog(LOG_ERR, "can%d gateway: can't create socket", gw_config->unit); + return NULL; + } - can_ll_tx(&frame); - } - } + // Bind and listen + memset(&sin, 0, sizeof(sin)); + sin.sin6_family = AF_INET6; + memcpy(&sin.sin6_addr.un.u32_addr, &in6addr_any, sizeof(in6addr_any)); + sin.sin6_port = htons(gw_config->port); - close(gw_config->client); + if(bind(gw_config->socket, (struct sockaddr *) &sin, sizeof (sin))) { + syslog(LOG_ERR, "can%d gateway: can't bind to port %d",gw_config->unit, gw_config->port); + return NULL; + } - return NULL; -} + if (listen(gw_config->socket, 5)) { + syslog(LOG_ERR, "can%d gateway: can't listen on port %d",gw_config->unit, gw_config->port); + return NULL; + } -static void *gw_thread(void *arg) { - // Create an setup socket - struct sockaddr_in6 sin; - - gw_config->socket = socket(AF_INET6, SOCK_STREAM, 0); - if (gw_config->socket < 0) { - syslog(LOG_ERR, "can%d gateway: can't create socket", gw_config->unit); - return NULL; - } - - // Bind and listen - memset(&sin, 0, sizeof(sin)); - sin.sin6_family = AF_INET6; - memcpy(&sin.sin6_addr.un.u32_addr, &in6addr_any, sizeof(in6addr_any)); - sin.sin6_port = htons(gw_config->port); - - if(bind(gw_config->socket, (struct sockaddr *) &sin, sizeof (sin))) { - syslog(LOG_ERR, "can%d gateway: can't bind to port %d",gw_config->unit, gw_config->port); - return NULL; - } - - if (listen(gw_config->socket, 5)) { - syslog(LOG_ERR, "can%d gateway: can't listen on port %d",gw_config->unit, gw_config->port); - return NULL; - } - - syslog(LOG_INFO, "can%d gateway: started at port %d", gw_config->unit, gw_config->port); - - while (!gw_config->stop) { - // Wait for a connection - gw_config->client = accept(gw_config->socket, (struct sockaddr*) NULL, NULL); - if (gw_config->client > 0) { - syslog(LOG_INFO, "can%d gateway: client connected", gw_config->unit); - - // Start threads for client - pthread_t thread_up; - pthread_t thread_down; - pthread_attr_t attr; - - pthread_attr_init(&attr); - - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - if (pthread_create(&thread_up, &attr, gw_thread_up, NULL)) { - syslog(LOG_ERR, "can%d gateway: can't start up thread", gw_config->unit); - return NULL; - } - - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - if (pthread_create(&thread_down, &attr, gw_thread_down, NULL)) { - syslog(LOG_ERR, "can%d gateway: can't start down thread", gw_config->unit); - return NULL; - } - - pthread_setname_np(thread_up, "can_gw_up"); - pthread_setname_np(thread_down, "can_gw_down"); - - pthread_join(thread_up, NULL); - pthread_join(thread_down, NULL); - } - } - - close(gw_config->socket); - - return NULL; + syslog(LOG_INFO, "can%d gateway: started at port %d", gw_config->unit, gw_config->port); + + while (!gw_config->stop) { + // Wait for a connection + gw_config->client = accept(gw_config->socket, (struct sockaddr*) NULL, NULL); + if (gw_config->client > 0) { + syslog(LOG_INFO, "can%d gateway: client connected", gw_config->unit); + + // Start threads for client + pthread_t thread_up; + pthread_t thread_down; + pthread_attr_t attr; + + pthread_attr_init(&attr); + + pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); + if (pthread_create(&thread_up, &attr, gw_thread_up, NULL)) { + syslog(LOG_ERR, "can%d gateway: can't start up thread", gw_config->unit); + return NULL; + } + + pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); + if (pthread_create(&thread_down, &attr, gw_thread_down, NULL)) { + syslog(LOG_ERR, "can%d gateway: can't start down thread", gw_config->unit); + return NULL; + } + + pthread_setname_np(thread_up, "can_gw_up"); + pthread_setname_np(thread_down, "can_gw_down"); + + pthread_join(thread_up, NULL); + pthread_join(thread_down, NULL); + } + } + + close(gw_config->socket); + + return NULL; } /* @@ -256,290 +317,313 @@ static void *gw_thread(void *arg) { driver_error_t *can_setup(int32_t unit, uint32_t speed, uint16_t rx_size) { #if CONFIG_LUA_RTOS_USE_HARDWARE_LOCKS - driver_unit_lock_error_t *lock_error = NULL; + driver_unit_lock_error_t *lock_error = NULL; #endif - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - if (!setup) { + if (!setup) { #if CONFIG_LUA_RTOS_USE_HARDWARE_LOCKS - // Lock TX pin - if ((lock_error = driver_lock(CAN_DRIVER, 0, GPIO_DRIVER, CONFIG_LUA_RTOS_CAN_TX, DRIVER_ALL_FLAGS, "TX"))) { - // Revoked lock on pin - return driver_lock_error(CAN_DRIVER, lock_error); - } - - // Lock RX pin - if ((lock_error = driver_lock(CAN_DRIVER, 0, GPIO_DRIVER, CONFIG_LUA_RTOS_CAN_RX, DRIVER_ALL_FLAGS, "RX"))) { - // Revoked lock on pin - return driver_lock_error(CAN_DRIVER, lock_error); - } -#endif - } - - // Set CAN configuration - CAN_cfg.speed = speed; - CAN_cfg.tx_pin_id = CONFIG_LUA_RTOS_CAN_TX; - CAN_cfg.rx_pin_id = CONFIG_LUA_RTOS_CAN_RX; - - if (!setup) { - CAN_cfg.rx_queue = xQueueCreate(rx_size,sizeof(CAN_frame_t));; - - // Init filters - uint8_t i; - for(i=0;i < CAN_NUM_FILTERS;i++) { - can_filter[i].fromID = -1; - can_filter[i].toID = -1; - } - - filters = 0; - - if (!CAN_cfg.rx_queue) { - return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY, NULL); - } - } + // Lock TX pin + if ((lock_error = driver_lock(CAN_DRIVER, 0, GPIO_DRIVER, CONFIG_LUA_RTOS_CAN_TX, DRIVER_ALL_FLAGS, "TX"))) { + // Revoked lock on pin + return driver_lock_error(CAN_DRIVER, lock_error); + } - // Start CAN module - CAN_init(); + // Lock RX pin + if ((lock_error = driver_lock(CAN_DRIVER, 0, GPIO_DRIVER, CONFIG_LUA_RTOS_CAN_RX, DRIVER_ALL_FLAGS, "RX"))) { + // Revoked lock on pin + return driver_lock_error(CAN_DRIVER, lock_error); + } +#endif + } - if (!setup) { - mtx_init(&mtx, NULL, NULL, 0); + g_config.rx_queue_len = 20; + g_config.tx_queue_len = 20; + switch(speed) { + case 1000: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_1MBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 800: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_800KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 500: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_500KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 250: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_250KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 125: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_125KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 100: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_100KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + case 50: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_50KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + break; + default: { + can_timing_config_t set_config = CAN_TIMING_CONFIG_25KBITS(); + memcpy(&t_config, &set_config, sizeof(set_config)); + } + } - syslog(LOG_INFO, "can%d at pins tx=%s%d, rx=%s%d", 0, - gpio_portname(CONFIG_LUA_RTOS_CAN_TX), gpio_name(CONFIG_LUA_RTOS_CAN_TX), - gpio_portname(CONFIG_LUA_RTOS_CAN_RX), gpio_name(CONFIG_LUA_RTOS_CAN_RX) - ); - } + // Start CAN module + driver_error_t *error; + if ((error = can_check_error(can_driver_install(&g_config, &t_config, &f_config)))) { + return error; + } + if ((error = can_check_error(can_start()))) { + return error; + } - setup = 1; + if (!setup) { + syslog(LOG_INFO, "can%d at pins tx=%s%d, rx=%s%d", 0, + gpio_portname(CONFIG_LUA_RTOS_CAN_TX), gpio_name(CONFIG_LUA_RTOS_CAN_TX), + gpio_portname(CONFIG_LUA_RTOS_CAN_RX), gpio_name(CONFIG_LUA_RTOS_CAN_RX) + ); + } - return NULL; + setup = 1; + return NULL; } driver_error_t *can_tx(int32_t unit, uint32_t msg_id, uint8_t msg_type, uint8_t *data, uint8_t len) { - CAN_frame_t frame; + can_message_t frame; - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } - - if (len > 8) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FRAME_LENGTH, NULL); - } + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - if (!setup) { - return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); - } + if (len > 8) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FRAME_LENGTH, NULL); + } - // Populate frame - frame.MsgID = msg_id; - frame.FIR.B.DLC = len; - frame.FIR.B.FF = (msg_type == 1); - memcpy(&frame.data, data, len); + if (!setup) { + return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); + } - can_ll_tx(&frame); + // Populate frame + frame.identifier = msg_id; + frame.data_length_code = len; + frame.flags = (msg_type == 1 ? CAN_MSG_FLAG_EXTD:CAN_MSG_FLAG_NONE); + memcpy(&frame.data, data, len); - return NULL; + return can_ll_tx(&frame); } driver_error_t *can_rx(int32_t unit, uint32_t *msg_id, uint8_t *msg_type, uint8_t *data, uint8_t *len) { - CAN_frame_t frame; + can_message_t frame; - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } - - if (!setup) { - return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); - } - - can_ll_rx(&frame); + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - *msg_id = frame.MsgID; - *msg_type = frame.FIR.B.FF; - *len = frame.FIR.B.DLC; - memcpy(data, &frame.data, *len); + if (!setup) { + return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); + } - return NULL; + driver_error_t *error = can_ll_rx(&frame); + if (!error) { + *msg_id = frame.identifier; + *msg_type = (frame.flags & CAN_MSG_FLAG_EXTD ? 1 : 0); + *len = frame.data_length_code; + memcpy(data, &frame.data, *len); + } + return error; } driver_error_t *can_add_filter(int32_t unit, int32_t fromId, int32_t toId) { - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - if ((fromId < 0) || (toId < 0)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "must be >= 0"); - } + if ((fromId < 0) || (toId < 0)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "must be >= 0"); + } - if ((fromId > toId)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "from filter must be >= to filter"); - } + if ((fromId > toId)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "from filter must be >= to filter"); + } - if (!setup) { - return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); - } + if (!setup) { + return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); + } - // Check if there is some filter that match with the - // desired filter - uint8_t i; + // Check if there is some filter that match with the + // desired filter + uint8_t i; - mtx_lock(&mtx); + for(i=0;i < CAN_NUM_FILTERS;i++) { + if ((fromId >= can_filter[i].fromID) && (toId <= can_filter[i].toID)) { + return NULL; + } + } - for(i=0;i < CAN_NUM_FILTERS;i++) { - if ((fromId >= can_filter[i].fromID) && (toId <= can_filter[i].toID)) { - mtx_unlock(&mtx); + // Add filter + for(i=0;i < CAN_NUM_FILTERS;i++) { + if ((can_filter[i].fromID == -1) && (can_filter[i].toID == -1)) { + can_filter[i].fromID = fromId; + can_filter[i].toID = toId; + filters++; + break; + } + } - return NULL; - } - } + if (i == CAN_NUM_FILTERS) { + return driver_error(CAN_DRIVER, CAN_ERR_NO_MORE_FILTERS_ALLOWED, NULL); + } - // Add filter - for(i=0;i < CAN_NUM_FILTERS;i++) { - if ((can_filter[i].fromID == -1) && (can_filter[i].toID == -1)) { - can_filter[i].fromID = fromId; - can_filter[i].toID = toId; - filters++; - break; - } - } + // Reset rx queue + driver_error_t *error; + if ((error = can_check_error(can_stop()))) { + return error; + } + if ((error = can_check_error(can_start()))) { + return error; + } - if (i == CAN_NUM_FILTERS) { - mtx_unlock(&mtx); + return NULL; +} - return driver_error(CAN_DRIVER, CAN_ERR_NO_MORE_FILTERS_ALLOWED, NULL); - } +driver_error_t *can_remove_filter(int32_t unit, int32_t fromId, int32_t toId) { + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - // Reset rx queue - portDISABLE_INTERRUPTS(); - xQueueReset(CAN_cfg.rx_queue); - portENABLE_INTERRUPTS(); + if ((fromId < 0) || (toId < 0)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "must be >= 0"); + } - mtx_unlock(&mtx); + if ((fromId > toId)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "from filter must be >= to filter"); + } - return NULL; -} + if (!setup) { + return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); + } -driver_error_t *can_remove_filter(int32_t unit, int32_t fromId, int32_t toId) { - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } - - if ((fromId < 0) || (toId < 0)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "must be >= 0"); - } - - if ((fromId > toId)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_FILTER, "from filter must be >= to filter"); - } - - if (!setup) { - return driver_error(CAN_DRIVER, CAN_ERR_IS_NOT_SETUP, NULL); - } - - mtx_lock(&mtx); - - uint8_t i; - for(i=0;i < CAN_NUM_FILTERS;i++) { - if ((can_filter[i].fromID > -1) && (can_filter[i].toID > -1)) { - if ((can_filter[i].fromID == fromId) && (can_filter[i].toID == toId)) { - can_filter[i].fromID = -1; - can_filter[i].toID = -1; - filters--; - break; - } - } - } + uint8_t i; + for(i=0;i < CAN_NUM_FILTERS;i++) { + if ((can_filter[i].fromID > -1) && (can_filter[i].toID > -1)) { + if ((can_filter[i].fromID == fromId) && (can_filter[i].toID == toId)) { + can_filter[i].fromID = -1; + can_filter[i].toID = -1; + filters--; + break; + } + } + } // Reset rx queue - portDISABLE_INTERRUPTS(); - xQueueReset(CAN_cfg.rx_queue); - portENABLE_INTERRUPTS(); - - mtx_unlock(&mtx); + driver_error_t *error; + if ((error = can_check_error(can_stop()))) { + return error; + } + if ((error = can_check_error(can_start()))) { + return error; + } - return NULL; + return NULL; } driver_error_t *can_gateway_start(int32_t unit, uint32_t speed, int32_t port) { - driver_error_t *error; + driver_error_t *error; - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - if ((error = can_setup(unit, speed, 100))) { - return error; - } + if ((error = can_setup(unit, speed, 100))) { + return error; + } - // Allocate space for configuration - gw_config = calloc(1, sizeof(can_gw_config_t)); - if (!gw_config) { - return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY, NULL); - } + // Allocate space for configuration + gw_config = calloc(1, sizeof(can_gw_config_t)); + if (!gw_config) { + return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY, NULL); + } - gw_config->port = port; - gw_config->stop = 0; + gw_config->port = port; + gw_config->stop = 0; - // Start main thread - pthread_attr_t attr; + // Start main thread + pthread_attr_t attr; - pthread_attr_init(&attr); + pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - if (pthread_create(&gw_config->thread, &attr, gw_thread, NULL)) { - free(gw_config); + if (pthread_create(&gw_config->thread, &attr, gw_thread, NULL)) { + free(gw_config); - return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY, "can't start main thread"); - } + return driver_error(CAN_DRIVER, CAN_ERR_NOT_ENOUGH_MEMORY, "can't start main thread"); + } - pthread_setname_np(gw_config->thread, "can_gw"); + pthread_setname_np(gw_config->thread, "can_gw"); - return NULL; + return NULL; } driver_error_t *can_gateway_stop(int32_t unit) { - // Sanity checks - if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { - return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); - } + // Sanity checks + if ((unit < CPU_FIRST_CAN) || (unit > CPU_LAST_CAN)) { + return driver_error(CAN_DRIVER, CAN_ERR_INVALID_UNIT, NULL); + } - if (!gw_config) { - return driver_error(CAN_DRIVER, CAN_ERR_GW_NOT_STARTED, NULL); - } + if (!gw_config) { + return driver_error(CAN_DRIVER, CAN_ERR_GW_NOT_STARTED, NULL); + } - // Set stop flag - gw_config->stop = 1; + // Set stop flag + gw_config->stop = 1; - // Send an empty frame to the queue to unblock gw_thread_up - CAN_frame_t frame; - memset(&frame, 0, sizeof(frame)); - xQueueSend(CAN_cfg.rx_queue,&frame,0); + // Send an empty frame to the queue to unblock gw_thread_up + can_message_t frame; + memset(&frame, 0, sizeof(frame)); + driver_error_t *error; + if ((error = can_ll_tx(&frame))) { + return error; + } - // Close socket to unblock gw_thread - close(gw_config->socket); + // Close socket to unblock gw_thread + close(gw_config->socket); - pthread_join(gw_config->thread, NULL); + pthread_join(gw_config->thread, NULL); - free(gw_config); - gw_config = NULL; + free(gw_config); + gw_config = NULL; - // Reset queue - mtx_lock(&mtx); - portDISABLE_INTERRUPTS(); - xQueueReset(CAN_cfg.rx_queue); - portENABLE_INTERRUPTS(); - mtx_unlock(&mtx); + // Reset rx queue + if ((error = can_check_error(can_stop()))) { + return error; + } + if ((error = can_check_error(can_start()))) { + return error; + } - return NULL; + return NULL; } #endif diff --git a/components/sys/drivers/can.h b/components/sys/drivers/can.h index c7c1d1bdb..b084a361b 100644 --- a/components/sys/drivers/can.h +++ b/components/sys/drivers/can.h @@ -55,6 +55,33 @@ #define CAN_NUM_FILTERS 10 +/** + * \brief CAN frame type (standard/extended) + */ +typedef enum { + CAN_frame_std=0, /**< Standard frame, using 11 bit identifer. */ + CAN_frame_ext=1 /**< Extended frame, using 29 bit identifer. */ +}CAN_frame_format_t; + +/** + * \brief CAN RTR + */ +typedef enum { + CAN_no_RTR=0, /**< No RTR frame. */ + CAN_RTR=1 /**< RTR frame. */ +}CAN_RTR_t; + +/** \brief Frame information record type */ +typedef union{uint32_t U; /**< \brief Unsigned access */ + struct { + uint8_t DLC:4; /**< \brief [3:0] DLC, Data length container */ + unsigned int unknown_2:2; /**< \brief \internal unknown */ + CAN_RTR_t RTR:1; /**< \brief [6:6] RTR, Remote Transmission Request */ + CAN_frame_format_t FF:1; /**< \brief [7:7] Frame Format, see# CAN_frame_format_t*/ + unsigned int reserved_24:24; /**< \brief \internal Reserved */ + } B; +} CAN_FIR_t; + typedef struct { int32_t fromID; int32_t toID; @@ -125,10 +152,16 @@ struct can_frame { #define CAN_ERR_IS_NOT_SETUP (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 5) #define CAN_ERR_CANT_START (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 6) #define CAN_ERR_GW_NOT_STARTED (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 7) +//#define CAN_ERR_CANT_INIT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 0) +#define CAN_ERR_INVALID_ARGUMENT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 8) +#define CAN_ERR_NOT_SUPPORT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 9) +#define CAN_ERR_TRANSMIT_FAIL (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 10) +#define CAN_ERR_INVALID_STATE (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 11) extern const int can_errors; extern const int can_error_map; +driver_error_t *can_check_error(esp_err_t error); driver_error_t *can_setup(int32_t unit, uint32_t speed, uint16_t rx_size); driver_error_t *can_tx(int32_t unit, uint32_t msg_id, uint8_t msg_type, uint8_t *data, uint8_t len); driver_error_t *can_rx(int32_t unit, uint32_t *msg_id, uint8_t *msg_type, uint8_t *data, uint8_t *len); From d3259b1b3202ad3265877f30bc794d576ebd53c7 Mon Sep 17 00:00:00 2001 From: the0ne Date: Mon, 23 Sep 2019 09:53:48 +0200 Subject: [PATCH 2/3] fixed queue length added cpu.h required for CPU_FIRST_CAN and CPU_LAST_CAN --- components/sys/drivers/can.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/sys/drivers/can.c b/components/sys/drivers/can.c index 8dfda29e5..b9e165fa7 100755 --- a/components/sys/drivers/can.c +++ b/components/sys/drivers/can.c @@ -65,6 +65,7 @@ #include #include +#include #include #include @@ -341,8 +342,8 @@ driver_error_t *can_setup(int32_t unit, uint32_t speed, uint16_t rx_size) { #endif } - g_config.rx_queue_len = 20; - g_config.tx_queue_len = 20; + g_config.rx_queue_len = rx_size; + g_config.tx_queue_len = rx_size; switch(speed) { case 1000: { can_timing_config_t set_config = CAN_TIMING_CONFIG_1MBITS(); From ce436fd629e00835c3b7bc1ad081eb19edeb6acd Mon Sep 17 00:00:00 2001 From: the0ne Date: Fri, 3 Jan 2020 16:00:16 +0100 Subject: [PATCH 3/3] non-blocking can error handling make sure we won't block forever if * the can-bus is buggy/gone * resp. the queue is full does properly to auto-recover once the bus is back --- components/sys/drivers/can.c | 31 ++++++++++++++++++++++++------- components/sys/drivers/can.h | 27 ++++++++++++++------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/components/sys/drivers/can.c b/components/sys/drivers/can.c index b9e165fa7..3a387e9cf 100755 --- a/components/sys/drivers/can.c +++ b/components/sys/drivers/can.c @@ -110,6 +110,7 @@ DRIVER_REGISTER_BEGIN(CAN,can,0,NULL,NULL); DRIVER_REGISTER_ERROR(CAN, can, InvalidArg, "invalid argument", CAN_ERR_INVALID_ARGUMENT); DRIVER_REGISTER_ERROR(CAN, can, InvalidState, "invalid state", CAN_ERR_INVALID_STATE); DRIVER_REGISTER_ERROR(CAN, can, NotSupport, "can API is not supported yet", CAN_ERR_NOT_SUPPORT); + DRIVER_REGISTER_ERROR(CAN, can, TransmitTimeout, "timeout transmitting message", CAN_ERR_TRANSMIT_TIMEOUT); DRIVER_REGISTER_END(CAN,can,0,NULL,NULL); #define CAN_DRIVER driver_get_by_name("can") @@ -123,6 +124,7 @@ driver_error_t *can_check_error(esp_err_t error) { case ESP_ERR_INVALID_ARG: return driver_error(CAN_DRIVER, CAN_ERR_INVALID_ARGUMENT,NULL); case ESP_ERR_NOT_SUPPORTED: return driver_error(CAN_DRIVER, CAN_ERR_NOT_SUPPORT,NULL); case ESP_ERR_INVALID_STATE: return driver_error(CAN_DRIVER, CAN_ERR_INVALID_STATE,NULL); + case ESP_ERR_TIMEOUT: return driver_error(CAN_DRIVER, CAN_ERR_TRANSMIT_TIMEOUT,NULL); default: { char *buffer; @@ -145,18 +147,30 @@ driver_error_t *can_check_error(esp_err_t error) { * Helper functions */ +#define MAX_BUS_ERROR 127 +#define MAX_WAITMS_TX 100 + +void can_recovery() { + can_status_info_t status_info; + esp_err_t error = can_get_status_info(&status_info); + if (error == ESP_OK && status_info.state==CAN_STATE_RUNNING && status_info.bus_error_count 0) { CAN_FIR_t FIR = (CAN_FIR_t)frame->flags; diff --git a/components/sys/drivers/can.h b/components/sys/drivers/can.h index b084a361b..028a3e4ee 100644 --- a/components/sys/drivers/can.h +++ b/components/sys/drivers/can.h @@ -144,19 +144,20 @@ struct can_frame { #endif // CAN errors -#define CAN_ERR_NOT_ENOUGH_MEMORY (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 0) -#define CAN_ERR_INVALID_FRAME_LENGTH (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 1) -#define CAN_ERR_INVALID_UNIT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 2) -#define CAN_ERR_NO_MORE_FILTERS_ALLOWED (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 3) -#define CAN_ERR_INVALID_FILTER (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 4) -#define CAN_ERR_IS_NOT_SETUP (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 5) -#define CAN_ERR_CANT_START (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 6) -#define CAN_ERR_GW_NOT_STARTED (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 7) -//#define CAN_ERR_CANT_INIT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 0) -#define CAN_ERR_INVALID_ARGUMENT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 8) -#define CAN_ERR_NOT_SUPPORT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 9) -#define CAN_ERR_TRANSMIT_FAIL (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 10) -#define CAN_ERR_INVALID_STATE (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 11) +#define CAN_ERR_NOT_ENOUGH_MEMORY (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 0) +#define CAN_ERR_INVALID_FRAME_LENGTH (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 1) +#define CAN_ERR_INVALID_UNIT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 2) +#define CAN_ERR_NO_MORE_FILTERS_ALLOWED (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 3) +#define CAN_ERR_INVALID_FILTER (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 4) +#define CAN_ERR_IS_NOT_SETUP (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 5) +#define CAN_ERR_CANT_START (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 6) +#define CAN_ERR_GW_NOT_STARTED (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 7) +//#define CAN_ERR_CANT_INIT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 0) +#define CAN_ERR_INVALID_ARGUMENT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 8) +#define CAN_ERR_NOT_SUPPORT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 9) +#define CAN_ERR_TRANSMIT_FAIL (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 10) +#define CAN_ERR_INVALID_STATE (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 11) +#define CAN_ERR_TRANSMIT_TIMEOUT (DRIVER_EXCEPTION_BASE(CAN_DRIVER_ID) | 12) extern const int can_errors; extern const int can_error_map;