├── .gitignore ├── CMakeLists.txt ├── NMEA2000_esp32xx.cpp ├── NMEA2000_esp32xx.h ├── README.adoc ├── idf_component.yml └── library.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | FILE(GLOB_RECURSE sources ./*.*) 2 | idf_component_register(SRCS ${sources} INCLUDE_DIRS . 3 | REQUIRES NMEA2000 4 | ) -------------------------------------------------------------------------------- /NMEA2000_esp32xx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | NMEA2000_esp32xx.cpp 3 | 4 | Copyright (c) 2015-2020 Timo Lappalainen, Kave Oy, www.kave.fi 5 | Copyright (c) 2023 Jaume Clarens "jiauka" 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 11 | Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 19 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 21 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | Inherited NMEA2000 object for ESP32xx modules. See also NMEA2000 library. 25 | 26 | Thanks to Thomas Barth, barth-dev.de, who has written ESP32 CAN code. To avoid extra 27 | libraries, I implemented his code directly to the NMEA2000_esp32 to avoid extra 28 | can.h library, which may cause even naming problem. 29 | */ 30 | 31 | #include "esp_idf_version.h" 32 | #include "freertos/FreeRTOS.h" 33 | #include "freertos/task.h" 34 | #include "freertos/queue.h" 35 | #include "freertos/semphr.h" 36 | #include "esp_err.h" 37 | #include "esp_log.h" 38 | #include "driver/twai.h" 39 | #include "NMEA2000_esp32xx.h" 40 | 41 | #if !defined(round) 42 | #include 43 | #endif 44 | #if CORE_DEBUG_LEVEL >= ESP_LOG_DEBUG 45 | static const char *TAG = "TWAI_C3"; 46 | #endif 47 | 48 | bool tNMEA2000_esp32xx::CanInUse=false; 49 | tNMEA2000_esp32xx *pNMEA2000_esp32c3=0; 50 | //***************************************************************************** 51 | tNMEA2000_esp32xx::tNMEA2000_esp32xx(gpio_num_t _TxPin, gpio_num_t _RxPin) : 52 | tNMEA2000(), IsOpen(false), TxPin(_TxPin), RxPin(_RxPin) { 53 | } 54 | 55 | //***************************************************************************** 56 | bool tNMEA2000_esp32xx::CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool /*wait_sent*/) { 57 | twai_message_t tx_msg; 58 | tx_msg.flags=0; 59 | tx_msg.extd=1; /**< Extended Frame Format (29bit ID) */ 60 | tx_msg.data_length_code=len>8?8:len; 61 | 62 | tx_msg.dlc_non_comp=len>8?1:0; /**< Message's Data length code is larger than 8. This will break compliance with ISO 11898-1 */ 63 | tx_msg.ss=1; /**< Transmit as a Single Shot Transmission. Unused for received. */ 64 | tx_msg.identifier=id; 65 | memcpy(tx_msg.data,buf,len); 66 | return (twai_transmit(&tx_msg, 0)== ESP_OK); 67 | } 68 | 69 | //***************************************************************************** 70 | bool tNMEA2000_esp32xx::CANOpen() { 71 | if (IsOpen) return true; 72 | 73 | if (CanInUse) return false; // currently prevent accidental second instance. Maybe possible in future. 74 | 75 | pNMEA2000_esp32c3=this; 76 | IsOpen=true; 77 | CAN_init(); 78 | 79 | CanInUse=IsOpen; 80 | 81 | return IsOpen; 82 | } 83 | 84 | //***************************************************************************** 85 | bool tNMEA2000_esp32xx::CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf) { 86 | bool hasFrame=false; 87 | twai_message_t rx_msg; 88 | if ( twai_receive(&rx_msg, 0)==ESP_OK ) { 89 | hasFrame=true; 90 | id=rx_msg.identifier; 91 | len=rx_msg.data_length_code; 92 | memcpy(buf,rx_msg.data,len); 93 | } 94 | return hasFrame; 95 | } 96 | 97 | //***************************************************************************** 98 | void tNMEA2000_esp32xx::CAN_init() { 99 | twai_timing_config_t t_config; 100 | twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); 101 | twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TxPin, RxPin, TWAI_MODE_NORMAL); 102 | 103 | #ifndef NMEA2000_MANUAL_TWAI_CONFIG 104 | 105 | t_config = TWAI_TIMING_CONFIG_250KBITS(); // default {.brp = 16, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false} 106 | #else // use hand configuration 107 | t_config.brp =16; 108 | t_config.tseg_1 =16; 109 | t_config.tseg_2 =3; 110 | t_config.sjw =1; 111 | t_config.triple_sampling=true; 112 | #endif 113 | t_config.triple_sampling=true; 114 | ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); 115 | ESP_LOGD(TAG, "Driver installed"); 116 | ESP_ERROR_CHECK(twai_start()); 117 | ESP_LOGD(TAG, "Driver started"); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /NMEA2000_esp32xx.h: -------------------------------------------------------------------------------- 1 | /* 2 | NMEA2000_esp32xx.h 3 | 4 | Copyright (c) 2015-2020 Timo Lappalainen, Kave Oy, www.kave.fi 5 | Copyright (c) 2023 Jaume Clarens "jiauka" 6 | * 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 11 | Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 18 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 19 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 21 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 22 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | Inherited NMEA2000 object for ESP32 modules. See also NMEA2000 library. 25 | 26 | Thanks to Thomas Barth, barth-dev.de, who has written ESP32 CAN code. To avoid extra 27 | libraries, I implemented his code directly to the NMEA2000_esp32 to avoid extra 28 | can.h library, which may cause even naming problem. 29 | 30 | The library sets as default CAN Tx pin to GPIO 16 and CAN Rx pint to GPIO 4. If you 31 | want to use other pins (I have not tested can any pins be used), add defines e.g. 32 | #define ESP32_CAN_TX_PIN GPIO_NUM_34 33 | #define ESP32_CAN_RX_PIN GPIO_NUM_35 34 | before including NMEA2000_esp32xx.h 35 | */ 36 | 37 | #ifndef _NMEA2000_ESP32_H_ 38 | #define _NMEA2000_ESP32_H_ 39 | 40 | #include "freertos/FreeRTOS.h" 41 | #include "freertos/queue.h" 42 | #include "driver/gpio.h" 43 | #include "NMEA2000.h" 44 | #include "N2kMsg.h" 45 | 46 | 47 | #ifndef ESP32_CAN_TX_PIN 48 | #define ESP32_CAN_TX_PIN GPIO_NUM_5 49 | #endif 50 | #ifndef ESP32_CAN_RX_PIN 51 | #define ESP32_CAN_RX_PIN GPIO_NUM_4 52 | #endif 53 | 54 | #define NMEA2000_MANUAL_TWAI_CONFIG // see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html#bit-timing 55 | 56 | class tNMEA2000_esp32xx : public tNMEA2000 57 | { 58 | private: 59 | bool IsOpen; 60 | static bool CanInUse; 61 | public: 62 | 63 | struct tCANFrame { 64 | uint32_t id; // can identifier 65 | uint8_t len; // length of data 66 | uint8_t buf[8]; 67 | }; 68 | 69 | 70 | 71 | protected: 72 | gpio_num_t TxPin; 73 | gpio_num_t RxPin; 74 | protected: 75 | void CAN_send_frame(tCANFrame &frame); // Send frame 76 | void CAN_init(); 77 | 78 | protected: 79 | bool CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool wait_sent=true); 80 | bool CANOpen(); 81 | bool CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf); 82 | 83 | public: 84 | tNMEA2000_esp32xx(gpio_num_t _TxPin=ESP32_CAN_TX_PIN, gpio_num_t _RxPin=ESP32_CAN_RX_PIN); 85 | 86 | void InterruptHandler(); 87 | }; 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | [cols="1,1,1,1,1,1"] 2 | |=== 3 | |Supported Targets |ESP32 |ESP32-C2 |ESP32-C3 |ESP32-S2 |ESP32-S3 4 | 5 | |ESP-IDF 5.x | Yes |?|YES|?|? 6 | |=== 7 | 8 | 9 | = NMEA2000_esp32 library for ESP32xx boards using twai driver = 10 | 11 | Inherited object for use NMEA2000 library for ESP32 Boards. 12 | See also https://github.com/ttlappalainen/NMEA2000[NMEA2000] library. 13 | 14 | To use this library, you will also need NMEA2000 library. 15 | 16 | The library defines as default Tx pin to GPIO 16 and Rx pint to GPIO 4. You can 17 | change these with defines: 18 | 19 | #define ESP32_CAN_TX_PIN GPIO_NUM_5 20 | #define ESP32_CAN_RX_PIN GPIO_NUM_4 21 | 22 | before including NMEA2000_CAN.h or NMEA2000_esp32xx.h 23 | 24 | A working example can be found at https://github.com/jiauka/NMEA2000-windesp32xx-idf[NMEA2000-windesp32xx-idf] library 25 | 26 | == Thanks == 27 | 28 | Thanks to Thomas Barth, barth-dev.de and Timo Lappalainen the implementation 29 | of ESP32 CAN driver. This is based on their work 30 | 31 | == Changes == 32 | 2023-06-08 33 | - First release, WIP, only tested in RX 34 | 2023-06-09 35 | - V0.1 working on both ESP32 and ESP32c3 36 | 2023-06-10 37 | - V0.2 code cleanup 38 | 39 | == License == 40 | 41 | 42 | 2015-2022 Copyright (c) jiauka, Kave Oy, www.kave.fi All right reserved. 43 | 44 | Author: Jaume Clarens 45 | 46 | MIT License 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a copy of 49 | this software and associated documentation files (the "Software"), to deal in 50 | the Software without restriction, including without limitation the rights to use, 51 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 52 | Software, and to permit persons to whom the Software is furnished to do so, 53 | subject to the following conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in all 56 | copies or substantial portions of the Software. 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 59 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 60 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 61 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 62 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 63 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 | -------------------------------------------------------------------------------- /idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | ## Required IDF version 4 | idf: 5 | version: ">=5.0.0" 6 | # # Put list of dependencies here 7 | # # For components maintained by Espressif: 8 | # component: "~1.0.0" 9 | # # For 3rd party components: 10 | # username/component: ">=1.0.0,<2.0.0" 11 | # username2/component2: 12 | # version: "~1.0.0" 13 | # # For transient dependencies `public` flag can be set. 14 | # # `public` flag doesn't have an effect dependencies of the `main` component. 15 | # # All dependencies of `main` are public by default. 16 | # public: true 17 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=NMEA2000_esp32xx 2 | version=0.0.2 3 | author=Jaume Clarens 4 | maintainer=jiauka 5 | sentence=Inherited NMEA2000 object for ESP32xx. See also NMEA2000 library. 6 | paragraph=The NMEA2000 library feature: NMEA2000->PC/WiFi interface, NMEA2000 device node 7 | category=Communication 8 | url= 9 | architectures=* 10 | --------------------------------------------------------------------------------