├── web └── loco-32x32.png ├── docs ├── getting_started.md ├── images │ ├── lmd18200.jpg │ ├── lmd18200.png │ ├── deekrobot.png │ ├── ESPDuino-32.png │ ├── esp32devkitc.png │ ├── l298generic.png │ ├── ttgo-t1-back.png │ ├── ttgo-t1-front.png │ └── dcc-signal-split.png ├── building.md ├── README.md ├── build_env.md └── precompiled.md ├── main ├── idf_component.yml └── CMakeLists.txt ├── components ├── NeoPixelBus │ ├── CMakeLists.txt │ ├── library.properties │ ├── src │ │ ├── internal │ │ │ ├── NeoBusChannel.h │ │ │ ├── Esp32_i2s.h │ │ │ ├── NeoEsp8266DmaMethod.cpp │ │ │ ├── RgbColorBase.h │ │ │ ├── NeoBufferContext.h │ │ │ ├── NeoSettings.h │ │ │ ├── NeoGamma.h │ │ │ ├── HsbColor.cpp │ │ │ ├── NeoGamma.cpp │ │ │ ├── HslColor.cpp │ │ │ ├── NeoTopology.h │ │ │ ├── TwoWireBitBangImple.h │ │ │ ├── TwoWireHspiImple.h │ │ │ ├── NeoHueBlend.h │ │ │ ├── NeoRingTopology.h │ │ │ ├── RgbColorBase.cpp │ │ │ └── TwoWireBitBangImpleAvr.h │ │ └── NeoPixelSegmentBus.h │ ├── library.json │ └── ReadMe.md ├── AccessoryDecoderDB │ ├── idf_component.yml │ ├── AccessoryDecoderConstants.cpp │ ├── CMakeLists.txt │ ├── private_include │ │ ├── DccAccessoryDecoder.hxx │ │ └── OpenLCBAccessoryDecoder.hxx │ ├── DccAccessoryDecoder.cpp │ ├── include │ │ └── AccessoryDecoderDataTypes.hxx │ └── OpenLCBAccessoryDecoder.cpp ├── Config │ ├── CMakeLists.txt │ └── include │ │ ├── NodeIdConfigurationGroup.hxx │ │ ├── RealTimeClockConfigurationGroup.hxx │ │ ├── pinmap-lmd18200.hxx │ │ ├── pinmap-l298.hxx │ │ ├── ThermalConfigurationGroup.hxx │ │ ├── pinmap-bts7960.hxx │ │ └── TrackOutputDescriptor.hxx ├── TrainDatabase │ └── CMakeLists.txt ├── Utils │ ├── CMakeLists.txt │ └── include │ │ ├── FileSystem.hxx │ │ ├── AutoPersistCallbackFlow.h │ │ ├── Spinlock.hxx │ │ ├── FactoryResetHelper.hxx │ │ ├── EventBroadcastHelper.hxx │ │ ├── DelayRebootHelper.hxx │ │ └── HealthMonitor.hxx ├── OpenMRNExtensions │ ├── CMakeLists.txt │ └── src │ │ ├── trainsearch │ │ └── TrainSearchConstants.cpp │ │ ├── locomgr │ │ ├── LocoManagerConstants.cpp │ │ ├── LocoManager.cpp │ │ └── Defs.hxx │ │ └── locodb │ │ └── LocoDatabase.hxx ├── NvsManager │ ├── CMakeLists.txt │ ├── private_include │ │ ├── AbstractVirtualMemorySpace.hxx │ │ ├── NvsManagerStruct.hxx │ │ └── NodeIdMemoryConfigSpace.hxx │ └── include │ │ └── NvsManager.hxx ├── StatusDisplay │ ├── CMakeLists.txt │ └── include │ │ └── StatusDisplay.hxx ├── TrainManager │ ├── CMakeLists.txt │ ├── private_include │ │ ├── TrainIdentifyHandler.hxx │ │ ├── TrainCDISpace.hxx │ │ ├── TrainFDISpace.hxx │ │ ├── TrainSnipHandler.hxx │ │ ├── TrainPipHandler.hxx │ │ ├── FdiXmlGenerator.hxx │ │ ├── LazyInitTrainNode.hxx │ │ ├── PersistentTrainConfigSpace.hxx │ │ └── XmlGenerator.hxx │ ├── TrainCDISpace.cpp │ ├── TrainPipHandler.cpp │ ├── TrainFDISpace.cpp │ ├── TrainIdentifyHandler.cpp │ ├── XmlGenerator.cpp │ ├── TrainSnipHandler.cpp │ ├── FdiXmlGenerator.cpp │ └── LazyInitTrainNode.cpp ├── StatusLED │ ├── CMakeLists.txt │ ├── StatusLED.cpp │ ├── include │ │ └── StatusLED.hxx │ └── StatusLEDGpio.cpp ├── DCC │ ├── CMakeLists.txt │ ├── DccConstants.cpp │ ├── include │ │ └── DCCSignalVFS.hxx │ └── private_include │ │ └── TrackPowerHandler.hxx └── ULPADC │ ├── CMakeLists.txt │ ├── UlpAdcEsp32S3.cpp │ └── include │ └── UlpAdc.hxx ├── .gitignore ├── .github ├── adc_pinmap_esp32.txt ├── pinmap_L298.txt ├── pinmap_LMD18200.txt ├── adc_pinmap_esp32s3.txt ├── pinmap_BTS7960B.txt ├── workflows │ └── main.yml ├── pinmap_PCB.txt └── firmwarereadme.txt ├── ESP32CS-partitions.csv ├── ESP32CS-S3-partitions.csv ├── sdkconfig.defaults.esp32s3 ├── README.md └── todo.md /web/loco-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/web/loco-32x32.png -------------------------------------------------------------------------------- /docs/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting Started with ESP32 Command Station 2 | 3 | TBD 4 | 5 | [home](README.md) -------------------------------------------------------------------------------- /docs/images/lmd18200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/lmd18200.jpg -------------------------------------------------------------------------------- /docs/images/lmd18200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/lmd18200.png -------------------------------------------------------------------------------- /docs/images/deekrobot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/deekrobot.png -------------------------------------------------------------------------------- /docs/images/ESPDuino-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/ESPDuino-32.png -------------------------------------------------------------------------------- /docs/images/esp32devkitc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/esp32devkitc.png -------------------------------------------------------------------------------- /docs/images/l298generic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/l298generic.png -------------------------------------------------------------------------------- /docs/images/ttgo-t1-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/ttgo-t1-back.png -------------------------------------------------------------------------------- /docs/images/ttgo-t1-front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/ttgo-t1-front.png -------------------------------------------------------------------------------- /docs/images/dcc-signal-split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanisoft/ESP32CommandStation/HEAD/docs/images/dcc-signal-split.png -------------------------------------------------------------------------------- /main/idf_component.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | idf: ">=4.4.0,<5.0.0" 3 | OpenMRNIDF: 4 | git: https://github.com/atanisoft/OpenMRNIDF.git 5 | HttpServer: 6 | git: https://github.com/atanisoft/HttpServer.git -------------------------------------------------------------------------------- /components/NeoPixelBus/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS "driver") 2 | 3 | idf_component_register(SRC_DIRS "src/internal" 4 | INCLUDE_DIRS "src" 5 | REQUIRES "${IDF_DEPS}") 6 | -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/idf_component.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | idf: ">=4.4.0,<5.0.0" 3 | OpenMRNIDF: 4 | git: https://github.com/atanisoft/OpenMRNIDF.git 5 | HttpServer: 6 | git: https://github.com/atanisoft/HttpServer.git -------------------------------------------------------------------------------- /components/Config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | hal 3 | ) 4 | 5 | set(CUSTOM_DEPS 6 | OpenMRNIDF 7 | ) 8 | 9 | idf_component_register(INCLUDE_DIRS include 10 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | sdkconfig 3 | sdkconfig.old 4 | .clang_complete 5 | .gcc-flags.json 6 | .vscode 7 | *.code-workspace 8 | docs/html 9 | docs/esp32cs.tag 10 | docs/warnings 11 | web/*.gz 12 | pcb/*.*-bak 13 | managed_components 14 | dependencies.lock -------------------------------------------------------------------------------- /.github/adc_pinmap_esp32.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- ADC_CHANNEL Pin Map: 3 | 4 | ADC_CHANNEL_0 : GPIO 36 (SVP) 5 | ADC_CHANNEL_1 : not supported 6 | ADC_CHANNEL_2 : not supported 7 | ADC_CHANNEL_3 : GPIO 39 (SVN) 8 | ADC_CHANNEL_4 : GPIO 32 9 | ADC_CHANNEL_5 : GPIO 33 10 | ADC_CHANNEL_6 : GPIO 34 11 | ADC_CHANNEL_7 : GPIO 35 -------------------------------------------------------------------------------- /ESP32CS-partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x9000, 0x5000, 3 | otadata, data, ota, 0xe000, 0x2000, 4 | ota_0, app, ota_0, , 0x1B0000, 5 | ota_1, app, ota_1, , 0x1B0000, 6 | coredump, data, coredump,, 0x10000, 7 | spiffs, data, spiffs, , 0x80000, -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/AccessoryDecoderConstants.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: GPL-3.0 5 | * 6 | * This file is part of ESP32 Command Station. 7 | */ 8 | 9 | #include 10 | 11 | namespace esp32cs 12 | { 13 | DEFAULT_CONST(dcc_accessory_packet_repeats, 3); 14 | } -------------------------------------------------------------------------------- /components/TrainDatabase/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(IDF_DEPS 3 | json 4 | ) 5 | 6 | set(CUSTOM_DEPS 7 | OpenMRNIDF 8 | OpenMRNExtensions 9 | Utils 10 | ) 11 | 12 | idf_component_register(SRCS Esp32TrainDatabase.cpp Esp32TrainDbEntry.cpp 13 | INCLUDE_DIRS include 14 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 15 | 16 | -------------------------------------------------------------------------------- /ESP32CS-S3-partitions.csv: -------------------------------------------------------------------------------- 1 | # 8mb flash 2 | # two 3.5mb ota partitions, 512kb spiffs 3 | # Name, Type, SubType, Offset, Size, Flags 4 | nvs, data, nvs, 0x9000, 0x5000, 5 | otadata, data, ota, 0xe000, 0x2000, 6 | ota_0, app, ota_0, , 0x380000, 7 | ota_1, app, ota_1, , 0x380000, 8 | coredump, data, coredump,, 0x10000, 9 | spiffs, data, spiffs, , 0x80000, -------------------------------------------------------------------------------- /components/Utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(IDF_DEPS 3 | fatfs 4 | spi_flash 5 | spiffs 6 | vfs 7 | ) 8 | 9 | set(CUSTOM_DEPS 10 | Config 11 | StatusDisplay 12 | StatusLED 13 | HttpServer 14 | ) 15 | 16 | idf_component_register(SRCS FileSystem.cpp CDIClient.cpp CDIDownloader.cpp 17 | INCLUDE_DIRS include 18 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") -------------------------------------------------------------------------------- /components/OpenMRNExtensions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(IDF_DEPS 3 | ) 4 | 5 | set(CUSTOM_DEPS 6 | OpenMRNIDF 7 | Utils 8 | ) 9 | 10 | idf_component_register(SRC_DIRS src/locodb src/locomgr src/trainsearch 11 | INCLUDE_DIRS "src" 12 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 13 | 14 | set_source_files_properties(src/trainsearch/Defs.cpp PROPERTIES COMPILE_FLAGS "-Wno-type-limits") -------------------------------------------------------------------------------- /.github/pinmap_L298.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- L298 Pin Map: 3 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 4 | #define CONFIG_OPS_HBRIDGE_L298 1 5 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 6 | #define CONFIG_PROG_HBRIDGE_L298 1 7 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 8 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 9 | #define CONFIG_PROG_TRACK_ENABLE_PIN 23 10 | #define CONFIG_RAILCOM_DISABLED 1 11 | #define CONFIG_I2C_SCL_PIN 22 12 | #define CONFIG_I2C_SDA_PIN 21 -------------------------------------------------------------------------------- /components/NvsManager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | app_update 3 | nvs_flash 4 | ) 5 | 6 | set(CUSTOM_DEPS 7 | Config 8 | OpenMRNIDF 9 | OpenMRNExtensions 10 | StatusLED 11 | Utils 12 | ) 13 | 14 | idf_component_register(SRCS NvsManager.cpp 15 | INCLUDE_DIRS "include" 16 | PRIV_INCLUDE_DIRS "private_include" 17 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | json 3 | ) 4 | 5 | set(CUSTOM_DEPS 6 | Config 7 | Utils 8 | ) 9 | 10 | idf_component_register(SRCS AccessoryDecoderConstants.cpp AccessoryDecoderDB.cpp DccAccessoryDecoder.cpp OpenLCBAccessoryDecoder.cpp 11 | INCLUDE_DIRS "include" 12 | PRIV_INCLUDE_DIRS "private_include" 13 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") -------------------------------------------------------------------------------- /.github/pinmap_LMD18200.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- LMD18200 Pin Map: 3 | 4 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 5 | #define CONFIG_OPS_HBRIDGE_L298 1 6 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 7 | #define CONFIG_PROG_HBRIDGE_L298 1 8 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 9 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 10 | #define CONFIG_PROG_TRACK_ENABLE_PIN 23 11 | #define CONFIG_RAILCOM_DISABLED 1 12 | #define CONFIG_I2C_SCL_PIN 22 13 | #define CONFIG_I2C_SDA_PIN 21 14 | -------------------------------------------------------------------------------- /components/StatusDisplay/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | driver 3 | ) 4 | 5 | set(CUSTOM_DEPS 6 | Config 7 | NvsManager 8 | OpenMRNIDF 9 | OpenMRNExtensions 10 | ) 11 | 12 | idf_component_register(SRCS StatusDisplay.cpp StatusDisplayLCD.cpp StatusDisplayOLED.cpp 13 | INCLUDE_DIRS "include" 14 | PRIV_INCLUDE_DIRS "private_include" 15 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 16 | -------------------------------------------------------------------------------- /components/OpenMRNExtensions/src/trainsearch/TrainSearchConstants.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2022 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include 8 | 9 | /// Number of milliseconds to delay before allocating a new train node. 10 | DEFAULT_CONST(trainsearch_allocate_delay_ms, 200); 11 | 12 | /// Number of milliseconds to delay between checks for new train node being 13 | /// initialized checks. 14 | DEFAULT_CONST(trainsearch_new_node_check_interval_ms, 1); 15 | -------------------------------------------------------------------------------- /components/TrainManager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CUSTOM_DEPS 2 | OpenMRNIDF 3 | OpenMRNExtensions 4 | Utils 5 | ) 6 | 7 | idf_component_register(SRCS TrainManager.cpp LazyInitTrainNode.cpp TrainFDISpace.cpp TrainPipHandler.cpp TrainSnipHandler.cpp PersistentTrainConfigSpace.cpp TrainCDISpace.cpp TrainFDISpace.cpp TrainIdentifyHandler.cpp FdiXmlGenerator.cpp XmlGenerator.cpp 8 | INCLUDE_DIRS include 9 | PRIV_INCLUDE_DIRS private_include 10 | REQUIRES "${CUSTOM_DEPS}") 11 | -------------------------------------------------------------------------------- /components/StatusLED/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CUSTOM_DEPS 2 | Config 3 | OpenMRNIDF 4 | NeoPixelBus 5 | ) 6 | 7 | idf_build_get_property(idf_target IDF_TARGET) 8 | 9 | if(${idf_target} STREQUAL "esp32s3") 10 | idf_component_register(SRCS StatusLED.cpp StatusLEDGpio.cpp 11 | INCLUDE_DIRS "include" 12 | REQUIRES "${CUSTOM_DEPS}") 13 | else() 14 | idf_component_register(SRCS StatusLED.cpp StatusLEDNeoPixel.cpp 15 | INCLUDE_DIRS "include" 16 | REQUIRES "${CUSTOM_DEPS}") 17 | endif() -------------------------------------------------------------------------------- /components/DCC/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | driver 3 | esp_adc_cal 4 | esp_timer 5 | ulp 6 | vfs 7 | ) 8 | 9 | set(CUSTOM_DEPS 10 | Config 11 | AccessoryDecoderDB 12 | OpenMRNIDF 13 | OpenMRNExtensions 14 | StatusDisplay 15 | ULPADC 16 | Utils 17 | ) 18 | 19 | idf_component_register(SRCS DccConstants.cpp DCCSignalVFS.cpp PrioritizedUpdateLoop.cpp 20 | INCLUDE_DIRS "include" 21 | PRIV_INCLUDE_DIRS "private_include" 22 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 23 | -------------------------------------------------------------------------------- /.github/adc_pinmap_esp32s3.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- ADC_CHANNEL Pin Map: 3 | 4 | ADC_CHANNEL_0 : GPIO 1 5 | ADC_CHANNEL_1 : GPIO 2 6 | ADC_CHANNEL_2 : GPIO 3 7 | ADC_CHANNEL_3 : GPIO 4 8 | ADC_CHANNEL_4 : GPIO 5 9 | ADC_CHANNEL_5 : GPIO 6 10 | ADC_CHANNEL_6 : GPIO 7 11 | ADC_CHANNEL_7 : GPIO 8 12 | ADC_CHANNEL_8 : GPIO 9 13 | ADC_CHANNEL_9 : GPIO 10 14 | ADC2_CHANNEL_0 : GPIO 11 15 | ADC2_CHANNEL_1 : GPIO 12 16 | ADC2_CHANNEL_2 : GPIO 13 17 | ADC2_CHANNEL_3 : GPIO 14 18 | ADC2_CHANNEL_4 : GPIO 15 19 | ADC2_CHANNEL_5 : GPIO 16 20 | ADC2_CHANNEL_6 : GPIO 17 21 | ADC2_CHANNEL_7 : GPIO 18 22 | ADC2_CHANNEL_8 : GPIO 19 23 | ADC2_CHANNEL_9 : GPIO 20 -------------------------------------------------------------------------------- /components/ULPADC/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(IDF_DEPS 2 | driver 3 | ulp 4 | ) 5 | 6 | set(CUSTOM_DEPS 7 | Config 8 | OpenMRNIDF 9 | ) 10 | 11 | idf_build_get_property(target IDF_TARGET) 12 | 13 | if(${target} STREQUAL "esp32s3") 14 | idf_component_register(SRCS UlpAdcEsp32S3.cpp 15 | INCLUDE_DIRS "include" 16 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 17 | else() 18 | idf_component_register(SRCS UlpAdc.cpp 19 | INCLUDE_DIRS "include" 20 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 21 | 22 | ulp_embed_binary(ulp_adc_ops adc_ops.S UlpAdc.cpp) 23 | endif() 24 | 25 | -------------------------------------------------------------------------------- /.github/pinmap_BTS7960B.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- BTS7960 Pin Map: 3 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 4 | #define CONFIG_OPS_HBRIDGE_BTS7960B_5A 1 5 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 6 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 7 | #define CONFIG_I2C_SCL_PIN 22 8 | #define CONFIG_I2C_SDA_PIN 21 9 | 10 | ---- BTS7960x2 Pin Map: 11 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 12 | #define CONFIG_OPS_HBRIDGE_BTS7960B_5A 1 13 | #define CONFIG_PROG_HBRIDGE_BTS7960B_5A 1 14 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 15 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 16 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 17 | #define CONFIG_PROG_TRACK_ENABLE_PIN 23 18 | #define CONFIG_I2C_SCL_PIN 22 19 | #define CONFIG_I2C_SDA_PIN 21 -------------------------------------------------------------------------------- /components/OpenMRNExtensions/src/locomgr/LocoManagerConstants.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2022 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: MIT 5 | */ 6 | 7 | #include 8 | 9 | /// Default to enabling Marklin locomotives. 10 | DEFAULT_CONST_TRUE(trainmgr_support_marklin); 11 | 12 | /// Default to enabling DCC locomotives. 13 | DEFAULT_CONST_TRUE(trainmgr_support_dcc); 14 | 15 | /// Default to enabling OpenLCB User based locomotives. 16 | DEFAULT_CONST_TRUE(trainmgr_support_openlcb_user); 17 | 18 | /// Default to enabling automatic creation of locomotives in the database when 19 | /// not found. 20 | DEFAULT_CONST_TRUE(trainmgr_automatically_create_train_impl); 21 | -------------------------------------------------------------------------------- /components/OpenMRNExtensions/src/locomgr/LocoManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * SPDX-FileCopyrightText: 2020-2022 Mike Dunston (atanisoft) 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | #include "LocoManager.hxx" 9 | 10 | #include 11 | #include 12 | 13 | namespace locomgr 14 | { 15 | 16 | openlcb::TrainService *LocoManager::train_service() 17 | { 18 | return trainService_; 19 | } 20 | 21 | bool LocoManager::is_known_train_node(openlcb::Node *node) 22 | { 23 | return train_service()->is_known_train_node(node); 24 | } 25 | 26 | openlcb::If *LocoManager::iface() 27 | { 28 | return train_service()->iface(); 29 | } 30 | 31 | } // namespace locomgr 32 | -------------------------------------------------------------------------------- /components/NeoPixelBus/library.properties: -------------------------------------------------------------------------------- 1 | name=NeoPixelBus by Makuna 2 | version=2.6.6 3 | author=Michael C. Miller (makuna@live.com) 4 | maintainer=Michael C. Miller (makuna@live.com) 5 | sentence=A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813, SK6812, TM1829, TM1814, TM1914, TX1812) and DotStars (APA102, LPD8806, LPD6803, SK9822, WS2801, P9813) easy. 6 | paragraph=Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels and 7 Segment LED direct driven. Includes seperate RgbColor, RgbwColor, Rgb16Color, Rgb48Color, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. Supports Matrix layout of pixels. Includes Gamma corretion object. For all platforms; there are two methods of sending DotStar data, hardware SPI and software SPI. 7 | category=Display 8 | url=https://github.com/Makuna/NeoPixelBus/wiki 9 | architectures=* -------------------------------------------------------------------------------- /components/TrainManager/private_include/TrainIdentifyHandler.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | 11 | #ifndef TRAINIDENTIFYHANDLER_HXX_ 12 | #define TRAINIDENTIFYHANDLER_HXX_ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace trainmanager 19 | { 20 | 21 | class TrainManager; 22 | 23 | class TrainIdentifyHandler : public openlcb::IncomingMessageStateFlow 24 | { 25 | public: 26 | TrainIdentifyHandler(TrainManager *parent); 27 | ~TrainIdentifyHandler(); 28 | /// Handler callback for incoming messages. 29 | StateFlowBase::Action entry() override; 30 | 31 | private: 32 | TrainManager *parent_; 33 | openlcb::NodeID target_; 34 | STATE_FLOW_STATE(send_train_ident); 35 | }; 36 | 37 | } // namespace trainmanager 38 | 39 | #endif // TRAINIDENTIFYHANDLER_HXX_ -------------------------------------------------------------------------------- /components/OpenMRNExtensions/src/locomgr/Defs.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * SPDX-FileCopyrightText: 2020-2022 Mike Dunston (atanisoft) 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | #ifndef LOCOMGR_DEFS_HXX_ 9 | #define LOCOMGR_DEFS_HXX_ 10 | 11 | #include 12 | 13 | /// Declares that Marklin locomotives are supported by the locomotive manager. 14 | /// Defaults to TRUE. 15 | DECLARE_CONST(trainmgr_support_marklin); 16 | 17 | /// Declares that DCC locomotives are supported by the locomotive manager. 18 | /// Defaults to TRUE. 19 | DECLARE_CONST(trainmgr_support_dcc); 20 | 21 | /// Declares that OpenLCB User addressed locomotives are supported by the 22 | /// locomotive manager. Defaults to TRUE. 23 | DECLARE_CONST(trainmgr_support_openlcb_user); 24 | 25 | /// Declares that OpenLCB User addressed locomotives are supported by the 26 | /// locomotive manager. Defaults to TRUE. 27 | DECLARE_CONST(trainmgr_automatically_create_train_impl); 28 | 29 | #endif // LOCOMGR_DEFS_HXX_ -------------------------------------------------------------------------------- /components/TrainManager/private_include/TrainCDISpace.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | 11 | #ifndef TRAINCDISPACE_HXX_ 12 | #define TRAINCDISPACE_HXX_ 13 | 14 | #include 15 | #include 16 | 17 | namespace trainmanager 18 | { 19 | 20 | class TrainManager; 21 | 22 | class TrainCDISpace : public openlcb::MemorySpace 23 | { 24 | public: 25 | TrainCDISpace(TrainManager *parent); 26 | 27 | bool set_node(openlcb::Node* node) override; 28 | 29 | openlcb::MemorySpace::address_t max_address() override; 30 | 31 | size_t read(address_t source, uint8_t* dst, size_t len, errorcode_t* error, 32 | Notifiable* again) override; 33 | 34 | private: 35 | TrainManager *parent_; 36 | openlcb::MemorySpace *proxySpace_; 37 | }; 38 | 39 | } // namespace trainmanager 40 | 41 | #endif // TRAINCDISPACE_HXX_ -------------------------------------------------------------------------------- /components/DCC/DccConstants.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2020-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include 19 | 20 | namespace esp32cs 21 | { 22 | 23 | DEFAULT_CONST(min_refresh_delay_ms, 10); 24 | 25 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoBusChannel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // For those platforms/methods that support dynamic channel setting 4 | // 5 | // ESP32 - 8 TX channels 6 | // ESP32S2 - 4 TX channels 7 | // ESP32C3 - 2 TX channels 8 | // NRF52840 - 3 or 4 channels (some variants only have 3) 9 | 10 | enum NeoBusChannel 11 | { 12 | NeoBusChannel_0, 13 | NeoBusChannel_1, 14 | 15 | #if !defined(CONFIG_IDF_TARGET_ESP32C3) 16 | 17 | NeoBusChannel_2, 18 | 19 | // NRF52x has only 3 or 4 channels of PWM 20 | #if defined(ARDUINO_ARCH_NRF52840) 21 | 22 | #if defined(NRF_PWM3) 23 | NeoBusChannel_3, 24 | #endif 25 | 26 | // ESP32 has either 8, 4, or 2 channels (S2 has only 4, C3 only 2) 27 | #elif defined(ARDUINO_ARCH_ESP32) 28 | 29 | NeoBusChannel_3, 30 | 31 | #if !defined(CONFIG_IDF_TARGET_ESP32S2) 32 | NeoBusChannel_4, 33 | NeoBusChannel_5, 34 | NeoBusChannel_6, 35 | NeoBusChannel_7, 36 | #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) 37 | 38 | #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) 39 | 40 | #endif // ARDUINO_ARCH_ESP32 41 | 42 | NeoBusChannel_COUNT 43 | }; -------------------------------------------------------------------------------- /components/TrainManager/private_include/TrainFDISpace.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #ifndef TRAINFDISPACE_HXX_ 11 | #define TRAINFDISPACE_HXX_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace trainmanager 19 | { 20 | class TrainManager; 21 | 22 | class TrainFDISpace : public openlcb::MemorySpace 23 | { 24 | public: 25 | TrainFDISpace(TrainManager *parent); 26 | bool set_node(openlcb::Node *node) override; 27 | openlcb::MemorySpace::address_t max_address() override; 28 | size_t read(address_t source, uint8_t *dst, size_t len, errorcode_t *error, 29 | Notifiable *again) override; 30 | 31 | private: 32 | FdiXmlGenerator gen_; 33 | TrainManager *parent_; 34 | openlcb::Node *node_{nullptr}; 35 | void reset_file(); 36 | }; 37 | 38 | } // namespace trainmanager 39 | 40 | #endif // TRAINFDISPACE_HXX_ -------------------------------------------------------------------------------- /sdkconfig.defaults.esp32s3: -------------------------------------------------------------------------------- 1 | # 2 | # SDK configuration 3 | # 4 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y 5 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="ESP32CS-S3-partitions.csv" 6 | CONFIG_PARTITION_TABLE_FILENAME="ESP32CS-S3-partitions.csv" 7 | 8 | # 9 | # ESP32S3-Specific 10 | # 11 | CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y 12 | CONFIG_ESP32S3_ULP_COPROC_ENABLED=y 13 | CONFIG_ESP32S3_ULP_COPROC_RISCV=y 14 | CONFIG_ESP32S3_DEBUG_OCDAWARE=n 15 | CONFIG_ESP32S3_SPIRAM_SUPPORT=y 16 | 17 | # 18 | # Ultra Low Power (ULP) Co-processor 19 | # 20 | CONFIG_ULP_COPROC_ENABLED=y 21 | 22 | # 23 | # SPI RAM config 24 | # 25 | CONFIG_SPIRAM_TYPE_AUTO=y 26 | CONFIG_SPIRAM=y 27 | CONFIG_SPIRAM_USE_MALLOC=y 28 | CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=128 29 | CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y 30 | CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=0 31 | CONFIG_SPIRAM_IGNORE_NOTFOUND=y 32 | 33 | # 34 | # ESP System Settings 35 | # 36 | CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y 37 | 38 | # 39 | # LWIP 40 | # 41 | CONFIG_LWIP_L2_TO_L3_COPY=y 42 | 43 | # 44 | # Compiler options 45 | # 46 | CONFIG_COMPILER_CXX_EXCEPTIONS=y 47 | 48 | # 49 | # TCP 50 | # 51 | CONFIG_LWIP_TCP_RECVMBOX_SIZE=32 52 | CONFIG_LWIP_WND_SCALE=y 53 | -------------------------------------------------------------------------------- /components/NeoPixelBus/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NeoPixelBus", 3 | "keywords": "NeoPixel, WS2811, WS2812, WS2813, SK6812, DotStar, APA102, SK9822, APA106, LPD8806, LPD6803, P9813, TM1829, TM1814, TM1914, TX1812, WS2801 RGB, RGBW", 4 | "description": "A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813, SK6812, TM1829, TM1814, TM1914, TX1812) and DotStars (APA102, LPD8806, LPD6803, SK9822, WS2801, P9813) easy. Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels and 7 Segment LED direct driven. Includes seperate RgbColor, RgbwColor, Rgb16Color, Rgb48Color, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For all platforms; there are two methods of sending DotStar data, hardware SPI and software SPI.", 5 | "homepage": "https://github.com/Makuna/NeoPixelBus/wiki", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Makuna/NeoPixelBus" 9 | }, 10 | "version": "2.6.6", 11 | "frameworks": "arduino", 12 | "platforms": "*", 13 | "dependencies": [ 14 | { 15 | "name": "SPI" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /components/TrainManager/private_include/TrainSnipHandler.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | 11 | #ifndef TRAINSNIPHANDLER_HXX_ 12 | #define TRAINSNIPHANDLER_HXX_ 13 | 14 | #include 15 | 16 | namespace openlcb 17 | { 18 | class IncomingMessageStateFlow; 19 | class SimpleInfoFlow; 20 | struct SimpleInfoDescriptor; 21 | } 22 | 23 | namespace trainmanager 24 | { 25 | class TrainManager; 26 | 27 | class TrainSnipHandler : public openlcb::IncomingMessageStateFlow 28 | { 29 | public: 30 | TrainSnipHandler(TrainManager* parent, openlcb::SimpleInfoFlow* info_flow); 31 | ~TrainSnipHandler(); 32 | private: 33 | TrainManager* parent_; 34 | openlcb::SimpleInfoFlow* responseFlow_; 35 | BarrierNotifiable n_; 36 | string snipName_; 37 | string snipDesc_; 38 | static openlcb::SimpleInfoDescriptor snipResponse_[]; 39 | 40 | StateFlowBase::Action entry() override; 41 | STATE_FLOW_STATE(send_response_request); 42 | STATE_FLOW_STATE(send_done); 43 | }; 44 | } // namespace trainmanager 45 | 46 | #endif // TRAINSNIPHANDLER_HXX_ -------------------------------------------------------------------------------- /components/TrainManager/private_include/TrainPipHandler.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | 11 | #ifndef TRAINPIPHANDLER_HXX_ 12 | #define TRAINPIPHANDLER_HXX_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace trainmanager 20 | { 21 | class TrainManager; 22 | 23 | class TrainPipHandler : public openlcb::IncomingMessageStateFlow 24 | { 25 | public: 26 | TrainPipHandler(TrainManager* parent); 27 | ~TrainPipHandler(); 28 | private: 29 | static constexpr uint64_t pipReply_ = 30 | openlcb::Defs::SIMPLE_PROTOCOL_SUBSET | openlcb::Defs::DATAGRAM | 31 | openlcb::Defs::MEMORY_CONFIGURATION | openlcb::Defs::EVENT_EXCHANGE | 32 | openlcb::Defs::SIMPLE_NODE_INFORMATION | openlcb::Defs::TRACTION_CONTROL | 33 | openlcb::Defs::TRACTION_FDI | openlcb::Defs::CDI; 34 | TrainManager* parent_; 35 | 36 | StateFlowBase::Action entry() override; 37 | STATE_FLOW_STATE(fill_response_buffer); 38 | }; 39 | } // namespace trainmanager 40 | 41 | #endif // TRAINPIPHANDLER_HXX_ -------------------------------------------------------------------------------- /components/DCC/include/DCCSignalVFS.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include "TrackOutputDescriptor.hxx" 19 | 20 | #include 21 | 22 | namespace openlcb 23 | { 24 | class Node; 25 | } 26 | 27 | namespace esp32cs 28 | { 29 | 30 | void init_dcc(openlcb::Node *node, Service *service, 31 | const esp32cs::TrackOutputConfig &cfg); 32 | 33 | void shutdown_dcc(); 34 | 35 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/TrainManager/private_include/FdiXmlGenerator.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #ifndef FDIXMLGENERATOR_HXX_ 11 | #define FDIXMLGENERATOR_HXX_ 12 | 13 | #include "XmlGenerator.hxx" 14 | 15 | #include 16 | #include 17 | 18 | namespace trainmanager 19 | { 20 | 21 | class FdiXmlGenerator : public XmlGenerator 22 | { 23 | public: 24 | /// Call this after the lokdb on entry was overwritten with the new loco's 25 | /// data. 26 | void reset(std::shared_ptr entry); 27 | 28 | private: 29 | /// Generates XML field data for the next state. 30 | void generate_more() override; 31 | 32 | /// States used as part of generating the FDI XML data. 33 | enum State 34 | { 35 | STATE_START = 0, 36 | STATE_XMLHEAD = STATE_START, 37 | STATE_START_FN, 38 | STATE_FN_NAME, 39 | STATE_FN_NUMBER, 40 | STATE_FN_END, 41 | STATE_NO_MORE_FN, 42 | STATE_EOF 43 | }; 44 | 45 | State state_; 46 | std::shared_ptr entry_; 47 | int nextFunction_; 48 | }; 49 | 50 | } // namespace trainmanager 51 | 52 | #endif // FDIXMLGENERATOR_HXX_ -------------------------------------------------------------------------------- /docs/building.md: -------------------------------------------------------------------------------- 1 | # Building the compiled binary 2 | 3 | After configuring via `menuconfig` it is necessary to build the source code 4 | into a usable binary for the ESP32. 5 | 6 | ## Graphical or command line build 7 | 8 | If you are using VSCode with the [Espressif IDF plugin](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension) 9 | you can simply press the :gear: icon to build the source code. 10 | 11 | For command line based building, you will need to prepare your ESP-IDF build 12 | enviornment by running `source {IDF_PATH}/export.sh` if you are on Mac/Linux or 13 | `{IDF_PATH}\export.bat` on Windows, replace `{IDF_PATH}` with the actual path 14 | where ESP-IDF has been installed. This step will need to be done anytime a new 15 | shell is opened the first time for building. 16 | 17 | After the shell is configured for ESP-IDF navigate to the ESP32CommandStation 18 | directory and run `idf.py build`. 19 | 20 | The build will take between five and ten minutes depending on selected 21 | configuration options and the computer being used to build. 22 | 23 | ## Flashing binaries to the ESP32 24 | 25 | The generated binaries will be in the `build` directory and should be used in 26 | the same manner as pre-compiled binaries as described [here](precompiled.md). 27 | 28 | ## 29 | 30 | [home](README.md) -------------------------------------------------------------------------------- /components/Utils/include/FileSystem.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef FILESYSTEM_HXX_ 19 | #define FILESYSTEM_HXX_ 20 | 21 | namespace esp32cs 22 | { 23 | 24 | /// Mounts the persistent filesystem. 25 | /// @param cleanup will remove all files from the filesystem during startup. 26 | /// @return true if the filesystem is stored on an SD card, false for SPIFFS. 27 | bool mount_fs(bool cleanup = false); 28 | 29 | /// Unmounts the persistent filesystem. 30 | void unmount_fs(); 31 | 32 | } // namespace esp32cs 33 | 34 | #endif // FILESYSTEM_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/Esp32_i2s.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ESP32C3 I2S is not supported yet due to significant changes to interface 4 | #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #include "esp_err.h" 11 | 12 | #define I2S_DMA_MAX_DATA_LEN 4092// maximum bytes in one dma item 13 | 14 | typedef enum { 15 | I2S_CHAN_STEREO, I2S_CHAN_RIGHT_TO_LEFT, I2S_CHAN_LEFT_TO_RIGHT, I2S_CHAN_RIGHT_ONLY, I2S_CHAN_LEFT_ONLY 16 | } i2s_tx_chan_mod_t; 17 | 18 | typedef enum { 19 | I2S_FIFO_16BIT_DUAL, I2S_FIFO_16BIT_SINGLE, I2S_FIFO_32BIT_DUAL, I2S_FIFO_32BIT_SINGLE 20 | } i2s_tx_fifo_mod_t; 21 | 22 | void i2sInit(uint8_t bus_num, 23 | uint32_t bits_per_sample, 24 | uint32_t sample_rate, 25 | i2s_tx_chan_mod_t chan_mod, 26 | i2s_tx_fifo_mod_t fifo_mod, 27 | size_t dma_count, 28 | size_t dma_len); 29 | 30 | void i2sSetPins(uint8_t bus_num, int8_t out, bool invert); 31 | 32 | esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits_per_sample); 33 | esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t sample_rate, uint8_t bits_per_sample); 34 | 35 | size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent); 36 | bool i2sWriteDone(uint8_t bus_num); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif -------------------------------------------------------------------------------- /components/TrainManager/private_include/LazyInitTrainNode.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2023 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | */ 7 | 8 | #ifndef LAZYINITTRAINNODE_HXX_ 9 | #define LAZYINITTRAINNODE_HXX_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace openlcb 16 | { 17 | class DefaultTrainNode; 18 | class TrainService; 19 | } 20 | 21 | namespace trainmanager 22 | { 23 | 24 | class LazyInitTrainNode : public openlcb::DefaultTrainNode 25 | { 26 | public: 27 | /// Constructor. 28 | /// @param service the traction service object that will own this node. 29 | /// @param offset the @ref TrainDb assigned identifier for this node. 30 | /// @param mode the @ref DriveMode that this node should use. 31 | /// @param address the address of this node. 32 | LazyInitTrainNode(openlcb::TrainService *service, ssize_t offset, 33 | locodb::DriveMode mode, 34 | uint16_t address); 35 | ~LazyInitTrainNode(); 36 | openlcb::NodeID node_id() override; 37 | uint16_t address(); 38 | locodb::DriveMode mode(); 39 | ssize_t file_offset(); 40 | bool is_allocated(); 41 | openlcb::TrainImpl *train() override; 42 | private: 43 | ssize_t offset_; 44 | locodb::DriveMode mode_; 45 | uint16_t addr_; 46 | }; 47 | 48 | } // namespace trainmanager 49 | 50 | #endif // LAZYINITTRAINNODE_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoEsp8266DmaMethod.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixel library helper functions for Esp8266. 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #ifdef ARDUINO_ARCH_ESP8266 28 | 29 | #include 30 | #include "NeoSettings.h" 31 | #include "NeoBusChannel.h" 32 | #include "NeoEsp8266DmaMethod.h" 33 | 34 | 35 | NeoEsp8266DmaMethodCore* NeoEsp8266DmaMethodCore::s_this; 36 | 37 | #endif -------------------------------------------------------------------------------- /components/TrainManager/TrainCDISpace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | #include "TrainManager.hxx" 10 | #include "TrainCDISpace.hxx" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | namespace trainmanager 17 | { 18 | 19 | using locodb::LocoDatabase; 20 | 21 | using openlcb::MemorySpace; 22 | 23 | TrainCDISpace::TrainCDISpace(TrainManager* parent) : parent_(parent) 24 | { 25 | 26 | } 27 | 28 | bool TrainCDISpace::set_node(openlcb::Node* node) 29 | { 30 | if (!parent_->is_valid_train_node(node)) 31 | { 32 | return false; 33 | } 34 | if (!Singleton::instance()->is_valid_train(node->node_id())) 35 | { 36 | return false; 37 | } 38 | if (Singleton::instance()->get_entry_offset(node->node_id()) < 0) 39 | { 40 | proxySpace_ = &parent_->ro_tmp_train_cdi_; 41 | } 42 | else 43 | { 44 | proxySpace_ = &parent_->ro_train_cdi_; 45 | } 46 | return true; 47 | } 48 | 49 | openlcb::MemorySpace::address_t TrainCDISpace::max_address() 50 | { 51 | return proxySpace_->max_address(); 52 | } 53 | 54 | size_t TrainCDISpace::read(address_t source, uint8_t* dst, size_t len, errorcode_t* error, 55 | Notifiable* again) 56 | { 57 | return proxySpace_->read(source, dst, len, error, again); 58 | } 59 | 60 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/TrainManager/private_include/PersistentTrainConfigSpace.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | 11 | #ifndef PERSISTENTTRAINCONFIGSPACE_HXX_ 12 | #define PERSISTENTTRAINCONFIGSPACE_HXX_ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace trainmanager 20 | { 21 | 22 | class TrainManager; 23 | 24 | class PersistentTrainConfigSpace : public openlcb::VirtualMemorySpace 25 | { 26 | public: 27 | PersistentTrainConfigSpace(TrainManager *parent); 28 | bool set_node(openlcb::Node *node) override; 29 | 30 | private: 31 | template 32 | typename std::function 33 | typed_reader(int index); 34 | template 35 | std::function 36 | typed_writer(int index); 37 | 38 | std::function string_reader(int index); 39 | std::function string_writer(int index); 40 | 41 | TrainManager *parent_; 42 | LazyInitTrainNode *impl_{nullptr}; 43 | std::shared_ptr train_; 44 | }; 45 | 46 | } // namespace trainmanager 47 | 48 | #endif // PERSISTENTTRAINCONFIGSPACE_HXX_PERSISTENTTRAINCONFIGSPACE_HXX_ -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/private_include/DccAccessoryDecoder.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef TURNOUTS_HXX_ 19 | #define TURNOUTS_HXX_ 20 | 21 | #include 22 | #include 23 | #include "AccessoryDecoderDataTypes.hxx" 24 | 25 | namespace esp32cs 26 | { 27 | 28 | class DccAccessoryDecoder : public AccessoryBaseType 29 | { 30 | public: 31 | DccAccessoryDecoder(uint16_t address, std::string name, 32 | bool thrown = false, 33 | AccessoryType type = AccessoryType::UNKNOWN); 34 | bool set(bool state, bool is_on) override; 35 | std::string to_json(bool readable_strings = false) override; 36 | }; 37 | 38 | } // namespace esp32cs 39 | 40 | #endif // TURNOUTS_HXX_ -------------------------------------------------------------------------------- /components/Config/include/NodeIdConfigurationGroup.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef NODEID_CONFIG_GROUP_HXX_ 19 | #define NODEID_CONFIG_GROUP_HXX_ 20 | 21 | #include 22 | 23 | #include "sdkconfig.h" 24 | 25 | namespace esp32cs 26 | { 27 | 28 | CDI_GROUP(NodeIdConfig, Segment(CONFIG_OLCB_NODEID_MEMORY_SPACE_ID), 29 | Offset(CONFIG_OLCB_NODEID_MEMORY_SPACE_OFFSET)); 30 | CDI_GROUP_ENTRY(node_id, openlcb::StringConfigEntry<32>, Name("Node ID"), 31 | Description( 32 | R"!^!(Identifier to use for this device. 33 | NOTE: Changing this value will force a factory reset.)!^!")) 34 | CDI_GROUP_END(); 35 | 36 | } // namespace esp32cs 37 | 38 | #endif // NODEID_CONFIG_GROUP_HXX_ 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Status 2 | This project is currently not under active development and is unlikely to return to active development anytime soon. 3 | 4 | # What is ESP32 Command Station 5 | ESP32 Command Station is an open-source hardware and software OpenLCB enabled Command Station for the operation of DCC decoder equipped model railroads. 6 | 7 | The ESP32 Command Station consists of an ESP32 module with up to two h-bridge devices to generate the DCC signal for the tracks. Note that only one h-bridge will be enabled at any given time, it is not possible to use both OPS and PROG tracks simultaneously. It is also possible to disable either the OPS or PROG track output entirely via configuration settings. 8 | 9 | Support for the following add-ons is available: 10 | 1. CAN transceiver (MCP2551 or SN65HVD23X) for LCC CAN connectivity. 11 | 2. OLED or LCD display for command station status. 12 | 3. Addressable RGB LEDs for visual status indicators. 13 | 14 | Documentation can be found [here](./docs). 15 | 16 | [![Build Status](https://github.com/atanisoft/ESP32CommandStation/workflows/Build/badge.svg)](https://github.com/atanisoft/ESP32CommandStation/actions) 17 | [![Contributors](https://img.shields.io/github/contributors/atanisoft/ESP32CommandStation.svg)](https://github.com/atanisoft/ESP32CommandStation/graphs/contributors) 18 | [![Stars](https://img.shields.io/github/stars/atanisoft/ESP32CommandStation.svg)](https://github.com/atanisoft/ESP32CommandStation/stargazers) 19 | [![License](https://img.shields.io/github/license/atanisoft/ESP32CommandStation.svg)](https://github.com/atanisoft/ESP32CommandStation/blob/master/LICENSE) 20 | 21 | -Jan 11, 2024 22 | -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/RgbColorBase.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | RgbColorBase provides a RGB color object common support 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | #pragma once 27 | 28 | struct HslColor; 29 | struct HsbColor; 30 | struct Rgb16Color; 31 | 32 | struct RgbColorBase 33 | { 34 | 35 | protected: 36 | static float _CalcColor(float p, float q, float t); 37 | 38 | static void _HslToRgb(const HslColor& color, float* r, float* g, float* b); 39 | 40 | static void _HsbToRgb(const HsbColor& color, float* r, float* g, float* b); 41 | }; -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/DccAccessoryDecoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2022 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: GPL-3.0 5 | * 6 | * This file is part of ESP32 Command Station. 7 | */ 8 | 9 | #include "DccAccessoryDecoder.hxx" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace esp32cs 16 | { 17 | 18 | DccAccessoryDecoder::DccAccessoryDecoder( 19 | uint16_t address, std::string name, bool state, AccessoryType type) : 20 | AccessoryBaseType(address, name, state, type) 21 | { 22 | LOG(CONFIG_TURNOUT_LOG_LEVEL, 23 | "[DccAccessoryDecoder %d] Registered as %s with state of %s", 24 | address, ACCESSORY_TYPE_STRINGS[type], state ? "Thrown" : "Closed"); 25 | } 26 | 27 | string DccAccessoryDecoder::to_json(bool readableStrings) 28 | { 29 | string serialized = 30 | StringPrintf("{\"addr\":%d,\"name\":\"%s\",\"type\":%d,\"state\":", 31 | address(), name().c_str(), type()); 32 | if (readableStrings) 33 | { 34 | if (get()) 35 | { 36 | serialized += "\"Thrown\""; 37 | } 38 | else 39 | { 40 | serialized += "\"Closed\""; 41 | } 42 | } 43 | else 44 | { 45 | serialized += integer_to_string(get()); 46 | } 47 | serialized += "}"; 48 | return serialized; 49 | } 50 | 51 | bool DccAccessoryDecoder::set(bool state, bool is_on) 52 | { 53 | AccessoryBaseType::set(state, is_on); 54 | LOG(CONFIG_TURNOUT_LOG_LEVEL, "[DccAccessoryDecoder %d] Set to %s (%s)", 55 | address(), get() ? "Thrown" : "Closed", is_on ? "On" : "Off"); 56 | return true; 57 | } 58 | 59 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/NvsManager/private_include/AbstractVirtualMemorySpace.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2022 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef ABSTRACT_VIRTUAL_MEMORY_SPACE_HXX_ 19 | #define ABSTRACT_VIRTUAL_MEMORY_SPACE_HXX_ 20 | 21 | namespace esp32cs 22 | { 23 | 24 | /// Abstract base class for virtual memory space implementations providing a 25 | /// consistent API for tracking modifications that may require persistence. 26 | class AbstractVirtualMemorySpace 27 | { 28 | public: 29 | /// @return true if the memory space has been modified, false otherwise. 30 | bool modified() 31 | { 32 | return modified_; 33 | } 34 | protected: 35 | /// Helper method for implementations to flag that modifications have been 36 | /// made. 37 | /// @param value indicates modifications when true. 38 | void set_modified(bool value) 39 | { 40 | modified_ = value; 41 | } 42 | private: 43 | /// Tracking variable for modifications. 44 | bool modified_{false}; 45 | }; 46 | 47 | } // namespace esp32cs 48 | 49 | #endif // ABSTRACT_VIRTUAL_MEMORY_SPACE_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoBufferContext.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixel library 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | #pragma once 27 | 28 | // This is used to allow a template classes that share common buffer concept to 29 | // be able to pass that common information to functions 30 | // The template classes just need to expose a conversion operator to this type 31 | template struct NeoBufferContext 32 | { 33 | NeoBufferContext(uint8_t* pixels, 34 | size_t sizePixels) : 35 | Pixels(pixels), 36 | SizePixels(sizePixels) 37 | { 38 | } 39 | 40 | uint16_t PixelCount() const 41 | { 42 | return SizePixels / T_COLOR_FEATURE::PixelSize; 43 | }; 44 | 45 | uint8_t* Pixels; 46 | const size_t SizePixels; 47 | 48 | }; -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/private_include/OpenLCBAccessoryDecoder.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef OPENLCB_ACCESSORY_DECODER_HXX_ 19 | #define OPENLCB_ACCESSORY_DECODER_HXX_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "AccessoryDecoderDataTypes.hxx" 25 | 26 | namespace esp32cs 27 | { 28 | 29 | class OpenLCBAccessoryDecoder : public AccessoryBaseType 30 | { 31 | public: 32 | OpenLCBAccessoryDecoder(const uint16_t address, std::string name, 33 | std::string closed_events, 34 | std::string thrown_events, AccessoryType type, 35 | bool state); 36 | bool set(bool state, bool is_on) override; 37 | std::string to_json(bool readable_strings = false) override; 38 | void update_events(std::string closed_events, std::string thrown_events); 39 | private: 40 | std::vector closed_; 41 | std::vector thrown_; 42 | }; 43 | 44 | } // namespace esp32cs 45 | 46 | #endif // OPENLCB_ACCESSORY_DECODER_HXX_ -------------------------------------------------------------------------------- /components/TrainManager/TrainPipHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "TrainPipHandler.hxx" 11 | #include "TrainManager.hxx" 12 | namespace trainmanager 13 | { 14 | 15 | using openlcb::Defs; 16 | using openlcb::IncomingMessageStateFlow; 17 | 18 | TrainPipHandler::TrainPipHandler(TrainManager* parent) 19 | : IncomingMessageStateFlow(parent->train_service()->iface()), 20 | parent_(parent) 21 | { 22 | iface()->dispatcher()->register_handler( 23 | this, Defs::MTI::MTI_PROTOCOL_SUPPORT_INQUIRY, Defs::MTI::MTI_EXACT); 24 | } 25 | 26 | TrainPipHandler::~TrainPipHandler() 27 | { 28 | iface()->dispatcher()->unregister_handler( 29 | this, Defs::MTI::MTI_PROTOCOL_SUPPORT_INQUIRY, Defs::MTI::MTI_EXACT); 30 | } 31 | 32 | StateFlowBase::Action TrainPipHandler::entry() 33 | { 34 | if (!parent_->is_valid_train_node(nmsg()->dstNode)) 35 | { 36 | return release_and_exit(); 37 | } 38 | 39 | return allocate_and_call(iface()->addressed_message_write_flow(), 40 | STATE(fill_response_buffer)); 41 | } 42 | 43 | StateFlowBase::Action TrainPipHandler::fill_response_buffer() 44 | { 45 | // Grabs our allocated buffer. 46 | auto* b = get_allocation_result(iface()->addressed_message_write_flow()); 47 | auto reply = pipReply_; 48 | // Fills in response. We use node_id_to_buffer because that converts a 49 | // 48-bit value to a big-endian byte string. 50 | b->data()->reset(Defs::MTI_PROTOCOL_SUPPORT_REPLY, 51 | nmsg()->dstNode->node_id(), nmsg()->src, 52 | openlcb::node_id_to_buffer(reply)); 53 | 54 | // Passes the response to the addressed message write flow. 55 | iface()->addressed_message_write_flow()->send(b); 56 | 57 | return release_and_exit(); 58 | } 59 | 60 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/ULPADC/UlpAdcEsp32S3.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include "UlpAdc.hxx" 19 | #include "sdkconfig.h" 20 | 21 | namespace esp32cs 22 | { 23 | 24 | /// Initialize and start the ULP co-processor for monitoring current sense ADC 25 | /// inputs. When thresholds are breached the ULP will raise an interrupt to the 26 | /// ESP32 SoC. When the interrupt is triggered the ESP32 SoC will evaluate the 27 | /// current state and raise event(s) as needed. 28 | void initialize_ulp_adc() 29 | { 30 | 31 | } 32 | 33 | void deinitialize_ulp_adc() 34 | { 35 | } 36 | 37 | uint16_t get_last_ops_reading() 38 | { 39 | return 4095; 40 | } 41 | 42 | uint32_t get_ops_load() 43 | { 44 | return -1; 45 | } 46 | 47 | uint16_t get_ops_short_threshold() 48 | { 49 | return 4095; 50 | } 51 | 52 | uint16_t get_ops_shutdown_threshold() 53 | { 54 | return 4095; 55 | } 56 | 57 | uint16_t get_ops_warning_threshold() 58 | { 59 | return 4095; 60 | } 61 | 62 | uint16_t get_last_prog_reading() 63 | { 64 | return 4095; 65 | } 66 | 67 | uint16_t get_last_tempsensor_reading() 68 | { 69 | return 4095; 70 | } 71 | 72 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/NeoPixelBus/ReadMe.md: -------------------------------------------------------------------------------- 1 | # NeoPixelBus 2 | 3 | [![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4) 4 | 5 | Arduino NeoPixel library 6 | 7 | A library to control one wire protocol RGB and RGBW leds like APA106, SK6812, WS2811, WS2812 and WS2813 that are commonly refered to as NeoPixels and two wire protocol RGB like Lpd8806, APA102 and SK9822 commonly refered to as DotStars. 8 | Supports most Arduino platforms. 9 | 10 | Please read this best practices link before connecting your NeoPixels, it will save you a lot of time and effort. 11 | [Adafruit NeoPixel Best Practices](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices) 12 | 13 | For quick questions and support: 14 | * [Try the new Github Discussions](https://github.com/Makuna/NeoPixelBus/discussions) 15 | * [Discord NeoPixelBus Invitation](https://discord.gg/c6FrysvZyV) or if you are already a member of [Discord Server NeoPixelBus](https://discord.com/channels/789177382221119519/789177382221119521) 16 | * Or jump on Gitter 17 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/NeoPixelBus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 18 | 19 | For bugs, make sure there isn't an active issue and then create one. 20 | 21 | ## Why this library and not FastLED or some other library? 22 | See [Why this Library in the Wiki](https://github.com/Makuna/NeoPixelBus/wiki/Library-Comparisons). 23 | 24 | ## Documentation 25 | [See Wiki](https://github.com/Makuna/NeoPixelBus/wiki) 26 | 27 | ## Installing This Library (preferred, you just want to use it) 28 | Open the Library Manager and search for "NeoPixelBus by Makuna" and install 29 | 30 | ## Installing This Library From GitHub (advanced, you want to contribute) 31 | Create a directory in your Arduino\Library folder named "NeoPixelBus" 32 | Clone (Git) this project into that folder. 33 | It should now show up in the import list when you restart Arduino IDE. 34 | -------------------------------------------------------------------------------- /components/Utils/include/AutoPersistCallbackFlow.h: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2019-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef AUTO_PERSIST_CB_FLOW_H_ 19 | #define AUTO_PERSIST_CB_FLOW_H_ 20 | 21 | #include 22 | #include 23 | 24 | class AutoPersistFlow : private StateFlowBase 25 | { 26 | public: 27 | AutoPersistFlow(Service *service 28 | , uint64_t interval 29 | , std::function callback) 30 | : StateFlowBase(service) 31 | , interval_(interval) 32 | , callback_(std::move(callback)) 33 | { 34 | HASSERT(callback_); 35 | start_flow(STATE(sleep_and_persist)); 36 | } 37 | 38 | void stop() 39 | { 40 | set_terminated(); 41 | timer_.ensure_triggered(); 42 | } 43 | 44 | private: 45 | StateFlowTimer timer_{this}; 46 | uint64_t interval_; 47 | std::function callback_; 48 | StateFlowBase::Action sleep_and_persist() 49 | { 50 | return sleep_and_call(&timer_, interval_, STATE(persist)); 51 | } 52 | StateFlowBase::Action persist() 53 | { 54 | callback_(); 55 | return yield_and_call(STATE(sleep_and_persist)); 56 | } 57 | }; 58 | #endif // AUTO_PERSIST_CB_FLOW_H_ -------------------------------------------------------------------------------- /components/NvsManager/private_include/NvsManagerStruct.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef NVS_STRUCT_HXX_ 19 | #define NVS_STRUCT_HXX_ 20 | 21 | #include 22 | 23 | namespace esp32cs 24 | { 25 | typedef struct 26 | { 27 | uint64_t node_id; 28 | wifi_mode_t wifi_mode; 29 | char hostname_prefix[16]; 30 | char station_ssid[33]; 31 | char station_pass[33]; 32 | char softap_ssid[33]; 33 | char softap_pass[33]; 34 | wifi_auth_mode_t softap_auth; 35 | uint8_t softap_channel; 36 | char sntp_server[33]; 37 | char timezone[33]; 38 | bool sntp_enabled; 39 | uint8_t led_brightness; 40 | uint64_t fastclock_id; 41 | int16_t fastclock_rate; // 42 | uint8_t fastclock_year; // 0 = 1900 43 | uint8_t fastclock_month; // 1-12 44 | uint8_t fastclock_day; // 1-31 45 | uint8_t fastclock_hour; // 0-23 46 | uint8_t fastclock_minute; // 0-59 47 | bool fastclock_enabled; 48 | bool realtimeclock_enabled; 49 | uint64_t realtimeclock_id; 50 | uint8_t reserved[20]; 51 | } node_config_t; 52 | 53 | } // namespace esp32cs 54 | 55 | #endif // NVS_STRUCT_HXX_ -------------------------------------------------------------------------------- /components/Utils/include/Spinlock.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef SPINLOCK_HXX_ 19 | #define SPINLOCK_HXX_ 20 | 21 | #include 22 | 23 | namespace esp32cs 24 | { 25 | 26 | class Spinlock 27 | { 28 | public: 29 | Spinlock() 30 | { 31 | spinlock_initialize(&lock_); 32 | } 33 | 34 | /// Locks the specific critical section. 35 | void lock() 36 | { 37 | spinlock_acquire(&lock_, SPINLOCK_WAIT_FOREVER); 38 | } 39 | /// Unlocks the specific critical section. 40 | void unlock() 41 | { 42 | spinlock_release(&lock_); 43 | } 44 | 45 | private: 46 | /// Performs fine-grained spinloop locking. 47 | spinlock_t lock_; 48 | }; 49 | 50 | /// Simple wrapper to acquire and release a spinlock_t. 51 | class SpinlockHolder 52 | { 53 | public: 54 | /// Constructor. Grabs the spinlock_t as a side effect. 55 | /// 56 | /// @param parent the spinlock_t to hold. 57 | /// 58 | SpinlockHolder(Spinlock *parent) : parent_(parent) 59 | { 60 | parent_->lock(); 61 | } 62 | 63 | /// Destructor. Releases the spinlock_t as a side effect. 64 | ~SpinlockHolder() 65 | { 66 | parent_->unlock(); 67 | } 68 | 69 | private: 70 | /// Parent mutex we are holding. 71 | Spinlock *parent_; 72 | }; 73 | 74 | } // namespace esp32cs 75 | 76 | #endif // SPINLOCK_HOLDER_HXX_ -------------------------------------------------------------------------------- /components/Config/include/RealTimeClockConfigurationGroup.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef REALTIME_CLOCK_CONFIG_GROUP_HXX_ 19 | #define REALTIME_CLOCK_CONFIG_GROUP_HXX_ 20 | 21 | #include 22 | 23 | #include "sdkconfig.h" 24 | 25 | namespace esp32cs 26 | { 27 | 28 | CDI_GROUP(RealTimeClockConfiguration, 29 | Segment(CONFIG_OLCB_REALTIMECLOCK_MEMORY_SPACE_ID)); 30 | CDI_GROUP_ENTRY(enabled, openlcb::Uint8ConfigEntry, Name("Enable Clock"), 31 | Description( 32 | R"!^!(Enabling this option configures the Command Station to generate OpenLCB 33 | FastClock events.)!^!"), 34 | Min(0), Max(1), 35 | MapValues( 36 | R"!^!(0Disabled" 37 | "1Enabled)!^!"), 38 | Default(0)); 39 | CDI_GROUP_ENTRY(id, openlcb::StringConfigEntry<32>, Name("Clock ID"), 40 | Description( 41 | R"!^!(The Clock ID is used as the upper six bytes of all BroadcastTime events 42 | generated as part of the operation of the Fast Clock. 43 | Common ID values: 44 | 01.01.00.00.01.00 - Default Fast Clock 45 | 01.01.00.00.01.01 - Default Real-time Clock 46 | 01.01.00.00.01.02 - Alternate Clock 1 47 | 01.01.00.00.01.03 - Alternate Clock 2)!^!")); 48 | CDI_GROUP_END(); 49 | 50 | } // namespace esp32cs 51 | 52 | #endif // REALTIME_CLOCK_CONFIG_GROUP_HXX_ 53 | -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoSettings.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoSettings provides settings classes to describe settings 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | #pragma once 27 | 28 | class NeoNoSettings 29 | { 30 | }; 31 | 32 | class NeoRgbCurrentSettings 33 | { 34 | public: 35 | NeoRgbCurrentSettings(uint16_t red, uint16_t green, uint16_t blue) : 36 | RedTenthMilliAmpere(red), 37 | GreenTenthMilliAmpere(green), 38 | BlueTenthMilliAmpere(blue) 39 | { 40 | } 41 | 42 | uint16_t RedTenthMilliAmpere; // in 1/10th ma 43 | uint16_t GreenTenthMilliAmpere; // in 1/10th ma 44 | uint16_t BlueTenthMilliAmpere; // in 1/10th ma 45 | }; 46 | 47 | class NeoRgbwCurrentSettings 48 | { 49 | public: 50 | NeoRgbwCurrentSettings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) : 51 | RedTenthMilliAmpere(red), 52 | GreenTenthMilliAmpere(green), 53 | BlueTenthMilliAmpere(blue), 54 | WhiteCurrent(white) 55 | { 56 | } 57 | 58 | uint16_t RedTenthMilliAmpere; // in 1/10th ma 59 | uint16_t GreenTenthMilliAmpere; // in 1/10th ma 60 | uint16_t BlueTenthMilliAmpere; // in 1/10th ma 61 | uint16_t WhiteCurrent; // in 1/10th ma 62 | }; -------------------------------------------------------------------------------- /components/StatusLED/StatusLED.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2019-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include "StatusLED.hxx" 19 | #include 20 | 21 | namespace esp32cs 22 | { 23 | 24 | StatusLED::StatusLED() 25 | { 26 | if (brightness_ < 8) 27 | { 28 | brightness_ = 8; 29 | } 30 | clear(); 31 | } 32 | 33 | #ifndef CONFIG_STATUS_LED_UPDATE_INTERVAL_MSEC 34 | #define CONFIG_STATUS_LED_UPDATE_INTERVAL_MSEC 450 35 | #endif 36 | 37 | static constexpr uint32_t LED_UPDATE_TASK_STACK = 2048; 38 | static constexpr BaseType_t LED_UPDATE_TASK_PRIORITY = 3; 39 | static constexpr BaseType_t LED_UPDATE_TASK_CORE = APP_CPU_NUM; 40 | static constexpr TickType_t LED_UPDATE_INTERVAL = 41 | pdMS_TO_TICKS(CONFIG_STATUS_LED_UPDATE_INTERVAL_MSEC); 42 | 43 | static void led_update(void *arg) 44 | { 45 | StatusLED *led = (StatusLED *)arg; 46 | while(true) 47 | { 48 | vTaskDelay(LED_UPDATE_INTERVAL); 49 | led->refresh(); 50 | } 51 | } 52 | 53 | void StatusLED::start_task() 54 | { 55 | xTaskCreatePinnedToCore(led_update, "StatusLED", LED_UPDATE_TASK_STACK, this, 56 | LED_UPDATE_TASK_PRIORITY, nullptr /* task handle */, 57 | LED_UPDATE_TASK_CORE); 58 | } 59 | 60 | void StatusLED::set(const LED led, const COLOR color, const bool on) 61 | { 62 | colors_[led] = color; 63 | state_[led] = on; 64 | } 65 | 66 | void StatusLED::clear() 67 | { 68 | for(int index = 0; index < LED::MAX_LED; index++) 69 | { 70 | colors_[index] = OFF; 71 | state_[index] = false; 72 | } 73 | } 74 | 75 | } // namespace esp32cs -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | max-parallel: 3 16 | matrix: 17 | target: 18 | - esp32-v4.4-L298-NONE 19 | - esp32-v4.4-LMD18200-NONE 20 | - esp32-v4.4-BTS7960B-NONE 21 | - esp32-v4.4-L298-LCD 22 | - esp32-v4.4-L298-OLED 23 | #- esp32-v4.4-PCB 24 | steps: 25 | - uses: actions/checkout@v3 26 | with: 27 | submodules: recursive 28 | fetch-depth: 0 29 | - uses: jungwinter/split@v2 30 | id: target 31 | with: 32 | msg: ${{ matrix.target }} 33 | separator: '-' 34 | - name: Configure default pin mapping / display 35 | run: | 36 | echo "CONFIG_ESP32CS_${{ steps.target.outputs._2 }}=y" > sdkconfig 37 | echo "CONFIG_DISPLAY_TYPE_${{ steps.target.outputs._3 }}=y" >> sdkconfig 38 | - name: Build 39 | uses: espressif/esp-idf-ci-action@main 40 | with: 41 | esp_idf_version: ${{ steps.target.outputs._1 }} 42 | target: ${{ steps.target.outputs._0 }} 43 | - name: Prepare Binaries 44 | run: | 45 | mkdir -p binaries 46 | cp .github/firmwarereadme.txt binaries/readme.txt 47 | cp build/ESP32CommandStation.bin binaries 48 | cp build/partition_table/partition-table.bin binaries 49 | cp build/ota_data_initial.bin binaries 50 | cp build/bootloader/bootloader.bin binaries 51 | egrep 'I2C|STATUS|FACTORY|BOOTLOADER|TWAI' sdkconfig | grep _PIN | egrep -v '^#'> binaries/pinmap.txt 52 | egrep 'CONFIG_SD_SPI' sdkconfig | egrep -v '^#' >> binaries/pinmap.txt 53 | egrep 'CONFIG_WIFI_SOFTAP_[SSID|PASSWORD]|CONFIG_WIFI_STATION' sdkconfig | egrep -v '^#' >> binaries/wifi.txt 54 | cat .github/pinmap_${{ steps.target.outputs._2 }}.txt >> binaries/pinmap.txt 55 | cat .github/adc_pinmap_${{ steps.target.outputs._0 }}.txt >> binaries/pinmap.txt 56 | - name: Package binaries 57 | uses: actions/upload-artifact@v1 58 | with: 59 | name: ESP32CommandStation-${{ matrix.target }} 60 | path: binaries 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /components/NeoPixelBus/src/NeoPixelSegmentBus.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixelBus library wrapper template class that provides enhanced methods 3 | for writing to segment based strips 4 | 5 | Written by Michael C. Miller. 6 | 7 | I invest time and resources providing this open source code, 8 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 9 | 10 | ------------------------------------------------------------------------- 11 | This file is part of the Makuna/NeoPixelBus library. 12 | 13 | NeoPixelBus is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Lesser General Public License as 15 | published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | NeoPixelBus is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | 28 | #pragma once 29 | 30 | #include "NeoPixelBus.h" 31 | 32 | template class NeoPixelSegmentBus : 33 | public NeoPixelBus 34 | { 35 | public: 36 | NeoPixelSegmentBus(uint16_t countPixels, uint8_t pin) : 37 | NeoPixelBus(countPixels, pin) 38 | { 39 | } 40 | 41 | NeoPixelSegmentBus(uint16_t countPixels) : 42 | NeoPixelBus(countPixels) 43 | { 44 | } 45 | 46 | void SetString(uint16_t indexDigit, 47 | const char* str, 48 | uint8_t brightness, 49 | uint8_t defaultBrightness = 0) 50 | { 51 | T_COLOR_FEATURE::ColorObject::SetString(*this, 52 | indexDigit, 53 | str, 54 | brightness, 55 | defaultBrightness); 56 | } 57 | 58 | void SetString(uint16_t indexDigit, 59 | const String& str, 60 | uint8_t brightness, 61 | uint8_t defaultBrightness = 0) 62 | { 63 | SetString(indexDigit, str.c_str(), brightness, defaultBrightness); 64 | } 65 | }; 66 | 67 | 68 | -------------------------------------------------------------------------------- /components/NvsManager/include/NvsManager.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef NVS_MANAGER_H_ 19 | #define NVS_MANAGER_H_ 20 | 21 | #include "sdkconfig.h" 22 | #include 23 | #include 24 | #include 25 | 26 | namespace openlcb 27 | { 28 | class BroadcastTimeServer; 29 | class Node; 30 | class SimpleStackBase; 31 | } 32 | namespace openmrn_arduino 33 | { 34 | class Esp32WiFiManager; 35 | } 36 | namespace esp32cs 37 | { 38 | 39 | class NvsManager : public Singleton 40 | { 41 | public: 42 | void init(uint8_t reset_reason); 43 | bool should_reset_config(); 44 | bool should_reset_events(); 45 | bool start_stack(); 46 | void force_factory_reset(); 47 | void force_reset_events(); 48 | void set_led_brightness(uint8_t level); 49 | void restart_fast_clock(); 50 | void save_fast_clock_time(); 51 | 52 | bool memory_spaces_modified(); 53 | void register_virtual_memory_spaces(openlcb::SimpleStackBase *stack); 54 | void register_clocks(openlcb::Node *node, openmrn_arduino::Esp32WiFiManager *wifi_mgr); 55 | 56 | uint64_t node_id(); 57 | void node_id(uint64_t node_id); 58 | wifi_mode_t wifi_mode(); 59 | void wifi_mode(wifi_mode_t mode); 60 | const char *station_ssid(); 61 | const char *station_password(); 62 | const char *softap_ssid(); 63 | const char *softap_password(); 64 | uint8_t softap_channel(); 65 | wifi_auth_mode_t softap_auth(); 66 | const char *hostname_prefix(); 67 | bool sntp_enabled(); 68 | const char *sntp_server(); 69 | const char *timezone(); 70 | }; 71 | 72 | } // namespace esp32cs 73 | 74 | #endif // NVS_MANAGER_H_ -------------------------------------------------------------------------------- /components/TrainManager/TrainFDISpace.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "TrainFDISpace.hxx" 11 | 12 | #include "TrainManager.hxx" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace trainmanager 20 | { 21 | #ifndef TRAINCONFIG_LOGLEVEL 22 | #ifdef CONFIG_LOCOMGR_CONFIG_LOGGING 23 | #define TRAINCONFIG_LOGLEVEL CONFIG_LOCOMGR_CONFIG_LOGGING 24 | #else 25 | #define TRAINCONFIG_LOGLEVEL VERBOSE 26 | #endif // CONFIG_LOCOMGR_CONFIG_LOGGING 27 | #endif // TRAINCONFIG_LOGLEVEL 28 | 29 | using openlcb::Defs; 30 | using openlcb::MemorySpace; 31 | using openlcb::Node; 32 | using locodb::LocoDatabase; 33 | 34 | TrainFDISpace::TrainFDISpace(TrainManager *parent) : parent_(parent) 35 | { 36 | } 37 | 38 | bool TrainFDISpace::set_node(Node *node) 39 | { 40 | if (node_ && node_ == node) 41 | { 42 | // same node. 43 | return true; 44 | } 45 | if (parent_->is_valid_train_node(node)) 46 | { 47 | node_ = node; 48 | reset_file(); 49 | return true; 50 | } 51 | return false; 52 | } 53 | 54 | MemorySpace::address_t TrainFDISpace::max_address() 55 | { 56 | // We don't really know how long this space is; 16 MB is an upper bound. 57 | return 16 << 20; 58 | } 59 | 60 | size_t TrainFDISpace::read( 61 | address_t source, uint8_t *dst, size_t len, errorcode_t *error, 62 | Notifiable *again) 63 | { 64 | if (source <= gen_.file_offset()) 65 | { 66 | reset_file(); 67 | } 68 | ssize_t result = gen_.read(source, dst, len); 69 | if (result < 0) 70 | { 71 | LOG_ERROR("[TrainFDI] Read failure: %u, %zu: %zu (%s)", source, len, 72 | result, strerror(errno)); 73 | *error = Defs::ERROR_PERMANENT; 74 | return 0; 75 | } 76 | if (result == 0) 77 | { 78 | LOG(TRAINCONFIG_LOGLEVEL, "[TrainFDI] Out-of-bounds read: %u, %zu", 79 | source, len); 80 | *error = openlcb::MemoryConfigDefs::ERROR_OUT_OF_BOUNDS; 81 | } 82 | else 83 | { 84 | *error = 0; 85 | } 86 | return result; 87 | } 88 | 89 | void TrainFDISpace::reset_file() 90 | { 91 | auto e = Singleton::instance()->get_entry(node_->node_id()); 92 | e->start_read_functions(); 93 | gen_.reset(std::move(e)); 94 | } 95 | 96 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/StatusLED/include/StatusLED.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2019-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef STATUS_LED_H_ 19 | #define STATUS_LED_H_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "sdkconfig.h" 29 | 30 | #ifndef CONFIG_STATUS_LED_BRIGHTNESS 31 | #define CONFIG_STATUS_LED_BRIGHTNESS 128 32 | #endif 33 | 34 | namespace esp32cs 35 | { 36 | 37 | class StatusLED : public Singleton 38 | { 39 | public: 40 | enum COLOR : uint8_t 41 | { 42 | OFF 43 | , RED 44 | , GREEN 45 | , YELLOW 46 | , BLUE 47 | , RED_BLINK 48 | , GREEN_BLINK 49 | , BLUE_BLINK 50 | , YELLOW_BLINK 51 | }; 52 | 53 | enum LED : uint8_t 54 | { 55 | WIFI_STA, 56 | WIFI_AP, 57 | BOOTLOADER, 58 | OPS_TRACK, 59 | PROG_TRACK, 60 | MAX_LED 61 | }; 62 | 63 | StatusLED(); 64 | void hw_init(); 65 | void set(const LED led, const COLOR color, const bool on = false); 66 | void clear(); 67 | void setBrightness(uint8_t level) 68 | { 69 | brightness_ = level; 70 | } 71 | uint8_t getBrightness() 72 | { 73 | return brightness_; 74 | } 75 | void start_task(); 76 | 77 | /// Refreshes the LEDs. 78 | /// 79 | /// NOTE: This is not intended to be called from outside of the StatuLED 80 | /// module. 81 | void refresh(); 82 | 83 | private: 84 | uint8_t brightness_{CONFIG_STATUS_LED_BRIGHTNESS}; 85 | COLOR colors_[LED::MAX_LED]; 86 | bool state_[LED::MAX_LED]; 87 | }; 88 | 89 | } // namespace esp32cs 90 | #endif // STATUS_LED_H_ -------------------------------------------------------------------------------- /components/ULPADC/include/UlpAdc.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include 19 | 20 | namespace esp32cs 21 | { 22 | 23 | /// Initializes and starts the ULP ADC operations in the background. 24 | /// 25 | /// When the ULP-ADC is running a watchdog task will be created to ensure the 26 | /// ULP remains in a running state as expected. If the ULP stops processing or 27 | /// updating the ADC values as expected the get_last_XXX_reading methods below 28 | /// will return 4095 until the ULP has been restarted by the watchdog. 29 | void initialize_ulp_adc(); 30 | 31 | /// Disables and stops all ULP ADC operations and the ULP watchdog task. 32 | void deinitialize_ulp_adc(); 33 | 34 | /// @return the last reading from the OPS track ADC pin. May return 4095 if no 35 | /// reading is available. 36 | uint16_t get_last_ops_reading(); 37 | 38 | /// @return the estimated load (in mA) for the OPS track. 39 | uint32_t get_ops_load(); 40 | 41 | /// @return the OPS track short threshold. Will return 4095 if OPS track is 42 | /// disabled. 43 | uint16_t get_ops_short_threshold(); 44 | 45 | /// @return the OPS track shutdown threshold. Will return 4095 if OPS track is 46 | /// disabled. 47 | uint16_t get_ops_shutdown_threshold(); 48 | 49 | /// @return the OPS track warning threshold. Will return 4095 if OPS track is 50 | /// disabled. 51 | uint16_t get_ops_warning_threshold(); 52 | 53 | /// @return the last reading from the PROG track ADC pin. May return 4095 if no 54 | /// reading is available. 55 | uint16_t get_last_prog_reading(); 56 | 57 | /// @return the last reading from the TEMP SENSOR ADC pin. May return 4095 if 58 | /// no reading is available. 59 | uint16_t get_last_tempsensor_reading(); 60 | 61 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoGamma.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoGamma class is used to correct RGB colors for human eye gamma levels equally 3 | across all color channels 4 | 5 | Written by Michael C. Miller. 6 | 7 | I invest time and resources providing this open source code, 8 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 9 | 10 | ------------------------------------------------------------------------- 11 | This file is part of the Makuna/NeoPixelBus library. 12 | 13 | NeoPixelBus is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Lesser General Public License as 15 | published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | NeoPixelBus is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | #pragma once 28 | 29 | // NeoGammaEquationMethod uses no memory but is slower than NeoGammaTableMethod 30 | class NeoGammaEquationMethod 31 | { 32 | public: 33 | static uint8_t Correct(uint8_t value) 34 | { 35 | return static_cast(255.0f * NeoEase::Gamma(value / 255.0f) + 0.5f); 36 | } 37 | }; 38 | 39 | // NeoGammaTableMethod uses 256 bytes of memory, but is significantly faster 40 | class NeoGammaTableMethod 41 | { 42 | public: 43 | static uint8_t Correct(uint8_t value) 44 | { 45 | return _table[value]; 46 | } 47 | 48 | private: 49 | static const uint8_t _table[256]; 50 | }; 51 | 52 | 53 | // use one of the method classes above as a converter for this template class 54 | template class NeoGamma 55 | { 56 | public: 57 | RgbColor Correct(const RgbColor& original) 58 | { 59 | return RgbColor(T_METHOD::Correct(original.R), 60 | T_METHOD::Correct(original.G), 61 | T_METHOD::Correct(original.B)); 62 | } 63 | 64 | RgbwColor Correct(const RgbwColor& original) 65 | { 66 | return RgbwColor(T_METHOD::Correct(original.R), 67 | T_METHOD::Correct(original.G), 68 | T_METHOD::Correct(original.B), 69 | T_METHOD::Correct(original.W) ); 70 | } 71 | }; 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/HsbColor.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | HsbColor provides a color object that can be directly consumed by NeoPixelBus 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #include "RgbColor.h" 28 | #include "Rgb48Color.h" 29 | #include "HsbColor.h" 30 | 31 | void HsbColor::_RgbToHsb(float r, float g, float b, HsbColor* color) 32 | { 33 | float max = (r > g && r > b) ? r : (g > b) ? g : b; 34 | float min = (r < g&& r < b) ? r : (g < b) ? g : b; 35 | 36 | float d = max - min; 37 | 38 | float h = 0.0; 39 | float v = max; 40 | float s = (v == 0.0f) ? 0 : (d / v); 41 | 42 | if (d != 0.0f) 43 | { 44 | if (r == max) 45 | { 46 | h = (g - b) / d + (g < b ? 6.0f : 0.0f); 47 | } 48 | else if (g == max) 49 | { 50 | h = (b - r) / d + 2.0f; 51 | } 52 | else 53 | { 54 | h = (r - g) / d + 4.0f; 55 | } 56 | h /= 6.0f; 57 | } 58 | 59 | 60 | color->H = h; 61 | color->S = s; 62 | color->B = v; 63 | } 64 | 65 | HsbColor::HsbColor(const RgbColor& color) 66 | { 67 | // convert colors to float between (0.0 - 1.0) 68 | float r = color.R / 255.0f; 69 | float g = color.G / 255.0f; 70 | float b = color.B / 255.0f; 71 | 72 | _RgbToHsb(r, g, b, this); 73 | } 74 | 75 | HsbColor::HsbColor(const Rgb48Color& color) 76 | { 77 | // convert colors to float between (0.0 - 1.0) 78 | float r = color.R / 65535.0f; 79 | float g = color.G / 65535.0f; 80 | float b = color.B / 65535.0f; 81 | 82 | _RgbToHsb(r, g, b, this); 83 | } -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # What is ESP32 Command Station? 2 | 3 | ESP32 Command Station is an open-source NMRA compliant DCC Command Station for 4 | the operation of DCC-equipped model railroads with integrated support for using 5 | RailCom and OpenLCB (LCC). 6 | 7 | Please refer to [Supported Hardware](supported_hardware.md) for what hardware 8 | can be used with this software. 9 | 10 | ## Features 11 | 12 | * Supports most variants of the ESP32 or ESP32-S3. 13 | * Support for multiple h-bridge types (Arduino Motor Shield, Pololu MC33926 Motor Shield, BTS7960B, LMD18200, DRV8873, DRV8800/DRV8801). 14 | * Built-in web interface for controlling locomotives or configuring the ESP32 Command Station. 15 | * Built-in support for OpenLCB (LCC) either via WiFi or an external CAN transceiver. 16 | * Built-in support for generating RailCom cut-out and receiving RailCom feedback. 17 | 18 | ## Development Status 19 | 20 | | Release Type | Label | Date | 21 | | ------------ | ----- | ---- | 22 | | Stable | [![GitHub release](https://img.shields.io/github/release/atanisoft/ESP32CommandStation.svg?label=Stable&style=plastic)](https://github.com/atanisoft/ESP32CommandStation/releases) | [![GitHub release date](https://img.shields.io/github/release-date/atanisoft/ESP32CommandStation.svg?style=plastic)](https://github.com/atanisoft/ESP32CommandStation/releases) | 23 | | Preview | [![GitHub release](https://img.shields.io/github/release-pre/atanisoft/ESP32CommandStation.svg?label=Preview&style=plastic)](https://github.com/atanisoft/ESP32CommandStation/releases) | [![GitHub release date](https://img.shields.io/github/release-date-pre/atanisoft/ESP32CommandStation.svg?style=plastic)](https://github.com/atanisoft/ESP32CommandStation/releases) | 24 | 25 | ## Using this software 26 | 27 | This software is provided in source code form and will require compilation 28 | using the [Espressif IDF](https://github.com/espressif/esp-idf) Framework. 29 | [Pre-compiled](precompiled.md) binaries are available for common configurations 30 | as part of releases starting with v2.0.0. 31 | 32 | If a customized version of the firmware is required, it will be necessary to 33 | setup the [Espressif IDF](https://github.com/espressif/esp-idf) build 34 | environment by following [these](build_env.md) instructions. After the build 35 | env has been configured proceed to [Configuring](configuring.md). 36 | 37 | ### After flashing, what's next? 38 | 39 | After this software has been flashed to the ESP32 you should be able to connect 40 | the track connections and supply power to the ESP32 (and h-bridge). The 41 | software will automatically start when the ESP32 is powered. 42 | 43 | Proceed to [Getting Started](getting_started.md) for instructions on how to use 44 | this software. -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # ESP32 COMMAND STATION 3 | # 4 | # COPYRIGHT (c) 2017-2021 Mike Dunston 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see http://www.gnu.org/licenses 16 | ############################################################################### 17 | 18 | set(IDF_DEPS 19 | app_update 20 | bootloader_support 21 | driver 22 | efuse 23 | esp_adc_cal 24 | esp_common 25 | esp_system 26 | espcoredump 27 | json 28 | nvs_flash 29 | soc 30 | ) 31 | 32 | # starting in IDF v5 esp_ipc component has been merged into esp_system 33 | if (IDF_VERSION_MAJOR LESS 5) 34 | list(APPEND IDF_DEPS esp_ipc) 35 | endif() 36 | 37 | set(CUSTOM_DEPS 38 | AccessoryDecoderDB 39 | Config 40 | DCC 41 | NeoPixelBus 42 | NvsManager 43 | OpenMRNExtensions 44 | StatusDisplay 45 | StatusLED 46 | TrainDatabase 47 | TrainManager 48 | ULPADC 49 | Utils 50 | ) 51 | 52 | idf_component_register(SRCS ESP32CommandStation.cpp WebServer.cpp 53 | REQUIRES "${IDF_DEPS} ${CUSTOM_DEPS}") 54 | 55 | ############################################################################### 56 | # Automatic configuration selection 57 | ############################################################################### 58 | 59 | if(CONFIG_ESP32CS_L298) 60 | message(STATUS "Automatic configuration of OPS and PROG using L298") 61 | elseif(CONFIG_ESP32CS_BTS7960B) 62 | message(STATUS "Automatic configuration of OPS only using BTS7960B") 63 | elseif(CONFIG_ESP32CS_BTS7960B_X2) 64 | message(STATUS "Automatic configuration of OPS and PROG using 2x BTS7960B") 65 | elseif(CONFIG_ESP32CS_LMD18200) 66 | message(STATUS "Automatic configuration of OPS only using LMD18200") 67 | elseif(CONFIG_ESP32CS_PCB_V100) 68 | message(STATUS "Automatic configuration of OPS and PROG using CS PCB v1.0") 69 | elseif(CONFIG_ESP32CS_PCB_V150) 70 | message(STATUS "Automatic configuration of OPS and PROG using CS PCB v1.5") 71 | elseif(CONFIG_ESP32CS_PCB_V200) 72 | message(STATUS "Automatic configuration of OPS and PROG using CS PCB v2.0") 73 | endif() -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoGamma.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixelGamma class is used to correct RGB colors for human eye gamma levels 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #include "NeoPixelBus.h" 28 | 29 | const uint8_t NeoGammaTableMethod::_table[] = { 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 32 | 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 33 | 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 34 | 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 35 | 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 36 | 29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 37 | 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54, 38 | 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 39 | 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89, 40 | 91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 41 | 112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134, 42 | 136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160, 43 | 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189, 44 | 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 45 | 223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255 46 | }; -------------------------------------------------------------------------------- /docs/build_env.md: -------------------------------------------------------------------------------- 1 | # Configuring the build environment 2 | 3 | The ESP32 Command Station code is built using the ESP-IDF framework. 4 | 5 | ## Setting up ESP-IDF build environment 6 | 7 | ESP-IDF is a required component and unfortunately there are only a few options 8 | for setting up the build environment. For all options it is required to have 9 | Python3 and the Git client installed and available in the path. 10 | 11 | ### VSCode "Espressif IDF" extension 12 | 13 | The [Espressif IDF plugin](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension) 14 | provides a relatively easy way to install all components and configure them for 15 | building. There are a few bugs in the plugin still but overall it will work. 16 | 17 | Once installed proceed to [Configuring build options](configuring.md). 18 | 19 | ### Command line building on Windows 20 | 21 | The easiest way to install the dependencies is to use the 22 | [ESP-IDF Windows Installer](https://dl.espressif.com/dl/esp-idf/?idf=4.4). 23 | This utility will download and configure all tools automatically for you. When 24 | prompted it is recommended to install ESP-IDF v4.4. 25 | 26 | Once completed proceed to [Configuring build options](configuring.md). 27 | 28 | ### Command line building on Linux 29 | 30 | Many Linux distributions include all necessary tools by default. In some cases 31 | it will be necessary to install additional tools. Please use 32 | [this](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-setup.html) 33 | guide to install required software updates. 34 | 35 | ### Command line building on MacOS 36 | 37 | MacOS includes most of the required tools, please use 38 | [this](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/macos-setup.html) 39 | guide to install required software updates. 40 | 41 | ## Obtaining ESP-IDF 42 | 43 | ESP32 Command Station supports ESP-IDF v4.3 (or later) with v4.4 being the 44 | recommended version. For Linux/MacOS the ESP-IDF framework should be downloaded 45 | via Git using the commands below: 46 | 47 | ``` 48 | mkdir -p ~/esp 49 | cd ~/esp 50 | git clone --recursive https://github.com/espressif/esp-idf.git --branch release/v4.4 51 | ``` 52 | 53 | ## Configuring ESP-IDF Environment 54 | 55 | Once ESP-IDF has been downloaded it needs to be installed using the following 56 | command: 57 | 58 | ``` 59 | cd ~/esp 60 | sh install.sh 61 | ``` 62 | 63 | This will install and configure a python virtual environment which is used for 64 | all build related activities. You will need to run `source ~/esp/export.sh` 65 | from any shell which is used for building ESP-IDF based projects. 66 | 67 | ## What's next? 68 | 69 | Proceed to [Configuring build options](configuring.md). 70 | 71 | [home](README.md) -------------------------------------------------------------------------------- /components/Utils/include/FactoryResetHelper.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef FACTORY_RESET_HELPER_HXX_ 19 | #define FACTORY_RESET_HELPER_HXX_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace esp32cs 27 | { 28 | 29 | class FactoryResetHelper : public DefaultConfigUpdateListener 30 | { 31 | public: 32 | FactoryResetHelper(const openlcb::UserInfoSegment &cfg) : cfg_(cfg) 33 | { 34 | } 35 | 36 | UpdateAction apply_configuration(int fd, bool initial_load, 37 | BarrierNotifiable *done) override 38 | { 39 | AutoNotify n(done); 40 | LOG(VERBOSE, "[CFG] apply_configuration(%d, %d)", fd, initial_load); 41 | 42 | // If this is not our initial load and virtual memory spaces have been 43 | // modified we will likely need a reboot. 44 | if (!initial_load && 45 | Singleton::instance()->memory_spaces_modified()) 46 | { 47 | LOG(WARNING, "[CFG] NVS has been updated requesting a restart."); 48 | return ConfigUpdateListener::UpdateAction::REBOOT_NEEDED; 49 | } 50 | 51 | return ConfigUpdateListener::UpdateAction::UPDATED; 52 | } 53 | 54 | void factory_reset(int fd) override 55 | { 56 | LOG(INFO, "[CDI] Node configuration factory reset invoked."); 57 | // set the name of the node to the SNIP model name 58 | cfg_.name().write(fd, openlcb::SNIP_STATIC_DATA.model_name); 59 | std::string node_id = 60 | utils::node_id_to_string( 61 | Singleton::instance()->node_id()); 62 | cfg_.description().write(fd, node_id.c_str()); 63 | } 64 | private: 65 | const openlcb::UserInfoSegment cfg_; 66 | }; 67 | 68 | } // namespace esp32cs 69 | 70 | #endif // FACTORY_RESET_HELPER_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/HslColor.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | HslColor provides a color object that can be directly consumed by NeoPixelBus 3 | 4 | 5 | Written by Michael C. Miller. 6 | 7 | I invest time and resources providing this open source code, 8 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 9 | 10 | ------------------------------------------------------------------------- 11 | This file is part of the Makuna/NeoPixelBus library. 12 | 13 | NeoPixelBus is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Lesser General Public License as 15 | published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | NeoPixelBus is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | 28 | #include "RgbColor.h" 29 | #include "Rgb48Color.h" 30 | #include "HslColor.h" 31 | 32 | void HslColor::_RgbToHsl(float r, float g, float b, HslColor* color) 33 | { 34 | float max = (r > g && r > b) ? r : (g > b) ? g : b; 35 | float min = (r < g && r < b) ? r : (g < b) ? g : b; 36 | 37 | float h, s, l; 38 | l = (max + min) / 2.0f; 39 | 40 | if (max == min) 41 | { 42 | h = s = 0.0f; 43 | } 44 | else 45 | { 46 | float d = max - min; 47 | s = (l > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min); 48 | 49 | if (r > g && r > b) 50 | { 51 | h = (g - b) / d + (g < b ? 6.0f : 0.0f); 52 | } 53 | else if (g > b) 54 | { 55 | h = (b - r) / d + 2.0f; 56 | } 57 | else 58 | { 59 | h = (r - g) / d + 4.0f; 60 | } 61 | h /= 6.0f; 62 | } 63 | 64 | color->H = h; 65 | color->S = s; 66 | color->L = l; 67 | } 68 | 69 | HslColor::HslColor(const RgbColor& color) 70 | { 71 | // convert colors to float between (0.0 - 1.0) 72 | float r = color.R / 255.0f; 73 | float g = color.G / 255.0f; 74 | float b = color.B / 255.0f; 75 | 76 | _RgbToHsl(r, g, b, this); 77 | } 78 | 79 | HslColor::HslColor(const Rgb48Color& color) 80 | { 81 | // convert colors to float between (0.0 - 1.0) 82 | float r = color.R / 65535.0f; 83 | float g = color.G / 65535.0f; 84 | float b = color.B / 65535.0f; 85 | 86 | _RgbToHsl(r, g, b, this); 87 | } -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoTopology.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*------------------------------------------------------------------------- 4 | NeoTopology provides a mapping feature of a 2d cordinate to linear 1d cordinate 5 | It is used to map a matrix of NeoPixels to a index on the NeoPixelBus 6 | 7 | Written by Michael C. Miller. 8 | 9 | I invest time and resources providing this open source code, 10 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 11 | 12 | ------------------------------------------------------------------------- 13 | This file is part of the Makuna/NeoPixelBus library. 14 | 15 | NeoPixelBus is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU Lesser General Public License as 17 | published by the Free Software Foundation, either version 3 of 18 | the License, or (at your option) any later version. 19 | 20 | NeoPixelBus is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU Lesser General Public License for more details. 24 | 25 | You should have received a copy of the GNU Lesser General Public 26 | License along with NeoPixel. If not, see 27 | . 28 | -------------------------------------------------------------------------*/ 29 | 30 | enum NeoTopologyHint 31 | { 32 | NeoTopologyHint_FirstOnPanel, 33 | NeoTopologyHint_InPanel, 34 | NeoTopologyHint_LastOnPanel, 35 | NeoTopologyHint_OutOfBounds 36 | }; 37 | 38 | template class NeoTopology 39 | { 40 | public: 41 | NeoTopology(uint16_t width, uint16_t height) : 42 | _width(width), 43 | _height(height) 44 | { 45 | 46 | } 47 | 48 | uint16_t Map(int16_t x, int16_t y) const 49 | { 50 | if (x >= _width) 51 | { 52 | x = _width - 1; 53 | } 54 | else if (x < 0) 55 | { 56 | x = 0; 57 | } 58 | if (y >= _height) 59 | { 60 | y = _height - 1; 61 | } 62 | else if (y < 0) 63 | { 64 | y = 0; 65 | } 66 | return T_LAYOUT::Map(_width, _height, x, y); 67 | } 68 | 69 | uint16_t MapProbe(int16_t x, int16_t y) const 70 | { 71 | if (x < 0 || x >= _width || y < 0 || y >= _height) 72 | { 73 | return _width * _height; // count, out of bounds 74 | } 75 | return T_LAYOUT::Map(_width, _height, x, y); 76 | } 77 | 78 | uint16_t getWidth() const 79 | { 80 | return _width; 81 | } 82 | 83 | uint16_t getHeight() const 84 | { 85 | return _height; 86 | } 87 | 88 | private: 89 | const uint16_t _width; 90 | const uint16_t _height; 91 | }; 92 | -------------------------------------------------------------------------------- /components/TrainManager/TrainIdentifyHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "TrainIdentifyHandler.hxx" 11 | 12 | #include "TrainManager.hxx" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace trainmanager 20 | { 21 | 22 | #ifndef TRAINIDENT_LOGLEVEL 23 | #ifdef CONFIG_LOCOMGR_IDENT_LOGGING_LEVEL 24 | #define TRAINIDENT_LOGLEVEL CONFIG_LOCOMGR_IDENT_LOGGING_LEVEL 25 | #else 26 | #define TRAINIDENT_LOGLEVEL VERBOSE 27 | #endif // CONFIG_LOCOMGR_IDENT_LOGGING_LEVEL 28 | #endif // TRAINIDENT_LOGLEVEL 29 | 30 | using openlcb::Defs; 31 | using openlcb::IncomingMessageStateFlow; 32 | using openlcb::TractionDefs; 33 | 34 | TrainIdentifyHandler::TrainIdentifyHandler(TrainManager *parent) 35 | : IncomingMessageStateFlow(parent->train_service()->iface()) 36 | , parent_(parent) 37 | { 38 | iface()->dispatcher()->register_handler( 39 | this, Defs::MTI::MTI_VERIFY_NODE_ID_GLOBAL, Defs::MTI::MTI_EXACT); 40 | } 41 | 42 | TrainIdentifyHandler::~TrainIdentifyHandler() 43 | { 44 | iface()->dispatcher()->unregister_handler( 45 | this, Defs::MTI_VERIFY_NODE_ID_GLOBAL, Defs::MTI::MTI_EXACT); 46 | } 47 | 48 | StateFlowBase::Action TrainIdentifyHandler::entry() 49 | { 50 | openlcb::GenMessage *m = message()->data(); 51 | if (!m->payload.empty() && m->payload.size() == 6) 52 | { 53 | target_ = openlcb::buffer_to_node_id(m->payload); 54 | #if TRAINIDENT_LOGLEVEL >= VERBOSE 55 | LOG(TRAINIDENT_LOGLEVEL, 56 | "[TrainIdent] received global identify for node %s", 57 | utils::node_id_to_string(target_).c_str()); 58 | #endif // TRAINIDENT_LOGLEVEL >= VERBOSE 59 | openlcb::NodeID masked = target_ & TractionDefs::NODE_ID_MASK; 60 | if ((masked == TractionDefs::NODE_ID_DCC || 61 | masked == TractionDefs::NODE_ID_MARKLIN_MOTOROLA || 62 | masked == locomgr::NODE_ID_OLCB) && 63 | parent_->is_valid_train_node(target_)) 64 | 65 | { 66 | LOG(TRAINIDENT_LOGLEVEL, "[TrainIdent] matched a known train db entry"); 67 | release(); 68 | return allocate_and_call(iface()->global_message_write_flow(), 69 | STATE(send_train_ident)); 70 | } 71 | } 72 | return release_and_exit(); 73 | } 74 | 75 | StateFlowBase::Action TrainIdentifyHandler::send_train_ident() 76 | { 77 | auto *b = 78 | get_allocation_result(iface()->global_message_write_flow()); 79 | openlcb::GenMessage *m = b->data(); 80 | m->reset(Defs::MTI_VERIFIED_NODE_ID_NUMBER, target_ 81 | , openlcb::node_id_to_buffer(target_)); 82 | iface()->global_message_write_flow()->send(b); 83 | return exit(); 84 | } 85 | 86 | } // namespace trainmanager -------------------------------------------------------------------------------- /.github/pinmap_PCB.txt: -------------------------------------------------------------------------------- 1 | 2 | ---- CS PCB v1.5 Pin Map: 3 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 16 4 | #define CONFIG_OPS_HBRIDGE_DRV8873_5A 1 5 | #define CONFIG_OPS_TRACK_ENABLE_PIN 17 6 | #define CONFIG_PROG_HBRIDGE_DRV880X 1 7 | #define CONFIG_PROG_TRACK_ENABLE_PIN 18 8 | #define CONFIG_RAILCOM_TRIGGER_PIN 12 9 | #define CONFIG_RAILCOM_DATA_PIN 26 10 | #define CONFIG_RAILCOM_DIRECTION_PIN 25 11 | #define CONFIG_OLED_RESET_PIN 0 12 | #define CONFIG_FACTORY_RESET_PIN 32 13 | #define CONFIG_BOOTLOADER_PIN 33 14 | #define CONFIG_OLCB_TWAI_RX_PIN 4 15 | #define CONFIG_OLCB_TWAI_TX_PIN 5 16 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 17 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 18 | #define CONFIG_I2C_SCL_PIN 21 19 | #define CONFIG_I2C_SDA_PIN 23 20 | #define CONFIG_STATUS_LED_DATA_PIN 22 21 | #define CONFIG_TEMPSENSOR_ADC_CHANNEL_7 1 22 | #define CONFIG_RAILCOM_CUT_OUT_ENABLED 1 23 | #define CONFIG_RAILCOM_DATA_ENABLED 1 24 | 25 | ---- CS PCB v1.0 Pin Map: 26 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 17 27 | #define CONFIG_OPS_HBRIDGE_LMD18200 1 28 | #define CONFIG_OPS_TRACK_ENABLE_PIN 4 29 | #define CONFIG_DCC_TRACK_BRAKE_PIN 26 30 | #define CONFIG_PROG_HBRIDGE_L298 1 31 | #define CONFIG_PROG_TRACK_ENABLE_PIN 18 32 | #define CONFIG_RAILCOM_TRIGGER_PIN 12 33 | #define CONFIG_RAILCOM_DATA_PIN 33 34 | #define CONFIG_RAILCOM_DIRECTION_PIN 25 35 | #define CONFIG_OLED_RESET_PIN -1 36 | #define CONFIG_FACTORY_RESET_PIN 34 37 | #define CONFIG_BOOTLOADER_PIN -1 38 | #define CONFIG_OLCB_TWAI_RX_PIN 27 39 | #define CONFIG_OLCB_TWAI_TX_PIN 32 40 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 41 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 42 | #define CONFIG_I2C_SCL_PIN 21 43 | #define CONFIG_I2C_SDA_PIN 23 44 | #define CONFIG_STATUS_LED_DATA_PIN 22 45 | #define CONFIG_TEMPSENSOR_ADC_CHANNEL_7 1 46 | #define CONFIG_RAILCOM_CUT_OUT_ENABLED 1 47 | #define CONFIG_RAILCOM_DATA_ENABLED 1 48 | 49 | ---- CS PCB v2.0 Pin Map (ESP32-S3): 50 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 10 51 | #define CONFIG_DCC_OLCB_ENABLE_PIN 12 52 | #define CONFIG_OPS_HBRIDGE_DRV8873_5A 1 53 | #define CONFIG_PROG_HBRIDGE_DRV880X 1 54 | #define CONFIG_OPSTRACK_ADC_I2C_CHANNEL_1 1 55 | #define CONFIG_PROGTRACK_ADC_I2C_CHANNEL_2 1 56 | #define CONFIG_RAILCOM_TRIGGER_PIN 21 57 | #define CONFIG_RAILCOM_DATA_PIN 47 58 | #define CONFIG_RAILCOM_DIRECTION_PIN 48 59 | #define CONFIG_RAILCOM_SHORT_PIN 45 60 | #define CONFIG_I2C_SCL_PIN 18 61 | #define CONFIG_I2C_SDA_PIN 8 62 | #define CONFIG_I2C_ADC_ALERT_PIN 46 63 | #define CONFIG_STATUS_LED_WIFI_STA_PIN 15 64 | #define CONFIG_STATUS_LED_WIFI_AP_PIN 7 65 | #define CONFIG_STATUS_LED_BOOTLOADER_ACTIVE_PIN 6 66 | #define CONFIG_STATUS_LED_OPS_ACTIVE_PIN 5 67 | #define CONFIG_STATUS_LED_PROG_ACTIVE_PIN 4 68 | #define CONFIG_OLED_RESET_PIN 3 69 | #define CONFIG_FACTORY_RESET_PIN 2 70 | #define CONFIG_BOOTLOADER_PIN 1 71 | #define CONFIG_OLCB_TWAI_RX_PIN 16 72 | #define CONFIG_OLCB_TWAI_TX_PIN 17 73 | #define CONFIG_TEMPSENSOR_ADC2_CHANNEL_2 1 74 | #define CONFIG_RAILCOM_CUT_OUT_ENABLED 1 75 | #define CONFIG_RAILCOM_DATA_ENABLED 1 -------------------------------------------------------------------------------- /.github/firmwarereadme.txt: -------------------------------------------------------------------------------- 1 | Using this binary firmware bundle 2 | --------------------------------- 3 | 4 | This firmware bundle contains a pre-compiled and pre-configured version of the 5 | ESP32CommandStation code. 6 | 7 | There are currently four ways to utilize this firmware bundle: 8 | 9 | 1. esptool. 10 | 2. Espressif Flash Download Tool. 11 | 3. JMRI Firmware Update utility. 12 | 4. Firmware Update via built-in web interface. 13 | 14 | esptool 15 | ------- 16 | 17 | esptool is a command line utility for flashing binary firmware to various ESP32 18 | devices. This is the preferred method for initial firmware flashing. 19 | 20 | The command below can be used to flash the firmware to the ESP32: 21 | 22 | esptool.py --port /dev/ttyUSB0 --before=default_reset --after=hard_reset 23 | --baud 460800 write_flash 0x1000 bootloader.bin 0x8000 partition-table.bin 24 | 0xe000 ota_data_initial.bin 0x10000 ESP32CommandStation.bin 25 | 26 | Note: The command above should be a single line. 27 | 28 | Note: For the ESP32-S3 the bootloader.bin should be flashed at 0x0000 instead 29 | of 0x1000 as listed above. 30 | 31 | The port parameter should be adjusted to your environment, on Windows this is 32 | usually prefixed by COM rather. On Linux it will be similar to the provided 33 | value. On Mac the ESP32 may show up as /dev/cu.SLAB_USBtoUART and you may also 34 | require additional drivers. 35 | 36 | If you need/want to erase the flash on the ESP32 the following command can be 37 | used: 38 | 39 | esptool.py --port /dev/ttyUSB0 erase_flash 40 | 41 | Note: The port parameter will need to be adjusted similar to the flashing 42 | command above. 43 | 44 | Espressif Flash Download Tool 45 | ----------------------------- 46 | 47 | The Espressif Flash Download Tool is a graphical Windows only utility that 48 | operates similar to esptool. This tool can be downloaded via the link below: 49 | https://www.espressif.com/en/support/download/other-tools 50 | 51 | Use the following offsets and binaries for this utility: 52 | 53 | 0x8000 partition-table.bin 54 | 0xe000 ota_data_initial.bin 55 | 0x1000 bootloader.bin 56 | 0x10000 ESP32CommandStation.bin 57 | 58 | JMRI Firmware Update Utility 59 | ---------------------------- 60 | 61 | JMRI has built-in support for uploading firmware to OpenLCB (LCC) connected 62 | devices. At this time ESP32 Command Station only supports this feature when 63 | using a CAN (TWAI) physical connection between the ESP32 Command Station and 64 | the computer running JMRI. This approach can not be used as the initial 65 | firmware upload to the ESP32. 66 | 67 | When using JMRI to upload the firmware only ESP32CommandStation.bin should be 68 | used for upload. 69 | 70 | 71 | Firmware Update via built-in web interface 72 | ------------------------------------------ 73 | 74 | After the initial firmware flashing has been completed it is possible to use 75 | the built-in web interface to upload new firmware versions to the ESP32 Command 76 | Station. Using this interface only ESP32CommandStation.bin should be uploaded. -------------------------------------------------------------------------------- /components/TrainManager/XmlGenerator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2015 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "XmlGenerator.hxx" 11 | #include 12 | 13 | namespace trainmanager 14 | { 15 | 16 | ssize_t XmlGenerator::read(size_t offset, void* buf, size_t len) 17 | { 18 | if (offset < fileOffset_) 19 | { 20 | return -1; 21 | } 22 | offset -= fileOffset_; 23 | char* output = static_cast(buf); 24 | 25 | while (len > 0) 26 | { 27 | if (pendingActions_.empty()) 28 | { 29 | generate_more(); 30 | if (pendingActions_.empty()) 31 | { 32 | // EOF. 33 | break; 34 | } 35 | TypedQueue reversed; 36 | while (!pendingActions_.empty()) 37 | { 38 | reversed.push_front(pendingActions_.pop_front()); 39 | } 40 | std::swap(pendingActions_, reversed); 41 | init_front_action(); 42 | } 43 | 44 | const char* b = get_front_buffer(); 45 | bufferOffset_ = 0; 46 | /*if (offset <= bufferOffset_) { 47 | bufferOffset_ = offset; 48 | offset = 0; 49 | }*/ 50 | // Skip data that we don't need. 51 | while (*b && offset > 0) 52 | { 53 | --offset; 54 | ++b; 55 | ++bufferOffset_; 56 | } 57 | // Copy data from the front action buffer. 58 | while (*b && len > 0) 59 | { 60 | *output++ = *b++; 61 | len--; 62 | bufferOffset_++; 63 | } 64 | if (!*b) 65 | { 66 | // Consume front of the actions. 67 | delete pendingActions_.pop_front(); 68 | fileOffset_ += bufferOffset_; 69 | if (!pendingActions_.empty()) { 70 | init_front_action(); 71 | } 72 | } 73 | } 74 | return output - static_cast(buf); 75 | } 76 | 77 | const char* XmlGenerator::get_front_buffer() 78 | { 79 | switch (pendingActions_.front()->type) 80 | { 81 | case RENDER_INT: 82 | { 83 | return buffer_; 84 | } 85 | case CONST_LITERAL: 86 | { 87 | return static_cast(pendingActions_.front()->pointer); 88 | } 89 | default: 90 | DIE("Unknown XML generation action."); 91 | } 92 | } 93 | 94 | void XmlGenerator::init_front_action() 95 | { 96 | bufferOffset_ = 0; 97 | switch (pendingActions_.front()->type) 98 | { 99 | case RENDER_INT: 100 | { 101 | integer_to_buffer(pendingActions_.front()->integer, buffer_); 102 | break; 103 | } 104 | case CONST_LITERAL: 105 | { 106 | break; 107 | } 108 | default: 109 | DIE("Unknown XML generation action."); 110 | } 111 | } 112 | 113 | void XmlGenerator::internal_reset() 114 | { 115 | fileOffset_ = 0; 116 | while (!pendingActions_.empty()) 117 | { 118 | delete pendingActions_.pop_front(); 119 | } 120 | } 121 | 122 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/TwoWireBitBangImple.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #pragma once 28 | 29 | 30 | class TwoWireBitBangImple 31 | { 32 | public: 33 | typedef NeoNoSettings SettingsObject; 34 | 35 | TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : 36 | _pinClock(pinClock), 37 | _pinData(pinData) 38 | { 39 | pinMode(pinClock, OUTPUT); 40 | pinMode(pinData, OUTPUT); 41 | } 42 | 43 | ~TwoWireBitBangImple() 44 | { 45 | pinMode(_pinClock, INPUT); 46 | pinMode(_pinData, INPUT); 47 | } 48 | 49 | void begin() 50 | { 51 | digitalWrite(_pinClock, LOW); 52 | digitalWrite(_pinData, LOW); 53 | } 54 | 55 | void beginTransaction() 56 | { 57 | 58 | } 59 | 60 | void endTransaction() 61 | { 62 | digitalWrite(_pinData, LOW); 63 | } 64 | 65 | void transmitByte(uint8_t data) 66 | { 67 | for (int bit = 7; bit >= 0; bit--) 68 | { 69 | // set data bit on pin 70 | digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); 71 | 72 | // set clock high as data is ready 73 | digitalWrite(_pinClock, HIGH); 74 | 75 | data <<= 1; 76 | 77 | // set clock low as data pin is changed 78 | digitalWrite(_pinClock, LOW); 79 | } 80 | } 81 | 82 | void transmitBytes(const uint8_t* data, size_t dataSize) 83 | { 84 | const uint8_t* endData = data + dataSize; 85 | while (data < endData) 86 | { 87 | transmitByte(*data++); 88 | } 89 | } 90 | 91 | void applySettings(const SettingsObject& settings) 92 | { 93 | } 94 | 95 | private: 96 | const uint8_t _pinClock; // output pin number for clock line 97 | const uint8_t _pinData; // output pin number for data line 98 | }; -------------------------------------------------------------------------------- /components/DCC/private_include/TrackPowerHandler.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2020-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | #ifndef TRACK_POWER_HANDLER_HXX_ 18 | #define TRACK_POWER_HANDLER_HXX_ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace esp32cs 25 | { 26 | 27 | template 28 | class TrackPowerBit : public openlcb::BitEventInterface 29 | { 30 | public: 31 | TrackPowerBit(openlcb::Node *node) 32 | : openlcb::BitEventInterface(openlcb::Defs::CLEAR_EMERGENCY_OFF_EVENT 33 | , openlcb::Defs::EMERGENCY_OFF_EVENT) 34 | , node_(node) 35 | { 36 | LOG(INFO, 37 | "[Track Power] Registering OpenLCB event consumer (On:%s, Off:%s)", 38 | utils::event_id_to_string(event_on()).c_str(), 39 | utils::event_id_to_string(event_off()).c_str()); 40 | } 41 | 42 | openlcb::EventState get_current_state() override 43 | { 44 | LOG(VERBOSE, "[Track Power] Query event state: %d", 45 | DCC_BOOSTER::should_be_enabled()); 46 | if (DCC_BOOSTER::should_be_enabled()) 47 | { 48 | LOG(VERBOSE, "[Track Power] ON (%s)", 49 | utils::event_id_to_string(event_on()).c_str()); 50 | return openlcb::EventState::VALID; 51 | } 52 | LOG(VERBOSE, "[Track Power] OFF (%s)", 53 | utils::event_id_to_string(event_off()).c_str()); 54 | return openlcb::EventState::INVALID; 55 | } 56 | 57 | void set_state(bool new_value) override 58 | { 59 | if (new_value) 60 | { 61 | LOG(INFO, "[Track Power] Clearing global emergency off"); 62 | DCC_BOOSTER::clear_disable_reason(DccOutput::DisableReason::GLOBAL_EOFF); 63 | OLCB_DCC_BOOSTER::clear_disable_reason(DccOutput::DisableReason::GLOBAL_EOFF); 64 | } 65 | else 66 | { 67 | LOG(INFO, "[Track Power] Setting global emergency off"); 68 | DCC_BOOSTER::set_disable_reason(DccOutput::DisableReason::GLOBAL_EOFF); 69 | OLCB_DCC_BOOSTER::set_disable_reason(DccOutput::DisableReason::GLOBAL_EOFF); 70 | } 71 | } 72 | 73 | openlcb::Node *node() 74 | { 75 | return node_; 76 | } 77 | 78 | private: 79 | openlcb::Node *node_; 80 | }; 81 | 82 | } // namespace esp32cs 83 | 84 | #endif // TRACK_POWER_HANDLER_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/TwoWireHspiImple.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixel library helper functions for DotStars using ESP32's alternate SPI (HSPI) (APA102/LPD8806). 3 | 4 | Written by Michael C. Miller. 5 | Minor changes adapting TwoWireSpiImple to support HSPI by Louis Beaudoin (Pixelvation) 6 | 7 | I invest time and resources providing this open source code, 8 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 9 | 10 | ------------------------------------------------------------------------- 11 | This file is part of the Makuna/NeoPixelBus library. 12 | 13 | NeoPixelBus is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Lesser General Public License as 15 | published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | NeoPixelBus is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | template class TwoWireHspiImple 33 | { 34 | public: 35 | typedef typename T_SPISPEED::SettingsObject SettingsObject; 36 | 37 | TwoWireHspiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI 38 | { 39 | _hspi = new SPIClass(HSPI); 40 | } 41 | 42 | ~TwoWireHspiImple() 43 | { 44 | _hspi->end(); 45 | delete _hspi; 46 | } 47 | 48 | #if defined(ARDUINO_ARCH_ESP32) 49 | // for cases where hardware SPI can have pins changed 50 | void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) 51 | { 52 | _hspi->begin(sck, miso, mosi, ss); 53 | } 54 | #endif 55 | 56 | void begin() 57 | { 58 | _hspi->begin(); 59 | } 60 | 61 | void beginTransaction() 62 | { 63 | _hspi->beginTransaction(SPISettings(_speed.Clock, MSBFIRST, SPI_MODE0)); 64 | } 65 | 66 | void endTransaction() 67 | { 68 | _hspi->endTransaction(); 69 | } 70 | 71 | void transmitByte(uint8_t data) 72 | { 73 | _hspi->transfer(data); 74 | } 75 | 76 | void transmitBytes(const uint8_t* data, size_t dataSize) 77 | { 78 | // ESPs have a method to write without inplace overwriting the send buffer 79 | // since we don't care what gets received, use it for performance 80 | // FIX: but for what ever reason on Esp32, its not const 81 | _hspi->writeBytes(const_cast(data), dataSize); 82 | } 83 | 84 | void applySettings(const SettingsObject& settings) 85 | { 86 | _speed.applySettings(settings); 87 | } 88 | 89 | private: 90 | SPIClass * _hspi = NULL; 91 | T_SPISPEED _speed; 92 | }; -------------------------------------------------------------------------------- /components/TrainManager/private_include/XmlGenerator.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2015 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #ifndef _BRACZ_MOBILESTATION_XMLGENERATOR_HXX_ 11 | #define _BRACZ_MOBILESTATION_XMLGENERATOR_HXX_ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace trainmanager 18 | { 19 | 20 | class XmlGenerator 21 | { 22 | public: 23 | XmlGenerator() 24 | { 25 | 26 | } 27 | 28 | /// Reads from the buffer, or generates more data to read. Returns the number 29 | /// of bytes written to buf. Returns a short read (including 0) if and only 30 | /// if EOF is reached. 31 | ssize_t read(size_t offset, void* buf, size_t len); 32 | 33 | size_t file_offset() 34 | { 35 | return fileOffset_; 36 | } 37 | 38 | protected: 39 | struct GeneratorAction; 40 | 41 | /// This function will be called repeatedly in order to fill in the output 42 | /// buffer. Each call must call add_to_output at least once unless the EOF is 43 | /// reached. 44 | virtual void generate_more() = 0; 45 | 46 | /// Call this method from the driver API in order to 47 | void internal_reset(); 48 | 49 | /// Call this function from generate_more to extend the output buffer. 50 | void add_to_output(GeneratorAction* action) 51 | { 52 | pendingActions_.push_front(action); 53 | } 54 | 55 | 56 | GeneratorAction* from_const_string(const char* data) 57 | { 58 | GeneratorAction* a = new GeneratorAction; 59 | a->type = CONST_LITERAL; 60 | a->pointer = data; 61 | return a; 62 | } 63 | 64 | GeneratorAction* from_integer(int data) 65 | { 66 | GeneratorAction* a = new GeneratorAction; 67 | a->type = RENDER_INT; 68 | a->integer = data; 69 | return a; 70 | } 71 | 72 | struct GeneratorAction : public QMember 73 | { 74 | uint8_t type; 75 | union { 76 | const void* pointer; 77 | int integer; 78 | }; 79 | }; 80 | 81 | private: 82 | friend class TestEmptyXmlGenerator; 83 | 84 | enum ActionType 85 | { 86 | CONST_LITERAL, 87 | RENDER_INT, 88 | }; 89 | 90 | /// Sets up the internal structures needed based on the action in the front 91 | /// of the pendingQueue_. 92 | void init_front_action(); 93 | 94 | /// Returns the pointer to the data representing the front action. 95 | const char* get_front_buffer(); 96 | 97 | /// Actions that were generated by the last call of generate_more(). Note 98 | /// that the order of these action is REVERSED during the call to 99 | /// generate_more(). 100 | TypedQueue pendingActions_; 101 | 102 | /// The offset (in the file) of the first byte of the first Action in 103 | /// pendingActions_. 104 | size_t fileOffset_; 105 | 106 | unsigned bufferOffset_; 107 | /// For rendering integers. 108 | char buffer_[16]; 109 | }; 110 | 111 | } // namespace trainmanager 112 | 113 | #endif // _BRACZ_MOBILESTATION_XMLGENERATOR_HXX_ -------------------------------------------------------------------------------- /components/Config/include/pinmap-lmd18200.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2022 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef HARDWARE_PINMAP_LMD18200_HXX_ 19 | #define HARDWARE_PINMAP_LMD18200_HXX_ 20 | 21 | #include "sdkconfig.h" 22 | 23 | #undef CONFIG_DCC_TRACK_SIGNAL_PIN 24 | #undef CONFIG_OPS_HBRIDGE_L298 25 | #undef CONFIG_OPS_HBRIDGE_LMD18200 26 | #undef CONFIG_OPS_HBRIDGE_DRV880X 27 | #undef CONFIG_OPS_HBRIDGE_DRV8873 28 | #undef CONFIG_OPS_HBRIDGE_DRV8873_5A 29 | #undef CONFIG_OPS_HBRIDGE_POLOLU 30 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_5A 31 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_10A 32 | #undef CONFIG_RAILCOM_TRIGGER_PIN 33 | #undef CONFIG_RAILCOM_DATA_PIN 34 | #undef CONFIG_RAILCOM_DIRECTION_PIN 35 | #undef CONFIG_RAILCOM_SHORT_PIN 36 | #undef CONFIG_OLED_RESET_PIN 37 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_1 38 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_2 39 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_3 40 | #undef CONFIG_PROG_TRACK_ENABLE_PIN 41 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_1 42 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_2 43 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_3 44 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 45 | #undef CONFIG_RAILCOM_DATA_ENABLED 46 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_0 47 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_1 48 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_2 49 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_3 50 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_4 51 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_5 52 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_6 53 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_7 54 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_0 55 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_1 56 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_2 57 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_3 58 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_4 59 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_5 60 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_6 61 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_7 62 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 63 | #undef CONFIG_RAILCOM_DATA_ENABLED 64 | #undef CONFIG_PROG_TRACK_ENABLED 65 | #undef CONFIG_I2C_SCL_PIN 66 | #undef CONFIG_I2C_SDA_PIN 67 | 68 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 69 | 70 | #define CONFIG_OPS_HBRIDGE_LMD18200 1 71 | 72 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 73 | 74 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 75 | 76 | #define CONFIG_PROG_TRACK_ENABLE_PIN -1 77 | 78 | #define CONFIG_I2C_SCL_PIN 22 79 | 80 | #define CONFIG_I2C_SDA_PIN 21 81 | 82 | #endif // HARDWARE_PINMAP_LMD18200_HXX_ -------------------------------------------------------------------------------- /components/TrainManager/TrainSnipHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "TrainManager.hxx" 11 | #include "TrainSnipHandler.hxx" 12 | 13 | #include 14 | #include 15 | 16 | namespace trainmanager 17 | { 18 | 19 | using locodb::LocoDatabase; 20 | using openlcb::Defs; 21 | using openlcb::IncomingMessageStateFlow; 22 | using openlcb::SimpleInfoDescriptor; 23 | using openlcb::SimpleInfoFlow; 24 | using openlcb::SNIP_STATIC_DATA; 25 | 26 | TrainSnipHandler::TrainSnipHandler(TrainManager* parent, SimpleInfoFlow* info_flow) 27 | : IncomingMessageStateFlow(parent->train_service()->iface()), 28 | parent_(parent), 29 | responseFlow_(info_flow) 30 | { 31 | iface()->dispatcher()->register_handler( 32 | this, Defs::MTI::MTI_IDENT_INFO_REQUEST, Defs::MTI::MTI_EXACT); 33 | } 34 | 35 | TrainSnipHandler::~TrainSnipHandler() 36 | { 37 | iface()->dispatcher()->unregister_handler( 38 | this, Defs::MTI::MTI_IDENT_INFO_REQUEST, Defs::MTI::MTI_EXACT); 39 | } 40 | 41 | StateFlowBase::Action TrainSnipHandler::entry() 42 | { 43 | // Let's find the train ID. 44 | if (!parent_->is_valid_train_node(nmsg()->dstNode)) 45 | { 46 | return release_and_exit(); 47 | } 48 | return allocate_and_call(responseFlow_, STATE(send_response_request)); 49 | } 50 | 51 | StateFlowBase::Action TrainSnipHandler::send_response_request() 52 | { 53 | auto* b = get_allocation_result(responseFlow_); 54 | auto entry = 55 | Singleton::instance()->get_entry(nmsg()->dstNode->node_id()); 56 | if (entry) 57 | { 58 | snipName_ = entry->get_train_name(); 59 | snipDesc_ = entry->get_train_description(); 60 | } 61 | else 62 | { 63 | snipName_.clear(); 64 | snipDesc_.clear(); 65 | } 66 | snipResponse_[6].data = snipName_.c_str(); 67 | snipResponse_[7].data = snipDesc_.c_str(); 68 | b->data()->reset(nmsg(), snipResponse_, Defs::MTI_IDENT_INFO_REPLY); 69 | // We must wait for the data to be sent out because we have a static member 70 | // that we are changing constantly. 71 | b->set_done(n_.reset(this)); 72 | responseFlow_->send(b); 73 | release(); 74 | return wait_and_call(STATE(send_done)); 75 | } 76 | 77 | StateFlowBase::Action TrainSnipHandler::send_done() 78 | { 79 | return exit(); 80 | } 81 | 82 | openlcb::SimpleInfoDescriptor TrainSnipHandler::snipResponse_[] = 83 | { 84 | {SimpleInfoDescriptor::LITERAL_BYTE, 4, 0, nullptr}, 85 | {SimpleInfoDescriptor::C_STRING, 0, 0, SNIP_STATIC_DATA.manufacturer_name}, 86 | {SimpleInfoDescriptor::C_STRING, 41, 0, "Virtual train node"}, 87 | {SimpleInfoDescriptor::C_STRING, 0, 0, "n/a"}, 88 | {SimpleInfoDescriptor::C_STRING, 0, 0, SNIP_STATIC_DATA.software_version}, 89 | {SimpleInfoDescriptor::LITERAL_BYTE, 2, 0, nullptr}, // version 90 | {SimpleInfoDescriptor::C_STRING, 63, 1, nullptr}, // name 91 | {SimpleInfoDescriptor::C_STRING, 64, 64, nullptr}, // description 92 | {SimpleInfoDescriptor::END_OF_DATA, 0, 0, 0} 93 | }; 94 | 95 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/Utils/include/EventBroadcastHelper.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef EVENT_BROADCAST_HELPER_HXX_ 19 | #define EVENT_BROADCAST_HELPER_HXX_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace esp32cs 28 | { 29 | 30 | /// Utility class that will send an event out onto the bus. 31 | class EventBroadcastHelper : public Singleton 32 | { 33 | public: 34 | /// Constructor. 35 | /// 36 | /// @param service is the @ref Service that will execute this flow. 37 | EventBroadcastHelper(Service *service, openlcb::Node *node) 38 | : flow_(service, node) 39 | { 40 | } 41 | 42 | void send_event(openlcb::EventId eventID) 43 | { 44 | BufferPtr b(flow_.alloc()); 45 | b->data()->reset(eventID); 46 | b->data()->done.reset(EmptyNotifiable::DefaultInstance()); 47 | flow_.send(b->ref()); 48 | } 49 | private: 50 | struct EventRequest : public CallableFlowRequestBase 51 | { 52 | void reset(openlcb::EventId event) 53 | { 54 | reset_base(); 55 | this->eventID = event; 56 | } 57 | openlcb::EventId eventID; 58 | }; 59 | 60 | class EventFlow : public CallableFlow 61 | { 62 | public: 63 | EventFlow(Service *service, openlcb::Node *node) : 64 | CallableFlow(service), node_(node) 65 | { 66 | } 67 | StateFlowBase::Action entry() override 68 | { 69 | LOG(VERBOSE, "[EventHelper] Sending: %s", 70 | utils::event_id_to_string(request()->eventID).c_str()); 71 | writer_.WriteAsync(node_, openlcb::Defs::MTI_EVENT_REPORT, 72 | openlcb::WriteHelper::global(), 73 | openlcb::eventid_to_buffer(request()->eventID), 74 | this); 75 | return wait_and_return_ok(); 76 | } 77 | private: 78 | openlcb::Node *node_; 79 | openlcb::WriteHelper writer_; 80 | }; 81 | 82 | EventFlow flow_; 83 | }; 84 | 85 | } // namespace esp32cs 86 | 87 | #endif // EVENT_BROADCAST_HELPER_HXX_ -------------------------------------------------------------------------------- /components/Config/include/pinmap-l298.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2022 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef HARDWARE_PINMAP_L298_HXX_ 19 | #define HARDWARE_PINMAP_L298_HXX_ 20 | 21 | #include "sdkconfig.h" 22 | 23 | #undef CONFIG_DCC_TRACK_SIGNAL_PIN 24 | #undef CONFIG_OPS_HBRIDGE_L298 25 | #undef CONFIG_OPS_HBRIDGE_LMD18200 26 | #undef CONFIG_OPS_HBRIDGE_DRV880X 27 | #undef CONFIG_OPS_HBRIDGE_DRV8873 28 | #undef CONFIG_OPS_HBRIDGE_DRV8873_5A 29 | #undef CONFIG_OPS_HBRIDGE_POLOLU 30 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_5A 31 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_10A 32 | #undef CONFIG_RAILCOM_TRIGGER_PIN 33 | #undef CONFIG_RAILCOM_DATA_PIN 34 | #undef CONFIG_RAILCOM_DIRECTION_PIN 35 | #undef CONFIG_RAILCOM_SHORT_PIN 36 | #undef CONFIG_OLED_RESET_PIN 37 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_1 38 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_2 39 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_3 40 | #undef CONFIG_PROG_TRACK_ENABLE_PIN 41 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_1 42 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_2 43 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_3 44 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 45 | #undef CONFIG_RAILCOM_DATA_ENABLED 46 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_0 47 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_1 48 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_2 49 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_3 50 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_4 51 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_5 52 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_6 53 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_7 54 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_0 55 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_1 56 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_2 57 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_3 58 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_4 59 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_5 60 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_6 61 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_7 62 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 63 | #undef CONFIG_RAILCOM_DATA_ENABLED 64 | #undef CONFIG_I2C_SCL_PIN 65 | #undef CONFIG_I2C_SDA_PIN 66 | 67 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 68 | 69 | #define CONFIG_OPS_HBRIDGE_L298 1 70 | 71 | #define CONFIG_OPSTRACK_ADC_CHANNEL_7 1 72 | 73 | #define CONFIG_PROG_HBRIDGE_L298 1 74 | 75 | #define CONFIG_PROGTRACK_ADC_CHANNEL_6 1 76 | 77 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 78 | 79 | #define CONFIG_PROG_TRACK_ENABLE_PIN 23 80 | 81 | #define CONFIG_I2C_SCL_PIN 22 82 | 83 | #define CONFIG_I2C_SDA_PIN 21 84 | 85 | #endif // HARDWARE_PINMAP_L298_HXX_ -------------------------------------------------------------------------------- /components/NvsManager/private_include/NodeIdMemoryConfigSpace.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2022 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: GPL-3.0 5 | * 6 | * This file is part of ESP32 Command Station. 7 | */ 8 | 9 | #ifndef NODEID_MEMORY_CONFIG_SPACE_HXX_ 10 | #define NODEID_MEMORY_CONFIG_SPACE_HXX_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include "sdkconfig.h" 22 | #include "AbstractVirtualMemorySpace.hxx" 23 | 24 | namespace esp32cs 25 | { 26 | 27 | /// Node configuration holder 28 | NodeIdConfig node_id_config(CONFIG_OLCB_NODEID_MEMORY_SPACE_OFFSET); 29 | 30 | /// Virtual memory space that allows reconfiguration of the persistent node 31 | /// identifier. 32 | class NodeIdMemoryConfigSpace 33 | : public openlcb::VirtualMemorySpace, 34 | public Singleton, 35 | public AbstractVirtualMemorySpace 36 | { 37 | public: 38 | /// Constructor. 39 | /// 40 | /// @param stack is the @ref SimpleStackBase that this memory space should 41 | /// be registered with. 42 | /// @param node_id is the current node identifier. 43 | NodeIdMemoryConfigSpace(openlcb::SimpleStackBase *stack, NvsManager *nvs) 44 | : nvs_(nvs), id_(utils::node_id_to_string(nvs->node_id())), 45 | nodeid_(nvs->node_id()) 46 | { 47 | register_string(node_id_config.node_id(), 48 | [&](unsigned repeat, string *contents, BarrierNotifiable *done) 49 | { 50 | AutoNotify n(done); 51 | LOG(VERBOSE, "[NodeIdMemCfg-READ] %s", id_.c_str()); 52 | *contents = id_; 53 | }, 54 | [&](unsigned repeat, string contents, BarrierNotifiable *done) 55 | { 56 | AutoNotify n(done); 57 | LOG(VERBOSE, "[NodeIdMemCfg-WRITE] %s", contents.c_str()); 58 | uint64_t new_node_id = utils::string_to_uint64(contents); 59 | nvs->node_id(new_node_id); 60 | set_modified(true); 61 | nodeid_ = new_node_id; 62 | id_ = std::move(contents); 63 | } 64 | ); 65 | LOG(INFO, "[NodeIdMemCfg:%02x] NodeID: %s", SPACE, id_.c_str()); 66 | stack->memory_config_handler()->registry()->insert( 67 | stack->node(), SPACE, this); 68 | } 69 | 70 | /// Returns the currently configured node identifier. 71 | uint64_t node_id() 72 | { 73 | return nodeid_; 74 | } 75 | 76 | private: 77 | static constexpr uint8_t SPACE = CONFIG_OLCB_NODEID_MEMORY_SPACE_ID; 78 | NvsManager *nvs_; 79 | /// temporary holder for the node id in a hex string format. 80 | /// NOTE: the value will be a dot expanded hex format, 81 | /// ie: 05.02.01.03.10.00. 82 | std::string id_; 83 | 84 | /// temporary holder for the currently assigned node id. 85 | uint64_t nodeid_{0}; 86 | }; 87 | 88 | } // namespace esp32cs 89 | 90 | #endif // NODEID_MEMORY_CONFIG_SPACE_HXX_ 91 | -------------------------------------------------------------------------------- /components/Utils/include/DelayRebootHelper.hxx: -------------------------------------------------------------------------------- 1 | /** \copyright 2 | * Copyright (c) 2020, Mike Dunston 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 11 | * - Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | * \file DelayReboot.hxx 28 | * 29 | * Implementation of a countdown to reboot 30 | * 31 | * @author Mike Dunston 32 | * @date 14 July 2020 33 | */ 34 | 35 | #ifndef DELAY_REBOOT_HXX_ 36 | #define DELAY_REBOOT_HXX_ 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | extern "C" void reboot(); 44 | 45 | namespace esp32cs 46 | { 47 | 48 | /// Utility class that will reboot the node after a pre-defined time has 49 | /// elapsed. 50 | class DelayRebootHelper : public StateFlowBase 51 | , public Singleton 52 | { 53 | public: 54 | /// Constructor. 55 | /// 56 | /// @param service is the @ref Service that will execute this flow. 57 | DelayRebootHelper(Service *service) : StateFlowBase(service) 58 | { 59 | } 60 | 61 | /// Starts the countdown timer. 62 | void start() 63 | { 64 | start_flow(STATE(delay)); 65 | } 66 | 67 | private: 68 | StateFlowTimer timer_{this}; 69 | const uint16_t DELAY_INTERVAL_MSEC{250}; 70 | const uint64_t DELAY_INTERVAL_NSEC{ 71 | (uint64_t)MSEC_TO_NSEC(DELAY_INTERVAL_MSEC)}; 72 | uint16_t delayCountdown_{2000}; 73 | 74 | /// Counts down the time until reboot should occur. 75 | Action delay() 76 | { 77 | delayCountdown_ -= DELAY_INTERVAL_MSEC; 78 | if (delayCountdown_) 79 | { 80 | LOG(WARNING 81 | , "[Reboot] %u ms remaining until reboot", delayCountdown_); 82 | return sleep_and_call(&timer_, DELAY_INTERVAL_NSEC, STATE(delay)); 83 | } 84 | reboot(); 85 | return exit(); 86 | } 87 | }; 88 | 89 | } // namespace esp32cs 90 | 91 | #endif // DELAY_REBOOT_HXX_ -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/include/AccessoryDecoderDataTypes.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef TURNOUTDATATYPES_HXX_ 19 | #define TURNOUTDATATYPES_HXX_ 20 | 21 | #include "sdkconfig.h" 22 | #include 23 | #include 24 | #include 25 | 26 | namespace esp32cs 27 | { 28 | 29 | /// Supported Types of accessory decoders. 30 | enum AccessoryType 31 | { 32 | SWITCH_LEFT=0, 33 | SWITCH_RIGHT, 34 | SWITCH_WYE, 35 | SWITCH_MULTI, 36 | UNKNOWN, 37 | UNCHANGED, 38 | MAX_ACCESSORY_TYPES // NOTE: this must be the last entry in the enum. 39 | }; 40 | 41 | static constexpr const char *ACCESSORY_TYPE_STRINGS[] = 42 | { 43 | "Left diverging switch", 44 | "Right diverging switch", 45 | "Wye switch", 46 | "Multi-directional switch", 47 | "Unknown type" 48 | }; 49 | 50 | class AccessoryBaseType 51 | { 52 | public: 53 | uint16_t address() const 54 | { 55 | return address_; 56 | } 57 | 58 | std::string name() const 59 | { 60 | return name_; 61 | } 62 | 63 | bool toggle() 64 | { 65 | return set(!get()); 66 | } 67 | 68 | bool get() const 69 | { 70 | return state_; 71 | } 72 | 73 | AccessoryType type() const 74 | { 75 | return type_; 76 | } 77 | 78 | void type(AccessoryType type) 79 | { 80 | type_ = type; 81 | } 82 | 83 | virtual bool set(bool state, bool is_on = true) 84 | { 85 | state_ = state; 86 | isOn_ = is_on; 87 | return false; 88 | } 89 | 90 | virtual bool is_on() 91 | { 92 | return isOn_; 93 | } 94 | 95 | virtual std::string to_json(bool readable_strings = false) 96 | { 97 | return "{}"; 98 | } 99 | 100 | void update(uint16_t address, std::string name, AccessoryType type) 101 | { 102 | address_ = address; 103 | name_ = name; 104 | if (type != AccessoryType::UNCHANGED) 105 | { 106 | type_ = type; 107 | } 108 | 109 | LOG(CONFIG_TURNOUT_LOG_LEVEL, "[Turnout %d] Updated type %s", address_, 110 | ACCESSORY_TYPE_STRINGS[type_]); 111 | } 112 | 113 | protected: 114 | AccessoryBaseType(uint16_t address, std::string name, bool state, 115 | AccessoryType type = AccessoryType::UNKNOWN) 116 | : address_(address), name_(name), state_(state), type_(type) 117 | { 118 | } 119 | 120 | uint16_t address_; 121 | std::string name_; 122 | bool state_; 123 | bool isOn_; 124 | AccessoryType type_; 125 | }; 126 | 127 | } // namespace esp32cs 128 | 129 | #endif // TURNOUTDATATYPES_HXX_ -------------------------------------------------------------------------------- /components/StatusLED/StatusLEDGpio.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2019-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #include "StatusLED.hxx" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace esp32cs 24 | { 25 | 26 | #if CONFIG_STATUS_LED_WIFI_STA_PIN == -1 27 | typedef DummyPinWithRead WIFI_STA_Pin; 28 | #else 29 | GPIO_PIN(WIFI_STA, GpioOutputSafeHighInvert, CONFIG_STATUS_LED_WIFI_STA_PIN); 30 | #endif 31 | 32 | #if CONFIG_STATUS_LED_WIFI_AP_PIN == -1 33 | typedef DummyPinWithRead WIFI_AP_Pin; 34 | #else 35 | GPIO_PIN(WIFI_AP, GpioOutputSafeHighInvert, CONFIG_STATUS_LED_WIFI_AP_PIN); 36 | #endif 37 | 38 | #if CONFIG_STATUS_LED_BOOTLOADER_ACTIVE_PIN == -1 39 | typedef DummyPinWithRead BOOTLOADER_Pin; 40 | #else 41 | GPIO_PIN(BOOTLOADER, GpioOutputSafeHighInvert, 42 | CONFIG_STATUS_LED_BOOTLOADER_ACTIVE_PIN); 43 | #endif 44 | 45 | #if CONFIG_STATUS_LED_OPS_ACTIVE_PIN == -1 46 | typedef DummyPinWithRead OPS_ACTIVE_Pin; 47 | #else 48 | GPIO_PIN(OPS_ACTIVE, GpioOutputSafeHighInvert, 49 | CONFIG_STATUS_LED_OPS_ACTIVE_PIN); 50 | #endif 51 | 52 | #if CONFIG_STATUS_LED_PROG_ACTIVE_PIN == -1 53 | typedef DummyPinWithRead PROG_ACTIVE_Pin; 54 | #else 55 | GPIO_PIN(PROG_ACTIVE, GpioOutputSafeHighInvert, 56 | CONFIG_STATUS_LED_PROG_ACTIVE_PIN); 57 | #endif 58 | 59 | typedef GpioInitializer GpioInit; 62 | 63 | const Gpio *LEDS[StatusLED::LED::MAX_LED] = 64 | { 65 | WIFI_STA_Pin::instance(), 66 | WIFI_AP_Pin::instance(), 67 | BOOTLOADER_Pin::instance(), 68 | OPS_ACTIVE_Pin::instance(), 69 | PROG_ACTIVE_Pin::instance() 70 | }; 71 | 72 | void StatusLED::hw_init() 73 | { 74 | GpioInit::hw_init(); 75 | for(int led = 0; led < LED::MAX_LED; led++) 76 | { 77 | LEDS[led]->set(); 78 | vTaskDelay(pdMS_TO_TICKS(100)); 79 | LEDS[led]->clr(); 80 | } 81 | start_task(); 82 | } 83 | 84 | void StatusLED::refresh() 85 | { 86 | for(int led = 0; led < LED::MAX_LED; led++) 87 | { 88 | if(colors_[led] == RED_BLINK || 89 | colors_[led] == GREEN_BLINK || 90 | colors_[led] == BLUE_BLINK || 91 | colors_[led] == YELLOW_BLINK) 92 | { 93 | state_[led] = !state_[led]; 94 | LEDS[led]->write(state_[led]); 95 | } 96 | else if (colors_[led] == OFF) 97 | { 98 | LEDS[led]->clr(); 99 | } 100 | else 101 | { 102 | LEDS[led]->set(); 103 | } 104 | } 105 | } 106 | 107 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/Utils/include/HealthMonitor.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef HEALTHMONITOR_HXX_ 19 | #define HEALTHMONITOR_HXX_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "sdkconfig.h" 27 | 28 | namespace esp32cs 29 | { 30 | 31 | /// Utility class providing periodic reporting of general health of the 32 | /// ESP32. 33 | class HealthMonitor : public StateFlowBase 34 | { 35 | public: 36 | /// Constructor. 37 | /// 38 | /// @param service is the @ref Service to attach this flow to. 39 | HealthMonitor(Service *service) : StateFlowBase(service) 40 | { 41 | start_flow(STATE(update)); 42 | } 43 | 44 | /// Stops the flow and cancels the timer (if needed). 45 | void stop() 46 | { 47 | shutdown_ = true; 48 | set_terminated(); 49 | timer_.ensure_triggered(); 50 | } 51 | private: 52 | /// @ref StateFlowTimer used for periodic wakeup. 53 | StateFlowTimer timer_{this}; 54 | 55 | /// Interval at which to wake up. 56 | const uint64_t reportInterval_{SEC_TO_NSEC(15)}; 57 | 58 | /// Internal flag to track if a shutdown request has been requested. 59 | bool shutdown_{false}; 60 | 61 | /// Wakes up and blinks the heartbeat LED and prints general health when 62 | /// the required count of wakeups has expired. 63 | Action update() 64 | { 65 | if (shutdown_) 66 | { 67 | return exit(); 68 | } 69 | struct timeval tv; 70 | struct tm ti; 71 | gettimeofday(&tv, NULL); 72 | localtime_r(&tv.tv_sec, &ti); 73 | LOG(INFO, "%02d:%02d:%02d.%03ld: heap: %.2fkB/%.2fKb (max block size: %.2fkB), " 74 | #if CONFIG_SPIRAM 75 | "PSRAM: %.2fkB/%.2fKb (max block size: %.2fkB), " 76 | #endif // CONFIG_SPIRAM 77 | "mainBufferPool: %.2fkB", 78 | ti.tm_hour, ti.tm_min, ti.tm_sec, tv.tv_usec / 1000, 79 | heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024.0f, 80 | heap_caps_get_total_size(MALLOC_CAP_INTERNAL) / 1024.0f, 81 | heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL) / 1024.0f, 82 | #if CONFIG_SPIRAM 83 | heap_caps_get_free_size(MALLOC_CAP_SPIRAM) / 1024.0f, 84 | heap_caps_get_total_size(MALLOC_CAP_SPIRAM) / 1024.0f, 85 | heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM) / 1024.0f, 86 | #endif // CONFIG_SPIRAM 87 | mainBufferPool->total_size() / 1024.0f); 88 | return sleep_and_call(&timer_, reportInterval_, STATE(update)); 89 | } 90 | }; 91 | 92 | } // namespace esp32cs 93 | 94 | #endif // HEALTHMONITOR_HXX_ -------------------------------------------------------------------------------- /docs/precompiled.md: -------------------------------------------------------------------------------- 1 | # Pre-compiled binaries 2 | 3 | Pre-compiled binaries are generally available with releases. Binaries can also 4 | be obtained from [Actions](https://github.com/atanisoft/ESP32CommandStation/actions) 5 | when a pull-request is submitted or updated, these however should be considered 6 | as unstable. 7 | 8 | The pre-compiled binaries include three text files which should be referenced 9 | as part of connecting your hardware together or connecting to the default 10 | SoftAP. 11 | 12 | * readme.txt - This file contains basic instructions on how to use the binaries. 13 | * pinmap.txt - This file contains GPIO pin mappings. 14 | * wifi.txt - This file contains the default WiFi configuration. 15 | 16 | ## Using pre-compiled binaries 17 | 18 | The pre-compiled firmware bundle can be used in four ways: 19 | 20 | 1. esptool. 21 | 2. Espressif Flash Download Tool. 22 | 3. JMRI Firmware Update utility. 23 | 4. Firmware Update via built-in web interface. 24 | 25 | ### esptool 26 | 27 | esptool is a command line utility for flashing binary firmware to various ESP32 28 | devices. This is the preferred method for initial firmware flashing. 29 | 30 | The command below can be used to flash the firmware to the ESP32: 31 | 32 | esptool.py --port /dev/ttyUSB0 --before=default_reset --after=hard_reset 33 | --baud 460800 write_flash 0x1000 bootloader.bin 0x8000 partition-table.bin 34 | 0xe000 ota_data_initial.bin 0x10000 ESP32CommandStation.bin 35 | 36 | **Note:** The command above should be all on a single line. 37 | 38 | **Note:** For the ESP32-S3 the bootloader.bin should be flashed at 0x0000 39 | instead of 0x1000 as listed above. 40 | 41 | The port parameter should be adjusted to your environment, on Windows this is 42 | usually prefixed by COM rather. On Linux it will be similar to the provided 43 | value. On Mac the ESP32 may show up as /dev/cu.SLAB_USBtoUART and you may also 44 | require additional drivers. 45 | 46 | If you need/want to erase the flash on the ESP32 the following command can be 47 | used: 48 | 49 | esptool.py --port /dev/ttyUSB0 erase_flash 50 | 51 | Note: The port parameter will need to be adjusted similar to the flashing 52 | command above. 53 | 54 | ### Espressif Flash Download Tool 55 | 56 | The Espressif Flash Download Tool is a graphical Windows only utility that 57 | operates similar to esptool. This tool can be downloaded via the link below: 58 | https://www.espressif.com/en/support/download/other-tools 59 | 60 | Use the following offsets and binaries for this utility: 61 | 62 | | Offset | File | 63 | |--------|------| 64 | | 0x1000 | bootloader.bin | 65 | | 0x8000 | partition-table.bin | 66 | | 0xe000 | ota_data_initial.bin | 67 | | 0x10000 | ESP32CommandStation.bin | 68 | 69 | **Note:** For the ESP32-S3 the bootloader.bin should be flashed at 0x0000 70 | instead of 0x1000 as listed above. 71 | 72 | ### JMRI Firmware Update Utility 73 | 74 | JMRI has built-in support for uploading firmware to OpenLCB (LCC) connected 75 | devices. At this time ESP32 Command Station only supports this feature when 76 | using a CAN (TWAI) physical connection between the ESP32 Command Station and 77 | the computer running JMRI. This approach can not be used as the initial 78 | firmware upload to the ESP32. 79 | 80 | When using JMRI to upload the firmware only ESP32CommandStation.bin should be 81 | used for upload. 82 | 83 | ### Firmware Update via built-in web interface 84 | 85 | After the initial firmware flashing has been completed it is possible to use 86 | the built-in web interface to upload new firmware versions to the ESP32 Command 87 | Station. Using this interface only ESP32CommandStation.bin should be uploaded. 88 | 89 | [home](README.md) -------------------------------------------------------------------------------- /components/AccessoryDecoderDB/OpenLCBAccessoryDecoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017-2022 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: GPL-3.0 5 | * 6 | * This file is part of ESP32 Command Station. 7 | */ 8 | 9 | #include "OpenLCBAccessoryDecoder.hxx" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace esp32cs 18 | { 19 | 20 | OpenLCBAccessoryDecoder::OpenLCBAccessoryDecoder( 21 | const uint16_t address, string name, string closed_events, 22 | string thrown_events, AccessoryType type, bool state) : 23 | AccessoryBaseType(address, name, state, type) 24 | { 25 | LOG(CONFIG_TURNOUT_LOG_LEVEL, 26 | "[OpenLCBAccessoryDecoder %d] Registered as %s with state of %s", 27 | address, ACCESSORY_TYPE_STRINGS[type], state ? "Thrown" : "Closed"); 28 | update_events(closed_events, thrown_events); 29 | } 30 | 31 | void OpenLCBAccessoryDecoder::update_events(string closed_events, 32 | string thrown_events) 33 | { 34 | vector closed; 35 | vector thrown; 36 | http::tokenize(closed_events, closed, ",", true, true); 37 | http::tokenize(thrown_events, thrown, ",", true, true); 38 | closed_.clear(); 39 | for (auto event : closed) 40 | { 41 | uint64_t evt = utils::string_to_uint64(event); 42 | LOG(CONFIG_TURNOUT_LOG_LEVEL, 43 | "[OpenLCBAccessoryDecoder %d] Closed event: %s", address(), 44 | utils::event_id_to_string(evt).c_str()); 45 | closed_.push_back(evt); 46 | } 47 | thrown_.clear(); 48 | for (auto event : thrown) 49 | { 50 | uint64_t evt = utils::string_to_uint64(event); 51 | LOG(CONFIG_TURNOUT_LOG_LEVEL, 52 | "[OpenLCBAccessoryDecoder %d] Thrown event: %s", address(), 53 | utils::event_id_to_string(evt).c_str()); 54 | thrown_.push_back(evt); 55 | } 56 | } 57 | 58 | bool OpenLCBAccessoryDecoder::set(bool state, bool is_on) 59 | { 60 | AccessoryBaseType::set(state, is_on); 61 | auto eventHelper = Singleton::instance(); 62 | if (get()) 63 | { 64 | for (auto event : thrown_) 65 | { 66 | eventHelper->send_event(event); 67 | } 68 | } 69 | else 70 | { 71 | for (auto event : closed_) 72 | { 73 | eventHelper->send_event(event); 74 | } 75 | } 76 | LOG(CONFIG_TURNOUT_LOG_LEVEL, "[OpenLCBAccessoryDecoder %d] Set to %s", 77 | address(), get() ? "Thrown" : "Closed"); 78 | return false; 79 | } 80 | 81 | std::string OpenLCBAccessoryDecoder::to_json(bool readableStrings) 82 | { 83 | vector closed_events; 84 | vector thrown_events; 85 | for (auto event : closed_) 86 | { 87 | closed_events.push_back(uint64_to_string_hex(event)); 88 | } 89 | for (auto event : thrown_) 90 | { 91 | thrown_events.push_back(uint64_to_string_hex(event)); 92 | } 93 | string serialized = 94 | StringPrintf(R"!^!({"addr":%d,"name":"%s","type":%d,"olcb":{"closed":"%s","thrown":"%s"},"state":)!^!", 95 | address(), name().c_str(), type(), 96 | http::string_join(closed_events, ",").c_str(), 97 | http::string_join(thrown_events, ",").c_str()); 98 | if (readableStrings) 99 | { 100 | serialized += 101 | StringPrintf(R"!^!("%s")!^!", get() ? "Thrown" : "Closed"); 102 | } 103 | else 104 | { 105 | serialized += integer_to_string(get()); 106 | } 107 | serialized += "}"; 108 | return serialized; 109 | } 110 | 111 | } // namespace esp32cs -------------------------------------------------------------------------------- /components/TrainManager/FdiXmlGenerator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2016 Balazs Racz 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | * 6 | * SPDX-FileContributor: 2020-2023 Mike Dunston (atanisoft) 7 | * 8 | */ 9 | 10 | #include "FdiXmlGenerator.hxx" 11 | #include 12 | 13 | namespace trainmanager 14 | { 15 | 16 | using locodb::LocoDatabaseEntry; 17 | using locodb::function_to_string; 18 | 19 | static const char kFdiXmlHead[] = R"( 20 | 21 | 22 | 23 | )"; 24 | static const char kFdiXmlTail[] = ""; 25 | 26 | static const char kFdiXmlBinaryFunction[] = 27 | R"( 28 | )"; 29 | 30 | static const char kFdiXmlMomentaryFunction[] = 31 | R"( 32 | )"; 33 | 34 | void FdiXmlGenerator::reset(std::shared_ptr lok) 35 | { 36 | state_ = STATE_START; 37 | entry_ = lok; 38 | internal_reset(); 39 | } 40 | 41 | void FdiXmlGenerator::generate_more() 42 | { 43 | while (true) 44 | { 45 | switch (state_) 46 | { 47 | case STATE_XMLHEAD: 48 | { 49 | add_to_output(from_const_string(kFdiXmlHead)); 50 | nextFunction_ = 0; 51 | state_ = STATE_START_FN; 52 | return; 53 | } 54 | case STATE_START_FN: 55 | { 56 | while ( 57 | nextFunction_ <= entry_->get_max_fn() && 58 | !entry_->is_function_valid(nextFunction_)) 59 | { 60 | ++nextFunction_; 61 | } 62 | if (nextFunction_ > entry_->get_max_fn()) 63 | { 64 | state_ = STATE_NO_MORE_FN; 65 | continue; 66 | } 67 | if (entry_->is_function_momentary(nextFunction_)) 68 | { 69 | add_to_output(from_const_string(kFdiXmlMomentaryFunction)); 70 | } 71 | else 72 | { 73 | add_to_output(from_const_string(kFdiXmlBinaryFunction)); 74 | } 75 | state_ = STATE_FN_NAME; 76 | return; 77 | } 78 | case STATE_FN_NAME: 79 | { 80 | add_to_output(from_const_string("")); 81 | const char* label = 82 | function_to_string(entry_->get_function_def(nextFunction_)); 83 | if (label) 84 | { 85 | add_to_output(from_const_string(label)); 86 | } 87 | else 88 | { 89 | add_to_output(from_const_string("F")); 90 | add_to_output(from_integer(nextFunction_)); 91 | } 92 | add_to_output(from_const_string("\n")); 93 | state_ = STATE_FN_NUMBER; 94 | return; 95 | } 96 | case STATE_FN_NUMBER: 97 | { 98 | add_to_output(from_const_string("")); 99 | add_to_output(from_integer(nextFunction_)); 100 | add_to_output(from_const_string("\n\n")); 101 | state_ = STATE_FN_END; 102 | return; 103 | } 104 | case STATE_FN_END: 105 | { 106 | ++nextFunction_; 107 | state_ = STATE_START_FN; 108 | continue; 109 | } 110 | case STATE_NO_MORE_FN: 111 | { 112 | add_to_output(from_const_string(kFdiXmlTail)); 113 | state_ = STATE_EOF; 114 | return; 115 | } 116 | case STATE_EOF: 117 | { 118 | return; 119 | } 120 | } 121 | } 122 | } 123 | 124 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/Config/include/ThermalConfigurationGroup.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2020-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef THERMAL_CONFIGURATION_HXX_ 19 | #define THERMAL_CONFIGURATION_HXX_ 20 | 21 | #include "hardware.hxx" 22 | #include 23 | 24 | #ifndef CONFIG_THERMALMONITOR_WARNING 25 | #define CONFIG_THERMALMONITOR_WARNING 50 26 | #endif 27 | 28 | #ifndef CONFIG_THERMALMONITOR_SHUTDOWN 29 | #define CONFIG_THERMALMONITOR_SHUTDOWN 80 30 | #endif 31 | 32 | namespace esp32cs 33 | { 34 | /// Thermal Configuration for an external temperature sensor. 35 | CDI_GROUP(ThermalConfiguration); 36 | 37 | /// Controls enabling the thermal monitoring support. 38 | CDI_GROUP_ENTRY(enable, openlcb::Uint8ConfigEntry, 39 | Min(0), Max(1), 40 | #if CONFIG_TEMPSENSOR_DISABLED 41 | Default(0), /* disabled */ 42 | #else 43 | Default(1), /* enabled */ 44 | #endif 45 | Name("Enable thermal monitoring"), 46 | Description("Enabling this option will allow the node to monitor an " 47 | "external temperature sensor and emit events when configured " 48 | "thresholds are breached."), 49 | MapValues("0No" 50 | "1Yes") 51 | ); 52 | 53 | /// This is the warning temperature in celsius. 54 | CDI_GROUP_ENTRY(temperature_warning, openlcb::Int8ConfigEntry, 55 | Default(CONFIG_THERMALMONITOR_WARNING), Min(0), Max(125), 56 | Name("Warning Temperature"), 57 | Description("Temperature (in celsius) to use for thermal warning " 58 | "threshold.")); 59 | 60 | /// This is the shutdown temperature in celsius. 61 | CDI_GROUP_ENTRY(temperature_shutdown, openlcb::Int8ConfigEntry, 62 | Default(CONFIG_THERMALMONITOR_SHUTDOWN), Min(0), Max(125), 63 | Name("Shutdown Temperature"), 64 | Description("Temperature (in celsius) to use for thermal shutdown " 65 | "threshold.")); 66 | 67 | /// This event will be produced when the temperature is above the warning 68 | /// temperature but below the shutdown temperature. 69 | CDI_GROUP_ENTRY(event_warning, openlcb::EventConfigEntry, // 70 | Name("Warning Temperature Exceeded"), 71 | Description("This event will be produced when the temperature has exceeded " 72 | "the warning temperature but is below the shutdown " 73 | "temperature.")); 74 | 75 | /// This event will be produced when the temperature is above the shutdown 76 | /// temperature. 77 | CDI_GROUP_ENTRY(event_shutdown, openlcb::EventConfigEntry, // 78 | Name("Shutdown Temperature Exceeded"), 79 | Description("This event will be produced when the temperature has exceeded " 80 | "the shutdown temperature or there is a failure in reading the " 81 | "temperature.")); 82 | 83 | CDI_GROUP_END(); 84 | 85 | } // namespace esp32s2io 86 | 87 | #endif // THERMAL_CONFIGURATION_HXX_ -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # Esp32 Command Station v2.0 TODO list 2 | 3 | ## Command Station TODO list 4 | 5 | ### Required for v2.0 6 | 7 | * [x] Adjust tasks to pin to specific cores: 8 | - WiFi: PRO_CPU 9 | - LwIP: APP_CPU 10 | - OpenMRN: PRO_CPU (inherit app_main) 11 | - Esp32WiFiManager: float priority 3 12 | - StatusLED: APP_CPU priority 3 13 | - HttpServer: Listener runs standalone, HttpServer leverages Esp32WiFiManager Executor. 14 | - TWAI: ISR APP_CPU, task float priority is one less than LwIP. 15 | - RMT: ISR PRO_CPU 16 | * [ ] DCC: ULP current sense / ACK. 17 | - [x] Implementation of ULP code to read ADC and wake main SoC when thresholds breached. 18 | - [x] Disable track when short occurs. 19 | - [x] Enable track when short has cleared. 20 | - [x] Send short/shutdown events for OPS. 21 | - [x] Shunt support 22 | * [x] DCC: ProgrammingTrackBackend support (UWT-100 dependency). 23 | * [x] Deps: Remove nlohmann_json dependency in favor of cJSON. 24 | * [ ] Docs: Add user guide and how to build guide under docs tree. 25 | * [ ] OpenLCB: Verify bootloader firmware update works as expected. 26 | * [ ] RailCom: Verify timing of cut-out and adjust timing delay counts. 27 | * [ ] RailCom: Verify incoming data stream with logic analyzer. 28 | * [ ] RailCom: Integrate RailCom hub with rest of stack (TrainSearch, Prog Backend, etc). 29 | * [x] TrainDB: reduce function types to: light, horn (momentary), bell, mute, coupler, other, other (momentary). 30 | * [x] TrainDB: Remove Marklin support. 31 | * [x] TrainDB: Enable editing via loco CDI. 32 | * [x] AccessoryDecoderDB: Verify all functionality. 33 | * [x] AccessoryDecoderDB: Directly consume OpenLCB events. 34 | * [x] AccessoryDecoderDB: Add name to decoder. 35 | * [x] TempSensor: Move ADC read into ULP. 36 | * [x] WebUI: Cross check against WebServer.cpp for uniformity in parameters/json. 37 | * [ ] WebUI: Test all endpoints. 38 | * [x] WebUI: Roster save via WS. 39 | * [x] WebUI: Expose FastClock configuration (non-realtime). 40 | * [x] FastClock: Re-add FastClock support. 41 | * [x] Build: Add automatic config selector for PCB, "Uno" form-factor with L298, etc. 42 | 43 | ### Nice to have for v2.0 44 | 45 | * Build: Improve robustness of gzip search. 46 | * RailCom: Migrate Esp32RailComDriver to use HAL APIs (portability work) 47 | * RailCom: Login packet support. 48 | * TrainDB: Configurable timeout for idle trains. 49 | * TrainDB: Customizable function label names. 50 | * TrainSearch: General code formatting / cleanup 51 | * TrainSearch: Move e-stop handling to this module rather than main. 52 | * WebServer: Document all endpoints and data formats (including WS) 53 | * WebUI: urldecode all field data from json. 54 | * WebUI: Add function name/label editing via web interface. 55 | * WebUI: Show remaining characters for various text fields. 56 | * WebUI: Filtering of accessories/locos. 57 | * WiThrottle support. 58 | * Build: IDF v5+ migrate from driver/timer.h to driver/gptimer.h 59 | 60 | ### Future planning 61 | 62 | * TrainDB: Expose via Memory Space? 63 | * AccessoryDecoderDB: Routes. 64 | * Import roster/routes/accessories from JMRI 65 | * Build: Migrate to IDF components rather than submodules? 66 | 67 | ## OpenMRNIDF TODO list 68 | 69 | ### Required for v2.0 70 | 71 | [x] Remove dedicated task from Esp32WiFiManager in favor of state flows. 72 | [ ] Verify OSSelectWakeup and TWAI is not using VFS sem after invalidation. 73 | 74 | ### Nice to have for v2.0 75 | 76 | * Further refinements in Esp32Gpio. 77 | 78 | ### Not required for v2.0 79 | 80 | * DCC: DCC-14 speed step support 81 | * Add option for inline translation in Esp32Ws2812 rather than on-demand translation. 82 | * Add support for more LED types in Esp32Ws2812. 83 | 84 | ## HttpServer TODO list 85 | 86 | * Expose HttpRequest::param(string name, string default) -------------------------------------------------------------------------------- /components/Config/include/pinmap-bts7960.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2022 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef HARDWARE_PINMAP_BTS7960_HXX_ 19 | #define HARDWARE_PINMAP_BTS7960_HXX_ 20 | 21 | #include "sdkconfig.h" 22 | 23 | #undef CONFIG_DCC_TRACK_SIGNAL_PIN 24 | #undef CONFIG_OPS_HBRIDGE_L298 25 | #undef CONFIG_OPS_HBRIDGE_LMD18200 26 | #undef CONFIG_OPS_HBRIDGE_DRV880X 27 | #undef CONFIG_OPS_HBRIDGE_DRV8873 28 | #undef CONFIG_OPS_HBRIDGE_DRV8873_5A 29 | #undef CONFIG_OPS_HBRIDGE_POLOLU 30 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_5A 31 | #undef CONFIG_OPS_HBRIDGE_BTS7960B_10A 32 | #undef CONFIG_RAILCOM_TRIGGER_PIN 33 | #undef CONFIG_RAILCOM_DATA_PIN 34 | #undef CONFIG_RAILCOM_DIRECTION_PIN 35 | #undef CONFIG_RAILCOM_SHORT_PIN 36 | #undef CONFIG_OLED_RESET_PIN 37 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_1 38 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_2 39 | #undef CONFIG_OPSTRACK_ADC_I2C_CHANNEL_3 40 | #undef CONFIG_PROG_TRACK_ENABLE_PIN 41 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_1 42 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_2 43 | #undef CONFIG_PROGTRACK_ADC_I2C_CHANNEL_3 44 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 45 | #undef CONFIG_RAILCOM_DATA_ENABLED 46 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_0 47 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_1 48 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_2 49 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_3 50 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_4 51 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_5 52 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_6 53 | #undef CONFIG_OPSTRACK_ADC_CHANNEL_7 54 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_0 55 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_1 56 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_2 57 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_3 58 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_4 59 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_5 60 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_6 61 | #undef CONFIG_PROGTRACK_ADC_CHANNEL_7 62 | #undef CONFIG_RAILCOM_CUT_OUT_ENABLED 63 | #undef CONFIG_RAILCOM_DATA_ENABLED 64 | #undef CONFIG_I2C_SCL_PIN 65 | #undef CONFIG_I2C_SDA_PIN 66 | 67 | #if CONFIG_ESP32CS_BTS7960B 68 | 69 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 70 | 71 | #define CONFIG_OPS_HBRIDGE_BTS7960B_5A 1 72 | 73 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 74 | 75 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 76 | #define CONFIG_PROG_TRACK_ENABLE_PIN -1 77 | 78 | #undef CONFIG_PROG_TRACK_ENABLED 79 | 80 | #elif CONFIG_ESP32CS_BTS7960B_X2 81 | 82 | #define CONFIG_DCC_TRACK_SIGNAL_PIN 19 83 | 84 | #define CONFIG_OPS_HBRIDGE_BTS7960B_5A 1 85 | 86 | #define CONFIG_PROG_HBRIDGE_BTS7960B_5A 1 87 | 88 | #define CONFIG_OPSTRACK_ADC_CHANNEL_0 1 89 | 90 | #define CONFIG_PROGTRACK_ADC_CHANNEL_3 1 91 | 92 | #define CONFIG_OPS_TRACK_ENABLE_PIN 25 93 | 94 | #define CONFIG_PROG_TRACK_ENABLE_PIN 23 95 | #endif // H-BRIDGE AUTO-ASSIGNMENT 96 | 97 | #define CONFIG_I2C_SCL_PIN 22 98 | 99 | #define CONFIG_I2C_SDA_PIN 21 100 | 101 | #endif // HARDWARE_PINMAP_BTS7960_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoHueBlend.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoHueBlend provides method objects that can be directly consumed by 3 | blend template functions in HslColor and HsbColor 4 | 5 | Written by Michael C. Miller. 6 | 7 | I invest time and resources providing this open source code, 8 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 9 | 10 | ------------------------------------------------------------------------- 11 | This file is part of the Makuna/NeoPixelBus library. 12 | 13 | NeoPixelBus is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Lesser General Public License as 15 | published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | NeoPixelBus is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | #pragma once 28 | 29 | class NeoHueBlendBase 30 | { 31 | protected: 32 | static float FixWrap(float value) 33 | { 34 | if (value < 0.0f) 35 | { 36 | value += 1.0f; 37 | } 38 | else if (value > 1.0f) 39 | { 40 | value -= 1.0f; 41 | } 42 | return value; 43 | } 44 | }; 45 | 46 | class NeoHueBlendShortestDistance : NeoHueBlendBase 47 | { 48 | public: 49 | static float HueBlend(float left, float right, float progress) 50 | { 51 | float delta = right - left; 52 | float base = left; 53 | if (delta > 0.5f) 54 | { 55 | base = right; 56 | delta = 1.0f - delta; 57 | progress = 1.0f - progress; 58 | } 59 | else if (delta < -0.5f) 60 | { 61 | delta = 1.0f + delta; 62 | } 63 | return FixWrap(base + (delta) * progress); 64 | }; 65 | }; 66 | 67 | class NeoHueBlendLongestDistance : NeoHueBlendBase 68 | { 69 | public: 70 | static float HueBlend(float left, float right, float progress) 71 | { 72 | float delta = right - left; 73 | float base = left; 74 | if (delta < 0.5f && delta >= 0.0f) 75 | { 76 | base = right; 77 | delta = 1.0f - delta; 78 | progress = 1.0f - progress; 79 | } 80 | else if (delta > -0.5f && delta < 0.0f) 81 | { 82 | delta = 1.0f + delta; 83 | } 84 | return FixWrap(base + delta * progress); 85 | }; 86 | }; 87 | 88 | class NeoHueBlendClockwiseDirection : NeoHueBlendBase 89 | { 90 | public: 91 | static float HueBlend(float left, float right, float progress) 92 | { 93 | float delta = right - left; 94 | float base = left; 95 | if (delta < 0.0f) 96 | { 97 | delta = 1.0f + delta; 98 | } 99 | 100 | return FixWrap(base + delta * progress); 101 | }; 102 | }; 103 | 104 | class NeoHueBlendCounterClockwiseDirection : NeoHueBlendBase 105 | { 106 | public: 107 | static float HueBlend(float left, float right, float progress) 108 | { 109 | float delta = right - left; 110 | float base = left; 111 | if (delta > 0.0f) 112 | { 113 | delta = delta - 1.0f; 114 | } 115 | 116 | return FixWrap(base + delta * progress); 117 | }; 118 | }; 119 | -------------------------------------------------------------------------------- /components/OpenMRNExtensions/src/locodb/LocoDatabase.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2014 Balazs Racz 3 | * SPDX-FileCopyrightText: 2020-2022 Mike Dunston (atanisoft) 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | #ifndef _LOCODB_LOCODATABASE_HXX_ 9 | #define _LOCODB_LOCODATABASE_HXX_ 10 | 11 | #include "locodb/Defs.hxx" 12 | #include "locodb/LocoDatabaseEntry.hxx" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace locodb 21 | { 22 | 23 | /// This class defines a common API for a Locomotive Database. This is used by 24 | /// the @ref TrainSearchProtocolServer and @ref LocoManager to lookup available 25 | /// locomotives. 26 | class LocoDatabase : public Singleton 27 | { 28 | public: 29 | /// @returns the number of traindb entries. The valid train IDs will then be 30 | /// 0 <= id < size(). 31 | virtual size_t size() = 0; 32 | 33 | /// Returns true if a train of a specific identifier is known to the traindb. 34 | /// @param train_id is the train identifier. Valid values: anything. 35 | /// Typical values: 0..NUM_TRAINS 36 | virtual bool is_valid_train(size_t train_id) = 0; 37 | 38 | /// Returns true if a train of a specific identifier is known to the traindb. 39 | /// @param train_id is the node id of the train being queried. 40 | virtual bool is_valid_train(openlcb::NodeID train_id) = 0; 41 | 42 | /// Returns true if a train of a specific identifier is known to the traindb. 43 | /// @param train_id is the node id of the train being queried. 44 | virtual int get_entry_offset(openlcb::NodeID train_id) = 0; 45 | 46 | /// Returns a train DB entry if the train ID is known, otherwise nullptr. The 47 | /// ownership of the entry is not transferred. 48 | /// @return @ref LocoDatabaseEntry for the train or null if not found. 49 | virtual std::shared_ptr get_entry( 50 | const std::string &name) = 0; 51 | 52 | /// Returns a train DB entry if the train ID is known, otherwise nullptr. The 53 | /// ownership of the entry is not transferred. 54 | /// @param train_id is the train identifier. 55 | /// @param done will be notified exactly once, either inline (if the answer 56 | /// is ready) or out of line (if it is not). 57 | /// @return @ref LocoDatabaseEntry for the train or null if not found. 58 | virtual std::shared_ptr get_entry(size_t train_id) = 0; 59 | 60 | /// Searches for an entry by the traction node ID. Returns nullptr if not 61 | /// found. 62 | /// @param traction_node_id node id of the train to search for. 63 | /// @param hint is a train_id that might be a match. 64 | /// @return @ref LocoDatabaseEntry for the train or null if not found. 65 | virtual std::shared_ptr get_entry( 66 | openlcb::NodeID traction_node_id, unsigned hint = 0) = 0; 67 | 68 | /// Inserts a given entry into the train database. 69 | /// @param address the locomotive address to create. 70 | /// @param mode the operating mode for the new locomotive. 71 | /// @returns the new train_id for the given entry. 72 | virtual size_t create_entry(uint16_t address, DriveMode mode) = 0; 73 | 74 | /// Removes a train from the database by it's identifier. 75 | /// @param train_id is the train identifier. Valid values: anything. 76 | /// Typical values: 0..NUM_TRAINS 77 | virtual void remove_entry(size_t train_id) = 0; 78 | 79 | /// Removes a train from the database that matches the specified criteria. 80 | /// @param address the locomotive address to remove. 81 | /// @param mode the operating mode for the locomotive to be removed. 82 | virtual void remove_entry(uint16_t address, DriveMode mode) = 0; 83 | }; 84 | 85 | } // namespace locodb 86 | 87 | #endif // _LOCODB_LOCODATABASE_HXX_ -------------------------------------------------------------------------------- /components/TrainManager/LazyInitTrainNode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020-2023 Mike Dunston (atanisoft) 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include "LazyInitTrainNode.hxx" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace trainmanager 16 | { 17 | 18 | using dcc::Dcc128Train; 19 | using dcc::Dcc28Train; 20 | using dcc::DccLongAddress; 21 | using dcc::DccShortAddress; 22 | 23 | using locodb::DriveMode; 24 | using locodb::drive_mode_to_address_type; 25 | 26 | using openlcb::DefaultTrainNode; 27 | using openlcb::NodeID; 28 | using openlcb::TractionDefs; 29 | using openlcb::TrainService; 30 | 31 | #ifndef NODE_LOG_LEVEL 32 | #ifdef LOCOMGR_NODE_LOGGING_LEVEL 33 | #define NODE_LOG_LEVEL LOCOMGR_NODE_LOGGING_LEVEL 34 | #else 35 | #define NODE_LOG_LEVEL VERBOSE 36 | #endif // LOCOMGR_NODE_LOGGING_LEVEL 37 | #endif // NODE_LOG_LEVEL 38 | 39 | LazyInitTrainNode::LazyInitTrainNode( 40 | TrainService *service, ssize_t offset, DriveMode mode, 41 | uint16_t address) 42 | : DefaultTrainNode(service, nullptr), offset_(offset), mode_(mode), 43 | addr_(address) 44 | { 45 | service->register_train(this); 46 | 47 | // If automatic idle is enabled for new train impls, call to create the 48 | // new train impl instance. 49 | if (config_trainmgr_automatically_create_train_impl() == CONSTANT_TRUE) 50 | { 51 | train(); 52 | } 53 | } 54 | 55 | LazyInitTrainNode::~LazyInitTrainNode() 56 | { 57 | service_->unregister_train(this); 58 | delete train_; 59 | } 60 | 61 | NodeID LazyInitTrainNode::node_id() 62 | { 63 | return TractionDefs::train_node_id_from_legacy( 64 | drive_mode_to_address_type(mode_, addr_), addr_); 65 | } 66 | 67 | uint16_t LazyInitTrainNode::address() 68 | { 69 | return addr_; 70 | } 71 | 72 | DriveMode LazyInitTrainNode::mode() 73 | { 74 | return mode_; 75 | } 76 | 77 | ssize_t LazyInitTrainNode::file_offset() 78 | { 79 | return offset_; 80 | } 81 | 82 | bool LazyInitTrainNode::is_allocated() 83 | { 84 | return train_ != nullptr; 85 | } 86 | 87 | openlcb::TrainImpl *LazyInitTrainNode::train() 88 | { 89 | if (train_ == nullptr) 90 | { 91 | switch (mode_) 92 | { 93 | case DriveMode::DCC_14: 94 | case DriveMode::DCC_14_LONG_ADDRESS: 95 | // TODO: DCC-14 not implemented in OpenMRN (yet) 96 | case DriveMode::DCC_28: 97 | case DriveMode::DCC_28_LONG_ADDRESS: 98 | { 99 | LOG(NODE_LOG_LEVEL, "[Train:%d] Creating new DCC-14/28 instance", 100 | addr_); 101 | if ((mode_ & DriveMode::DCC_LONG_ADDRESS) || 102 | addr_ >= DccShortAddress::ADDRESS_MAX) 103 | { 104 | train_ = new Dcc28Train(DccLongAddress(addr_)); 105 | } 106 | else 107 | { 108 | train_ = new Dcc28Train(DccShortAddress(addr_)); 109 | } 110 | break; 111 | } 112 | case DriveMode::DCC_128: 113 | case DriveMode::DCC_128_LONG_ADDRESS: 114 | { 115 | LOG(NODE_LOG_LEVEL, "[Train:%d] Creating new DCC-128 instance", 116 | addr_); 117 | if ((mode_ & DriveMode::DCC_LONG_ADDRESS) || 118 | addr_ >= DccShortAddress::ADDRESS_MAX) 119 | { 120 | train_ = new Dcc128Train(DccLongAddress(addr_)); 121 | } 122 | else 123 | { 124 | train_ = new Dcc128Train(DccShortAddress(addr_)); 125 | } 126 | break; 127 | } 128 | default: 129 | train_ = nullptr; 130 | LOG_ERROR("[Train:%d] Unhandled train drive mode: %d.", addr_, 131 | mode_); 132 | } 133 | } 134 | return train_; 135 | } 136 | 137 | } // namespace trainmanager -------------------------------------------------------------------------------- /components/StatusDisplay/include/StatusDisplay.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2017-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef STATUS_DISPLAY_HXX_ 19 | #define STATUS_DISPLAY_HXX_ 20 | 21 | #include "sdkconfig.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace openmrn_arduino 31 | { 32 | class Esp32WiFiManager; 33 | } 34 | 35 | namespace esp32cs 36 | { 37 | class NvsManager; 38 | 39 | class StatusDisplay : public StateFlowBase, 40 | public Singleton 41 | { 42 | public: 43 | StatusDisplay(Service *service, openmrn_arduino::Esp32WiFiManager *wifi, 44 | NvsManager *nvs); 45 | void clear(); 46 | void info(const std::string&, ...); 47 | void status(const std::string&, ...); 48 | void wifi(const std::string&, ...); 49 | void track_power(const std::string&, ...); 50 | private: 51 | STATE_FLOW_STATE(resetOLED); 52 | STATE_FLOW_STATE(init); 53 | STATE_FLOW_STATE(initOLED); 54 | STATE_FLOW_STATE(initLCD); 55 | STATE_FLOW_STATE(update); 56 | void renderOLED(uint8_t line); 57 | void renderLCD(uint8_t line); 58 | 59 | /// Cache of the text to display on the OLED/LCD 60 | std::string lines_[8]; 61 | bool lineChanged_[8]; 62 | 63 | uint8_t i2cAddr_; 64 | bool redraw_{true}; 65 | bool sh1106_{false}; 66 | StateFlowTimer timer_{this}; 67 | uint8_t regZero_{0}; 68 | uint8_t rotatingIndex_{0}; 69 | uint8_t updateCount_{0}; 70 | esp32cs::NvsManager *nvs_; 71 | openmrn_arduino::Esp32WiFiManager *wifi_; 72 | }; 73 | 74 | static constexpr TickType_t DISPLAY_I2C_TIMEOUT = 75 | pdMS_TO_TICKS(CONFIG_DISPLAY_I2C_TIMEOUT_MSEC); 76 | 77 | #define I2C_READ_REG(address, reg, data, data_size, status) \ 78 | { \ 79 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); \ 80 | i2c_master_start(cmd); \ 81 | i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true); \ 82 | i2c_master_write_byte(cmd, reg, true); \ 83 | i2c_master_start(cmd); \ 84 | i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_READ, true); \ 85 | if (data_size > 1) \ 86 | { \ 87 | i2c_master_read(cmd, &data, data_size - 1, I2C_MASTER_ACK); \ 88 | } \ 89 | i2c_master_read_byte(cmd, &data + data_size - 1, I2C_MASTER_NACK); \ 90 | i2c_master_stop(cmd); \ 91 | status = i2c_master_cmd_begin(I2C_NUM_0, cmd, DISPLAY_I2C_TIMEOUT); \ 92 | i2c_cmd_link_delete(cmd); \ 93 | } 94 | 95 | } // namespace esp32cs 96 | 97 | #endif // STATUS_DISPLAY_HXX_ -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/NeoRingTopology.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*------------------------------------------------------------------------- 4 | NeoRingTopology provides a mapping feature of a 2d polar cordinate to a 5 | linear 1d cordinate. 6 | It is used to map a series of concentric rings of NeoPixels to a index on 7 | the NeoPixelBus. 8 | 9 | Written by Michael C. Miller. 10 | 11 | I invest time and resources providing this open source code, 12 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 13 | 14 | ------------------------------------------------------------------------- 15 | This file is part of the Makuna/NeoPixelBus library. 16 | 17 | NeoPixelBus is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU Lesser General Public License as 19 | published by the Free Software Foundation, either version 3 of 20 | the License, or (at your option) any later version. 21 | 22 | NeoPixelBus is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU Lesser General Public License for more details. 26 | 27 | You should have received a copy of the GNU Lesser General Public 28 | License along with NeoPixel. If not, see 29 | . 30 | -------------------------------------------------------------------------*/ 31 | 32 | template class NeoRingTopology : protected T_LAYOUT 33 | { 34 | public: 35 | NeoRingTopology() 36 | { 37 | } 38 | 39 | uint16_t Map(uint8_t ring, uint16_t pixel) const 40 | { 41 | if (pixel >= getPixelCountAtRing(ring)) 42 | { 43 | return 0; // invalid ring and/or pixel argument, always return a valid value, the first one 44 | } 45 | 46 | return _map(ring, pixel); 47 | } 48 | 49 | uint16_t MapProbe(uint8_t ring, uint16_t pixel) const 50 | { 51 | if (pixel >= getPixelCountAtRing(ring)) 52 | { 53 | return getPixelCount(); // total count, out of bounds 54 | } 55 | 56 | return _map(ring, pixel); 57 | } 58 | 59 | uint16_t RingPixelShift(uint8_t ring, uint16_t pixel, int16_t shift) 60 | { 61 | int32_t ringPixel = pixel; 62 | ringPixel += shift; 63 | 64 | if (ringPixel < 0) 65 | { 66 | ringPixel = 0; 67 | } 68 | else 69 | { 70 | uint16_t count = getPixelCountAtRing(ring); 71 | if (ringPixel >= count) 72 | { 73 | ringPixel = count - 1; 74 | } 75 | } 76 | return ringPixel; 77 | } 78 | 79 | uint16_t RingPixelRotate(uint8_t ring, uint16_t pixel, int16_t rotate) 80 | { 81 | int32_t ringPixel = pixel; 82 | ringPixel += rotate; 83 | return ringPixel % getPixelCountAtRing(ring); 84 | } 85 | 86 | uint8_t getCountOfRings() const 87 | { 88 | return _ringCount() - 1; // minus one as the Rings includes the extra value 89 | } 90 | 91 | uint16_t getPixelCountAtRing(uint8_t ring) const 92 | { 93 | if (ring >= getCountOfRings()) 94 | { 95 | return 0; // invalid, no pixels 96 | } 97 | 98 | return T_LAYOUT::Rings[ring + 1] - T_LAYOUT::Rings[ring]; // using the extra value for count calc 99 | } 100 | 101 | uint16_t getPixelCount() const 102 | { 103 | return T_LAYOUT::Rings[_ringCount() - 1]; // the last entry is the total count 104 | } 105 | 106 | private: 107 | uint16_t _map(uint8_t ring, uint16_t pixel) const 108 | { 109 | return T_LAYOUT::Rings[ring] + pixel; 110 | } 111 | 112 | uint8_t _ringCount() const 113 | { 114 | return sizeof(T_LAYOUT::Rings) / sizeof(T_LAYOUT::Rings[0]); 115 | } 116 | }; 117 | -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/RgbColorBase.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | RgbColorBase provides a RGB color object common support 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #include "RgbColorBase.h" 28 | #include "RgbColor.h" 29 | #include "Rgb48Color.h" 30 | #include "HslColor.h" 31 | #include "HsbColor.h" 32 | 33 | float RgbColorBase::_CalcColor(float p, float q, float t) 34 | { 35 | if (t < 0.0f) 36 | t += 1.0f; 37 | if (t > 1.0f) 38 | t -= 1.0f; 39 | 40 | if (t < 1.0f / 6.0f) 41 | return p + (q - p) * 6.0f * t; 42 | 43 | if (t < 0.5f) 44 | return q; 45 | 46 | if (t < 2.0f / 3.0f) 47 | return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f); 48 | 49 | return p; 50 | } 51 | 52 | void RgbColorBase::_HslToRgb(const HslColor& color, float* r, float* g, float* b) 53 | { 54 | float h = color.H; 55 | float s = color.S; 56 | float l = color.L; 57 | 58 | 59 | if (color.S == 0.0f || color.L == 0.0f) 60 | { 61 | *r = *g = *b = l; // achromatic or black 62 | } 63 | else 64 | { 65 | float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); 66 | float p = 2.0f * l - q; 67 | *r = _CalcColor(p, q, h + 1.0f / 3.0f); 68 | *g = _CalcColor(p, q, h); 69 | *b = _CalcColor(p, q, h - 1.0f / 3.0f); 70 | } 71 | } 72 | 73 | void RgbColorBase::_HsbToRgb(const HsbColor& color, float* r, float* g, float* b) 74 | { 75 | float h = color.H; 76 | float s = color.S; 77 | float v = color.B; 78 | 79 | if (color.S == 0.0f) 80 | { 81 | *r = *g = *b = v; // achromatic or black 82 | } 83 | else 84 | { 85 | if (h < 0.0f) 86 | { 87 | h += 1.0f; 88 | } 89 | else if (h >= 1.0f) 90 | { 91 | h -= 1.0f; 92 | } 93 | h *= 6.0f; 94 | int i = (int)h; 95 | float f = h - i; 96 | float q = v * (1.0f - s * f); 97 | float p = v * (1.0f - s); 98 | float t = v * (1.0f - s * (1.0f - f)); 99 | switch (i) 100 | { 101 | case 0: 102 | *r = v; 103 | *g = t; 104 | *b = p; 105 | break; 106 | case 1: 107 | *r = q; 108 | *g = v; 109 | *b = p; 110 | break; 111 | case 2: 112 | *r = p; 113 | *g = v; 114 | *b = t; 115 | break; 116 | case 3: 117 | *r = p; 118 | *g = q; 119 | *b = v; 120 | break; 121 | case 4: 122 | *r = t; 123 | *g = p; 124 | *b = v; 125 | break; 126 | default: 127 | *r = v; 128 | *g = p; 129 | *b = q; 130 | break; 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /components/NeoPixelBus/src/internal/TwoWireBitBangImpleAvr.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). 3 | 4 | Written by Michael C. Miller. 5 | 6 | I invest time and resources providing this open source code, 7 | please support me by dontating (see https://github.com/Makuna/NeoPixelBus) 8 | 9 | ------------------------------------------------------------------------- 10 | This file is part of the Makuna/NeoPixelBus library. 11 | 12 | NeoPixelBus is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Lesser General Public License as 14 | published by the Free Software Foundation, either version 3 of 15 | the License, or (at your option) any later version. 16 | 17 | NeoPixelBus is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Lesser General Public License for more details. 21 | 22 | You should have received a copy of the GNU Lesser General Public 23 | License along with NeoPixel. If not, see 24 | . 25 | -------------------------------------------------------------------------*/ 26 | 27 | #pragma once 28 | 29 | 30 | class TwoWireBitBangImple 31 | { 32 | public: 33 | typedef NeoNoSettings SettingsObject; 34 | 35 | TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : 36 | _pinClock(pinClock), 37 | _pinData(pinData) 38 | { 39 | pinMode(pinClock, OUTPUT); 40 | pinMode(pinData, OUTPUT); 41 | 42 | _portClock = portOutputRegister(digitalPinToPort(_pinClock)); 43 | _pinMaskClock = digitalPinToBitMask(_pinClock); 44 | _portData = portOutputRegister(digitalPinToPort(_pinData)); 45 | _pinMaskData = digitalPinToBitMask(_pinData); 46 | } 47 | 48 | ~TwoWireBitBangImple() 49 | { 50 | pinMode(_pinClock, INPUT); 51 | pinMode(_pinData, INPUT); 52 | } 53 | 54 | void begin() 55 | { 56 | digitalWrite(_pinClock, LOW); 57 | digitalWrite(_pinData, LOW); 58 | } 59 | 60 | void beginTransaction() 61 | { 62 | 63 | } 64 | 65 | void endTransaction() 66 | { 67 | digitalWrite(_pinData, LOW); 68 | } 69 | 70 | void transmitByte(uint8_t data) 71 | { 72 | for (int bit = 7; bit >= 0; bit--) 73 | { 74 | // set data bit on pin 75 | // digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); 76 | if (data & 0x80) 77 | { 78 | *_portData |= _pinMaskData; 79 | } 80 | else 81 | { 82 | *_portData &= ~_pinMaskData; 83 | } 84 | 85 | // set clock high as data is ready 86 | // digitalWrite(_pinClock, HIGH); 87 | *_portClock |= _pinMaskClock; 88 | 89 | data <<= 1; 90 | 91 | // set clock low as data pin is changed 92 | // digitalWrite(_pinClock, LOW); 93 | *_portClock &= ~_pinMaskClock; 94 | } 95 | } 96 | 97 | void transmitBytes(const uint8_t* data, size_t dataSize) 98 | { 99 | const uint8_t* endData = data + dataSize; 100 | while (data < endData) 101 | { 102 | transmitByte(*data++); 103 | } 104 | } 105 | 106 | void applySettings(const SettingsObject& settings) 107 | { 108 | } 109 | 110 | private: 111 | const uint8_t _pinClock; // output pin number for clock line 112 | const uint8_t _pinData; // output pin number for data line 113 | 114 | volatile uint8_t* _portData; // Output PORT register 115 | uint8_t _pinMaskData; // Output PORT bitmask 116 | volatile uint8_t* _portClock; // Output PORT register 117 | uint8_t _pinMaskClock; // Output PORT bitmask 118 | }; -------------------------------------------------------------------------------- /components/Config/include/TrackOutputDescriptor.hxx: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | ESP32 COMMAND STATION 3 | 4 | COPYRIGHT (c) 2019-2021 Mike Dunston 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see http://www.gnu.org/licenses 16 | **********************************************************************/ 17 | 18 | #ifndef TRACK_OUTPUT_DESCRIPTOR_H_ 19 | #define TRACK_OUTPUT_DESCRIPTOR_H_ 20 | 21 | #include 22 | 23 | #include "hardware.hxx" 24 | 25 | namespace esp32cs 26 | { 27 | /// of possible keys and descriptive values to show to the user for 28 | /// the enable fields below. 29 | static constexpr const char *DCC_BOOLEAN_MAP = 30 | "0Disabled" 31 | "1Enabled"; 32 | /// DCC output behavior 33 | CDI_GROUP(AdvancedDCCConfig) 34 | CDI_GROUP_ENTRY(ops_preamble_bits, openlcb::Uint8ConfigEntry, 35 | Name("Operations Track Preamble bit count"), 36 | Min(11), Max(20), Default(16)); 37 | CDI_GROUP_ENTRY(prog_preamble_bits, openlcb::Uint8ConfigEntry, 38 | Name("Programming Track Preamble bit count"), 39 | Min(22), Max(50), Default(22)); 40 | CDI_GROUP_ENTRY(enable_railcom, openlcb::Uint8ConfigEntry, 41 | Name("Enable RailCom cut out generation"), 42 | Description( 43 | R"!^!(Enabling this option configures the Command Station to generate the 44 | RailCom cut-out. 45 | NOTE: this applys to both the OPS track output and the OpenLCB output (if 46 | enabled).)!^!"), 47 | Min(0), Max(1), 48 | Default(1), /* On */ 49 | MapValues(DCC_BOOLEAN_MAP)); 50 | CDI_GROUP_ENTRY(enable_railcom_receiver, openlcb::Uint8ConfigEntry, 51 | Name("Enable RailCom Receiver"), 52 | Description( 53 | R"!^!(Enabling this option configures the Command Station to interpret the 54 | data received during the RailCom cut-out. 55 | NOTE: this applys to both the OPS track output and the OpenLCB output (if 56 | enabled).)!^!"), 57 | Min(0), Max(1), 58 | Default(1), /* On */ 59 | MapValues(DCC_BOOLEAN_MAP)); 60 | CDI_GROUP_END(); 61 | 62 | /// Track output configuration 63 | CDI_GROUP(TrackOutputConfig); 64 | CDI_GROUP_ENTRY(ops_current_limit, openlcb::Uint32ConfigEntry, 65 | Name("Operations Track Current Limit (mA)"), 66 | Min(0), Max(CONFIG_OPS_HBRIDGE_MAX_MILLIAMPS), 67 | Default(CONFIG_OPS_HBRIDGE_LIMIT_MILLIAMPS)); 68 | CDI_GROUP_ENTRY(event_short, 69 | openlcb::EventConfigEntry, 70 | Name("Short Detected"), 71 | Description("This event will be produced when a short has " 72 | "been detected on the track output.")); 73 | CDI_GROUP_ENTRY(event_shutdown, 74 | openlcb::EventConfigEntry, 75 | Name("H-Bridge Shutdown"), 76 | Description("This event will be produced when the track " 77 | "output power has exceeded the safety threshold " 78 | "of the H-Bridge.")); 79 | CDI_GROUP_ENTRY(advanced, AdvancedDCCConfig, 80 | Name("Advanced Configuration Settings")); 81 | CDI_GROUP_END(); 82 | } // namespace esp32cs 83 | 84 | #endif // TRACK_OUTPUT_DESCRIPTOR_H_ --------------------------------------------------------------------------------