From d95096ded852429f04310c1546a57fd9f990b190 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Wed, 30 Nov 2022 10:11:27 +0800 Subject: [PATCH 01/54] Fixes STM32 compiler warning, and WIT/WIFI diags --- EXRAIL2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 96cb447..67cfce4 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -965,7 +965,7 @@ void RMFT2::delayMe(long delay) { delayStart=millis(); } -boolean RMFT2::setFlag(VPIN id,byte onMask, byte offMask) { +bool RMFT2::setFlag(VPIN id,byte onMask, byte offMask) { if (FLAGOVERFLOW(id)) return false; // Outside range limit byte f=flags[id]; f &= ~offMask; From 45b36c48cbfd4fbeda4b85cb946b33d38fb672f9 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Wed, 30 Nov 2022 13:16:04 +0100 Subject: [PATCH 02/54] be more strict about int vs char for the wifi diag --- WifiInterface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WifiInterface.cpp b/WifiInterface.cpp index 4d93eda..347d7ef 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -377,11 +377,12 @@ bool WifiInterface::checkForOK( const unsigned int timeout, const FSH * waitfor, char *locator = (char *)waitfor; DIAG(F("Wifi Check: [%E]"), waitfor); while ( millis() - startTime < timeout) { - while (wifiStream->available()) { - int ch = wifiStream->read(); + int nextchar; + while (wifiStream->available() && (nextchar = wifiStream->read()) > -1) { + char ch = (char)nextchar; if (echo) { if (escapeEcho) StringFormatter::printEscape( ch); /// THIS IS A DIAG IN DISGUISE - else USB_SERIAL.print((char)ch); + else USB_SERIAL.print(ch); } if (ch != GETFLASH(locator)) locator = (char *)waitfor; if (ch == GETFLASH(locator)) { From b671d70dfe87356feb65ec842efc7bc61fce3d22 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 4 Dec 2022 20:09:14 +0100 Subject: [PATCH 03/54] fix static IP addr --- EthernetInterface.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/EthernetInterface.cpp b/EthernetInterface.cpp index 8dd4d31..7c5d768 100644 --- a/EthernetInterface.cpp +++ b/EthernetInterface.cpp @@ -60,14 +60,14 @@ EthernetInterface::EthernetInterface() connected=false; #ifdef IP_ADDRESS - if (Ethernet.begin(mac, IP_ADDRESS) == 0) + Ethernet.begin(mac, IP_ADDRESS); #else if (Ethernet.begin(mac) == 0) - #endif { DIAG(F("Ethernet.begin FAILED")); return; } + #endif if (Ethernet.hardwareStatus() == EthernetNoHardware) { DIAG(F("Ethernet shield not found or W5100")); } @@ -135,7 +135,10 @@ bool EthernetInterface::checkLink() { if(!connected) { DIAG(F("Ethernet cable connected")); connected=true; - IPAddress ip = Ethernet.localIP(); // reassign the obtained ip address + #ifdef IP_ADDRESS + setLocalIP(IP_ADDRESS); // for static IP, set it again + #endif + IPAddress ip = Ethernet.localIP(); // look what IP was obtained (dynamic or static) server = new EthernetServer(IP_PORT); // Ethernet Server listening on default port IP_PORT server->begin(); LCD(4,F("IP: %d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); From cb1fc75077986ddffcff3379ea8d0b29ecb179da Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Sun, 4 Dec 2022 20:12:04 +0100 Subject: [PATCH 04/54] version --- GITHUB_SHA.h | 2 +- version.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index 12884d8..db58e06 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202211181919Z" +#define GITHUB_SHA "devel-202212041810Z" diff --git a/version.h b/version.h index 0244840..580bfdf 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,8 @@ #include "StringFormatter.h" -#define VERSION "4.2.6" +#define VERSION "4.2.7pre1" +// 4.2.7 FIX: Static IP addr // 4.2.6 FIX: Remove RAM thief // FIX: ADC port 8-15 fix // 4.2.5 Make GETFLASHW code more universal From 13368c319a506d5bf193445ec0c0ac4d5c676294 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Mon, 5 Dec 2022 15:52:23 +0100 Subject: [PATCH 05/54] reuse WiThrottle list entries --- GITHUB_SHA.h | 2 +- WiThrottle.cpp | 2 +- version.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GITHUB_SHA.h b/GITHUB_SHA.h index db58e06..d6c9738 100644 --- a/GITHUB_SHA.h +++ b/GITHUB_SHA.h @@ -1 +1 @@ -#define GITHUB_SHA "devel-202212041810Z" +#define GITHUB_SHA "devel-202212051450Z" diff --git a/WiThrottle.cpp b/WiThrottle.cpp index cfc4a74..019a515 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -378,7 +378,7 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ } //use first empty "slot" on this client's list, will be added to DCC registration list for (int loco=0;loco Date: Thu, 8 Dec 2022 14:21:01 +1000 Subject: [PATCH 06/54] Basic shell of device driver started --- IO_EXIOExpander.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++ myPinMap.example.h | 28 ++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 IO_EXIOExpander.h create mode 100644 myPinMap.example.h diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h new file mode 100644 index 0000000..c979176 --- /dev/null +++ b/IO_EXIOExpander.h @@ -0,0 +1,79 @@ +/* + * © 2021, Peter Cole. All rights reserved. + * + * This file is part of EX-CommandStation + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . +*/ + +/* +* The IO_EX-IOExpander.h device driver integrates with one or more EX-IOExpander devices. +* This device driver will configure the device and all I/O ports on startup, along with +* interacting with the device for all input/output duties. +*/ + +#ifndef IO_EX_IOEXPANDER_H +#define IO_EX_IOEXPANDER_H + +#include "IO_GPIOBase.h" +#include "FSH.h" + +#if __has_include ("myPinMap.h") + #include "myPinMap.h" +#else + #warning myPinMap.h not found. Using defaults from myPinMap.example.h + #include "myPinMap.example.h" +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * IODevice subclass for EX-IOExpander. + */ + +class EXIOExpander : public IODevice { +public: + static void create(VPIN vpin, int nPins, uint8_t i2cAddress) { + if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress); + } + +private: + // Constructor + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress) { + _firstVpin = firstVpin; + _nPins = nPins; + _i2cAddress = i2cAddress; + addDevice(this); + } + + void _begin() { + // Initialise EX-IOExander device + if (I2CManager.exists(_i2cAddress)) { +#ifdef DIAG_IO + _display(); +#endif + } else { + DIAG(F("EX-IOExpander device not found, I2C:%x"), _i2cAddress); + _deviceState = DEVSTATE_FAILED; + } + } + + void _display() override { + DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, + _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); + } + + uint8_t _i2cAddress; +}; + +#endif \ No newline at end of file diff --git a/myPinMap.example.h b/myPinMap.example.h new file mode 100644 index 0000000..3afebc1 --- /dev/null +++ b/myPinMap.example.h @@ -0,0 +1,28 @@ +/* + * © 2022 Peter Cole. All rights reserved. + * + * This is the example configuration file for the EX-IOExpander pin map file. + * + * It is highly recommended to copy this to "myPinMap.h" and modify to suit your specific + * requirements. + * + * NOTE: Modifications to this file will be overwritten by future software updates. + */ +#ifndef MYPINMAP_H +#define MYPINMAP_H + +///////////////////////////////////////////////////////////////////////////////////// +// Define the number of I/O pins to be configured on the EX-IOExpander device +// +#define NUMBER_OF_DIGITAL_PINS 12 +#define NUMBER_OF_ANALOGUE_PINS 4 + +///////////////////////////////////////////////////////////////////////////////////// +// Define the pin map +// +// You must define the correct number of pins as per NUMBER_OF_PINS above +// +static uint8_t digitalPinMap[NUMBER_OF_DIGITAL_PINS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; +static uint8_t analoguePinMap[NUMBER_OF_ANALOGUE_PINS] = {A0, A1, A2, A3}; + +#endif \ No newline at end of file From 2d27cb052d499fa23454239c567670f88bb9c98c Mon Sep 17 00:00:00 2001 From: peteGSX Date: Fri, 9 Dec 2022 14:41:48 +1000 Subject: [PATCH 07/54] Add registers --- IO_EXIOExpander.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index c979176..67cbb3d 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -74,6 +74,15 @@ private: } uint8_t _i2cAddress; + + enum { + REG_EXIOINIT = 0x00, // Flag to initialise setup procedure + REG_EXIODPIN = 0x01, // Flag we're sending digital pin assignments + REG_EXIOAPIN = 0x02, // Flag we're sending analogue pin assignments + REG_EXIORDY = 0x03, // Flag we have completed setup procedure, also for EX-IO to ACK setup + REG_EXIODDIR = 0x04, // Flag we're sending digital pin direction configuration + REG_EXIODPUP = 0x05, // Flag we're sending digital pin pullup configuration + }; }; #endif \ No newline at end of file From 06945bb114fcfe009de039c0fa5ee4215d347873 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sat, 10 Dec 2022 08:23:46 +1000 Subject: [PATCH 08/54] Try to add pin map classes --- EX-IOExpanderPinMaps.h | 38 +++++++++++++++++++++++++++ IO_EXIOExpander.h | 54 ++++++++++++++++++++++++++++++++------- myEX-IOExpander.example.h | 23 +++++++++++++++++ myPinMap.example.h | 28 -------------------- 4 files changed, 106 insertions(+), 37 deletions(-) create mode 100644 EX-IOExpanderPinMaps.h create mode 100644 myEX-IOExpander.example.h delete mode 100644 myPinMap.example.h diff --git a/EX-IOExpanderPinMaps.h b/EX-IOExpanderPinMaps.h new file mode 100644 index 0000000..b09dca3 --- /dev/null +++ b/EX-IOExpanderPinMaps.h @@ -0,0 +1,38 @@ +/* + * © 2022 Peter Cole + * + * This file is part of EX-CommandStation + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +/* +* This file defines default pin maps for the various architectures supported +* by default by EX-IOExpander. +* +* Custom user defined pinmaps should be defined in myEX-IOExpander.h. +* +* Any modifications to this file will be overwritten by future software updates. +*/ + +#define DEFAULT_NANO_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) +#define DEFAULT_NANO_ANALOGUE_PINMAP new EXIOAnaloguePinMap(6,A0,A1,A2,A3,A6,A7) + +#define DEFAULT_UNO F("DEFAULT_UNO"), \ + new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) \ + new EXIOAnaloguePinMap(4,A0,A1,A2,A3) + +#define DEFAULT_MEGA F("DEFAULT_MEGA"), \ + new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) \ + new EXIOAnaloguePinMap(4,A0,A1,A2,A3) \ No newline at end of file diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index c979176..052ad72 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -28,31 +28,65 @@ #include "IO_GPIOBase.h" #include "FSH.h" +#include "EX-IOExpanderPinMaps.h" -#if __has_include ("myPinMap.h") - #include "myPinMap.h" -#else - #warning myPinMap.h not found. Using defaults from myPinMap.example.h - #include "myPinMap.example.h" +// Include user defined pin maps in myEX-IOExpander if defined +#if __has_include ("myEX-IOExpander.h") + #include "myEX-IOExpander.h" #endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * EXIODigitalPinMap class for EX-IOExpander. + */ +class EXIODigitalPinMap { + public: + EXIODigitalPinMap(uint8_t numDigitalPins, uint8_t...); + EXIODigitalPinMap() = default; + + private: + EXIODigitalPinMap(uint8_t numDigitalPins, ...) { + _numDigitalPins = numDigitalPins; + uint8_t _digitalPinMap[_numDigitalPins]; + va_list _pinList; + va_start(_pinList, _numDigitalPins); + for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { + _digitalPinMap[pin] = va_arg(_pinList, int); + } + va_end(_pinList); + } + + uint8_t _numDigitalPins; +}; + +///////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * EXIOAnaloguePinMap class for EX-IOExpander. + */ +class EXIOAnaloguePinMap { + public: + EXIOAnaloguePinMap(uint8_t numAnaloguePins, ...); + EXIOAnaloguePinMap() = default; +}; + ///////////////////////////////////////////////////////////////////////////////////////////////////// /* * IODevice subclass for EX-IOExpander. */ - class EXIOExpander : public IODevice { public: - static void create(VPIN vpin, int nPins, uint8_t i2cAddress) { - if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress); + static void create(VPIN vpin, int nPins, uint8_t i2cAddress, EXIODigitalPinMap digitalPinMap, EXIOAnaloguePinMap analoguePinMap) { + if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress, digitalPinMap, analoguePinMap); } private: // Constructor - EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress) { + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, EXIODigitalPinMap digitalPinMap, EXIOAnaloguePinMap analoguePinMap) { _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; + _digitalPinMap = digitalPinMap; + _analoguePinMap = analoguePinMap; addDevice(this); } @@ -74,6 +108,8 @@ private: } uint8_t _i2cAddress; + EXIODigitalPinMap _digitalPinMap; + EXIOAnaloguePinMap _analoguePinMap; }; #endif \ No newline at end of file diff --git a/myEX-IOExpander.example.h b/myEX-IOExpander.example.h new file mode 100644 index 0000000..3402c92 --- /dev/null +++ b/myEX-IOExpander.example.h @@ -0,0 +1,23 @@ +/* + * © 2022 Peter Cole. All rights reserved. + * + * This is the example configuration file for a custom EX-IOExpander pin map file. + * + * It is highly recommended to copy this to "myEX-IOExpander.h" and modify to suit your specific + * requirements. + * + * If you are simply using a default definition for a defined microcontroller, then you don't + * need to use this file, and instead can use one of the existing definitions. + * + * Refer to https://dcc-ex.com for the full documentation. + * + * NOTE: Modifications to this file will be overwritten by future software updates. + */ +#ifndef MYEX_IOEXPANDER_H +#define MYEX_IOEXPANDER_H + +#define MY_CUSTOM_NANO F("MY_NANO_PINMAP"), \ + new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13) \ + new EXIOAnaloguePinMap(4,A0,A1,A2,A3) + +#endif \ No newline at end of file diff --git a/myPinMap.example.h b/myPinMap.example.h deleted file mode 100644 index 3afebc1..0000000 --- a/myPinMap.example.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * © 2022 Peter Cole. All rights reserved. - * - * This is the example configuration file for the EX-IOExpander pin map file. - * - * It is highly recommended to copy this to "myPinMap.h" and modify to suit your specific - * requirements. - * - * NOTE: Modifications to this file will be overwritten by future software updates. - */ -#ifndef MYPINMAP_H -#define MYPINMAP_H - -///////////////////////////////////////////////////////////////////////////////////// -// Define the number of I/O pins to be configured on the EX-IOExpander device -// -#define NUMBER_OF_DIGITAL_PINS 12 -#define NUMBER_OF_ANALOGUE_PINS 4 - -///////////////////////////////////////////////////////////////////////////////////// -// Define the pin map -// -// You must define the correct number of pins as per NUMBER_OF_PINS above -// -static uint8_t digitalPinMap[NUMBER_OF_DIGITAL_PINS] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; -static uint8_t analoguePinMap[NUMBER_OF_ANALOGUE_PINS] = {A0, A1, A2, A3}; - -#endif \ No newline at end of file From 91049560094987a6c8df2456ac1c6905a66817fa Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sat, 10 Dec 2022 08:28:20 +1000 Subject: [PATCH 09/54] Fix default pin maps --- EX-IOExpanderPinMaps.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/EX-IOExpanderPinMaps.h b/EX-IOExpanderPinMaps.h index b09dca3..b4fed55 100644 --- a/EX-IOExpanderPinMaps.h +++ b/EX-IOExpanderPinMaps.h @@ -29,10 +29,8 @@ #define DEFAULT_NANO_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) #define DEFAULT_NANO_ANALOGUE_PINMAP new EXIOAnaloguePinMap(6,A0,A1,A2,A3,A6,A7) -#define DEFAULT_UNO F("DEFAULT_UNO"), \ - new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) \ - new EXIOAnaloguePinMap(4,A0,A1,A2,A3) +#define DEFAULT_UNO_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) +#define DEFAULT_UNO_ANALOGUE_PINMAP new EXIOAnaloguePinMap(4,A0,A1,A2,A3) -#define DEFAULT_MEGA F("DEFAULT_MEGA"), \ - new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) \ - new EXIOAnaloguePinMap(4,A0,A1,A2,A3) \ No newline at end of file +#define DEFAULT_MEGA_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) +#define DEFAULT_MEGA_ANALOGUE_PINMAP new EXIOAnaloguePinMap(4,A0,A1,A2,A3) From 7bc043319704670a3abacc030327504bdef586a0 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sat, 10 Dec 2022 08:32:15 +1000 Subject: [PATCH 10/54] Add myHal.cpp example to driver --- IO_EXIOExpander.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 352711f..2157b79 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -21,6 +21,15 @@ * The IO_EX-IOExpander.h device driver integrates with one or more EX-IOExpander devices. * This device driver will configure the device and all I/O ports on startup, along with * interacting with the device for all input/output duties. +* +* To create EX-IOExpander devices, these are defined in myHal.cpp: +* +* #include "IO_EX-IOExpander.h" +* +* void halSetup() { +* // EXIOExpander::create(vpin, num_vpins, i2c_address, digital_pinmap, analogue_pinmap); +* EXIOExpander::create(800, 18, 0x90, DEFAULT_NANO_DIGITAL_PINMAP, DEFAULT_NANO_ANALOGUE_PINMAP); +} */ #ifndef IO_EX_IOEXPANDER_H From 1d5897d2d22973e50252e91065ec2479f608fbea Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sat, 10 Dec 2022 19:14:32 +1000 Subject: [PATCH 11/54] A bit lost --- EX-IOExpanderPinMaps.h | 13 ++++++----- IO_EXIOExpander.h | 48 ++++----------------------------------- myEX-IOExpander.example.h | 5 ++-- 3 files changed, 14 insertions(+), 52 deletions(-) diff --git a/EX-IOExpanderPinMaps.h b/EX-IOExpanderPinMaps.h index b4fed55..46d03a9 100644 --- a/EX-IOExpanderPinMaps.h +++ b/EX-IOExpanderPinMaps.h @@ -26,11 +26,12 @@ * Any modifications to this file will be overwritten by future software updates. */ -#define DEFAULT_NANO_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) -#define DEFAULT_NANO_ANALOGUE_PINMAP new EXIOAnaloguePinMap(6,A0,A1,A2,A3,A6,A7) +#define DEFAULT_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 +#define DEFAULT_NANO_ANALOGUE_PINMAP A0,A1,A2,A3,A6,A7 -#define DEFAULT_UNO_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) -#define DEFAULT_UNO_ANALOGUE_PINMAP new EXIOAnaloguePinMap(4,A0,A1,A2,A3) +#define DEFAULT_UNO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 +#define DEFAULT_UNO_ANALOGUE_PINMAP A0,A1,A2,A3 -#define DEFAULT_MEGA_DIGITAL_PINMAP new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13,A0,A1,A2,A3,A6,A7) -#define DEFAULT_MEGA_ANALOGUE_PINMAP new EXIOAnaloguePinMap(4,A0,A1,A2,A3) +#define DEFAULT_MEGA_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,26,27,28,29, \ + 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49 +#define DEFAULT_MEGA_ANALOGUE_PINMAP A0,A1,A2,A3,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15 diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 2157b79..0521ac7 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -27,8 +27,8 @@ * #include "IO_EX-IOExpander.h" * * void halSetup() { -* // EXIOExpander::create(vpin, num_vpins, i2c_address, digital_pinmap, analogue_pinmap); -* EXIOExpander::create(800, 18, 0x90, DEFAULT_NANO_DIGITAL_PINMAP, DEFAULT_NANO_ANALOGUE_PINMAP); +* // EXIOExpander::create(vpin, num_vpins, i2c_address); +* EXIOExpander::create(800, 18, 0x90); } */ @@ -44,58 +44,22 @@ #include "myEX-IOExpander.h" #endif -///////////////////////////////////////////////////////////////////////////////////////////////////// -/* - * EXIODigitalPinMap class for EX-IOExpander. - */ -class EXIODigitalPinMap { - public: - EXIODigitalPinMap(uint8_t numDigitalPins, uint8_t...); - EXIODigitalPinMap() = default; - - private: - EXIODigitalPinMap(uint8_t numDigitalPins, ...) { - _numDigitalPins = numDigitalPins; - uint8_t _digitalPinMap[_numDigitalPins]; - va_list _pinList; - va_start(_pinList, _numDigitalPins); - for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { - _digitalPinMap[pin] = va_arg(_pinList, int); - } - va_end(_pinList); - } - - uint8_t _numDigitalPins; -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////// -/* - * EXIOAnaloguePinMap class for EX-IOExpander. - */ -class EXIOAnaloguePinMap { - public: - EXIOAnaloguePinMap(uint8_t numAnaloguePins, ...); - EXIOAnaloguePinMap() = default; -}; - ///////////////////////////////////////////////////////////////////////////////////////////////////// /* * IODevice subclass for EX-IOExpander. */ class EXIOExpander : public IODevice { public: - static void create(VPIN vpin, int nPins, uint8_t i2cAddress, EXIODigitalPinMap digitalPinMap, EXIOAnaloguePinMap analoguePinMap) { - if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress, digitalPinMap, analoguePinMap); + static void create(VPIN vpin, int nPins, uint8_t i2cAddress) { + if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress); } private: // Constructor - EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, EXIODigitalPinMap digitalPinMap, EXIOAnaloguePinMap analoguePinMap) { + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress) { _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; - _digitalPinMap = digitalPinMap; - _analoguePinMap = analoguePinMap; addDevice(this); } @@ -117,8 +81,6 @@ private: } uint8_t _i2cAddress; - EXIODigitalPinMap _digitalPinMap; - EXIOAnaloguePinMap _analoguePinMap; enum { REG_EXIOINIT = 0x00, // Flag to initialise setup procedure diff --git a/myEX-IOExpander.example.h b/myEX-IOExpander.example.h index 3402c92..94e378e 100644 --- a/myEX-IOExpander.example.h +++ b/myEX-IOExpander.example.h @@ -16,8 +16,7 @@ #ifndef MYEX_IOEXPANDER_H #define MYEX_IOEXPANDER_H -#define MY_CUSTOM_NANO F("MY_NANO_PINMAP"), \ - new EXIODigitalPinMap(12,2,3,4,5,6,7,8,9,10,11,12,13) \ - new EXIOAnaloguePinMap(4,A0,A1,A2,A3) +#define MY_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 +#define MY_NANO_ANALOGUE_PINMAP A0,A1,A2,A3 #endif \ No newline at end of file From cb9a8bb7a66a14fb67f707b9c1333936e7a9e438 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 11 Dec 2022 10:22:48 +1000 Subject: [PATCH 12/54] Getting somewhere --- EX-IOExpanderPins.h | 46 +++++++++++++++++++++++++++++++++++++++++++++ IO_EXIOExpander.h | 36 +++++++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 EX-IOExpanderPins.h diff --git a/EX-IOExpanderPins.h b/EX-IOExpanderPins.h new file mode 100644 index 0000000..fa32873 --- /dev/null +++ b/EX-IOExpanderPins.h @@ -0,0 +1,46 @@ +/* + * © 2022 Peter Cole + * + * This file is part of EX-CommandStation + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ + +/* +* This file defines default pin maps for the various architectures supported +* by default by EX-IOExpander. +* +* Custom user defined pinmaps should be defined in myEX-IOExpander.h. +* +* Any modifications to this file will be overwritten by future software updates. +*/ + +// #define DEFAULT_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 +// #define DEFAULT_NANO_ANALOGUE_PINMAP A0,A1,A2,A3,A6,A7 + +#define EXIO_UNO_DIGITAL_PINS 12 +#define EXIO_UNO_ANALOGUE_PINS 4 + +#define EXIO_NANO_DIGITAL_PINS 12 +#define EXIO_NANO_ANALOGUE_PINS 6 + +#define EXIO_MEGA_DIGITAL_PINS 46 +#define EXIO_MEGA_ANALOGUE_PINS 16 + +// #define EXIO_UNO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 +// #define EXIO_UNO_ANALOGUE_PINMAP A0,A1,A2,A3 + +// #define DEFAULT_MEGA_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,26,27,28,29, \ +// 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49 +// #define DEFAULT_MEGA_ANALOGUE_PINMAP A0,A1,A2,A3,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15 diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 0521ac7..efd09cd 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -37,7 +37,7 @@ #include "IO_GPIOBase.h" #include "FSH.h" -#include "EX-IOExpanderPinMaps.h" +#include "EX-IOExpanderPins.h" // Include user defined pin maps in myEX-IOExpander if defined #if __has_include ("myEX-IOExpander.h") @@ -50,16 +50,18 @@ */ class EXIOExpander : public IODevice { public: - static void create(VPIN vpin, int nPins, uint8_t i2cAddress) { - if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress); + static void create(VPIN vpin, int nPins, uint8_t i2cAddress, uint8_t numDigitalPins, uint8_t numAnaloguePins) { + if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress, numDigitalPins, numAnaloguePins); } private: // Constructor - EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress) { + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, uint8_t numDigitalPins, uint8_t numAnaloguePins) { _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; + _numDigitalPins = numDigitalPins; + _numAnaloguePins = numAnaloguePins; addDevice(this); } @@ -69,18 +71,44 @@ private: #ifdef DIAG_IO _display(); #endif + _setupDevice(); } else { DIAG(F("EX-IOExpander device not found, I2C:%x"), _i2cAddress); _deviceState = DEVSTATE_FAILED; } } + void _setupDevice() { + // Send digital and analogue pin counts + I2CManager.write(_i2cAddress, 3, REG_EXIOINIT, _numDigitalPins, _numAnaloguePins); + // Enable digital ports + _digitalPinBytes = (_numDigitalPins + 7) / 8; + uint8_t enableDigitalPins[_digitalPinBytes]; + for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { + int pinByte = ((pin + 7) / 8); + bitSet(enableDigitalPins[pinByte], (pin - (pinByte * 8))); + } + I2CManager.write(_i2cAddress, _digitalPinBytes + 1, REG_EXIODPIN, enableDigitalPins); + // Enable analogue ports + _analoguePinBytes = (_numAnaloguePins + 7) / 8; + uint8_t enableAnaloguePins[_analoguePinBytes]; + for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { + int pinByte = ((pin + 7) / 8); + bitSet(enableAnaloguePins[pinByte], (pin - (pinByte * 8))); + } + I2CManager.write(_i2cAddress, _analoguePinBytes + 1, REG_EXIOAPIN, enableAnaloguePins); + } + void _display() override { DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); } uint8_t _i2cAddress; + uint8_t _numDigitalPins; + uint8_t _numAnaloguePins; + int _digitalPinBytes; + int _analoguePinBytes; enum { REG_EXIOINIT = 0x00, // Flag to initialise setup procedure From 9699a44081d8972776cd61ebf2b662d9c9dbf015 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 11 Dec 2022 10:25:29 +1000 Subject: [PATCH 13/54] Rename pin file --- EX-IOExpanderPinMaps.h | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 EX-IOExpanderPinMaps.h diff --git a/EX-IOExpanderPinMaps.h b/EX-IOExpanderPinMaps.h deleted file mode 100644 index 46d03a9..0000000 --- a/EX-IOExpanderPinMaps.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * © 2022 Peter Cole - * - * This file is part of EX-CommandStation - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * It is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CommandStation. If not, see . - */ - -/* -* This file defines default pin maps for the various architectures supported -* by default by EX-IOExpander. -* -* Custom user defined pinmaps should be defined in myEX-IOExpander.h. -* -* Any modifications to this file will be overwritten by future software updates. -*/ - -#define DEFAULT_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 -#define DEFAULT_NANO_ANALOGUE_PINMAP A0,A1,A2,A3,A6,A7 - -#define DEFAULT_UNO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 -#define DEFAULT_UNO_ANALOGUE_PINMAP A0,A1,A2,A3 - -#define DEFAULT_MEGA_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,26,27,28,29, \ - 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49 -#define DEFAULT_MEGA_ANALOGUE_PINMAP A0,A1,A2,A3,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15 From 785b515f9ec3c340604883fa3c30fd9331b955b5 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 11 Dec 2022 19:44:42 +1000 Subject: [PATCH 14/54] Bug fixes, update registers --- EX-IOExpanderPins.h | 14 +------------- IO_EXIOExpander.h | 34 ++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/EX-IOExpanderPins.h b/EX-IOExpanderPins.h index fa32873..cbb726f 100644 --- a/EX-IOExpanderPins.h +++ b/EX-IOExpanderPins.h @@ -18,17 +18,12 @@ */ /* -* This file defines default pin maps for the various architectures supported +* This file defines default pin numbers for the various architectures supported * by default by EX-IOExpander. * -* Custom user defined pinmaps should be defined in myEX-IOExpander.h. -* * Any modifications to this file will be overwritten by future software updates. */ -// #define DEFAULT_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 -// #define DEFAULT_NANO_ANALOGUE_PINMAP A0,A1,A2,A3,A6,A7 - #define EXIO_UNO_DIGITAL_PINS 12 #define EXIO_UNO_ANALOGUE_PINS 4 @@ -37,10 +32,3 @@ #define EXIO_MEGA_DIGITAL_PINS 46 #define EXIO_MEGA_ANALOGUE_PINS 16 - -// #define EXIO_UNO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 -// #define EXIO_UNO_ANALOGUE_PINMAP A0,A1,A2,A3 - -// #define DEFAULT_MEGA_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,22,23,24,25,26,27,28,29, \ -// 30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49 -// #define DEFAULT_MEGA_ANALOGUE_PINMAP A0,A1,A2,A3,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15 diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index efd09cd..ca2bf10 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -84,19 +84,25 @@ private: // Enable digital ports _digitalPinBytes = (_numDigitalPins + 7) / 8; uint8_t enableDigitalPins[_digitalPinBytes]; - for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { - int pinByte = ((pin + 7) / 8); - bitSet(enableDigitalPins[pinByte], (pin - (pinByte * 8))); + for (uint8_t byte = 0; byte < _digitalPinBytes; byte++) { + enableDigitalPins[byte] = 0; } - I2CManager.write(_i2cAddress, _digitalPinBytes + 1, REG_EXIODPIN, enableDigitalPins); + for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { + int pinByte = pin / 8; + bitSet(enableDigitalPins[pinByte], pin - pinByte * 8); + } + I2CManager.write(_i2cAddress, _digitalPinBytes + 1, REG_EXIODPIN, *enableDigitalPins); // Enable analogue ports _analoguePinBytes = (_numAnaloguePins + 7) / 8; uint8_t enableAnaloguePins[_analoguePinBytes]; - for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { - int pinByte = ((pin + 7) / 8); - bitSet(enableAnaloguePins[pinByte], (pin - (pinByte * 8))); + for (uint8_t byte = 0; byte < _analoguePinBytes; byte++) { + enableAnaloguePins[byte] = 0; } - I2CManager.write(_i2cAddress, _analoguePinBytes + 1, REG_EXIOAPIN, enableAnaloguePins); + for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { + int pinByte = pin / 8; + bitSet(enableAnaloguePins[pinByte], pin - pinByte * 8); + } + I2CManager.write(_i2cAddress, _analoguePinBytes + 1, REG_EXIOAPIN, *enableAnaloguePins); } void _display() override { @@ -111,12 +117,12 @@ private: int _analoguePinBytes; enum { - REG_EXIOINIT = 0x00, // Flag to initialise setup procedure - REG_EXIODPIN = 0x01, // Flag we're sending digital pin assignments - REG_EXIOAPIN = 0x02, // Flag we're sending analogue pin assignments - REG_EXIORDY = 0x03, // Flag we have completed setup procedure, also for EX-IO to ACK setup - REG_EXIODDIR = 0x04, // Flag we're sending digital pin direction configuration - REG_EXIODPUP = 0x05, // Flag we're sending digital pin pullup configuration + REG_EXIOINIT = 0xE0, // Flag to initialise setup procedure + REG_EXIODPIN = 0xE1, // Flag we're sending digital pin assignments + REG_EXIOAPIN = 0xE2, // Flag we're sending analogue pin assignments + REG_EXIORDY = 0xE3, // Flag we have completed setup procedure, also for EX-IO to ACK setup + REG_EXIODDIR = 0xE4, // Flag we're sending digital pin direction configuration + REG_EXIODPUP = 0xE5, // Flag we're sending digital pin pullup configuration }; }; From 3862f7250dfcf4bee139ed5e511c90bcc27bf564 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 12 Dec 2022 19:54:20 +1000 Subject: [PATCH 15/54] Fix bugs, learn I2CManager --- IO_EXIOExpander.h | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index ca2bf10..1c2c570 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -35,7 +35,9 @@ #ifndef IO_EX_IOEXPANDER_H #define IO_EX_IOEXPANDER_H -#include "IO_GPIOBase.h" +#include "IODevice.h" +#include "I2CManager.h" +#include "DIAG.h" #include "FSH.h" #include "EX-IOExpanderPins.h" @@ -82,27 +84,29 @@ private: // Send digital and analogue pin counts I2CManager.write(_i2cAddress, 3, REG_EXIOINIT, _numDigitalPins, _numAnaloguePins); // Enable digital ports - _digitalPinBytes = (_numDigitalPins + 7) / 8; - uint8_t enableDigitalPins[_digitalPinBytes]; - for (uint8_t byte = 0; byte < _digitalPinBytes; byte++) { - enableDigitalPins[byte] = 0; + _digitalPinBytes = (_numDigitalPins + 7) / 8 + 1; + uint8_t _enableDigitalPins[_digitalPinBytes]; + _enableDigitalPins[0] = REG_EXIODPIN; + for (uint8_t byte = 1; byte < _digitalPinBytes; byte++) { + _enableDigitalPins[byte] = 0; } for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { int pinByte = pin / 8; - bitSet(enableDigitalPins[pinByte], pin - pinByte * 8); + bitSet(_enableDigitalPins[pinByte + 1], pin - pinByte * 8); } - I2CManager.write(_i2cAddress, _digitalPinBytes + 1, REG_EXIODPIN, *enableDigitalPins); + I2CManager.write(_i2cAddress, _enableDigitalPins, _digitalPinBytes, &_i2crb); // Enable analogue ports - _analoguePinBytes = (_numAnaloguePins + 7) / 8; - uint8_t enableAnaloguePins[_analoguePinBytes]; - for (uint8_t byte = 0; byte < _analoguePinBytes; byte++) { - enableAnaloguePins[byte] = 0; + _analoguePinBytes = (_numAnaloguePins + 7) / 8 + 1; + uint8_t _enableAnaloguePins[_analoguePinBytes]; + _enableAnaloguePins[0] = REG_EXIOAPIN; + for (uint8_t byte = 1; byte < _analoguePinBytes; byte++) { + _enableAnaloguePins[byte] = 0; } for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { int pinByte = pin / 8; - bitSet(enableAnaloguePins[pinByte], pin - pinByte * 8); + bitSet(_enableAnaloguePins[pinByte + 1], pin - pinByte * 8); } - I2CManager.write(_i2cAddress, _analoguePinBytes + 1, REG_EXIOAPIN, *enableAnaloguePins); + I2CManager.write(_i2cAddress, _enableAnaloguePins, _analoguePinBytes, &_i2crb); } void _display() override { @@ -115,6 +119,7 @@ private: uint8_t _numAnaloguePins; int _digitalPinBytes; int _analoguePinBytes; + I2CRB _i2crb; enum { REG_EXIOINIT = 0xE0, // Flag to initialise setup procedure From 8ecb408da7de74885d86bd6e2170e2a681dfaf97 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 13 Dec 2022 19:51:41 +1000 Subject: [PATCH 16/54] Update I2C address, fix bug setting analogue pins --- IO_EXIOExpander.h | 92 +++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 1c2c570..2331715 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -82,31 +82,58 @@ private: void _setupDevice() { // Send digital and analogue pin counts - I2CManager.write(_i2cAddress, 3, REG_EXIOINIT, _numDigitalPins, _numAnaloguePins); - // Enable digital ports - _digitalPinBytes = (_numDigitalPins + 7) / 8 + 1; - uint8_t _enableDigitalPins[_digitalPinBytes]; - _enableDigitalPins[0] = REG_EXIODPIN; - for (uint8_t byte = 1; byte < _digitalPinBytes; byte++) { - _enableDigitalPins[byte] = 0; + uint8_t _setupBuffer[3] = {EXIOINIT, _numDigitalPins, _numAnaloguePins}; + // I2CManager.write(_i2cAddress, 3, EXIOINIT, _numDigitalPins, _numAnaloguePins); + I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); + _activity = EXIODPIN; + } + + void _loop(unsigned long currentMicros) override { + if (_i2crb.status == I2C_STATUS_PENDING) return; + if (_i2crb.status == I2C_STATUS_OK) { + switch(_activity) { + case EXIODPIN: + // Enable digital ports + _digitalPinBytes = (_numDigitalPins + 7) / 8 + 1; + // uint8_t _enableDigitalPins[_digitalPinBytes]; + // _enableDigitalPins[0] = EXIODPIN; + _digitalOutBuffer[0] = EXIODPIN; + for (uint8_t byte = 1; byte < _digitalPinBytes; byte++) { + // _enableDigitalPins[byte] = 0; + _digitalOutBuffer[byte] = 0; + } + for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { + int pinByte = pin / 8; + // bitSet(_enableDigitalPins[pinByte + 1], pin - pinByte * 8); + bitSet(_digitalOutBuffer[pinByte + 1], pin - pinByte * 8); + } + // I2CManager.write(_i2cAddress, _enableDigitalPins, _digitalPinBytes, &_i2crb); + I2CManager.write(_i2cAddress, _digitalOutBuffer, _digitalPinBytes, &_i2crb); + _activity = EXIOAPIN; + break; + case EXIOAPIN: + // Enable analogue ports + _analoguePinBytes = (_numAnaloguePins + 7) / 8 + 1; + // uint8_t _enableAnaloguePins[_analoguePinBytes]; + // _enableAnaloguePins[0] = EXIOAPIN; + _analogueOutBuffer[0] = EXIOAPIN; + for (uint8_t byte = 1; byte < _analoguePinBytes; byte++) { + // _enableAnaloguePins[byte] = 0; + _analogueOutBuffer[byte] = 0; + } + for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { + int pinByte = pin / 8; + // bitSet(_enableAnaloguePins[pinByte + 1], pin - pinByte * 8); + bitSet(_analogueOutBuffer[pinByte + 1], pin - pinByte * 8); + } + // I2CManager.write(_i2cAddress, _enableAnaloguePins, _analoguePinBytes, &_i2crb); + I2CManager.write(_i2cAddress, _analogueOutBuffer, _analoguePinBytes, &_i2crb); + _activity = EXIORDY; + break; + default: + break; + } } - for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { - int pinByte = pin / 8; - bitSet(_enableDigitalPins[pinByte + 1], pin - pinByte * 8); - } - I2CManager.write(_i2cAddress, _enableDigitalPins, _digitalPinBytes, &_i2crb); - // Enable analogue ports - _analoguePinBytes = (_numAnaloguePins + 7) / 8 + 1; - uint8_t _enableAnaloguePins[_analoguePinBytes]; - _enableAnaloguePins[0] = REG_EXIOAPIN; - for (uint8_t byte = 1; byte < _analoguePinBytes; byte++) { - _enableAnaloguePins[byte] = 0; - } - for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { - int pinByte = pin / 8; - bitSet(_enableAnaloguePins[pinByte + 1], pin - pinByte * 8); - } - I2CManager.write(_i2cAddress, _enableAnaloguePins, _analoguePinBytes, &_i2crb); } void _display() override { @@ -119,15 +146,20 @@ private: uint8_t _numAnaloguePins; int _digitalPinBytes; int _analoguePinBytes; + uint8_t _digitalOutBuffer[EXIO_NANO_DIGITAL_PINS + 1]; + uint8_t _digitalInBufer[EXIO_NANO_DIGITAL_PINS]; + uint8_t _analogueOutBuffer[EXIO_NANO_ANALOGUE_PINS + 1]; + uint8_t _analogueInBuffer[EXIO_NANO_ANALOGUE_PINS]; + uint8_t _activity; I2CRB _i2crb; enum { - REG_EXIOINIT = 0xE0, // Flag to initialise setup procedure - REG_EXIODPIN = 0xE1, // Flag we're sending digital pin assignments - REG_EXIOAPIN = 0xE2, // Flag we're sending analogue pin assignments - REG_EXIORDY = 0xE3, // Flag we have completed setup procedure, also for EX-IO to ACK setup - REG_EXIODDIR = 0xE4, // Flag we're sending digital pin direction configuration - REG_EXIODPUP = 0xE5, // Flag we're sending digital pin pullup configuration + EXIOINIT = 0xE0, // Flag to initialise setup procedure + EXIODPIN = 0xE1, // Flag we're sending digital pin assignments + EXIOAPIN = 0xE2, // Flag we're sending analogue pin assignments + EXIORDY = 0xE3, // Flag we have completed setup procedure, also for EX-IO to ACK setup + EXIODDIR = 0xE4, // Flag we're sending digital pin direction configuration + EXIODPUP = 0xE5, // Flag we're sending digital pin pullup configuration }; }; From ad294ea17e0d5428fa786926850a0dae99330f29 Mon Sep 17 00:00:00 2001 From: Harald Barth Date: Tue, 13 Dec 2022 15:29:20 +0100 Subject: [PATCH 17/54] typo --- MotorDrivers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MotorDrivers.h b/MotorDrivers.h index 328d5e6..c066052 100644 --- a/MotorDrivers.h +++ b/MotorDrivers.h @@ -182,7 +182,7 @@ #define STACKED_MOTOR_SHIELD F("STACKED_MOTOR_SHIELD"),\ new MotorDriver( 3, 12, UNUSED_PIN, 9, A0, 2.99, 1500, UNUSED_PIN), \ new MotorDriver(11, 13, UNUSED_PIN, 8, A1, 2.99, 1500, UNUSED_PIN), \ - new MotorDriver( 2, 10, UNUSED_PIN, 7, A3, 2.99, 1500, UNUSED_PIN), \ - new MotorDriver( 5, 4, UNUSED_PIN, 6, A4, 2.99, 1500, UNUSED_PIN) + new MotorDriver( 2, 10, UNUSED_PIN, 7, A4, 2.99, 1500, UNUSED_PIN), \ + new MotorDriver( 5, 4, UNUSED_PIN, 6, A5, 2.99, 1500, UNUSED_PIN) // #endif From 75f1a8f43a9187f0d09a7ad6daa3a265074c5428 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Wed, 14 Dec 2022 07:49:09 +1000 Subject: [PATCH 18/54] More bugs to fix --- IO_EXIOExpander.h | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 2331715..f3cbfbe 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -27,8 +27,8 @@ * #include "IO_EX-IOExpander.h" * * void halSetup() { -* // EXIOExpander::create(vpin, num_vpins, i2c_address); -* EXIOExpander::create(800, 18, 0x90); +* // EXIOExpander::create(vpin, num_vpins, i2c_address, digitalPinCount, analoguePinCount); +* EXIOExpander::create(800, 18, 0x90, 12, 6); } */ @@ -69,64 +69,56 @@ private: void _begin() { // Initialise EX-IOExander device + uint8_t _check = I2CManager.checkAddress(_i2cAddress); + DIAG(F("I2C status check: %d"), _check); if (I2CManager.exists(_i2cAddress)) { + _activity = EXIOINIT; #ifdef DIAG_IO _display(); #endif - _setupDevice(); } else { - DIAG(F("EX-IOExpander device not found, I2C:%x"), _i2cAddress); + DIAG(F("EX-IOExpander device not found, I2C:x%x"), _i2cAddress); _deviceState = DEVSTATE_FAILED; } } - void _setupDevice() { - // Send digital and analogue pin counts - uint8_t _setupBuffer[3] = {EXIOINIT, _numDigitalPins, _numAnaloguePins}; - // I2CManager.write(_i2cAddress, 3, EXIOINIT, _numDigitalPins, _numAnaloguePins); - I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); - _activity = EXIODPIN; - } - void _loop(unsigned long currentMicros) override { if (_i2crb.status == I2C_STATUS_PENDING) return; if (_i2crb.status == I2C_STATUS_OK) { switch(_activity) { + case EXIOINIT: + // Send digital and analogue pin counts + _setupBuffer[0] = EXIOINIT; + _setupBuffer[1] = _numDigitalPins; + _setupBuffer[2] = _numAnaloguePins; + I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); + _activity = EXIODPIN; + break; case EXIODPIN: // Enable digital ports _digitalPinBytes = (_numDigitalPins + 7) / 8 + 1; - // uint8_t _enableDigitalPins[_digitalPinBytes]; - // _enableDigitalPins[0] = EXIODPIN; _digitalOutBuffer[0] = EXIODPIN; for (uint8_t byte = 1; byte < _digitalPinBytes; byte++) { - // _enableDigitalPins[byte] = 0; _digitalOutBuffer[byte] = 0; } for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { int pinByte = pin / 8; - // bitSet(_enableDigitalPins[pinByte + 1], pin - pinByte * 8); bitSet(_digitalOutBuffer[pinByte + 1], pin - pinByte * 8); } - // I2CManager.write(_i2cAddress, _enableDigitalPins, _digitalPinBytes, &_i2crb); I2CManager.write(_i2cAddress, _digitalOutBuffer, _digitalPinBytes, &_i2crb); _activity = EXIOAPIN; break; case EXIOAPIN: // Enable analogue ports _analoguePinBytes = (_numAnaloguePins + 7) / 8 + 1; - // uint8_t _enableAnaloguePins[_analoguePinBytes]; - // _enableAnaloguePins[0] = EXIOAPIN; _analogueOutBuffer[0] = EXIOAPIN; for (uint8_t byte = 1; byte < _analoguePinBytes; byte++) { - // _enableAnaloguePins[byte] = 0; _analogueOutBuffer[byte] = 0; } for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { int pinByte = pin / 8; - // bitSet(_enableAnaloguePins[pinByte + 1], pin - pinByte * 8); bitSet(_analogueOutBuffer[pinByte + 1], pin - pinByte * 8); } - // I2CManager.write(_i2cAddress, _enableAnaloguePins, _analoguePinBytes, &_i2crb); I2CManager.write(_i2cAddress, _analogueOutBuffer, _analoguePinBytes, &_i2crb); _activity = EXIORDY; break; @@ -146,6 +138,7 @@ private: uint8_t _numAnaloguePins; int _digitalPinBytes; int _analoguePinBytes; + uint8_t _setupBuffer[3]; uint8_t _digitalOutBuffer[EXIO_NANO_DIGITAL_PINS + 1]; uint8_t _digitalInBufer[EXIO_NANO_DIGITAL_PINS]; uint8_t _analogueOutBuffer[EXIO_NANO_ANALOGUE_PINS + 1]; From 070daa37dc5bcc6fd5ba780c128623f34358fb15 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 15 Dec 2022 07:58:21 +1000 Subject: [PATCH 19/54] Move buffers to constructor --- IO_EXIOExpander.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index f3cbfbe..f936677 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -52,18 +52,22 @@ */ class EXIOExpander : public IODevice { public: - static void create(VPIN vpin, int nPins, uint8_t i2cAddress, uint8_t numDigitalPins, uint8_t numAnaloguePins) { + static void create(VPIN vpin, int nPins, uint8_t i2cAddress, byte numDigitalPins, byte numAnaloguePins) { if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress, numDigitalPins, numAnaloguePins); } private: // Constructor - EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, uint8_t numDigitalPins, uint8_t numAnaloguePins) { + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, byte numDigitalPins, byte numAnaloguePins) { _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; + _digitalOutBuffer = (byte *)calloc(_numDigitalPins + 1, 1); + _digitalInBuffer = (byte *)calloc(_numDigitalPins, 1); + _analogueOutBuffer = (byte *)calloc(_numAnaloguePins + 1, 1); + _analogueInBuffer = (byte *)calloc(_numAnaloguePins, 1); addDevice(this); } @@ -139,10 +143,10 @@ private: int _digitalPinBytes; int _analoguePinBytes; uint8_t _setupBuffer[3]; - uint8_t _digitalOutBuffer[EXIO_NANO_DIGITAL_PINS + 1]; - uint8_t _digitalInBufer[EXIO_NANO_DIGITAL_PINS]; - uint8_t _analogueOutBuffer[EXIO_NANO_ANALOGUE_PINS + 1]; - uint8_t _analogueInBuffer[EXIO_NANO_ANALOGUE_PINS]; + byte * _digitalOutBuffer = NULL; + byte * _digitalInBuffer = NULL; + byte * _analogueOutBuffer = NULL; + byte * _analogueInBuffer = NULL; uint8_t _activity; I2CRB _i2crb; From a480a5a3d29d1b7ed1bb93f2bdab568a537d038e Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 15 Dec 2022 15:10:53 +1000 Subject: [PATCH 20/54] Add comments, remove unnecessary functions --- IO_EXIOExpander.h | 55 ++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index f936677..fee4884 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -28,8 +28,16 @@ * * void halSetup() { * // EXIOExpander::create(vpin, num_vpins, i2c_address, digitalPinCount, analoguePinCount); -* EXIOExpander::create(800, 18, 0x90, 12, 6); -} +* EXIOExpander::create(800, 18, 0x65, EXIO_NANO_DIGITAL_PINS, EXIO_NANO_ANALOGUE_PINS); +* } +* +* Note when defining the number of digital and analogue pins, there is no way to sanity check +* this from the device driver, and it is up to the user to define the correct values here. +* +* Vpins are allocated to digital pins first, and then analogue pins, so digital pins will +* populate the first part of the specified vpin range, with the analogue pins populating the +* last part of the vpin range. +* Eg. for a default Nano, 800 - 811 are digital (D2 - D13), 812 to 817 are analogue (A0 - A3, A6/A7). */ #ifndef IO_EX_IOEXPANDER_H @@ -74,9 +82,8 @@ private: void _begin() { // Initialise EX-IOExander device uint8_t _check = I2CManager.checkAddress(_i2cAddress); - DIAG(F("I2C status check: %d"), _check); if (I2CManager.exists(_i2cAddress)) { - _activity = EXIOINIT; + _activity = EXIOINIT; // First thing to do is configure EX-IOExpander device #ifdef DIAG_IO _display(); #endif @@ -87,43 +94,15 @@ private: } void _loop(unsigned long currentMicros) override { - if (_i2crb.status == I2C_STATUS_PENDING) return; + if (_i2crb.status == I2C_STATUS_PENDING) return; // Do nothing if I2C isn't ready yet if (_i2crb.status == I2C_STATUS_OK) { switch(_activity) { case EXIOINIT: - // Send digital and analogue pin counts + // Send digital and analogue pin counts to configure EX-IOExpander _setupBuffer[0] = EXIOINIT; _setupBuffer[1] = _numDigitalPins; _setupBuffer[2] = _numAnaloguePins; I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); - _activity = EXIODPIN; - break; - case EXIODPIN: - // Enable digital ports - _digitalPinBytes = (_numDigitalPins + 7) / 8 + 1; - _digitalOutBuffer[0] = EXIODPIN; - for (uint8_t byte = 1; byte < _digitalPinBytes; byte++) { - _digitalOutBuffer[byte] = 0; - } - for (uint8_t pin = 0; pin < _numDigitalPins; pin++) { - int pinByte = pin / 8; - bitSet(_digitalOutBuffer[pinByte + 1], pin - pinByte * 8); - } - I2CManager.write(_i2cAddress, _digitalOutBuffer, _digitalPinBytes, &_i2crb); - _activity = EXIOAPIN; - break; - case EXIOAPIN: - // Enable analogue ports - _analoguePinBytes = (_numAnaloguePins + 7) / 8 + 1; - _analogueOutBuffer[0] = EXIOAPIN; - for (uint8_t byte = 1; byte < _analoguePinBytes; byte++) { - _analogueOutBuffer[byte] = 0; - } - for (uint8_t pin = 0; pin < _numAnaloguePins; pin++) { - int pinByte = pin / 8; - bitSet(_analogueOutBuffer[pinByte + 1], pin - pinByte * 8); - } - I2CManager.write(_i2cAddress, _analogueOutBuffer, _analoguePinBytes, &_i2crb); _activity = EXIORDY; break; default: @@ -152,11 +131,9 @@ private: enum { EXIOINIT = 0xE0, // Flag to initialise setup procedure - EXIODPIN = 0xE1, // Flag we're sending digital pin assignments - EXIOAPIN = 0xE2, // Flag we're sending analogue pin assignments - EXIORDY = 0xE3, // Flag we have completed setup procedure, also for EX-IO to ACK setup - EXIODDIR = 0xE4, // Flag we're sending digital pin direction configuration - EXIODPUP = 0xE5, // Flag we're sending digital pin pullup configuration + EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup + EXIODDIR = 0xE2, // Flag we're sending digital pin direction configuration + EXIODPUP = 0xE3, // Flag we're sending digital pin pullup configuration }; }; From 1d61a8f3f99ff71a4dd6fbe5614cf33f4047f910 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Fri, 16 Dec 2022 13:14:48 +0000 Subject: [PATCH 21/54] HIGHMEM + WITHROTTLE EXRAIL HIGHMEM feature affects parser and withrottle. Ringstream and wifi fixes Withrottle connecting / reconnecting --- CommandDistributor.cpp | 2 +- DCCEXParser.cpp | 24 +-- EXRAIL2.cpp | 198 ++++++++++++++++++------ EXRAIL2.h | 21 ++- EXRAIL2MacroReset.h | 6 + EXRAILMacros.h | 55 +++++-- FSH.h | 65 ++++---- RingStream.cpp | 22 +-- RingStream.h | 2 +- StringBuffer.h | 2 +- StringFormatter.cpp | 9 +- WiThrottle.cpp | 336 ++++++++++++++++++----------------------- WiThrottle.h | 16 +- WifiInboundHandler.cpp | 4 +- WifiInboundHandler.h | 6 +- WifiInterface.cpp | 3 +- defines.h | 6 + platformio.ini | 12 +- version.h | 5 +- 19 files changed, 465 insertions(+), 329 deletions(-) diff --git a/CommandDistributor.cpp b/CommandDistributor.cpp index 8c79652..9f2baa3 100644 --- a/CommandDistributor.cpp +++ b/CommandDistributor.cpp @@ -97,7 +97,7 @@ void CommandDistributor::parse(byte clientId,byte * buffer, RingStream * stream } void CommandDistributor::forget(byte clientId) { - // keep for later if (clients[clientId]==WITHROTTLE_TYPE) WiThrottle::forget(clientId); + if (clients[clientId]==WITHROTTLE_TYPE) WiThrottle::forget(clientId); clients[clientId]=NONE_TYPE; } #endif diff --git a/DCCEXParser.cpp b/DCCEXParser.cpp index 8e7cd33..cbb152e 100644 --- a/DCCEXParser.cpp +++ b/DCCEXParser.cpp @@ -41,6 +41,14 @@ #include "DCCTimer.h" #include "EXRAIL2.h" +// This macro can't be created easily as a portable function because the +// flashlist requires a far pointer for high flash access. +#define SENDFLASHLIST(stream,flashList) \ + for (int16_t i=0;;i+=sizeof(flashList[0])) { \ + int16_t value=GETHIGHFLASHW(flashList,i); \ + if (value==0) break; \ + StringFormatter::send(stream,F(" %d"),value); \ + } // These keywords are used in the <1> command. The number is what you get if you use the keyword as a parameter. @@ -569,8 +577,8 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) StringFormatter::send(stream, F(" #ifdef EXRAIL_ACTIVE - sendFlashList(stream,RMFT2::routeIdList); - sendFlashList(stream,RMFT2::automationIdList); + SENDFLASHLIST(stream,RMFT2::routeIdList) + SENDFLASHLIST(stream,RMFT2::automationIdList) #endif } else { // @@ -589,7 +597,9 @@ void DCCEXParser::parseOne(Print *stream, byte *com, RingStream * ringStream) case HASH_KEYWORD_R: // returns rosters StringFormatter::send(stream, F("\n")); } -void DCCEXParser::sendFlashList(Print * stream,const int16_t flashList[]) { - for (int16_t i=0;;i++) { - int16_t value=GETFLASHW(flashList+i); - if (value==0) return; - StringFormatter::send(stream,F(" %d"),value); - } -} - bool DCCEXParser::parseZ(Print *stream, int16_t params, int16_t p[]) { diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index 67cfce4..e72e057 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -41,6 +41,7 @@ */ #include +#include "defines.h" #include "EXRAIL2.h" #include "DCC.h" #include "DCCWaveform.h" @@ -90,15 +91,25 @@ LookList * RMFT2::onDeactivateLookup=NULL; LookList * RMFT2::onRedLookup=NULL; LookList * RMFT2::onAmberLookup=NULL; LookList * RMFT2::onGreenLookup=NULL; -#define GET_OPCODE GETFLASH(RMFT2::RouteCode+progCounter) -#ifdef ARDUINO_ARCH_AVR -#define GET_OPERAND(n) GETFLASHW(RMFT2::RouteCode+progCounter+1+(n*3)) -#else -#define GET_OPERAND(n) GETOPW(RMFT2::RouteCode+progCounter+1+(n*3)) -#define GETOPW(A) (((uint32_t)A)%2 ? GETFLASH((const byte *)A) | (GETFLASH(1+(const byte *)A)<<8) : GETFLASHW(A)) -#endif + +#define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter) #define SKIPOP progCounter+=3 +// getOperand instance version, uses progCounter from instance. +uint16_t RMFT2::getOperand(byte n) { + return getOperand(progCounter,n); +} + +// getOperand static version, must be provided prog counter from loop etc. +uint16_t RMFT2::getOperand(int progCounter,byte n) { + int offset=progCounter+1+(n*3); + if (offset&1) { + byte lsb=GETHIGHFLASH(RouteCode,offset); + byte msb=GETHIGHFLASH(RouteCode,offset+1); + return msb<<8|lsb; + } + return GETHIGHFLASHW(RouteCode,offset); +} LookList::LookList(int16_t size) { m_size=size; @@ -139,12 +150,17 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { for (progCounter=0;; SKIPOP) { byte opcode=GET_OPCODE; if (opcode==OPCODE_ENDEXRAIL) break; - if (opcode==op1 || opcode==op2 || opcode==op3) list->add(GET_OPERAND(0),progCounter); + if (opcode==op1 || opcode==op2 || opcode==op3) list->add(getOperand(progCounter,0),progCounter); } return list; } /* static */ void RMFT2::begin() { + + DIAG(F("EXRAIL RoutCode at =%P"),RouteCode); + + bool saved_diag=diag; + diag=true; DCCEXParser::setRMFTFilter(RMFT2::ComandFilter); for (int f=0;fsetHidden(GETFLASH(getTurnoutDescription(t->getId()))==0x01); } char RMFT2::getRouteType(int16_t id) { - for (int16_t i=0;;i++) { - int16_t rid= GETFLASHW(routeIdList+i); + for (int16_t i=0;;i+=2) { + int16_t rid= GETHIGHFLASHW(routeIdList,i); if (rid==id) return 'R'; if (rid==0) break; } - for (int16_t i=0;;i++) { - int16_t rid= GETFLASHW(automationIdList+i); + for (int16_t i=0;;i+=2) { + int16_t rid= GETHIGHFLASHW(automationIdList,i); if (rid==id) return 'A'; if (rid==0) break; } @@ -308,7 +328,7 @@ bool RMFT2::parseSlash(Print * stream, byte & paramCount, int16_t p[]) { // do the signals // flags[n] represents the state of the nth signal in the table for (int sigslot=0;;sigslot++) { - VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigslot*4); + VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8); if (sigid==0) break; // end of signal list byte flag=flags[sigslot] & SIGNAL_MASK; // obtain signal flags for this id StringFormatter::send(stream,F("\n%S[%d]"), @@ -555,7 +575,7 @@ void RMFT2::loop2() { if (delayTime!=0 && millis()-delayStart < delayTime) return; byte opcode = GET_OPCODE; - int16_t operand = GET_OPERAND(0); + int16_t operand = getOperand(0); // skipIf will get set to indicate a failing IF condition bool skipIf=false; @@ -621,13 +641,13 @@ void RMFT2::loop2() { case OPCODE_ATGTE: // wait for analog sensor>= value timeoutFlag=false; - if (IODevice::readAnalogue(operand) >= (int)(GET_OPERAND(1))) break; + if (IODevice::readAnalogue(operand) >= (int)(getOperand(1))) break; delayMe(50); return; case OPCODE_ATLT: // wait for analog sensor < value timeoutFlag=false; - if (IODevice::readAnalogue(operand) < (int)(GET_OPERAND(1))) break; + if (IODevice::readAnalogue(operand) < (int)(getOperand(1))) break; delayMe(50); return; @@ -638,7 +658,7 @@ void RMFT2::loop2() { case OPCODE_ATTIMEOUT2: if (readSensor(operand)) break; // success without timeout - if (millis()-timeoutStart > 100*GET_OPERAND(1)) { + if (millis()-timeoutStart > 100*getOperand(1)) { timeoutFlag=true; break; // and drop through } @@ -681,7 +701,7 @@ void RMFT2::loop2() { break; case OPCODE_POM: - if (loco) DCC::writeCVByteMain(loco, operand, GET_OPERAND(1)); + if (loco) DCC::writeCVByteMain(loco, operand, getOperand(1)); break; case OPCODE_POWEROFF: @@ -715,11 +735,11 @@ void RMFT2::loop2() { break; case OPCODE_IFGTE: // do next operand if sensor>= value - skipIf=IODevice::readAnalogue(operand)<(int)(GET_OPERAND(1)); + skipIf=IODevice::readAnalogue(operand)<(int)(getOperand(1)); break; case OPCODE_IFLT: // do next operand if sensor< value - skipIf=IODevice::readAnalogue(operand)>=(int)(GET_OPERAND(1)); + skipIf=IODevice::readAnalogue(operand)>=(int)(getOperand(1)); break; case OPCODE_IFNOT: // do next operand if sensor not set @@ -802,11 +822,11 @@ void RMFT2::loop2() { } case OPCODE_XFON: - DCC::setFn(operand,GET_OPERAND(1),true); + DCC::setFn(operand,getOperand(1),true); break; case OPCODE_XFOFF: - DCC::setFn(operand,GET_OPERAND(1),false); + DCC::setFn(operand,getOperand(1),false); break; case OPCODE_DCCACTIVATE: { @@ -898,7 +918,7 @@ void RMFT2::loop2() { case OPCODE_SENDLOCO: // cab, route { - int newPc=sequenceLookup->find(GET_OPERAND(1)); + int newPc=sequenceLookup->find(getOperand(1)); if (newPc<0) break; RMFT2* newtask=new RMFT2(newPc); // create new task newtask->loco=operand; @@ -916,7 +936,7 @@ void RMFT2::loop2() { case OPCODE_SERVO: // OPCODE_SERVO,V(vpin),OPCODE_PAD,V(position),OPCODE_PAD,V(profile),OPCODE_PAD,V(duration) - IODevice::writeAnalogue(operand,GET_OPERAND(1),GET_OPERAND(2),GET_OPERAND(3)); + IODevice::writeAnalogue(operand,getOperand(1),getOperand(2),getOperand(3)); break; case OPCODE_WAITFOR: // OPCODE_SERVO,V(pin) @@ -986,8 +1006,8 @@ void RMFT2::kill(const FSH * reason, int operand) { } int16_t RMFT2::getSignalSlot(int16_t id) { - for (int sigpos=0;;sigpos+=4) { - int16_t sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos); + for (int sigslot=0;;sigslot++) { + int16_t sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigslot*8); if (sigid==0) { // end of signal list DIAG(F("EXRAIL Signal %d not defined"), id); return -1; @@ -997,9 +1017,10 @@ int16_t RMFT2::getSignalSlot(int16_t id) { // but for a servo signal it will also have SERVO_SIGNAL_FLAG set. if ((sigid & SIGNAL_ID_MASK)!= id) continue; // keep looking - return sigpos/4; // relative slot in signals table + return sigslot; // relative slot in signals table } } + /* static */ void RMFT2::doSignal(int16_t id,char rag) { if (diag) DIAG(F(" doSignal %d %x"),id,rag); @@ -1016,11 +1037,11 @@ int16_t RMFT2::getSignalSlot(int16_t id) { setFlag(sigslot,rag,SIGNAL_MASK); // Correct signal definition found, get the rag values - int16_t sigpos=sigslot*4; - VPIN sigid=GETFLASHW(RMFT2::SignalDefinitions+sigpos); - VPIN redpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+1); - VPIN amberpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+2); - VPIN greenpin=GETFLASHW(RMFT2::SignalDefinitions+sigpos+3); + int16_t sigpos=sigslot*8; + VPIN sigid=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos); + VPIN redpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+2); + VPIN amberpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+4); + VPIN greenpin=GETHIGHFLASHW(RMFT2::SignalDefinitions,sigpos+6); if (diag) DIAG(F("signal %d %d %d %d %d"),sigid,id,redpin,amberpin,greenpin); VPIN sigtype=sigid & ~SIGNAL_ID_MASK; @@ -1096,3 +1117,96 @@ void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) { void RMFT2::printMessage2(const FSH * msg) { DIAG(F("EXRAIL(%d) %S"),loco,msg); } +static StringBuffer * buffer=NULL; +/* thrungeString is used to stream a HIGHFLASH string to a suitable Serial +and handle the oddities like LCD, BROADCAST and PARSE */ +void RMFT2::thrungeString(uint32_t strfar, thrunger mode, byte id) { + //DIAG(F("thrunge addr=%l mode=%d id=%d"), strfar,mode,id); + Print * stream=NULL; + // Find out where the string is going + switch (mode) { + case thrunge_print: + StringFormatter::send(&Serial,F("<* EXRAIL(%d) "),loco); + stream=&Serial; + break; + + case thrunge_serial: stream=&Serial; break; + case thrunge_serial1: + #ifdef SERIAL1_COMMANDS + stream=&Serial1; + #endif + break; + case thrunge_serial2: + #ifdef SERIAL2_COMMANDS + stream=&Serial2; + #endif + break; + case thrunge_serial3: + #ifdef SERIAL3_COMMANDS + stream=&Serial3; + #endif + break; + case thrunge_serial4: + #ifdef SERIAL4_COMMANDS + stream=&Serial4; + #endif + break; + case thrunge_serial5: + #ifdef SERIAL5_COMMANDS + stream=&Serial5; + #endif + break; + case thrunge_serial6: + #ifdef SERIAL6_COMMANDS + stream=&Serial6; + #endif + break; + // TODO more serials for SAMx case thrunge_serial4: stream=&Serial4; break; + case thrunge_lcn: + #if defined(LCN_SERIAL) + stream=&LCN_SERIAL; + #endif + break; + case thrunge_parse: + case thrunge_broadcast: + case thrunge_lcd: + if (!buffer) buffer=new StringBuffer(); + buffer->flush(); + stream=buffer; + break; + } + if (!stream) return; + + #if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) + // if mega stream it out + for (;;strfar++) { + char c=pgm_read_byte_far(strfar); + if (c=='\0') break; + stream->write(c); + } + #else + // UNO/NANO CPUs dont have high memory + // 32 bit cpus dont care anyway + stream->print((FSH *)strfar); + #endif + + // and decide what to do next + switch (mode) { + case thrunge_print: + StringFormatter::send(&Serial,F(" *>\n")); + break; + // TODO more serials for SAMx case thrunge_serial4: stream=&Serial4; break; + case thrunge_parse: + DCCEXParser::parseOne(&Serial,(byte*)buffer->getString(),NULL); + break; + case thrunge_broadcast: + // TODO CommandDistributor::broadcastText(buffer->getString()); + break; + case thrunge_lcd: + LCD(id,F("%s"),buffer->getString()); + break; + + default: break; + } +} + \ No newline at end of file diff --git a/EXRAIL2.h b/EXRAIL2.h index 323ae57..6e6d0ca 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -67,6 +67,12 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE, OPCODE_IFCLOSED,OPCODE_IFTHROWN }; +enum thrunger: byte { + thrunge_print, thrunge_broadcast, thrunge_serial,thrunge_parse, + thrunge_serial1, thrunge_serial2, thrunge_serial3, + thrunge_serial4, thrunge_serial5, thrunge_serial6, + thrunge_lcd, thrunge_lcn}; + // Flag bits for status of hardware and TPL @@ -111,12 +117,11 @@ class LookList { static const int16_t ACTIVE_HIGH_SIGNAL_FLAG=0x2000; static const int16_t DCC_SIGNAL_FLAG=0x1000; static const int16_t SIGNAL_ID_MASK=0x0FFF; - // Throttle Info Access functions built by exrail macros static const byte rosterNameCount; - static const int16_t FLASH routeIdList[]; - static const int16_t FLASH automationIdList[]; - static const int16_t FLASH rosterIdList[]; + static const int16_t HIGHFLASH routeIdList[]; + static const int16_t HIGHFLASH automationIdList[]; + static const int16_t HIGHFLASH rosterIdList[]; static const FSH * getRouteDescription(int16_t id); static char getRouteType(int16_t id); static const FSH * getTurnoutDescription(int16_t id); @@ -137,6 +142,7 @@ private: static LookList* LookListLoader(OPCODE op1, OPCODE op2=OPCODE_ENDEXRAIL,OPCODE op3=OPCODE_ENDEXRAIL); static void handleEvent(const FSH* reason,LookList* handlers, int16_t id); + static uint16_t getOperand(int progCounter,byte n); static RMFT2 * loopTask; static RMFT2 * pausingTask; void delayMe(long millisecs); @@ -148,10 +154,12 @@ private: void kill(const FSH * reason=NULL,int operand=0); void printMessage(uint16_t id); // Built by RMFTMacros.h void printMessage2(const FSH * msg); + void thrungeString(uint32_t strfar, thrunger mode, byte id=0); + uint16_t getOperand(byte n); static bool diag; - static const FLASH byte RouteCode[]; - static const FLASH int16_t SignalDefinitions[]; + static const HIGHFLASH byte RouteCode[]; + static const HIGHFLASH int16_t SignalDefinitions[]; static byte flags[MAX_FLAGS]; static LookList * sequenceLookup; static LookList * onThrowLookup; @@ -161,7 +169,6 @@ private: static LookList * onRedLookup; static LookList * onAmberLookup; static LookList * onGreenLookup; - // Local variables - exist for each instance/task RMFT2 *next; // loop chain diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index 0211e22..63fc6bd 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -110,6 +110,9 @@ #undef SERIAL1 #undef SERIAL2 #undef SERIAL3 +#undef SERIAL4 +#undef SERIAL5 +#undef SERIAL6 #undef SERVO #undef SERVO2 #undef SERVO_TURNOUT @@ -220,6 +223,9 @@ #define SERIAL1(msg) #define SERIAL2(msg) #define SERIAL3(msg) +#define SERIAL4(msg) +#define SERIAL5(msg) +#define SERIAL6(msg) #define SERVO(id,position,profile) #define SERVO2(id,position,duration) #define SERVO_SIGNAL(vpin,redpos,amberpos,greenpos) diff --git a/EXRAILMacros.h b/EXRAILMacros.h index d5424c6..69ffed2 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -73,14 +73,14 @@ void exrailHalSetup() { #include "EXRAIL2MacroReset.h" #undef ROUTE #define ROUTE(id, description) id, -const int16_t FLASH RMFT2::routeIdList[]= { +const int16_t HIGHFLASH RMFT2::routeIdList[]= { #include "myAutomation.h" 0}; // Pass 2a create throttle automation list #include "EXRAIL2MacroReset.h" #undef AUTOMATION #define AUTOMATION(id, description) id, -const int16_t FLASH RMFT2::automationIdList[]= { +const int16_t HIGHFLASH RMFT2::automationIdList[]= { #include "myAutomation.h" 0}; @@ -100,30 +100,54 @@ const FSH * RMFT2::getRouteDescription(int16_t id) { // Pass 4... Create Text sending functions #include "EXRAIL2MacroReset.h" const int StringMacroTracker1=__COUNTER__; +#define THRUNGE(msg,mode) \ + case (__COUNTER__ - StringMacroTracker1) : {\ + static const char HIGHFLASH thrunge[]=msg;\ + strfar=(uint32_t)GETFARPTR(thrunge);\ + tmode=mode;\ + break;\ + } #undef BROADCAST -#define BROADCAST(msg) case (__COUNTER__ - StringMacroTracker1) : CommandDistributor::broadcastText(F(msg));break; +#define BROADCAST(msg) THRUNGE(msg,thrunge_broadcast) #undef PARSE -#define PARSE(msg) case (__COUNTER__ - StringMacroTracker1) : DCCEXParser::parse(F(msg));break; +#define PARSE(msg) THRUNGE(msg,thrunge_parse) #undef PRINT -#define PRINT(msg) case (__COUNTER__ - StringMacroTracker1) : printMessage2(F(msg));break; +#define PRINT(msg) THRUNGE(msg,thrunge_print) #undef LCN -#define LCN(msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::send(&LCN_SERIAL,F(msg));break; +#define LCN(msg) THRUNGE(msg,thrunge_lcn) #undef SERIAL -#define SERIAL(msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::send(&Serial,F(msg));break; +#define SERIAL(msg) THRUNGE(msg,thrunge_serial) #undef SERIAL1 -#define SERIAL1(msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::send(&Serial1,F(msg));break; +#define SERIAL1(msg) THRUNGE(msg,thrunge_serial1) #undef SERIAL2 -#define SERIAL2(msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::send(&Serial2,F(msg));break; +#define SERIAL2(msg) THRUNGE(msg,thrunge_serial2) #undef SERIAL3 -#define SERIAL3(msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::send(&Serial3,F(msg));break; +#define SERIAL3(msg) THRUNGE(msg,thrunge_serial3) +#undef SERIAL4 +#define SERIAL4(msg) THRUNGE(msg,thrunge_serial4) +#undef SERIAL5 +#define SERIAL5(msg) THRUNGE(msg,thrunge_serial5) +#undef SERIAL6 +#define SERIAL6(msg) THRUNGE(msg,thrunge_serial6) #undef LCD -#define LCD(id,msg) case (__COUNTER__ - StringMacroTracker1) : StringFormatter::lcd(id,F(msg));break; +#define LCD(id,msg) \ + case (__COUNTER__ - StringMacroTracker1) : {\ + static const char HIGHFLASH thrunge[]=msg;\ + strfar=(uint32_t)GETFARPTR(thrunge);\ + tmode=thrunge_lcd; \ + lcdid=id;\ + break;\ + } void RMFT2::printMessage(uint16_t id) { + thrunger tmode; + uint32_t strfar=0; + byte lcdid=0; switch(id) { #include "myAutomation.h" default: break ; } + if (strfar) thrungeString(strfar,tmode,lcdid); } @@ -158,7 +182,7 @@ const byte RMFT2::rosterNameCount=0 #include "EXRAIL2MacroReset.h" #undef ROSTER #define ROSTER(cabid,name,funcmap...) cabid, -const int16_t FLASH RMFT2::rosterIdList[]={ +const int16_t HIGHFLASH RMFT2::rosterIdList[]={ #include "myAutomation.h" 0}; @@ -198,7 +222,7 @@ const FSH * RMFT2::getRosterFunctions(int16_t id) { #undef VIRTUAL_SIGNAL #define VIRTUAL_SIGNAL(id) id,0,0,0, -const FLASH int16_t RMFT2::SignalDefinitions[] = { +const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #include "myAutomation.h" 0,0,0,0 }; @@ -299,6 +323,9 @@ const FLASH int16_t RMFT2::SignalDefinitions[] = { #define SERIAL1(msg) PRINT(msg) #define SERIAL2(msg) PRINT(msg) #define SERIAL3(msg) PRINT(msg) +#define SERIAL4(msg) PRINT(msg) +#define SERIAL5(msg) PRINT(msg) +#define SERIAL6(msg) PRINT(msg) #define SERVO(id,position,profile) OPCODE_SERVO,V(id),OPCODE_PAD,V(position),OPCODE_PAD,V(PCA9685::profile),OPCODE_PAD,V(0), #define SERVO2(id,position,ms) OPCODE_SERVO,V(id),OPCODE_PAD,V(position),OPCODE_PAD,V(PCA9685::Instant),OPCODE_PAD,V(ms/100L), #define SERVO_SIGNAL(vpin,redpos,amberpos,greenpos) @@ -323,7 +350,7 @@ const FLASH int16_t RMFT2::SignalDefinitions[] = { // Build RouteCode const int StringMacroTracker2=__COUNTER__; -const FLASH byte RMFT2::RouteCode[] = { +const HIGHFLASH byte RMFT2::RouteCode[] = { #include "myAutomation.h" OPCODE_ENDTASK,0,0,OPCODE_ENDEXRAIL,0,0 }; diff --git a/FSH.h b/FSH.h index 38cc052..f4bf47e 100644 --- a/FSH.h +++ b/FSH.h @@ -34,42 +34,51 @@ * PROGMEM use FLASH instead * pgm_read_byte_near use GETFLASH instead. * pgm_read_word_near use GETFLASHW instead. + * + * Also: + * HIGHFLASH - PROGMEM forced to end of link so needs far pointers. + * GETHIGHFLASH,GETHIGHFLASHW to access them * */ #include +#ifdef ARDUINO_ARCH_AVR +// AVR devices have flash memory mapped differently +// progmem can be accessed by _near functions or _far +typedef __FlashStringHelper FSH; +#define FLASH PROGMEM +#define GETFLASH(addr) pgm_read_byte_near(addr) -#if defined(ARDUINO_ARCH_MEGAAVR) +#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) +// AVR_MEGA memory deliberately placed at end of link may need _far functions +#define HIGHFLASH __attribute__((section(".fini2"))) +#define GETFARPTR(data) pgm_get_far_address(data) +#define GETHIGHFLASH(data,offset) pgm_read_byte_far(GETFARPTR(data)+offset) +#define GETHIGHFLASHW(data,offset) pgm_read_word_far(GETFARPTR(data)+offset) +#else +// AVR_UNO/NANO runtime does not support _far functions so just use _near equivalent +// as there is no progmem above 32kb anyway. +#define HIGHFLASH PROGMEM +#define GETFARPTR(data) ((uint32_t)(data)) +#define GETHIGHFLASH(data,offset) pgm_read_byte_near(GETFARPTR(data)+(offset)) +#define GETHIGHFLASHW(data,offset) pgm_read_word_near(GETFARPTR(data)+(offset)) +#endif + +#else +// Non-AVR Flat-memory devices have no need of this support so can be remapped to normal memory access #ifdef F #undef F #endif -#define F(str) (str) -typedef char FSH; -#define GETFLASH(addr) (*(const unsigned char *)(addr)) -#define GETFLASHW(addr) (*(const unsigned short *)(addr)) -#define FLASH -#define strlen_P strlen -#define strcpy_P strcpy - -#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_STM32) - -typedef __FlashStringHelper FSH; -#define GETFLASH(addr) pgm_read_byte(addr) -// pgm_read_word is buggy if addr is odd but here -// we do only read well aligned addrs, the others are -// taken care about in the GET_OPERAND(n) macro in EXRAIL2.cpp. -#define GETFLASHW(addr) pgm_read_word(addr) #ifdef FLASH #undef FLASH #endif -#define FLASH PROGMEM - -#else // AVR and AVR compat here - -typedef __FlashStringHelper FSH; -#define GETFLASH(addr) pgm_read_byte_near(addr) -#define GETFLASHW(addr) pgm_read_word_near(addr) -#define FLASH PROGMEM - -#endif // flash stuff -#endif // FSH +#define F(str) (str) +typedef char FSH; +#define FLASH +#define HIGHFLASH +#define GETFARPTR(data) ((uint32_t)(data)) +#define GETFLASH(addr) (*(const byte *)(addr)) +#define GETHIGHFLASH(data,offset) (*(const byte *)(GETFARPTR(data)+offset)) +#define GETHIGHFLASHW(data,offset) (*(const uint16_t *)(GETFARPTR(data)+offset)) +#endif +#endif diff --git a/RingStream.cpp b/RingStream.cpp index 7f10728..9377a0a 100644 --- a/RingStream.cpp +++ b/RingStream.cpp @@ -65,6 +65,13 @@ int RingStream::availableForWrite() { } size_t RingStream::printFlash(const FSH * flashBuffer) { + // This function does not work on a 32 bit processor where the runtime + // sometimes misrepresents the pointer size in uintptr_t. + // In any case its not really necessary in a 32 bit processor because + // we have adequate ram. + if (sizeof(void*)>2) return print(flashBuffer); + + // We are about to add a PROGMEM string to the buffer. // To save RAM we can insert a marker and the // progmem address into the buffer instead. @@ -107,8 +114,11 @@ int RingStream::read() { if ((_pos_read==_pos_write) && !_overflow) return -1; // empty byte b=readRawByte(); if (b!=FLASH_INSERT_MARKER) return b; -#ifndef ARDUINO_ARCH_ESP32 // Detected a flash insert + if (sizeof(void*)>2) { + DIAG(F("Detected invalid flash insert marker at pos %d"),_pos_read); + return '?'; + } // read address bytes LSB first (size depends on CPU) uintptr_t iFlash=0; for (byte f=0; f( iFlash); // and try again... so will read the first byte of the insert. return read(); -#else - DIAG(F("Detected flash insert marker at pos %d but there should not be one"),_pos_read); - return '\0'; -#endif } byte RingStream::readRawByte() { @@ -189,12 +195,6 @@ bool RingStream::commit() { _mark++; if (_mark==_len) _mark=0; _buffer[_mark]=lowByte(_count); - // Enable this for debugging only, it requires A LOT of RAM - //{ char s[_count+2]; - // strncpy(s, (const char*)&(_buffer[_mark+1]), _count); - // s[_count]=0; - // DIAG(F("RS commit count=%d core %d \"%s\""), _count, xPortGetCoreID(), s); - //} _ringClient = NO_CLIENT; return true; // commit worked } diff --git a/RingStream.h b/RingStream.h index 4f51a65..b477b77 100644 --- a/RingStream.h +++ b/RingStream.h @@ -27,7 +27,7 @@ class RingStream : public Print { public: RingStream( const uint16_t len); - static const int THIS_IS_A_RINGSTREAM=77; + static const int THIS_IS_A_RINGSTREAM=777; virtual size_t write(uint8_t b); // This availableForWrite function is subverted from its original intention so that a caller diff --git a/StringBuffer.h b/StringBuffer.h index fe227fb..ac42964 100644 --- a/StringBuffer.h +++ b/StringBuffer.h @@ -32,7 +32,7 @@ class StringBuffer : public Print { private: static const int buffer_max=64; // enough for long text msgs to throttles int16_t _pos_write; - char _buffer[buffer_max+1]; + char _buffer[buffer_max+2]; }; #endif \ No newline at end of file diff --git a/StringFormatter.cpp b/StringFormatter.cpp index 87c22e5..cc78714 100644 --- a/StringFormatter.cpp +++ b/StringFormatter.cpp @@ -91,9 +91,6 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { { const FSH* flash= (const FSH*)va_arg(args, char*); -#ifndef ARDUINO_ARCH_ESP32 - // On ESP32 the reading flashstring from rinstream code - // crashes, so don't use the flashstream hack on ESP32 #if WIFI_ON | ETHERNET_ON // RingStream has special logic to handle flash strings // but is not implemented unless wifi or ethernet are enabled. @@ -101,11 +98,11 @@ void StringFormatter::send2(Print * stream,const FSH* format, va_list args) { if (stream->availableForWrite()==RingStream::THIS_IS_A_RINGSTREAM) ((RingStream *)stream)->printFlash(flash); else -#endif #endif stream->print(flash); break; } + case 'P': stream->print((uint32_t)va_arg(args, void*), HEX); break; case 'd': printPadded(stream,va_arg(args, int), formatWidth, formatLeft); break; case 'u': printPadded(stream,va_arg(args, unsigned int), formatWidth, formatLeft); break; case 'l': printPadded(stream,va_arg(args, long), formatWidth, formatLeft); break; @@ -168,8 +165,8 @@ void StringFormatter::printEscape(Print * stream, char c) { case '\r': stream->print(F("\\r")); break; case '\0': stream->print(F("\\0")); return; case '\t': stream->print(F("\\t")); break; - case '\\': stream->print(F("\\")); break; - default: stream->print(c); + case '\\': stream->print(F("\\\\")); break; + default: stream->write(c); } } diff --git a/WiThrottle.cpp b/WiThrottle.cpp index 019a515..920ebd6 100644 --- a/WiThrottle.cpp +++ b/WiThrottle.cpp @@ -63,69 +63,6 @@ WiThrottle * WiThrottle::firstThrottle=NULL; -static uint8_t xstrncmp(const char *s1, const char *s2, uint8_t n) { - if (n == 0) - return 0; - do { - if (*s1 != *s2++) - return 1; - if (*s1++ == 0) - break; - } while (--n != 0); - return 0; -} - -void WiThrottle::findUniqThrottle(int id, char *u) { - WiThrottle *wtmyid = NULL; - WiThrottle *wtmyuniq = NULL; - - // search 1, look for clientid match - for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle){ - if (wt->clientid == id) { - if (xstrncmp(u, wt->uniq, 16) == 0) // should be most common case - return; - wtmyid = wt; - break; - } - } - // search 2, look for string match - for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle){ - if (xstrncmp(u, wt->uniq, 16) == 0) { - wtmyuniq = wt; - break; - } - } - - // analyse result of the two for loops: - if (wtmyid == NULL) { // should not happen - DIAG(F("Did not find my own wiThrottle handle")); - return; - } - // wtmyuniq == wtmyid has already returned in for loop 1 - if (wtmyuniq == NULL) { // register uniq in the found id - strncpy(wtmyid->uniq, u, 16); - wtmyid->uniq[16] = '\0'; - if (Diag::WITHROTTLE) DIAG(F("Client %d registered as %s"),wtmyid->clientid, wtmyid->uniq); - return; - } - // if we get here wtmyid and wtmyuniq point on objects but differnet ones - // so we need to do the copy (all other options covered above) - for(int n=0; n < MAX_MY_LOCO; n++) - wtmyid->myLocos[n] = wtmyuniq->myLocos[n]; - wtmyid->heartBeatEnable = wtmyuniq->heartBeatEnable; - wtmyid->heartBeat = wtmyuniq->heartBeat; - wtmyid->initSent = wtmyuniq->initSent; - wtmyid->exRailSent = wtmyuniq->exRailSent; - wtmyid->mostRecentCab = wtmyuniq->mostRecentCab; - wtmyid->turnoutListHash = wtmyuniq->turnoutListHash; - wtmyid->lastPowerState = wtmyuniq->lastPowerState; - strncpy(wtmyid->uniq, u, 16); - wtmyid->uniq[16] = '\0'; - if (Diag::WITHROTTLE) - DIAG(F("New client %d replaces old client %d as %s"), wtmyid->clientid, wtmyuniq->clientid, wtmyid->uniq); - forget(wtmyuniq->clientid); // do not use wtmyid after this -} - WiThrottle* WiThrottle::getThrottle( int wifiClient) { for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle) if (wt->clientid==wifiClient) return wt; @@ -135,6 +72,7 @@ WiThrottle* WiThrottle::getThrottle( int wifiClient) { void WiThrottle::forget( byte clientId) { for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle) if (wt->clientid==clientId) { + DIAG(F("Withrottle client %d dropped"),clientId); delete wt; break; } @@ -159,10 +97,7 @@ WiThrottle::WiThrottle( int wificlientid) { nextThrottle=firstThrottle; firstThrottle= this; clientid=wificlientid; - initSent=false; // prevent sending heartbeats before connection completed heartBeatEnable=false; // until client turns it on - turnoutListHash = -1; // make sure turnout list is sent once - exRailSent=false; mostRecentCab=0; for (int loco=0;loconext()){ - if (tt->isHidden()) continue; - int id=tt->getId(); - const FSH * tdesc=NULL; - #ifdef EXRAIL_ACTIVE - tdesc=RMFT2::getTurnoutDescription(id); - #endif - char tchar=Turnout::isClosed(id)?'2':'4'; - if (tdesc==NULL) // turnout with no description - StringFormatter::send(stream,F("]\\[%d}|{T%d}|{T%c"), id,id,tchar); - else - StringFormatter::send(stream,F("]\\[%d}|{%S}|{%c"), id,tdesc,tchar); - } - StringFormatter::send(stream,F("\n")); - turnoutListHash = Turnout::turnoutlistHash; // keep a copy of hash for later comparison - } - - else if (!exRailSent) { - // Send EX-RAIL routes list if not already sent (but not at same time as turnouts above) - exRailSent=true; -#ifdef EXRAIL_ACTIVE - StringFormatter::send(stream,F("PRT]\\[Routes}|{Route]\\[Set}|{2]\\[Handoff}|{4\nPRL")); - for (byte pass=0;pass<2;pass++) { - // first pass automations, second pass routes. - for (int ix=0;;ix++) { - int16_t id=GETFLASHW((pass?RMFT2::automationIdList:RMFT2::routeIdList)+ix); - if (id==0) break; - const FSH * desc=RMFT2::getRouteDescription(id); - StringFormatter::send(stream,F("]\\[%c%d}|{%S}|{%c"), - pass?'A':'R',id,desc, pass?'4':'2'); - } - } - StringFormatter::send(stream,F("\n")); -#endif - // allow heartbeat to slow down once all metadata sent - StringFormatter::send(stream,F("*%d\n"),HEARTBEAT_SECONDS); } } @@ -283,32 +188,14 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { } break; case 'N': // Heartbeat (2), only send if connection completed by 'HU' message - StringFormatter::send(stream, F("*%d\n"), initSent ? HEARTBEAT_SECONDS : HEARTBEAT_SECONDS/2); // return timeout value + StringFormatter::send(stream, F("*%d\n"), heartrateSent ? HEARTBEAT_SECONDS : HEARTBEAT_PRELOAD); // return timeout value break; case 'M': // multithrottle multithrottle(stream, cmd); break; case 'H': // send initial connection info after receiving "HU" message - if (cmd[1] == 'U') { - WiThrottle::findUniqThrottle(clientid, (char *)cmd+2); - StringFormatter::send(stream,F("VN2.0\nHTDCC-EX\nRL0\n")); - StringFormatter::send(stream,F("HtDCC-EX v%S, %S, %S, %S\n"), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA)); - StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[THROW}|{2]\\[CLOSE}|{4\n")); - StringFormatter::send(stream,F("PPA%x\n"),TrackManager::getMainPower()==POWERMODE::ON); -#ifdef EXRAIL_ACTIVE - StringFormatter::send(stream,F("RL%d"), RMFT2::rosterNameCount); - for (int16_t r=0;rwrite('\n'); // end roster -#endif - - - // set heartbeat to 5 seconds because we need to sync the metadata (1 second is too short!) - StringFormatter::send(stream,F("*%d\n"), HEARTBEAT_SECONDS/2); - initSent = true; + if (cmd[1] == 'U') { + sendIntro(stream); } break; case 'Q': // @@ -317,7 +204,7 @@ void WiThrottle::parse(RingStream * stream, byte * cmdx) { StringFormatter::send(stream, F("M%c-%c%d<;>\n"), myLocos[loco].throttle, LorS(myLocos[loco].cab), myLocos[loco].cab); } } - if (Diag::WITHROTTLE) DIAG(F("%l WiThrottle(%d) Quit"),millis(),clientid); + if (Diag::WITHROTTLE) DIAG(F("WiThrottle(%d) Quit"),clientid); delete this; break; } @@ -378,65 +265,17 @@ void WiThrottle::multithrottle(RingStream * stream, byte * cmd){ } //use first empty "slot" on this client's list, will be added to DCC registration list for (int loco=0;loco\n"), throttleChar, cmd[3] ,locoid); //tell client to add loco - int fkeys=29; - myLocos[loco].functionToggles=1<<2; // F2 (HORN) is a non-toggle - -#ifdef EXRAIL_ACTIVE - const char * functionNames=(char *) RMFT2::getRosterFunctions(locoid); - if (!functionNames) { - // no roster, use presets as above - } - else if (GETFLASH(functionNames)=='\0') { - // "" = Roster but no functions given - fkeys=0; - } - else { - // we have function names... - // scan names list emitting names, counting functions and - // flagging non-toggling things like horn. - myLocos[loco].functionToggles =0; - StringFormatter::send(stream, F("M%cL%c%d<;>]\\["), throttleChar,cmd[3],locoid); - fkeys=0; - bool firstchar=true; - for (int fx=0;;fx++) { - char c=GETFLASH(functionNames+fx); - if (c=='\0') { - fkeys++; - break; - } - if (c=='/') { - fkeys++; - StringFormatter::send(stream,F("]\\[")); - firstchar=true; - } - else if (firstchar && c=='*') { - myLocos[loco].functionToggles |= 1UL<write(c); - } - } - StringFormatter::send(stream,F("\n")); - } - -#endif - - for(int fKey=0; fKey=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),throttleChar,cmd[3],locoid,fstate,fKey); - } - //speed and direction will be published at next broadcast cycle - StringFormatter::send(stream, F("M%cA%c%d<;>s1\n"), throttleChar, cmd[3], locoid); //default speed step 128 - return; + if (myLocos[loco].throttle=='\0') { + myLocos[loco].throttle=throttleChar; + myLocos[loco].cab=locoid; + myLocos[loco].functionMap=DCC::getFunctionMap(locoid); + myLocos[loco].broadcastPending=true; // means speed/dir will be sent later + mostRecentCab=locoid; + StringFormatter::send(stream, F("M%c+%c%d<;>\n"), throttleChar, cmd[3] ,locoid); //tell client to add loco + sendFunctions(stream,loco); + //speed and direction will be published at next broadcast cycle + StringFormatter::send(stream, F("M%cA%c%d<;>s1\n"), throttleChar, cmd[3], locoid); //default speed step 128 + return; } } StringFormatter::send(stream, F("HMMax locos (%d) exceeded, %d not added!\n"), MAX_MY_LOCO ,locoid); @@ -540,8 +379,6 @@ void WiThrottle::loop(RingStream * stream) { // for each WiThrottle, check the heartbeat and broadcast needed for (WiThrottle* wt=firstThrottle; wt!=NULL ; wt=wt->nextThrottle) wt->checkHeartbeat(stream); - - } void WiThrottle::checkHeartbeat(RingStream * stream) { @@ -555,8 +392,8 @@ void WiThrottle::checkHeartbeat(RingStream * stream) { heartBeat=millis(); // We have just stopped everyting, we don't need to do that again at next loop. } } - //haba no, not necessary the only throttle and it may come back - //delete this; + // if it does come back, the throttle should re-acquire + delete this; return; } @@ -656,5 +493,120 @@ void WiThrottle::getLocoCallback(int16_t locoid) { DIAG(F("LocoCallback commit success")); stashStream->commit(); CommandDistributor::broadcastPower(); - } + +void WiThrottle::sendIntro(Print* stream) { + introSent=true; + StringFormatter::send(stream,F("VN2.0\nHTDCC-EX\nRL0\n")); + StringFormatter::send(stream,F("HtDCC-EX v%S, %S, %S, %S\n"), F(VERSION), F(ARDUINO_TYPE), DCC::getMotorShieldName(), F(GITHUB_SHA)); + StringFormatter::send(stream,F("PTT]\\[Turnouts}|{Turnout]\\[THROW}|{2]\\[CLOSE}|{4\n")); + StringFormatter::send(stream,F("PPA%x\n"),TrackManager::getMainPower()==POWERMODE::ON); + // set heartbeat to 2 seconds because we need to sync the metadata (1 second is too short!) + StringFormatter::send(stream,F("*%d\nHMConnecting..\n"), HEARTBEAT_PRELOAD); +} + +void WiThrottle::sendTurnouts(Print* stream) { + turnoutsSent=true; + StringFormatter::send(stream,F("PTL")); + for(Turnout *tt=Turnout::first();tt!=NULL;tt=tt->next()){ + if (tt->isHidden()) continue; + int id=tt->getId(); + const FSH * tdesc=NULL; + #ifdef EXRAIL_ACTIVE + tdesc=RMFT2::getTurnoutDescription(id); + #endif + char tchar=Turnout::isClosed(id)?'2':'4'; + if (tdesc==NULL) // turnout with no description + StringFormatter::send(stream,F("]\\[%d}|{T%d}|{T%c"), id,id,tchar); + else + StringFormatter::send(stream,F("]\\[%d}|{%S}|{%c"), id,tdesc,tchar); + } + StringFormatter::send(stream,F("\n")); +} +void WiThrottle::sendRoster(Print* stream) { + rosterSent=true; + #ifdef EXRAIL_ACTIVE + StringFormatter::send(stream,F("RL%d"), RMFT2::rosterNameCount); + for (int16_t r=0;r]\\["), myLocos[loco].throttle,LorS(locoid),locoid); + fkeys=0; + bool firstchar=true; + for (int fx=0;;fx++) { + char c=GETFLASH(functionNames+fx); + if (c=='\0') { + fkeys++; + break; + } + if (c=='/') { + fkeys++; + StringFormatter::send(stream,F("]\\[")); + firstchar=true; + } + else if (firstchar && c=='*') { + myLocos[loco].functionToggles |= 1UL<write(c); + } + } + StringFormatter::send(stream,F("\n")); + } + +#endif + + for(int fKey=0; fKey=0) StringFormatter::send(stream,F("M%cA%c%d<;>F%d%d\n"),myLocos[loco].throttle,LorS(locoid),locoid,fstate,fKey); + } +} \ No newline at end of file diff --git a/WiThrottle.h b/WiThrottle.h index 3fa973a..6756943 100644 --- a/WiThrottle.h +++ b/WiThrottle.h @@ -45,7 +45,8 @@ class WiThrottle { ~WiThrottle(); static const int MAX_MY_LOCO=10; // maximum number of locos assigned to a single client - static const int HEARTBEAT_SECONDS=10; // heartbeat at 4secs to provide messaging transport + static const int HEARTBEAT_SECONDS=10; // heartbeat at 10 secs to provide messaging transport + static const int HEARTBEAT_PRELOAD=2; // request fast callback when connecting multiple messages static const int ESTOP_SECONDS=20; // eStop if no incoming messages for more than 8secs static WiThrottle* firstThrottle; static int getInt(byte * cmd); @@ -61,10 +62,12 @@ class WiThrottle { MYLOCO myLocos[MAX_MY_LOCO]; bool heartBeatEnable; unsigned long heartBeat; - bool initSent; // valid connection established - bool exRailSent; // valid connection established + bool introSent=false; + bool turnoutsSent=false; + bool rosterSent=false; + bool routesSent=false; + bool heartrateSent=false; uint16_t mostRecentCab; - int turnoutListHash; // used to check for changes to turnout list bool lastPowerState; // last power state sent to this client int DCCToWiTSpeed(int DCCSpeed); @@ -74,6 +77,11 @@ class WiThrottle { void accessory(RingStream *, byte* cmd); void checkHeartbeat(RingStream * stream); void markForBroadcast2(int cab); + void sendIntro(Print * stream); + void sendTurnouts(Print * stream); + void sendRoster(Print * stream); + void sendRoutes(Print * stream); + void sendFunctions(Print* stream, byte loco); // callback stuff to support prog track acquire static RingStream * stashStream; static WiThrottle * stashInstance; diff --git a/WifiInboundHandler.cpp b/WifiInboundHandler.cpp index 2a8ec28..b570527 100644 --- a/WifiInboundHandler.cpp +++ b/WifiInboundHandler.cpp @@ -66,7 +66,7 @@ void WifiInboundHandler::loop1() { } - if (pendingCipsend) { + if (pendingCipsend && millis()-lastCIPSEND > CIPSENDgap) { if (Diag::WIFI) DIAG( F("WiFi: [[CIPSEND=%d,%d]]"), clientPendingCIPSEND, currentReplySize); StringFormatter::send(wifiStream, F("AT+CIPSEND=%d,%d\r\n"), clientPendingCIPSEND, currentReplySize); pendingCipsend=false; @@ -131,11 +131,13 @@ WifiInboundHandler::INBOUND_STATE WifiInboundHandler::loop2() { if (ch=='S') { // SEND OK probably loopState=SKIPTOEND; + lastCIPSEND=0; // no need to wait next time break; } if (ch=='b') { // This is a busy indicator... probabaly must restart a CIPSEND pendingCipsend=(clientPendingCIPSEND>=0); + if (pendingCipsend) lastCIPSEND=millis(); // forces a gap to next CIPSEND loopState=SKIPTOEND; break; } diff --git a/WifiInboundHandler.h b/WifiInboundHandler.h index d3410cd..08f6789 100644 --- a/WifiInboundHandler.h +++ b/WifiInboundHandler.h @@ -68,7 +68,9 @@ class WifiInboundHandler { Stream * wifiStream; static const int INBOUND_RING = 512; - static const int OUTBOUND_RING = 2048; + static const int OUTBOUND_RING = sizeof(void*)==2?2048:8192; + + static const int CIPSENDgap=100; // millis() between retries of cipsend. RingStream * inboundRing; RingStream * outboundRing; @@ -79,5 +81,7 @@ class WifiInboundHandler { int clientPendingCIPSEND=-1; int currentReplySize; bool pendingCipsend; + uint32_t lastCIPSEND=0; // millis() of previous cipsend + }; #endif diff --git a/WifiInterface.cpp b/WifiInterface.cpp index 347d7ef..bdc8dad 100644 --- a/WifiInterface.cpp +++ b/WifiInterface.cpp @@ -344,11 +344,10 @@ void WifiInterface::ATCommand(HardwareSerial * stream,const byte * command) { while (wifiStream->available()) stream->write(wifiStream->read()); if (stream->available()) { int cx=stream->read(); - // A newline followed by !!! is an exit + // A newline followed by ! is an exit if (cx=='\n' || cx=='\r') startOfLine=true; else if (startOfLine && cx=='!') break; else startOfLine=false; - stream->write(cx); wifiStream->write(cx); } } diff --git a/defines.h b/defines.h index c4d38a3..9ad5851 100644 --- a/defines.h +++ b/defines.h @@ -149,6 +149,12 @@ #define CPU_TYPE_ERROR #endif +// replace board type if provided by compiler +#ifdef BOARD_NAME + #undef ARDUINO_TYPE + #define ARDUINO_TYPE BOARD_NAME +#endif + //////////////////////////////////////////////////////////////////////////////// // // WIFI_ON: All prereqs for running with WIFI are met diff --git a/platformio.ini b/platformio.ini index bc1ef0e..5fcda00 100644 --- a/platformio.ini +++ b/platformio.ini @@ -184,7 +184,7 @@ platform = ststm32 board = nucleo_f411re framework = arduino lib_deps = ${env.lib_deps} -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 monitor_speed = 115200 monitor_echo = yes @@ -192,7 +192,7 @@ monitor_echo = yes platform = teensy board = teensy31 framework = arduino -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} lib_ignore = NativeEthernet @@ -200,7 +200,7 @@ lib_ignore = NativeEthernet platform = teensy board = teensy35 framework = arduino -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} lib_ignore = NativeEthernet @@ -208,7 +208,7 @@ lib_ignore = NativeEthernet platform = teensy board = teensy36 framework = arduino -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} lib_ignore = NativeEthernet @@ -216,7 +216,7 @@ lib_ignore = NativeEthernet platform = teensy board = teensy40 framework = arduino -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} lib_ignore = NativeEthernet @@ -224,6 +224,6 @@ lib_ignore = NativeEthernet platform = teensy board = teensy41 framework = arduino -build_flags = -std=c++17 -DDISABLE_EEPROM -Os -g2 +build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} lib_ignore = \ No newline at end of file diff --git a/version.h b/version.h index 5d36187..64281c1 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,10 @@ #include "StringFormatter.h" -#define VERSION "4.2.7pre1" +#define VERSION "4.2.8pre1" +// 4.2.8 HIGHMEM (EXRAIL support beyond 64kb) +// Withrottle connect/disconnect improvements +// Report BOARD_TYPE if provided by compiler // 4.2.7 FIX: Static IP addr // FIX: Reuse WiThrottle list entries // 4.2.6 FIX: Remove RAM thief From c8fea3a4a7b4e9e26bd0c81cec6fba5f0d76f14d Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 18 Dec 2022 09:43:11 +1000 Subject: [PATCH 22/54] Add version, analogue reads working --- IO_EXIOExpander.h | 30 ++++++++++++++++++++++++------ IO_EXIOExpander_version.h | 10 ++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 IO_EXIOExpander_version.h diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index fee4884..94bd589 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -48,6 +48,7 @@ #include "DIAG.h" #include "FSH.h" #include "EX-IOExpanderPins.h" +#include "IO_EXIOExpander_version.h" // Include user defined pin maps in myEX-IOExpander if defined #if __has_include ("myEX-IOExpander.h") @@ -60,13 +61,13 @@ */ class EXIOExpander : public IODevice { public: - static void create(VPIN vpin, int nPins, uint8_t i2cAddress, byte numDigitalPins, byte numAnaloguePins) { + static void create(VPIN vpin, int nPins, uint8_t i2cAddress, int numDigitalPins, int numAnaloguePins) { if (checkNoOverlap(vpin, nPins, i2cAddress)) new EXIOExpander(vpin, nPins, i2cAddress, numDigitalPins, numAnaloguePins); } private: // Constructor - EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, byte numDigitalPins, byte numAnaloguePins) { + EXIOExpander(VPIN firstVpin, int nPins, uint8_t i2cAddress, int numDigitalPins, int numAnaloguePins) { _firstVpin = firstVpin; _nPins = nPins; _i2cAddress = i2cAddress; @@ -74,8 +75,8 @@ private: _numAnaloguePins = numAnaloguePins; _digitalOutBuffer = (byte *)calloc(_numDigitalPins + 1, 1); _digitalInBuffer = (byte *)calloc(_numDigitalPins, 1); - _analogueOutBuffer = (byte *)calloc(_numAnaloguePins + 1, 1); - _analogueInBuffer = (byte *)calloc(_numAnaloguePins, 1); + _analogueValues = (uint16_t *)calloc(_numAnaloguePins, 1); + _currentAPin = _nPins - _numAnaloguePins; addDevice(this); } @@ -84,6 +85,7 @@ private: uint8_t _check = I2CManager.checkAddress(_i2cAddress); if (I2CManager.exists(_i2cAddress)) { _activity = EXIOINIT; // First thing to do is configure EX-IOExpander device + DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); #ifdef DIAG_IO _display(); #endif @@ -105,10 +107,22 @@ private: I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); _activity = EXIORDY; break; + case EXIORDY: + _analogueOutBuffer[0] = EXIORDAN; + _analogueOutBuffer[1] = _currentAPin - _numDigitalPins; + I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); + _analogueValues[_currentAPin] = (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; + if (++_currentAPin >= _numDigitalPins + _numAnaloguePins) _currentAPin = _nPins - _numAnaloguePins; default: break; } } + // delayUntil(currentMicros + 2000000); // Delay 2 seconds while bug fixing/developing + } + + int _readAnalogue(VPIN vpin) override { + int pin = vpin - _firstVpin; + return _analogueValues[pin]; } void _display() override { @@ -124,8 +138,10 @@ private: uint8_t _setupBuffer[3]; byte * _digitalOutBuffer = NULL; byte * _digitalInBuffer = NULL; - byte * _analogueOutBuffer = NULL; - byte * _analogueInBuffer = NULL; + byte _analogueInBuffer[2]; + byte _analogueOutBuffer[2]; + uint16_t * _analogueValues = NULL; + uint8_t _currentAPin; // Current analogue pin to read uint8_t _activity; I2CRB _i2crb; @@ -134,6 +150,8 @@ private: EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup EXIODDIR = 0xE2, // Flag we're sending digital pin direction configuration EXIODPUP = 0xE3, // Flag we're sending digital pin pullup configuration + EXIOOP = 0xE4, // Flag to say we're operating normally + EXIORDAN = 0xE5, // Flag to read an analogue input }; }; diff --git a/IO_EXIOExpander_version.h b/IO_EXIOExpander_version.h new file mode 100644 index 0000000..6d2e553 --- /dev/null +++ b/IO_EXIOExpander_version.h @@ -0,0 +1,10 @@ +#ifndef IO_EXIOEXPANDER_VERSION_H +#define IO_EXIOEXPANDER_VERSION_H + +#include "StringFormatter.h" + + +#define EXIO_VERSION "0.0.1alpha" +// 0.0.1 Initial version for alpha testing + +#endif \ No newline at end of file From 943494385f2a259a46f8d19e13abcdd8ba48a3d7 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Sun, 18 Dec 2022 18:59:16 +1000 Subject: [PATCH 23/54] Add digital write --- IO_EXIOExpander.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 94bd589..90dd06d 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -125,6 +125,14 @@ private: return _analogueValues[pin]; } + void _write(VPIN vpin, int value) override { + int pin = vpin - _firstVpin; + _digitalWriteBuffer[0] = EXIOWRD; + _digitalWriteBuffer[1] = pin; + _digitalWriteBuffer[2] = value; + I2CManager.write(_i2cAddress, _digitalWriteBuffer, 3, &_i2crb); + } + void _display() override { DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); @@ -140,6 +148,7 @@ private: byte * _digitalInBuffer = NULL; byte _analogueInBuffer[2]; byte _analogueOutBuffer[2]; + byte _digitalWriteBuffer[3]; uint16_t * _analogueValues = NULL; uint8_t _currentAPin; // Current analogue pin to read uint8_t _activity; @@ -152,6 +161,7 @@ private: EXIODPUP = 0xE3, // Flag we're sending digital pin pullup configuration EXIOOP = 0xE4, // Flag to say we're operating normally EXIORDAN = 0xE5, // Flag to read an analogue input + EXIOWRD = 0xE6, // Flag for digital write }; }; From 3973996344c7973dd66291d6cf5d3cd28990fb8c Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 19 Dec 2022 14:24:49 +1000 Subject: [PATCH 24/54] Digital pin config done, digital read in progress --- IO_EXIOExpander.h | 53 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 90dd06d..3641dfd 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -73,10 +73,11 @@ private: _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; - _digitalOutBuffer = (byte *)calloc(_numDigitalPins + 1, 1); - _digitalInBuffer = (byte *)calloc(_numDigitalPins, 1); + // _digitalOutBuffer = (byte *)calloc(_numDigitalPins + 1, 1); + // _digitalInBuffer = (byte *)calloc(_numDigitalPins, 1); _analogueValues = (uint16_t *)calloc(_numAnaloguePins, 1); _currentAPin = _nPins - _numAnaloguePins; + int _dPinArrayLen = (_numDigitalPins + 7) / 8; addDevice(this); } @@ -120,17 +121,40 @@ private: // delayUntil(currentMicros + 2000000); // Delay 2 seconds while bug fixing/developing } + bool _configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) override { + if (configType != CONFIGURE_INPUT) return false; + if (paramCount != 1) return false; + bool pullup = params[0]; + int pin = vpin - _firstVpin; + uint8_t mask = 1 << ((pin-_firstVpin) % 8); + DIAG(F("Configure vpin|pin %d|%d as input, pullup %d"), vpin, pin, pullup); + _digitalOutBuffer[0] = EXIODPUP; + _digitalOutBuffer[1] = pin; + _digitalOutBuffer[2] = pullup; + I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); + return true; + } + int _readAnalogue(VPIN vpin) override { int pin = vpin - _firstVpin; return _analogueValues[pin]; } + int _read(VPIN vpin) override { + int pin = vpin - _firstVpin; + _digitalOutBuffer[0] = EXIORDD; + _digitalOutBuffer[1] = pin; + _digitalOutBuffer[2] = 0x00; // Don't need to use this for reading + int _value = I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + return _value; + } + void _write(VPIN vpin, int value) override { int pin = vpin - _firstVpin; - _digitalWriteBuffer[0] = EXIOWRD; - _digitalWriteBuffer[1] = pin; - _digitalWriteBuffer[2] = value; - I2CManager.write(_i2cAddress, _digitalWriteBuffer, 3, &_i2crb); + _digitalOutBuffer[0] = EXIOWRD; + _digitalOutBuffer[1] = pin; + _digitalOutBuffer[2] = value; + I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); } void _display() override { @@ -144,11 +168,12 @@ private: int _digitalPinBytes; int _analoguePinBytes; uint8_t _setupBuffer[3]; - byte * _digitalOutBuffer = NULL; - byte * _digitalInBuffer = NULL; + // byte * _digitalOutBuffer = NULL; + // byte * _digitalInBuffer = NULL; byte _analogueInBuffer[2]; byte _analogueOutBuffer[2]; - byte _digitalWriteBuffer[3]; + byte _digitalOutBuffer[3]; + byte _digitalInBuffer[1]; uint16_t * _analogueValues = NULL; uint8_t _currentAPin; // Current analogue pin to read uint8_t _activity; @@ -157,11 +182,11 @@ private: enum { EXIOINIT = 0xE0, // Flag to initialise setup procedure EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup - EXIODDIR = 0xE2, // Flag we're sending digital pin direction configuration - EXIODPUP = 0xE3, // Flag we're sending digital pin pullup configuration - EXIOOP = 0xE4, // Flag to say we're operating normally - EXIORDAN = 0xE5, // Flag to read an analogue input - EXIOWRD = 0xE6, // Flag for digital write + EXIODPUP = 0xE2, // Flag we're sending digital pin pullup configuration + EXIOOP = 0xE3, // Flag to say we're operating normally + EXIORDAN = 0xE4, // Flag to read an analogue input + EXIOWRD = 0xE5, // Flag for digital write + EXIORDD = 0xE6, // Flag to read digital input }; }; From 25b325034514f2b8939005899169e7773b716d4c Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 20 Dec 2022 07:08:42 +1000 Subject: [PATCH 25/54] Digital read working --- IO_EXIOExpander.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 3641dfd..692e309 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -145,8 +145,8 @@ private: _digitalOutBuffer[0] = EXIORDD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = 0x00; // Don't need to use this for reading - int _value = I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); - return _value; + I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + return _digitalInBuffer[0]; } void _write(VPIN vpin, int value) override { From 2ad08029a4763e595db59ecef041094ec7e1aebc Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 20 Dec 2022 08:05:05 +1000 Subject: [PATCH 26/54] Remove excess DIAG output --- IO_EXIOExpander.h | 1 - 1 file changed, 1 deletion(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 692e309..591680d 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -127,7 +127,6 @@ private: bool pullup = params[0]; int pin = vpin - _firstVpin; uint8_t mask = 1 << ((pin-_firstVpin) % 8); - DIAG(F("Configure vpin|pin %d|%d as input, pullup %d"), vpin, pin, pullup); _digitalOutBuffer[0] = EXIODPUP; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = pullup; From 5170147e3e3c5e395177f8a4208d93583ab24a5e Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 20 Dec 2022 19:41:32 +1000 Subject: [PATCH 27/54] Error checking pin config, code tidy --- IO_EXIOExpander.h | 46 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 591680d..067caf8 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -73,9 +73,6 @@ private: _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; - // _digitalOutBuffer = (byte *)calloc(_numDigitalPins + 1, 1); - // _digitalInBuffer = (byte *)calloc(_numDigitalPins, 1); - _analogueValues = (uint16_t *)calloc(_numAnaloguePins, 1); _currentAPin = _nPins - _numAnaloguePins; int _dPinArrayLen = (_numDigitalPins + 7) / 8; addDevice(this); @@ -87,6 +84,15 @@ private: if (I2CManager.exists(_i2cAddress)) { _activity = EXIOINIT; // First thing to do is configure EX-IOExpander device DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); + _digitalOutBuffer[0] = EXIOINIT; + _digitalOutBuffer[1] = _numDigitalPins; + _digitalOutBuffer[2] = _numAnaloguePins; + I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + if (_digitalInBuffer[0] != EXIORDY) { + DIAG(F("ERROR configuring EX-IOExpander device, I2C:x%x"), _i2cAddress); + _deviceState = DEVSTATE_FAILED; + return; + } #ifdef DIAG_IO _display(); #endif @@ -96,31 +102,6 @@ private: } } - void _loop(unsigned long currentMicros) override { - if (_i2crb.status == I2C_STATUS_PENDING) return; // Do nothing if I2C isn't ready yet - if (_i2crb.status == I2C_STATUS_OK) { - switch(_activity) { - case EXIOINIT: - // Send digital and analogue pin counts to configure EX-IOExpander - _setupBuffer[0] = EXIOINIT; - _setupBuffer[1] = _numDigitalPins; - _setupBuffer[2] = _numAnaloguePins; - I2CManager.write(_i2cAddress, _setupBuffer, 3, &_i2crb); - _activity = EXIORDY; - break; - case EXIORDY: - _analogueOutBuffer[0] = EXIORDAN; - _analogueOutBuffer[1] = _currentAPin - _numDigitalPins; - I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); - _analogueValues[_currentAPin] = (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; - if (++_currentAPin >= _numDigitalPins + _numAnaloguePins) _currentAPin = _nPins - _numAnaloguePins; - default: - break; - } - } - // delayUntil(currentMicros + 2000000); // Delay 2 seconds while bug fixing/developing - } - bool _configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) override { if (configType != CONFIGURE_INPUT) return false; if (paramCount != 1) return false; @@ -136,7 +117,10 @@ private: int _readAnalogue(VPIN vpin) override { int pin = vpin - _firstVpin; - return _analogueValues[pin]; + _analogueOutBuffer[0] = EXIORDAN; + _analogueOutBuffer[1] = _currentAPin - _numDigitalPins; + I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); + return (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; } int _read(VPIN vpin) override { @@ -166,14 +150,10 @@ private: uint8_t _numAnaloguePins; int _digitalPinBytes; int _analoguePinBytes; - uint8_t _setupBuffer[3]; - // byte * _digitalOutBuffer = NULL; - // byte * _digitalInBuffer = NULL; byte _analogueInBuffer[2]; byte _analogueOutBuffer[2]; byte _digitalOutBuffer[3]; byte _digitalInBuffer[1]; - uint16_t * _analogueValues = NULL; uint8_t _currentAPin; // Current analogue pin to read uint8_t _activity; I2CRB _i2crb; From 1c7103c21ea3916ae75e4efbdca73d04d760ac77 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Wed, 21 Dec 2022 08:37:23 +1000 Subject: [PATCH 28/54] Analogue read bugfix --- IO_EXIOExpander.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 067caf8..fc5bc4b 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -73,7 +73,6 @@ private: _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; - _currentAPin = _nPins - _numAnaloguePins; int _dPinArrayLen = (_numDigitalPins + 7) / 8; addDevice(this); } @@ -83,7 +82,6 @@ private: uint8_t _check = I2CManager.checkAddress(_i2cAddress); if (I2CManager.exists(_i2cAddress)) { _activity = EXIOINIT; // First thing to do is configure EX-IOExpander device - DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; _digitalOutBuffer[2] = _numAnaloguePins; @@ -118,7 +116,7 @@ private: int _readAnalogue(VPIN vpin) override { int pin = vpin - _firstVpin; _analogueOutBuffer[0] = EXIORDAN; - _analogueOutBuffer[1] = _currentAPin - _numDigitalPins; + _analogueOutBuffer[1] = pin; I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); return (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; } @@ -143,6 +141,10 @@ private: void _display() override { DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); + DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); + DIAG(F("EX-IOExpander x%x: Digital Vpins %d-%d, Analogue Vpins %d-%d"), + _i2cAddress, _firstVpin, _firstVpin + _numDigitalPins - 1, _firstVpin + _numDigitalPins, + _firstVpin + _nPins - 1); } uint8_t _i2cAddress; @@ -154,7 +156,6 @@ private: byte _analogueOutBuffer[2]; byte _digitalOutBuffer[3]; byte _digitalInBuffer[1]; - uint8_t _currentAPin; // Current analogue pin to read uint8_t _activity; I2CRB _i2crb; From c44fb0ac44a5ffa90db7b3a45bce29afdd9fe21b Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 22 Dec 2022 07:22:04 +1000 Subject: [PATCH 29/54] Disable device driver version, add myHal example --- IO_EXIOExpander.h | 3 +-- IO_EXIOExpander_version.h | 10 ---------- myEX-IOExpander.example.h | 22 ---------------------- myHal.cpp_example.txt | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 34 deletions(-) delete mode 100644 IO_EXIOExpander_version.h delete mode 100644 myEX-IOExpander.example.h diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index fc5bc4b..6eb3492 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -48,7 +48,6 @@ #include "DIAG.h" #include "FSH.h" #include "EX-IOExpanderPins.h" -#include "IO_EXIOExpander_version.h" // Include user defined pin maps in myEX-IOExpander if defined #if __has_include ("myEX-IOExpander.h") @@ -141,7 +140,7 @@ private: void _display() override { DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); - DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); + // DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); DIAG(F("EX-IOExpander x%x: Digital Vpins %d-%d, Analogue Vpins %d-%d"), _i2cAddress, _firstVpin, _firstVpin + _numDigitalPins - 1, _firstVpin + _numDigitalPins, _firstVpin + _nPins - 1); diff --git a/IO_EXIOExpander_version.h b/IO_EXIOExpander_version.h deleted file mode 100644 index 6d2e553..0000000 --- a/IO_EXIOExpander_version.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef IO_EXIOEXPANDER_VERSION_H -#define IO_EXIOEXPANDER_VERSION_H - -#include "StringFormatter.h" - - -#define EXIO_VERSION "0.0.1alpha" -// 0.0.1 Initial version for alpha testing - -#endif \ No newline at end of file diff --git a/myEX-IOExpander.example.h b/myEX-IOExpander.example.h deleted file mode 100644 index 94e378e..0000000 --- a/myEX-IOExpander.example.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * © 2022 Peter Cole. All rights reserved. - * - * This is the example configuration file for a custom EX-IOExpander pin map file. - * - * It is highly recommended to copy this to "myEX-IOExpander.h" and modify to suit your specific - * requirements. - * - * If you are simply using a default definition for a defined microcontroller, then you don't - * need to use this file, and instead can use one of the existing definitions. - * - * Refer to https://dcc-ex.com for the full documentation. - * - * NOTE: Modifications to this file will be overwritten by future software updates. - */ -#ifndef MYEX_IOEXPANDER_H -#define MYEX_IOEXPANDER_H - -#define MY_NANO_DIGITAL_PINMAP 2,3,4,5,6,7,8,9,10,11,12,13 -#define MY_NANO_ANALOGUE_PINMAP A0,A1,A2,A3 - -#endif \ No newline at end of file diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index 32aa12e..3febc82 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -20,6 +20,8 @@ #include "IO_HCSR04.h" // Ultrasonic range sensor #include "IO_VL53L0X.h" // Laser time-of-flight sensor #include "IO_DFPlayer.h" // MP3 sound player +//#include "IO_EXTurntable.h" // Turntable-EX turntable controller +// #include "IO_EXIOExpander.h" // EX-IOExpander device driver //========================================================================== @@ -160,6 +162,39 @@ void halSetup() { // DFPlayer::create(10000, 10, Serial1); + //======================================================================= + // The following directive defines an EX-Turntable turntable instance. + //======================================================================= + // EXTurntable::create(VPIN, Number of VPINs, I2C Address) + // + // The parameters are: + // VPIN=600 + // Number of VPINs=1 (Note there is no reason to change this) + // I2C address=0x60 + // + // Note that the I2C address is defined in the EX-Turntable code, and 0x60 is the default. + + //EXTurntable::create(600, 1, 0x60); + + + //======================================================================= + // The following directive defines an EX-IOExpander instance. + //======================================================================= + // EXIOExpander::create(VPIN, Number of VPINs, I2C Address, Digital pin count, Analogue pin count) + // + // The parameters are: + // VPIN=an available Vpin + // Number of VPINs=Digital pin count + Analogue pin count (must match device in use as per documentation) + // I2C address=an available I2C address (default 0x65) + // + // Note that the I2C address is defined in the EX-IOExpander code, and 0x65 is the default. + // The first example is for an Arduino Nano with the default pin allocations. + // The second example is for an Arduino Uno using all pins as digital only. + + //EXIOExpander::create(800, 18, 0x65, EXIO_NANO_DIGITAL_PINS, EXIO_NANO_ANALOGUE_PINS); + //EXIOExpander::create(820, 16, 0x66, 16, 0); + + } #endif From 70845b49322b80bc532ee265c77a9cbbc18c9ea6 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 26 Dec 2022 06:44:15 +1000 Subject: [PATCH 30/54] Receive/display EXIO version --- IO_EXIOExpander.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 6eb3492..69c568d 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -84,12 +84,20 @@ private: _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; _digitalOutBuffer[2] = _numAnaloguePins; + // Send config, if EXIORDY returned, we're good, otherwise go offline I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); if (_digitalInBuffer[0] != EXIORDY) { DIAG(F("ERROR configuring EX-IOExpander device, I2C:x%x"), _i2cAddress); _deviceState = DEVSTATE_FAILED; return; } + // Attempt to get version, if we don't get it, we don't care, don't go offline + // Using digital buffers in reverse to save RAM + _digitalInBuffer[0] = EXIOVER; + I2CManager.read(_i2cAddress, _digitalOutBuffer, 3, _digitalInBuffer, 1, &_i2crb); + _majorVer = _digitalOutBuffer[0]; + _minorVer = _digitalOutBuffer[1]; + _patchVer = _digitalOutBuffer[2]; #ifdef DIAG_IO _display(); #endif @@ -138,12 +146,10 @@ private: } void _display() override { - DIAG(F("EX-IOExpander I2C:x%x Configured on Vpins:%d-%d %S"), _i2cAddress, _firstVpin, _firstVpin+_nPins-1, - _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); - // DIAG(F("EX-IOExpander x%x using driver version %S"), _i2cAddress, EXIO_VERSION); - DIAG(F("EX-IOExpander x%x: Digital Vpins %d-%d, Analogue Vpins %d-%d"), - _i2cAddress, _firstVpin, _firstVpin + _numDigitalPins - 1, _firstVpin + _numDigitalPins, - _firstVpin + _nPins - 1); + DIAG(F("EX-IOExpander I2C:x%x v%d.%d.%d: Digital Vpins %d-%d, Analogue Vpins %d-%d %S"), + _i2cAddress, _majorVer, _minorVer, _patchVer, _firstVpin, _firstVpin + _numDigitalPins - 1, + _firstVpin + _numDigitalPins, _firstVpin + _nPins - 1, + _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); } uint8_t _i2cAddress; @@ -155,6 +161,9 @@ private: byte _analogueOutBuffer[2]; byte _digitalOutBuffer[3]; byte _digitalInBuffer[1]; + uint8_t _majorVer = 0; + uint8_t _minorVer = 0; + uint8_t _patchVer = 0; uint8_t _activity; I2CRB _i2crb; @@ -162,7 +171,7 @@ private: EXIOINIT = 0xE0, // Flag to initialise setup procedure EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup EXIODPUP = 0xE2, // Flag we're sending digital pin pullup configuration - EXIOOP = 0xE3, // Flag to say we're operating normally + EXIOVER = 0xE3, // Flag to get version EXIORDAN = 0xE4, // Flag to read an analogue input EXIOWRD = 0xE5, // Flag for digital write EXIORDD = 0xE6, // Flag to read digital input From 71ce913712fff2877ca0756e0edc2c8feabc05b6 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 26 Dec 2022 07:36:12 +1000 Subject: [PATCH 31/54] Version bugfix --- IO_EXIOExpander.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 69c568d..cc3160c 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -92,12 +92,12 @@ private: return; } // Attempt to get version, if we don't get it, we don't care, don't go offline - // Using digital buffers in reverse to save RAM + // Using digital in buffer in reverse to save RAM _digitalInBuffer[0] = EXIOVER; - I2CManager.read(_i2cAddress, _digitalOutBuffer, 3, _digitalInBuffer, 1, &_i2crb); - _majorVer = _digitalOutBuffer[0]; - _minorVer = _digitalOutBuffer[1]; - _patchVer = _digitalOutBuffer[2]; + I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1, &_i2crb); + _majorVer = _versionBuffer[0]; + _minorVer = _versionBuffer[1]; + _patchVer = _versionBuffer[2]; #ifdef DIAG_IO _display(); #endif @@ -146,9 +146,18 @@ private: } void _display() override { - DIAG(F("EX-IOExpander I2C:x%x v%d.%d.%d: Digital Vpins %d-%d, Analogue Vpins %d-%d %S"), - _i2cAddress, _majorVer, _minorVer, _patchVer, _firstVpin, _firstVpin + _numDigitalPins - 1, - _firstVpin + _numDigitalPins, _firstVpin + _nPins - 1, + int _firstAnalogue, _lastAnalogue; + if (_numAnaloguePins == 0) { + _firstAnalogue = 0; + _lastAnalogue = 0; + } else { + _firstAnalogue = _firstVpin + _numDigitalPins; + _lastAnalogue = _firstVpin + _nPins - 1; + } + DIAG(F("EX-IOExpander I2C:x%x v%d.%d.%d: %d Digital Vpins %d-%d, %d Analogue Vpins %d-%d %S"), + _i2cAddress, _majorVer, _minorVer, _patchVer, + _numDigitalPins, _firstVpin, _firstVpin + _numDigitalPins - 1, + _numAnaloguePins, _firstAnalogue, _lastAnalogue, _deviceState == DEVSTATE_FAILED ? F("OFFLINE") : F("")); } @@ -161,6 +170,7 @@ private: byte _analogueOutBuffer[2]; byte _digitalOutBuffer[3]; byte _digitalInBuffer[1]; + uint8_t _versionBuffer[3]; uint8_t _majorVer = 0; uint8_t _minorVer = 0; uint8_t _patchVer = 0; From 0be25f6e7f27bccafe1c1f062e21df817e45a1ba Mon Sep 17 00:00:00 2001 From: Asbelos Date: Mon, 26 Dec 2022 10:41:15 +0000 Subject: [PATCH 32/54] Squashed commit of the following: commit e06668f042e4b4646f6eab298374fd8f062c7a7f Author: Asbelos Date: Mon Dec 26 10:09:34 2022 +0000 speedup commit 3e5d3b1caaac79757262ebb05d0d31ac0d2c9c7b Author: Asbelos Date: Sun Dec 25 22:11:56 2022 +0000 Rename commit 81099af42b9a4f977232595aaddcafa72e34158d Author: Asbelos Date: Sun Dec 25 21:35:38 2022 +0000 spelling and polling commit 9240e7c6bab74dfead59c5d12da29cf31518d98f Author: Asbelos Date: Sun Dec 25 20:52:07 2022 +0000 input working commit 6c1c681a26987a4cac6a49dd82f7e9974b58c9ad Author: Asbelos Date: Wed Dec 21 11:18:39 2022 +0000 input working 1 board, no kit map, output untested commit 5ce67fac972dc864cec4c930361a2ab9f12449c8 Author: Asbelos Date: Sun Dec 18 15:32:37 2022 +0000 Include IO_DNU08 automatically commit ac8d453d2c1877c5372b406dd10e6e03a2969e5f Author: Asbelos Date: Sun Dec 18 12:28:13 2022 +0000 BNOU8 HAL driver --- IODevice.h | 6 +- IO_duinoNodes.h | 172 ++++++++++++++++++++++++++++++++++++ Release_Notes/duinoNodes.md | 39 ++++++++ 3 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 IO_duinoNodes.h create mode 100644 Release_Notes/duinoNodes.md diff --git a/IODevice.h b/IODevice.h index ce47267..f3ffb17 100644 --- a/IODevice.h +++ b/IODevice.h @@ -161,6 +161,8 @@ public: // once the GPIO port concerned has been read. void setGPIOInterruptPin(int16_t pinNumber); + // Method to check if pins will overlap before creating new device. + static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, uint8_t i2cAddress=0); protected: @@ -234,9 +236,6 @@ protected: // pin low if an input changes state. int16_t _gpioInterruptPin = -1; - // Method to check if pins will overlap before creating new device. - static bool checkNoOverlap(VPIN firstPin, uint8_t nPins=1, uint8_t i2cAddress=0); - // Static support function for subclass creation static void addDevice(IODevice *newDevice); @@ -408,5 +407,6 @@ private: #include "IO_MCP23008.h" #include "IO_MCP23017.h" #include "IO_PCF8574.h" +#include "IO_duinoNodes.h" #endif // iodevice_h diff --git a/IO_duinoNodes.h b/IO_duinoNodes.h new file mode 100644 index 0000000..ae7d40c --- /dev/null +++ b/IO_duinoNodes.h @@ -0,0 +1,172 @@ +/* + * © 2022, Chris Harlow. All rights reserved. + * + * This file is part of DCC++EX API + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . + */ +#ifndef IO_duinoNodes_h + #define IO_duinoNodes_h +#include +#include "defines.h" +#include "IODevice.h" + +#define PIN_MASK(bit) (0x80>>(bit%8)) +#define GET_BIT(x) (_pinValues[(x)/8] & PIN_MASK((x)) ) +#define SET_BIT(x) _pinValues[(x)/8] |= PIN_MASK((x)) +#define CLR_BIT(x) _pinValues[(x)/8] &= ~PIN_MASK((x)) +#define DIAG_IO + + + +class IO_duinoNodes : public IODevice { + +public: + IO_duinoNodes(VPIN firstVpin, int nPins, + byte clockPin, byte latchPin, byte dataPin, + const byte* pinmap) : + IODevice(firstVpin, nPins) { + + _latchPin=latchPin; + _clockPin=clockPin; + _dataPin=dataPin; + _pinMap=pinmap; + _nShiftBytes=(nPins+7)/8; // rounded up to multiples of 8 bits + _pinValues=(byte*) calloc(_nShiftBytes,1); + // Connect to HAL so my _write, _read and _loop will be called as required. + IODevice::addDevice(this); + } + +// Called by HAL to start handling this device + void _begin() override { + _deviceState = DEVSTATE_NORMAL; + pinMode(_latchPin,OUTPUT); + pinMode(_clockPin,OUTPUT); + pinMode(_dataPin,_pinMap?INPUT_PULLUP:OUTPUT); + _display(); + } + +// loop called by HAL supervisor +void _loop(unsigned long currentMicros) override { + if (_pinMap) _loopInput(currentMicros); + else if (_xmitPending) _loopOutput(); +} + +void _loopInput(unsigned long currentMicros) { + + if (currentMicros-_prevMicros < POLL_MICROS) return; // Nothing to do + _prevMicros=currentMicros; + + //set latch to HIGH to freeze & store parallel data + ArduinoPins::fastWriteDigital(_latchPin, HIGH); + delayMicroseconds(1); + //set latch to LOW to enable the data to be transmitted serially + ArduinoPins::fastWriteDigital(_latchPin, LOW); + + // stream in the bitmap using mapping order provided at constructor + for (int xmitByte=0;xmitByte<_nShiftBytes; xmitByte++) { + byte newByte=0; + for (int xmitBit=0;xmitBit<8; xmitBit++) { + ArduinoPins::fastWriteDigital(_clockPin, LOW); + delayMicroseconds(1); + bool data = ArduinoPins::fastReadDigital(_dataPin); + byte map=_pinMap[xmitBit]; + if (data) newByte |= map; + else newByte &= ~map; + ArduinoPins::fastWriteDigital(_clockPin, HIGH); + delayMicroseconds(1); + } + _pinValues[xmitByte]=newByte; + // DIAG(F("DIN %x=%x"),xmitByte, newByte); + } + } + +void _loopOutput() { + // stream out the bitmap (highest pin first) + _xmitPending=false; + ArduinoPins::fastWriteDigital(_latchPin, LOW); + for (int xmitBit=_nShiftBytes*8 -1; xmitBit>=0; xmitBit--) { + ArduinoPins::fastWriteDigital(_dataPin,GET_BIT(xmitBit)); + ArduinoPins::fastWriteDigital(_clockPin,HIGH); + ArduinoPins::fastWriteDigital(_clockPin,LOW); + } + digitalWrite(_latchPin, HIGH); + } + + int _read(VPIN vpin) override { + int pin=vpin - _firstVpin; + bool b=GET_BIT(pin); + return b?1:0; + } + + void _write(VPIN vpin, int value) override { + int pin = vpin - _firstVpin; + bool oldval=GET_BIT(pin); + bool newval=value!=0; + if (newval==oldval) return; // no change + if (newval) SET_BIT(pin); + else CLR_BIT(pin); + _xmitPending=true; // shift register will be sent on next _loop() + } + + void _display() override { + DIAG(F("IO_duinoNodes %SPUT Configured on VPins:%d-%d shift=%d"), + _pinMap?F("IN"):F("OUT"), + (int)_firstVpin, + (int)_firstVpin+_nPins-1, _nShiftBytes*8); + } + +private: + static const unsigned long POLL_MICROS=100000; // 10 / S + unsigned long _prevMicros; + int _nShiftBytes=0; + VPIN _latchPin,_clockPin,_dataPin; + byte* _pinValues; + bool _xmitPending; // Only relevant in output mode + const byte* _pinMap; // NULL in output mode +}; + +class IO_DNIN8 { +public: + static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin ) + { + // input arrives as board pin 0,7,6,5,1,2,3,4 + static const byte pinmap[8]={0x80,0x01,0x02,0x04,0x40,0x20,0x10,0x08}; + if (IODevice::checkNoOverlap(firstVpin,nPins)) + new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,pinmap); + } + +}; + +class IO_DNIN8K { +public: + static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin ) + { + // input arrives as board pin 0, 1, 2, 3, 4, 5, 6, 7 + static const byte pinmap[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; + if (IODevice::checkNoOverlap(firstVpin,nPins)) + new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,pinmap); + } +}; + +class IO_DNOU8 { +public: + static void create(VPIN firstVpin, int nPins, byte clockPin, byte latchPin, byte dataPin ) + { + if (IODevice::checkNoOverlap(firstVpin,nPins)) + new IO_duinoNodes( firstVpin, nPins, clockPin, latchPin, dataPin,NULL); + } + +}; +#endif \ No newline at end of file diff --git a/Release_Notes/duinoNodes.md b/Release_Notes/duinoNodes.md new file mode 100644 index 0000000..64a2323 --- /dev/null +++ b/Release_Notes/duinoNodes.md @@ -0,0 +1,39 @@ +Using Lew's Duino Gear boards: + +1. DNIN8 Input + This is a shift-register implementation of a digital input collector. + Multiple DNIN8 may be connected in sequence but it is IMPORTANT that the software + configuratuion correctly represents the number of boards connected otherwise the results will be meaningless. + + Use in myAnimation.h + + HAL(IO_DNIN8, firstVpin, numPins, clockPin, latchPin, dataPin) + e.g. + HAL(IO_DNIN8, 400, 16, 40, 42, 44) + + OR Use in myHal.cpp + IO_DNIN8::create( firstVpin, numPins, clockPin, latchPin, dataPin) + + + + This will create virtaul pins 400-415 using two DNIN8 boards connected in sequence. + Vpins 400-407 will be on the first board (closest to the CS) and 408-415 on the second. + + Note: 16 pins uses two boards. You may specify a non-multiple-of-8 pins but this will be rounded up to a multiple of 8 and you must connect ONLY the number of boards that this takes. + + This example uses Arduino GPIO pins 40,42,44 as these are conveniently side-by-side on a Mega which is easier when you are using a 3 strand cable. + + The DNIN8K module works the same but you must use DNIN8K in the HAL setup instead of DNIN8. NO you cant mix 8 and 8k versions in the same string of boards but you can create another string of boards. + + + DNOU8 works the same way, + Use in myAnimation.h + + HAL(IO_DNOU8, firstVpin, numPins, clockPin, latchPin, dataPin) + e.g. + HAL(IO_DNIN8, 450, 16, 45, 47, 49) + + OR Use in myHal.cpp + IO_DNIN8::create( firstVpin, numPins, clockPin, latchPin, dataPin) + +This creates a string of input pins 450-465. Note the clock/latch/data pins must be different to any DNIN8/k pins. From b1bd28273d3e31834f41798f252c8f12650dbcf6 Mon Sep 17 00:00:00 2001 From: Asbelos Date: Mon, 26 Dec 2022 11:06:42 +0000 Subject: [PATCH 33/54] duinoNodes support --- IO_duinoNodes.h | 5 +++-- version.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/IO_duinoNodes.h b/IO_duinoNodes.h index ae7d40c..eac752e 100644 --- a/IO_duinoNodes.h +++ b/IO_duinoNodes.h @@ -1,7 +1,8 @@ /* * © 2022, Chris Harlow. All rights reserved. + * Based on original by: Robin Simonds, Beagle Bay Inc * - * This file is part of DCC++EX API + * This file is part of DCC-EX API * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -101,7 +102,7 @@ void _loopOutput() { ArduinoPins::fastWriteDigital(_clockPin,HIGH); ArduinoPins::fastWriteDigital(_clockPin,LOW); } - digitalWrite(_latchPin, HIGH); + ArduinoPins::fastWriteDigital(_latchPin, HIGH); } int _read(VPIN vpin) override { diff --git a/version.h b/version.h index 64281c1..a17babd 100644 --- a/version.h +++ b/version.h @@ -4,7 +4,8 @@ #include "StringFormatter.h" -#define VERSION "4.2.8pre1" +#define VERSION "4.2.9pre1" +// 4.2.9 duinoNodes support // 4.2.8 HIGHMEM (EXRAIL support beyond 64kb) // Withrottle connect/disconnect improvements // Report BOARD_TYPE if provided by compiler From eea13969979ce7f1c8a8613c1fb0118bb283b04c Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 27 Dec 2022 10:10:44 +1000 Subject: [PATCH 34/54] Remove EX-IO pin macros --- EX-IOExpanderPins.h | 34 ---------------------------------- IO_EXIOExpander.h | 1 - 2 files changed, 35 deletions(-) delete mode 100644 EX-IOExpanderPins.h diff --git a/EX-IOExpanderPins.h b/EX-IOExpanderPins.h deleted file mode 100644 index cbb726f..0000000 --- a/EX-IOExpanderPins.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * © 2022 Peter Cole - * - * This file is part of EX-CommandStation - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * It is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with CommandStation. If not, see . - */ - -/* -* This file defines default pin numbers for the various architectures supported -* by default by EX-IOExpander. -* -* Any modifications to this file will be overwritten by future software updates. -*/ - -#define EXIO_UNO_DIGITAL_PINS 12 -#define EXIO_UNO_ANALOGUE_PINS 4 - -#define EXIO_NANO_DIGITAL_PINS 12 -#define EXIO_NANO_ANALOGUE_PINS 6 - -#define EXIO_MEGA_DIGITAL_PINS 46 -#define EXIO_MEGA_ANALOGUE_PINS 16 diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index cc3160c..58c6a1d 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -47,7 +47,6 @@ #include "I2CManager.h" #include "DIAG.h" #include "FSH.h" -#include "EX-IOExpanderPins.h" // Include user defined pin maps in myEX-IOExpander if defined #if __has_include ("myEX-IOExpander.h") From 8f32ae712f1f2342aa06f0f0e820b9a425fff7e6 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 27 Dec 2022 10:13:08 +1000 Subject: [PATCH 35/54] Fix myHal example --- myHal.cpp_example.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index 3febc82..c56a03d 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -191,7 +191,7 @@ void halSetup() { // The first example is for an Arduino Nano with the default pin allocations. // The second example is for an Arduino Uno using all pins as digital only. - //EXIOExpander::create(800, 18, 0x65, EXIO_NANO_DIGITAL_PINS, EXIO_NANO_ANALOGUE_PINS); + //EXIOExpander::create(800, 18, 0x65, 12, 8); //EXIOExpander::create(820, 16, 0x66, 16, 0); From ffdf023de67d121005d291c1a144ae08c5324500 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 29 Dec 2022 05:10:37 +1000 Subject: [PATCH 36/54] Clean up --- IO_EXIOExpander.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 58c6a1d..ff6db8e 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -18,21 +18,23 @@ */ /* -* The IO_EX-IOExpander.h device driver integrates with one or more EX-IOExpander devices. -* This device driver will configure the device and all I/O ports on startup, along with +* The IO_EXIOExpander.h device driver integrates with one or more EX-IOExpander devices. +* This device driver will configure the device on startup, along with * interacting with the device for all input/output duties. * * To create EX-IOExpander devices, these are defined in myHal.cpp: * -* #include "IO_EX-IOExpander.h" +* #include "IO_EXIOExpander.h" * * void halSetup() { * // EXIOExpander::create(vpin, num_vpins, i2c_address, digitalPinCount, analoguePinCount); -* EXIOExpander::create(800, 18, 0x65, EXIO_NANO_DIGITAL_PINS, EXIO_NANO_ANALOGUE_PINS); +* EXIOExpander::create(800, 18, 0x65, 12, 8); * } * * Note when defining the number of digital and analogue pins, there is no way to sanity check * this from the device driver, and it is up to the user to define the correct values here. +* +* All pins available on the EX-IOExpander device must be accounted for. * * Vpins are allocated to digital pins first, and then analogue pins, so digital pins will * populate the first part of the specified vpin range, with the analogue pins populating the @@ -48,11 +50,6 @@ #include "DIAG.h" #include "FSH.h" -// Include user defined pin maps in myEX-IOExpander if defined -#if __has_include ("myEX-IOExpander.h") - #include "myEX-IOExpander.h" -#endif - ///////////////////////////////////////////////////////////////////////////////////////////////////// /* * IODevice subclass for EX-IOExpander. @@ -79,7 +76,6 @@ private: // Initialise EX-IOExander device uint8_t _check = I2CManager.checkAddress(_i2cAddress); if (I2CManager.exists(_i2cAddress)) { - _activity = EXIOINIT; // First thing to do is configure EX-IOExpander device _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; _digitalOutBuffer[2] = _numAnaloguePins; @@ -173,7 +169,6 @@ private: uint8_t _majorVer = 0; uint8_t _minorVer = 0; uint8_t _patchVer = 0; - uint8_t _activity; I2CRB _i2crb; enum { From 322cb3db54e88071a7230b2a6f3eda566eca3298 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 29 Dec 2022 08:44:08 +1000 Subject: [PATCH 37/54] Include driver in IODevice.h --- IODevice.h | 1 + IO_EXIOExpander.h | 4 +--- myHal.cpp_example.txt | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/IODevice.h b/IODevice.h index ce47267..942fb64 100644 --- a/IODevice.h +++ b/IODevice.h @@ -408,5 +408,6 @@ private: #include "IO_MCP23008.h" #include "IO_MCP23017.h" #include "IO_PCF8574.h" +#include "IO_EXIOExpander.h" #endif // iodevice_h diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index ff6db8e..151a319 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -23,8 +23,7 @@ * interacting with the device for all input/output duties. * * To create EX-IOExpander devices, these are defined in myHal.cpp: -* -* #include "IO_EXIOExpander.h" +* (Note the device driver is included by default) * * void halSetup() { * // EXIOExpander::create(vpin, num_vpins, i2c_address, digitalPinCount, analoguePinCount); @@ -45,7 +44,6 @@ #ifndef IO_EX_IOEXPANDER_H #define IO_EX_IOEXPANDER_H -#include "IODevice.h" #include "I2CManager.h" #include "DIAG.h" #include "FSH.h" diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index c56a03d..c95aaed 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -21,7 +21,6 @@ #include "IO_VL53L0X.h" // Laser time-of-flight sensor #include "IO_DFPlayer.h" // MP3 sound player //#include "IO_EXTurntable.h" // Turntable-EX turntable controller -// #include "IO_EXIOExpander.h" // EX-IOExpander device driver //========================================================================== From 94c8dafeb280304a2f3d32340c4e955585d69d2e Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 29 Dec 2022 10:38:04 +0000 Subject: [PATCH 38/54] renamed macros --- IO_duinoNodes.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/IO_duinoNodes.h b/IO_duinoNodes.h index eac752e..73de1a1 100644 --- a/IO_duinoNodes.h +++ b/IO_duinoNodes.h @@ -23,11 +23,10 @@ #include "defines.h" #include "IODevice.h" -#define PIN_MASK(bit) (0x80>>(bit%8)) -#define GET_BIT(x) (_pinValues[(x)/8] & PIN_MASK((x)) ) -#define SET_BIT(x) _pinValues[(x)/8] |= PIN_MASK((x)) -#define CLR_BIT(x) _pinValues[(x)/8] &= ~PIN_MASK((x)) -#define DIAG_IO +#define DN_PIN_MASK(bit) (0x80>>(bit%8)) +#define DN_GET_BIT(x) (_pinValues[(x)/8] & DN_PIN_MASK((x)) ) +#define DN_SET_BIT(x) _pinValues[(x)/8] |= DN_PIN_MASK((x)) +#define DN_CLR_BIT(x) _pinValues[(x)/8] &= ~DN_PIN_MASK((x)) @@ -98,7 +97,7 @@ void _loopOutput() { _xmitPending=false; ArduinoPins::fastWriteDigital(_latchPin, LOW); for (int xmitBit=_nShiftBytes*8 -1; xmitBit>=0; xmitBit--) { - ArduinoPins::fastWriteDigital(_dataPin,GET_BIT(xmitBit)); + ArduinoPins::fastWriteDigital(_dataPin,DN_GET_BIT(xmitBit)); ArduinoPins::fastWriteDigital(_clockPin,HIGH); ArduinoPins::fastWriteDigital(_clockPin,LOW); } @@ -107,17 +106,17 @@ void _loopOutput() { int _read(VPIN vpin) override { int pin=vpin - _firstVpin; - bool b=GET_BIT(pin); + bool b=DN_GET_BIT(pin); return b?1:0; } void _write(VPIN vpin, int value) override { int pin = vpin - _firstVpin; - bool oldval=GET_BIT(pin); + bool oldval=DN_GET_BIT(pin); bool newval=value!=0; if (newval==oldval) return; // no change - if (newval) SET_BIT(pin); - else CLR_BIT(pin); + if (newval) DN_SET_BIT(pin); + else DN_CLR_BIT(pin); _xmitPending=true; // shift register will be sent on next _loop() } From ec4dfb8c1e6c9cd6db6bcc3b58866c787ffcb9fc Mon Sep 17 00:00:00 2001 From: peteGSX Date: Fri, 30 Dec 2022 09:46:42 +1000 Subject: [PATCH 39/54] New working rotary encoder branch --- EXRAIL2.cpp | 12 ++++ EXRAIL2.h | 6 +- EXRAIL2MacroReset.h | 4 ++ EXRAILMacros.h | 2 + IO_RotaryEncoder.h | 127 ++++++++++++++++++++++++++++++++++++++++++ myHal.cpp_example.txt | 13 +++++ 6 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 IO_RotaryEncoder.h diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index e72e057..f44f9dc 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -91,6 +91,7 @@ LookList * RMFT2::onDeactivateLookup=NULL; LookList * RMFT2::onRedLookup=NULL; LookList * RMFT2::onAmberLookup=NULL; LookList * RMFT2::onGreenLookup=NULL; +LookList * RMFT2::onChangeLookup=NULL; #define GET_OPCODE GETHIGHFLASH(RMFT2::RouteCode,progCounter) #define SKIPOP progCounter+=3 @@ -173,6 +174,7 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { onRedLookup=LookListLoader(OPCODE_ONRED); onAmberLookup=LookListLoader(OPCODE_ONAMBER); onGreenLookup=LookListLoader(OPCODE_ONGREEN); + onChangeLookup=LookListLoader(OPCODE_ONCHANGE); // Second pass startup, define any turnouts or servos, set signals red // add sequences onRoutines to the lookups @@ -745,6 +747,10 @@ void RMFT2::loop2() { case OPCODE_IFNOT: // do next operand if sensor not set skipIf=readSensor(operand); break; + + case OPCODE_IFRE: // do next operand if rotary encoder != position + skipIf=IODevice::readAnalogue(operand)!=(int)(getOperand(1)); + break; case OPCODE_IFRANDOM: // do block on random percentage skipIf=(uint8_t)micros() >= operand * 255/100; @@ -968,6 +974,7 @@ void RMFT2::loop2() { case OPCODE_ONRED: case OPCODE_ONAMBER: case OPCODE_ONGREEN: + case OPCODE_ONCHANGE: break; @@ -1094,6 +1101,11 @@ void RMFT2::activateEvent(int16_t addr, bool activate) { if (activate) handleEvent(F("ACTIVATE"),onActivateLookup,addr); else handleEvent(F("DEACTIVATE"),onDeactivateLookup,addr); } + +void RMFT2::changeEvent(int16_t vpin, bool change) { + // Hunt for an ONCHANGE for this sensor + if (change) handleEvent(F("CHANGE"),onChangeLookup,vpin); +} void RMFT2::handleEvent(const FSH* reason,LookList* handlers, int16_t id) { int pc= handlers->find(id); diff --git a/EXRAIL2.h b/EXRAIL2.h index 6e6d0ca..2ea2ba1 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -54,6 +54,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE, OPCODE_ENDTASK,OPCODE_ENDEXRAIL, OPCODE_SET_TRACK, OPCODE_ONRED,OPCODE_ONAMBER,OPCODE_ONGREEN, + OPCODE_ONCHANGE, // OPcodes below this point are skip-nesting IF operations // placed here so that they may be skipped as a group @@ -64,7 +65,8 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE, OPCODE_IFTIMEOUT, OPCODE_IF,OPCODE_IFNOT, OPCODE_IFRANDOM,OPCODE_IFRESERVE, - OPCODE_IFCLOSED,OPCODE_IFTHROWN + OPCODE_IFCLOSED,OPCODE_IFTHROWN, + OPCODE_IFRE, }; enum thrunger: byte { @@ -113,6 +115,7 @@ class LookList { static void createNewTask(int route, uint16_t cab); static void turnoutEvent(int16_t id, bool closed); static void activateEvent(int16_t addr, bool active); + static void changeEvent(int16_t id, bool change); static const int16_t SERVO_SIGNAL_FLAG=0x4000; static const int16_t ACTIVE_HIGH_SIGNAL_FLAG=0x2000; static const int16_t DCC_SIGNAL_FLAG=0x1000; @@ -169,6 +172,7 @@ private: static LookList * onRedLookup; static LookList * onAmberLookup; static LookList * onGreenLookup; + static LookList * onChangeLookup; // Local variables - exist for each instance/task RMFT2 *next; // loop chain diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index 63fc6bd..32e28a2 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -72,6 +72,7 @@ #undef IFRESERVE #undef IFTHROWN #undef IFTIMEOUT +#undef IFRE #undef INVERT_DIRECTION #undef JOIN #undef KILLALL @@ -88,6 +89,7 @@ #undef ONGREEN #undef ONRED #undef ONTHROW +#undef ONCHANGE #undef PARSE #undef PAUSE #undef PIN_TURNOUT @@ -185,6 +187,7 @@ #define IFTHROWN(turnout_id) #define IFRESERVE(block) #define IFTIMEOUT +#define IFRE(sensor_id,value) #define INVERT_DIRECTION #define JOIN #define KILLALL @@ -201,6 +204,7 @@ #define ONGREEN(signal_id) #define ONRED(signal_id) #define ONTHROW(turnout_id) +#define ONCHANGE(sensor_id) #define PAUSE #define PIN_TURNOUT(id,pin,description...) #define PRINT(msg) diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 69ffed2..b5e78d9 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -285,6 +285,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define IFRESERVE(block) OPCODE_IFRESERVE,V(block), #define IFTHROWN(turnout_id) OPCODE_IFTHROWN,V(turnout_id), #define IFTIMEOUT OPCODE_IFTIMEOUT,0,0, +#define IFRE(sensor_id,value) OPCODE_IFRE,V(sensor_id),OPCODE_PAD,V(value), #define INVERT_DIRECTION OPCODE_INVERT_DIRECTION,0,0, #define JOIN OPCODE_JOIN,0,0, #define KILLALL OPCODE_KILLALL,0,0, @@ -301,6 +302,7 @@ const HIGHFLASH int16_t RMFT2::SignalDefinitions[] = { #define ONGREEN(signal_id) OPCODE_ONGREEN,V(signal_id), #define ONRED(signal_id) OPCODE_ONRED,V(signal_id), #define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id), +#define ONCHANGE(sensor_id) OPCODE_ONCHANGE,V(sensor_id), #define PAUSE OPCODE_PAUSE,0,0, #define PIN_TURNOUT(id,pin,description...) OPCODE_PINTURNOUT,V(id),OPCODE_PAD,V(pin), #define POM(cv,value) OPCODE_POM,V(cv),OPCODE_PAD,V(value), diff --git a/IO_RotaryEncoder.h b/IO_RotaryEncoder.h new file mode 100644 index 0000000..b4d538c --- /dev/null +++ b/IO_RotaryEncoder.h @@ -0,0 +1,127 @@ +/* + * © 2022, Peter Cole. All rights reserved. + * + * This file is part of EX-CommandStation + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CommandStation. If not, see . +*/ + +/* +* The IO_RotaryEncoder device driver is used to receive positions from a rotary encoder connected to an Arduino via I2C. +* +* There is separate code required for the Arduino the rotary encoder is connected to, which is located here: +* https://github.com/peteGSX-Projects/dcc-ex-rotary-encoder +* +* This device driver receives the rotary encoder position when the rotary encoder button is pushed, and these positions +* can be tested in EX-RAIL with: +* ONCHANGE(vpin) - flag when the rotary encoder position has changed from the previous position +* IFRE(vpin, position) - test to see if specified rotary encoder position has been received +* +* Further to this, feedback can be sent to the rotary encoder by using 2 Vpins, and sending a SET()/RESET() to the second Vpin. +* A SET(vpin) will flag that a turntable (or anything else) is in motion, and a RESET(vpin) that the motion has finished. +* +* Refer to the documentation for further information including the valid activities and examples. +*/ + +#ifndef IO_ROTARYENCODER_H +#define IO_ROTARYENCODER_H + +#include "EXRAIL2.h" +#include "IODevice.h" +#include "I2CManager.h" +#include "DIAG.h" + +class RotaryEncoder : public IODevice { +public: + // Constructor + RotaryEncoder(VPIN firstVpin, int nPins, uint8_t I2CAddress){ + _firstVpin = firstVpin; + _nPins = nPins; + _I2CAddress = I2CAddress; + addDevice(this); + } + static void create(VPIN firstVpin, int nPins, uint8_t I2CAddress) { + if (checkNoOverlap(firstVpin, nPins, I2CAddress)) new RotaryEncoder(firstVpin, nPins, I2CAddress); + } + +private: + // Initiate the device + void _begin() { + I2CManager.begin(); + if (I2CManager.exists(_I2CAddress)) { + byte _getVersion[1] = {RE_VER}; + I2CManager.read(_I2CAddress, _versionBuffer, 3, _getVersion, 1); + _majorVer = _versionBuffer[0]; + _minorVer = _versionBuffer[1]; + _patchVer = _versionBuffer[2]; + _buffer[0] = RE_OP; + I2CManager.write(_I2CAddress, _buffer, 1); +#ifdef DIAG_IO + _display(); +#endif + } else { + _deviceState = DEVSTATE_FAILED; + } + } + + void _loop(unsigned long currentMicros) override { + I2CManager.read(_I2CAddress, _buffer, 1); + _position = _buffer[0]; + // This here needs to have a change check, ie. position is a different value. + #if defined(EXRAIL_ACTIVE) + if (_position != _previousPosition) { + _previousPosition = _position; + RMFT2::changeEvent(_firstVpin,1); + } else { + RMFT2::changeEvent(_firstVpin,0); + } + #endif + delayUntil(currentMicros + 100000); + } + + // Device specific read function + int _readAnalogue(VPIN vpin) override { + if (_deviceState == DEVSTATE_FAILED) return 0; + return _position; + } + + void _write(VPIN vpin, int value) override { + if (vpin == _firstVpin + 1) { + byte _feedbackBuffer[2] = {RE_OP, value}; + I2CManager.write(_I2CAddress, _feedbackBuffer, 2); + } + } + + void _display() override { + DIAG(F("Rotary Encoder I2C:x%x v%d.%d.%d Configured on Vpin:%d-%d %S"), _I2CAddress, _majorVer, _minorVer, _patchVer, + (int)_firstVpin, _firstVpin+_nPins-1, (_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F("")); + } + + uint8_t _I2CAddress; + int8_t _position; + int8_t _previousPosition = 0; + uint8_t _versionBuffer[3]; + uint8_t _buffer[1]; + uint8_t _majorVer = 0; + uint8_t _minorVer = 0; + uint8_t _patchVer = 0; + + enum { + RE_VER = 0xA0, // Flag to retrieve rotary encoder version from the device + RE_OP = 0xA1, // Flag for normal operation + }; + +}; + +#endif diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index c95aaed..9752a8b 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -194,6 +194,19 @@ void halSetup() { //EXIOExpander::create(820, 16, 0x66, 16, 0); + //======================================================================= + // The following directive defines a rotary encoder instance. + //======================================================================= + // The parameters are: + // firstVpin = First available Vpin to allocate + // numPins= Number of Vpins to allocate, can be either 1 or 2 + // i2cAddress = Available I2C address (default 0x70) + + //RotaryEncoder::create(firstVpin, numPins, i2cAddress); + //RotaryEncoder::create(700, 1, 0x70); + //RotaryEncoder::create(701, 2, 0x71); + + } #endif From 3fccf6a484af7b3b19a14d84aa63dd62f396a430 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 3 Jan 2023 08:57:21 +1000 Subject: [PATCH 40/54] Fix EX-IOExpander myHal.cpp example --- myHal.cpp_example.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myHal.cpp_example.txt b/myHal.cpp_example.txt index 9752a8b..5470f76 100644 --- a/myHal.cpp_example.txt +++ b/myHal.cpp_example.txt @@ -190,7 +190,7 @@ void halSetup() { // The first example is for an Arduino Nano with the default pin allocations. // The second example is for an Arduino Uno using all pins as digital only. - //EXIOExpander::create(800, 18, 0x65, 12, 8); + //EXIOExpander::create(800, 18, 0x65, 12, 6); //EXIOExpander::create(820, 16, 0x66, 16, 0); From 658fca260195abbd881094598b12c502ad720cb3 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Mon, 9 Jan 2023 16:24:29 +0800 Subject: [PATCH 41/54] Nucleo-F446RE Build target support --- DCCTimerSTM32.cpp | 9 ++++----- platformio.ini | 33 +++++++++++++-------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index b26aa4d..1b96f70 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -30,13 +30,12 @@ #include "DCCTimer.h" -#if defined(ARDUINO_NUCLEO_F411RE) -// STM32F411RE doesn't have Serial1 defined by default +#if defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) +// Nucleo-64 boards don't have Serial1 defined by default HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F411RE // Serial2 is defined to use USART2 by default, but is in fact used as the diag console -// via the debugger on the Nucleo-64 STM32F411RE. It is therefore unavailable -// for other DCC-EX uses like WiFi, DFPlayer, etc. -// Let's define Serial6 as an additional serial port (the only other option for the F411RE) +// via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc. +// Let's define Serial6 as an additional serial port (the only other option for the Nucleo-64s) HardwareSerial Serial6(PA12, PA11); // Rx=PA12, Tx=PA11 -- CN10 pins 12 and 14 - F411RE #elif defined(ARDUINO_BLAH_F412ZG) || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) // Nucleo-144 boards don't have Serial1 defined by default diff --git a/platformio.ini b/platformio.ini index 5fcda00..46606b1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -24,8 +24,8 @@ default_envs = Teensy3.6 Teensy4.0 Teensy4.1 -src_dir = . -include_dir = . +src_dir = /Users/paul/Projects/CommandStation-EX-devel +include_dir = /Users/paul/Projects/CommandStation-EX-devel [env] build_flags = -Wall -Wextra @@ -50,19 +50,6 @@ monitor_speed = 115200 monitor_echo = yes build_flags = -std=c++17 -; Firebox disabled for now -; [env:samc21-firebox] -; platform = atmelsam -; board = firebox -; framework = arduino -; upload_protocol = atmel-ice -; lib_deps = -; ${env.lib_deps} -; SparkFun External EEPROM Arduino Library -;monitor_speed = 115200 -;monitor_echo = yes -;build_flags = -std=c++17 - [env:mega2560-debug] platform = atmelavr board = megaatmega2560 @@ -109,9 +96,6 @@ lib_deps = SPI monitor_speed = 115200 monitor_echo = yes -; Example, but v12 does generate bigger binaries -; platform_packages = toolchain-atmelavr@symlink:///opt/avr-gcc-12.1.0-x64-linux -; Should make binaries smaller build_flags = -mcall-prologues [env:mega328] @@ -160,7 +144,6 @@ lib_deps = SPI monitor_speed = 115200 monitor_echo = yes -; Should make binaries smaller build_flags = -mcall-prologues [env:nano] @@ -188,6 +171,15 @@ build_flags = -std=c++17 -Os -g2 monitor_speed = 115200 monitor_echo = yes +[env:Nucleo-F446RE] +platform = ststm32 +board = nucleo_f446re +framework = arduino +lib_deps = ${env.lib_deps} +build_flags = -std=c++17 -Os -g2 +monitor_speed = 115200 +monitor_echo = yes + [env:Teensy3.2] platform = teensy board = teensy31 @@ -226,4 +218,5 @@ board = teensy41 framework = arduino build_flags = -std=c++17 -Os -g2 lib_deps = ${env.lib_deps} -lib_ignore = \ No newline at end of file +lib_ignore = + From 402e16727c4b100f010f4d7f5fe59bf3433acf13 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Mon, 9 Jan 2023 16:47:29 +0800 Subject: [PATCH 42/54] Fix platformio for Nucleo-F446RE --- platformio.ini | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 46606b1..c82d8b4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,13 +19,14 @@ default_envs = samd21-zero-usb ESP32 Nucleo-F411RE + Nucleo-F446RE Teensy3.2 Teensy3.5 Teensy3.6 Teensy4.0 Teensy4.1 -src_dir = /Users/paul/Projects/CommandStation-EX-devel -include_dir = /Users/paul/Projects/CommandStation-EX-devel +src_dir = . +include_dir = . [env] build_flags = -Wall -Wextra From 6eff836473ac700b9c98ac24de7415a1b8e7d2c1 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Mon, 9 Jan 2023 17:18:50 +0800 Subject: [PATCH 43/54] Add -Wunused-variable build flag to Nucleo builds --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index c82d8b4..82167f2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -168,7 +168,7 @@ platform = ststm32 board = nucleo_f411re framework = arduino lib_deps = ${env.lib_deps} -build_flags = -std=c++17 -Os -g2 +build_flags = -std=c++17 -Os -g2 -Wunused-variable monitor_speed = 115200 monitor_echo = yes @@ -177,7 +177,7 @@ platform = ststm32 board = nucleo_f446re framework = arduino lib_deps = ${env.lib_deps} -build_flags = -std=c++17 -Os -g2 +build_flags = -std=c++17 -Os -g2 -Wunused-variable monitor_speed = 115200 monitor_echo = yes From e01893bcf14891504755537b177582cfd2b2f3f5 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 9 Jan 2023 20:03:18 +1000 Subject: [PATCH 44/54] Comment out unused variables --- IO_EXIOExpander.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 151a319..7e34352 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -66,13 +66,13 @@ private: _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; - int _dPinArrayLen = (_numDigitalPins + 7) / 8; + // int _dPinArrayLen = (_numDigitalPins + 7) / 8; addDevice(this); } void _begin() { // Initialise EX-IOExander device - uint8_t _check = I2CManager.checkAddress(_i2cAddress); + // uint8_t _check = I2CManager.checkAddress(_i2cAddress); if (I2CManager.exists(_i2cAddress)) { _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; @@ -105,7 +105,7 @@ private: if (paramCount != 1) return false; bool pullup = params[0]; int pin = vpin - _firstVpin; - uint8_t mask = 1 << ((pin-_firstVpin) % 8); + // uint8_t mask = 1 << ((pin-_firstVpin) % 8); _digitalOutBuffer[0] = EXIODPUP; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = pullup; From 9abcfb9e4f0591882e02992d358d3c52f9603f94 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Mon, 9 Jan 2023 20:08:36 +1000 Subject: [PATCH 45/54] Add begin delay to test --- IO_EXIOExpander.h | 1 + 1 file changed, 1 insertion(+) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 7e34352..5bff3ec 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -73,6 +73,7 @@ private: void _begin() { // Initialise EX-IOExander device // uint8_t _check = I2CManager.checkAddress(_i2cAddress); + delay(100); if (I2CManager.exists(_i2cAddress)) { _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; From 5c120efa1615ceeca8fcff092dc8c726dadfcf42 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 10 Jan 2023 08:16:42 +1000 Subject: [PATCH 46/54] Add being --- IO_EXIOExpander.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 5bff3ec..b3260fa 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -73,7 +73,7 @@ private: void _begin() { // Initialise EX-IOExander device // uint8_t _check = I2CManager.checkAddress(_i2cAddress); - delay(100); + I2CManager.begin(); if (I2CManager.exists(_i2cAddress)) { _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; From e48a40fafb0ea0bee5dfa33f19f01a1be5a7b0a8 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 10 Jan 2023 13:07:54 +1000 Subject: [PATCH 47/54] Change to blocking I2CManager calls --- IO_EXIOExpander.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index b3260fa..7661efc 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -79,7 +79,8 @@ private: _digitalOutBuffer[1] = _numDigitalPins; _digitalOutBuffer[2] = _numAnaloguePins; // Send config, if EXIORDY returned, we're good, otherwise go offline - I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + // I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3); if (_digitalInBuffer[0] != EXIORDY) { DIAG(F("ERROR configuring EX-IOExpander device, I2C:x%x"), _i2cAddress); _deviceState = DEVSTATE_FAILED; @@ -88,7 +89,8 @@ private: // Attempt to get version, if we don't get it, we don't care, don't go offline // Using digital in buffer in reverse to save RAM _digitalInBuffer[0] = EXIOVER; - I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1, &_i2crb); + // I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1, &_i2crb); + I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1); _majorVer = _versionBuffer[0]; _minorVer = _versionBuffer[1]; _patchVer = _versionBuffer[2]; @@ -110,7 +112,8 @@ private: _digitalOutBuffer[0] = EXIODPUP; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = pullup; - I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); + // I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); + I2CManager.write(_i2cAddress, _digitalOutBuffer, 3); return true; } @@ -118,7 +121,8 @@ private: int pin = vpin - _firstVpin; _analogueOutBuffer[0] = EXIORDAN; _analogueOutBuffer[1] = pin; - I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); + // I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); + I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2); return (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; } @@ -127,7 +131,8 @@ private: _digitalOutBuffer[0] = EXIORDD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = 0x00; // Don't need to use this for reading - I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + // I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); + I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3); return _digitalInBuffer[0]; } @@ -136,7 +141,8 @@ private: _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = value; - I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); + // I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); + I2CManager.write(_i2cAddress, _digitalOutBuffer, 3); } void _display() override { @@ -168,7 +174,7 @@ private: uint8_t _majorVer = 0; uint8_t _minorVer = 0; uint8_t _patchVer = 0; - I2CRB _i2crb; + // I2CRB _i2crb; enum { EXIOINIT = 0xE0, // Flag to initialise setup procedure From c26f53e1fa65dd280e5e5ff20b9528f3bd3f1ad3 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Tue, 10 Jan 2023 20:05:09 +1000 Subject: [PATCH 48/54] Device driver fixed --- IO_EXIOExpander.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index 7661efc..b36654f 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -66,20 +66,17 @@ private: _i2cAddress = i2cAddress; _numDigitalPins = numDigitalPins; _numAnaloguePins = numAnaloguePins; - // int _dPinArrayLen = (_numDigitalPins + 7) / 8; addDevice(this); } void _begin() { // Initialise EX-IOExander device - // uint8_t _check = I2CManager.checkAddress(_i2cAddress); I2CManager.begin(); if (I2CManager.exists(_i2cAddress)) { _digitalOutBuffer[0] = EXIOINIT; _digitalOutBuffer[1] = _numDigitalPins; _digitalOutBuffer[2] = _numAnaloguePins; // Send config, if EXIORDY returned, we're good, otherwise go offline - // I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3); if (_digitalInBuffer[0] != EXIORDY) { DIAG(F("ERROR configuring EX-IOExpander device, I2C:x%x"), _i2cAddress); @@ -89,7 +86,6 @@ private: // Attempt to get version, if we don't get it, we don't care, don't go offline // Using digital in buffer in reverse to save RAM _digitalInBuffer[0] = EXIOVER; - // I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1, &_i2crb); I2CManager.read(_i2cAddress, _versionBuffer, 3, _digitalInBuffer, 1); _majorVer = _versionBuffer[0]; _minorVer = _versionBuffer[1]; @@ -108,11 +104,9 @@ private: if (paramCount != 1) return false; bool pullup = params[0]; int pin = vpin - _firstVpin; - // uint8_t mask = 1 << ((pin-_firstVpin) % 8); _digitalOutBuffer[0] = EXIODPUP; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = pullup; - // I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); I2CManager.write(_i2cAddress, _digitalOutBuffer, 3); return true; } @@ -121,7 +115,6 @@ private: int pin = vpin - _firstVpin; _analogueOutBuffer[0] = EXIORDAN; _analogueOutBuffer[1] = pin; - // I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2, &_i2crb); I2CManager.read(_i2cAddress, _analogueInBuffer, 2, _analogueOutBuffer, 2); return (_analogueInBuffer[1] << 8) + _analogueInBuffer[0]; } @@ -131,7 +124,6 @@ private: _digitalOutBuffer[0] = EXIORDD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = 0x00; // Don't need to use this for reading - // I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3, &_i2crb); I2CManager.read(_i2cAddress, _digitalInBuffer, 1, _digitalOutBuffer, 3); return _digitalInBuffer[0]; } @@ -141,7 +133,6 @@ private: _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; _digitalOutBuffer[2] = value; - // I2CManager.write(_i2cAddress, _digitalOutBuffer, 3, &_i2crb); I2CManager.write(_i2cAddress, _digitalOutBuffer, 3); } @@ -174,7 +165,6 @@ private: uint8_t _majorVer = 0; uint8_t _minorVer = 0; uint8_t _patchVer = 0; - // I2CRB _i2crb; enum { EXIOINIT = 0xE0, // Flag to initialise setup procedure From 22e20f90922272dd6d546873c7ac60515dfcc77f Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 12 Jan 2023 07:27:42 +1000 Subject: [PATCH 49/54] Logic added and working --- IO_EXIOExpander.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index b36654f..d00e97c 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -90,6 +90,8 @@ private: _majorVer = _versionBuffer[0]; _minorVer = _versionBuffer[1]; _patchVer = _versionBuffer[2]; + DIAG(F("EX-IOExpander device found, I2C:x%x, Version v%d.%d.%d"), + _i2cAddress, _versionBuffer[0], _versionBuffer[1], _versionBuffer[2]); #ifdef DIAG_IO _display(); #endif @@ -102,6 +104,10 @@ private: bool _configure(VPIN vpin, ConfigTypeEnum configType, int paramCount, int params[]) override { if (configType != CONFIGURE_INPUT) return false; if (paramCount != 1) return false; + if (vpin >= _firstVpin + _numDigitalPins) { + DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); + return false; + } bool pullup = params[0]; int pin = vpin - _firstVpin; _digitalOutBuffer[0] = EXIODPUP; @@ -112,6 +118,10 @@ private: } int _readAnalogue(VPIN vpin) override { + if (vpin < _firstVpin + _numDigitalPins) { + DIAG(F("Vpin %d is a digital pin, cannot use as an analogue pin"), vpin); + return false; + } int pin = vpin - _firstVpin; _analogueOutBuffer[0] = EXIORDAN; _analogueOutBuffer[1] = pin; @@ -120,6 +130,10 @@ private: } int _read(VPIN vpin) override { + if (vpin >= _firstVpin + _numDigitalPins) { + DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); + return false; + } int pin = vpin - _firstVpin; _digitalOutBuffer[0] = EXIORDD; _digitalOutBuffer[1] = pin; @@ -129,6 +143,10 @@ private: } void _write(VPIN vpin, int value) override { + if (vpin >= _firstVpin + _numDigitalPins) { + DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); + return; + } int pin = vpin - _firstVpin; _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; From a8646a2f329d31519733d32aec395c9446f59219 Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 12 Jan 2023 07:33:50 +1000 Subject: [PATCH 50/54] Fix EX-Turntable diag message --- IO_EXTurntable.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IO_EXTurntable.h b/IO_EXTurntable.h index ea3dcb0..2dc9e6b 100644 --- a/IO_EXTurntable.h +++ b/IO_EXTurntable.h @@ -47,7 +47,7 @@ EXTurntable::EXTurntable(VPIN firstVpin, int nPins, uint8_t I2CAddress) { addDevice(this); } -// Initialisation of TurntableEX +// Initialisation of EXTurntable void EXTurntable::_begin() { I2CManager.begin(); I2CManager.setClock(1000000); @@ -103,7 +103,7 @@ void EXTurntable::_writeAnalogue(VPIN vpin, int value, uint8_t activity, uint16_ uint8_t stepsMSB = value >> 8; uint8_t stepsLSB = value & 0xFF; #ifdef DIAG_IO - DIAG(F("TurntableEX WriteAnalogue Vpin:%d Value:%d Activity:%d Duration:%d"), + DIAG(F("EX-Turntable WriteAnalogue Vpin:%d Value:%d Activity:%d Duration:%d"), vpin, value, activity, duration); DIAG(F("I2CManager write I2C Address:%d stepsMSB:%d stepsLSB:%d activity:%d"), _I2CAddress, stepsMSB, stepsLSB, activity); @@ -114,7 +114,7 @@ void EXTurntable::_writeAnalogue(VPIN vpin, int value, uint8_t activity, uint16_ // Display Turnetable-EX device driver info. void EXTurntable::_display() { - DIAG(F("TurntableEX I2C:x%x Configured on Vpins:%d-%d %S"), _I2CAddress, (int)_firstVpin, + DIAG(F("EX-Turntable I2C:x%x Configured on Vpins:%d-%d %S"), _I2CAddress, (int)_firstVpin, (int)_firstVpin+_nPins-1, (_deviceState==DEVSTATE_FAILED) ? F("OFFLINE") : F("")); } From 9b36bdcf46e2c2ec5fd01cc9cc9f02080e40651b Mon Sep 17 00:00:00 2001 From: peteGSX Date: Thu, 12 Jan 2023 08:10:41 +1000 Subject: [PATCH 51/54] Logic and diag message done --- IO_EXIOExpander.h | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/IO_EXIOExpander.h b/IO_EXIOExpander.h index d00e97c..1e20fac 100644 --- a/IO_EXIOExpander.h +++ b/IO_EXIOExpander.h @@ -105,7 +105,7 @@ private: if (configType != CONFIGURE_INPUT) return false; if (paramCount != 1) return false; if (vpin >= _firstVpin + _numDigitalPins) { - DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); + DIAG(F("EX-IOExpander ERROR: Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); return false; } bool pullup = params[0]; @@ -117,11 +117,16 @@ private: return true; } - int _readAnalogue(VPIN vpin) override { + // We only use this to detect incorrect use of analogue pins + int _configureAnalogIn(VPIN vpin) override { if (vpin < _firstVpin + _numDigitalPins) { - DIAG(F("Vpin %d is a digital pin, cannot use as an analogue pin"), vpin); - return false; + DIAG(F("EX-IOExpander ERROR: Vpin %d is a digital pin, cannot use as an analogue pin"), vpin); } + return false; + } + + int _readAnalogue(VPIN vpin) override { + if (vpin < _firstVpin + _numDigitalPins) return false; int pin = vpin - _firstVpin; _analogueOutBuffer[0] = EXIORDAN; _analogueOutBuffer[1] = pin; @@ -130,10 +135,7 @@ private: } int _read(VPIN vpin) override { - if (vpin >= _firstVpin + _numDigitalPins) { - DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); - return false; - } + if (vpin >= _firstVpin + _numDigitalPins) return false; int pin = vpin - _firstVpin; _digitalOutBuffer[0] = EXIORDD; _digitalOutBuffer[1] = pin; @@ -143,10 +145,7 @@ private: } void _write(VPIN vpin, int value) override { - if (vpin >= _firstVpin + _numDigitalPins) { - DIAG(F("Vpin %d is an analogue pin, cannot use as a digital pin"), vpin); - return; - } + if (vpin >= _firstVpin + _numDigitalPins) return; int pin = vpin - _firstVpin; _digitalOutBuffer[0] = EXIOWRD; _digitalOutBuffer[1] = pin; From 046e62a8b362bf288f0cea7c90dd1f14331673d8 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Fri, 13 Jan 2023 17:24:26 +0800 Subject: [PATCH 52/54] Minor fix to DCCTimerSTM32.cpp for F412ZG. --- DCCTimerSTM32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index 1b96f70..f81f386 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -37,7 +37,7 @@ HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F // via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc. // Let's define Serial6 as an additional serial port (the only other option for the Nucleo-64s) HardwareSerial Serial6(PA12, PA11); // Rx=PA12, Tx=PA11 -- CN10 pins 12 and 14 - F411RE -#elif defined(ARDUINO_BLAH_F412ZG) || defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) +#elif defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) // Nucleo-144 boards don't have Serial1 defined by default HardwareSerial Serial1(PG9, PG14); // Rx=PG9, Tx=PG14 -- D0, D1 - F412ZG/F446ZE #else From 1f433d0c178a33620cc38f87437c664861105de6 Mon Sep 17 00:00:00 2001 From: pmantoine Date: Sat, 14 Jan 2023 12:43:05 +0800 Subject: [PATCH 53/54] Serial1 for STM32F446RE corrected. --- DCCTimerSTM32.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index f81f386..432100a 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -30,13 +30,18 @@ #include "DCCTimer.h" -#if defined(ARDUINO_NUCLEO_F411RE) || defined(ARDUINO_NUCLEO_F446RE) +#if defined(ARDUINO_NUCLEO_F411RE) // Nucleo-64 boards don't have Serial1 defined by default HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F411RE // Serial2 is defined to use USART2 by default, but is in fact used as the diag console // via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc. // Let's define Serial6 as an additional serial port (the only other option for the Nucleo-64s) HardwareSerial Serial6(PA12, PA11); // Rx=PA12, Tx=PA11 -- CN10 pins 12 and 14 - F411RE +#elif defined(ARDUINO_NUCLEO_F446RE) +// Nucleo-64 boards don't have Serial1 defined by default +HardwareSerial Serial1(PA10, PB6); // Rx=PA10, Tx=PB6 -- CN10 pins 17 and 32 - F446RE +// Serial2 is defined to use USART2 by default, but is in fact used as the diag console +// via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc. #elif defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE) // Nucleo-144 boards don't have Serial1 defined by default HardwareSerial Serial1(PG9, PG14); // Rx=PG9, Tx=PG14 -- D0, D1 - F412ZG/F446ZE From 1be382a6edbead09e3538fda86f938ecf6c29c5a Mon Sep 17 00:00:00 2001 From: pmantoine Date: Sat, 14 Jan 2023 12:45:21 +0800 Subject: [PATCH 54/54] Fixed comment re Serial1 for STM32F446RE --- DCCTimerSTM32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DCCTimerSTM32.cpp b/DCCTimerSTM32.cpp index 432100a..0976bcd 100644 --- a/DCCTimerSTM32.cpp +++ b/DCCTimerSTM32.cpp @@ -39,7 +39,7 @@ HardwareSerial Serial1(PB7, PA15); // Rx=PB7, Tx=PA15 -- CN7 pins 17 and 21 - F HardwareSerial Serial6(PA12, PA11); // Rx=PA12, Tx=PA11 -- CN10 pins 12 and 14 - F411RE #elif defined(ARDUINO_NUCLEO_F446RE) // Nucleo-64 boards don't have Serial1 defined by default -HardwareSerial Serial1(PA10, PB6); // Rx=PA10, Tx=PB6 -- CN10 pins 17 and 32 - F446RE +HardwareSerial Serial1(PA10, PB6); // Rx=PA10, Tx=PB6 -- CN10 pins 17 and 33 - F446RE // Serial2 is defined to use USART2 by default, but is in fact used as the diag console // via the debugger on the Nucleo-64. It is therefore unavailable for other DCC-EX uses like WiFi, DFPlayer, etc. #elif defined(ARDUINO_NUCLEO_F412ZG) || defined(ARDUINO_NUCLEO_F429ZI) || defined(ARDUINO_NUCLEO_F446ZE)