From 54f8aaf116f7f0476f9a19128f386cb283024a7f Mon Sep 17 00:00:00 2001 From: Asbelos Date: Thu, 1 May 2025 09:29:05 +0100 Subject: [PATCH] 5.5.25 IO_Bitmap --- EXRAIL2.cpp | 37 +++++++++++++++- EXRAIL2.h | 6 ++- EXRAIL2MacroReset.h | 65 +++++++++++++++++++++++++++- EXRAILMacros.h | 10 +++++ EXRAILSensor.cpp | 10 ++--- EXRAILSensor.h | 8 ++-- IODeviceList.h | 30 +++++++++---- IO_Bitmap.h | 89 ++++++++++++++++++++++++++++++++++++++ Release_Notes/IO_Bitmap.md | 58 +++++++++++++++++++++++++ version.h | 3 +- 10 files changed, 294 insertions(+), 22 deletions(-) create mode 100644 IO_Bitmap.h create mode 100644 Release_Notes/IO_Bitmap.md diff --git a/EXRAIL2.cpp b/EXRAIL2.cpp index a3c965c..f73ba35 100644 --- a/EXRAIL2.cpp +++ b/EXRAIL2.cpp @@ -263,6 +263,8 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { case OPCODE_ATLT: case OPCODE_IFGTE: case OPCODE_IFLT: + case OPCODE_IFBITMAP_ALL: + case OPCODE_IFBITMAP_ANY: case OPCODE_DRIVE: { DIAG(F("EXRAIL analog input VPIN %u"),(VPIN)operand); IODevice::configureAnalogIn((VPIN)operand); @@ -273,6 +275,10 @@ LookList* RMFT2::LookListLoader(OPCODE op1, OPCODE op2, OPCODE op3) { if (compileFeatures & FEATURE_SENSOR) new EXRAILSensor(operand,progCounter+3,true ); break; + case OPCODE_ONBITMAP: + if (compileFeatures & FEATURE_SENSOR) + new EXRAILSensor(operand,progCounter+3,true, true ); + break; case OPCODE_ONBUTTON: if (compileFeatures & FEATURE_SENSOR) new EXRAILSensor(operand,progCounter+3,false ); @@ -762,6 +768,14 @@ void RMFT2::loop2() { case OPCODE_IFLT: // do next operand if sensor< value skipIf=IODevice::readAnalogue(operand)>=(int)(getOperand(1)); break; + + case OPCODE_IFBITMAP_ALL: // do next operand if sensor & mask == mask + skipIf=(IODevice::readAnalogue(operand) & getOperand(1)) != getOperand(1); + break; + + case OPCODE_IFBITMAP_ANY: // do next operand if sensor & mask !=0 + skipIf=(IODevice::readAnalogue(operand) & getOperand(1)) == 0; + break; case OPCODE_IFLOCO: // do if the loco is the active one skipIf=loco!=(uint16_t)operand; // bad luck if someone enters negative loco numbers into EXRAIL @@ -1094,7 +1108,27 @@ void RMFT2::loop2() { case OPCODE_SEQUENCE: //if (diag) DIAG(F("EXRAIL begin(%d)"),operand); break; - + + case OPCODE_BITMAP_INC: + IODevice::writeAnalogue(operand,IODevice::readAnalogue(operand)+1); + break; + case OPCODE_BITMAP_DEC: + { int newval=IODevice::readAnalogue(operand)-1; + if (newval<0) newval=0; + IODevice::writeAnalogue(operand,newval); + } + break; + + case OPCODE_BITMAP_AND: + IODevice::writeAnalogue(operand,IODevice::readAnalogue(operand) & getOperand(1)); + break; + case OPCODE_BITMAP_OR: + IODevice::writeAnalogue(operand,IODevice::readAnalogue(operand) | getOperand(1)); + break; + case OPCODE_BITMAP_XOR: + IODevice::writeAnalogue(operand,IODevice::readAnalogue(operand) ^ getOperand(1)); + break; + case OPCODE_AUTOSTART: // Handled only during begin process case OPCODE_PAD: // Just a padding for previous opcode needing >1 operand byte. case OPCODE_TURNOUT: // Turnout definition ignored at runtime @@ -1114,6 +1148,7 @@ void RMFT2::loop2() { case OPCODE_ONTIME: case OPCODE_ONBUTTON: case OPCODE_ONSENSOR: + case OPCODE_ONBITMAP: #ifndef IO_NO_HAL case OPCODE_DCCTURNTABLE: // Turntable definition ignored at runtime case OPCODE_EXTTTURNTABLE: // Turntable definition ignored at runtime diff --git a/EXRAIL2.h b/EXRAIL2.h index df1f5d0..ddef0c9 100644 --- a/EXRAIL2.h +++ b/EXRAIL2.h @@ -78,11 +78,12 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT, OPCODE_ROUTE_DISABLED, OPCODE_STASH,OPCODE_CLEAR_STASH,OPCODE_CLEAR_ALL_STASH,OPCODE_PICKUP_STASH, OPCODE_CLEAR_ANY_STASH, - OPCODE_ONBUTTON,OPCODE_ONSENSOR, + OPCODE_ONBUTTON,OPCODE_ONSENSOR,OPCODE_ONVP_SENSOR, OPCODE_NEOPIXEL, OPCODE_ONBLOCKENTER,OPCODE_ONBLOCKEXIT, OPCODE_ESTOPALL,OPCODE_XPOM, - // OPcodes below this point are skip-nesting IF operations + OPCODE_BITMAP_AND,OPCODE_BITMAP_OR,OPCODE_BITMAP_XOR,OPCODE_BITMAP_INC,OPCODE_BITMAP_DEC,OPCODE_ONBITMAP, + // OPcodes below this point are skip-nesting IF operations // placed here so that they may be skipped as a group // see skipIfBlock() IF_TYPE_OPCODES, // do not move this... @@ -96,6 +97,7 @@ enum OPCODE : byte {OPCODE_THROW,OPCODE_CLOSE,OPCODE_TOGGLE_TURNOUT, OPCODE_IFLOCO, OPCODE_IFTTPOSITION, OPCODE_IFSTASH, + OPCODE_IFBITMAP_ALL,OPCODE_IFBITMAP_ANY, }; // Ensure thrunge_lcd is put last as there may be more than one display, diff --git a/EXRAIL2MacroReset.h b/EXRAIL2MacroReset.h index eaa8f93..b6658dd 100644 --- a/EXRAIL2MacroReset.h +++ b/EXRAIL2MacroReset.h @@ -94,6 +94,8 @@ #undef IFTIMEOUT #undef IFTTPOSITION #undef IFRE +#undef IFBITMAP_ALL +#undef IFBITMAP_ANY #undef INVERT_DIRECTION #undef JMRI_SENSOR #undef JOIN @@ -133,6 +135,7 @@ #undef ONBUTTON #undef ONSENSOR #undef ONTHROW +#undef ONBITMAP #undef ONCHANGE #undef PARSE #undef PAUSE @@ -195,6 +198,11 @@ #undef VIRTUAL_TURNOUT #undef WAITFOR #ifndef IO_NO_HAL +#undef BITMAP_AND +#undef BITMAP_OR +#undef BITMAP_XOR +#undef BITMAP_INC +#undef BITMAP_DEC #undef WAITFORTT #endif #undef WITHROTTLE @@ -651,6 +659,22 @@ * @param value */ #define IFRE(vpin,value) +/** + * @def IFBITMAP_ALL(vpin,mask) + * @briaf Checks if (vpin pseudo-analog value & mask) == mask. + * @see IF + * @param vpin + * @param mask Binary mask applied to vpin value + */ +#define IFBITMAP_ALL(vpin,mask) +/** + * @def IFBITMAP_ANY(vpin,mask) + * @briaf Checks if vpin pseudo-analog value & mask is non zero + * @see IF + * @param vpin + * @param mask Binary mask applied to vpin value + */ +#define IFBITMAP_ANY(vpin,mask) /** * @def INVERT_DIRECTION * @brief Marks current task so that FWD and REV commands are inverted. @@ -899,6 +923,12 @@ * @param vpin */ #define ONSENSOR(vpin) +/** + * @def ONBITMAP(vpin) + * @brief Start task here when bitmap sensor changes state (debounced) + * @param vpin + */ +#define ONBITMAP(vpin) /** * @def ONBUTTON(vpin) * @brief Start task here when sensor changes HIGH to LOW. @@ -1322,9 +1352,42 @@ * @param description... quoted text or HIDDEN */ #define VIRTUAL_TURNOUT(id,description...) +/** + * @def BITMAP_AND(vpin1,mask) + * @brief Performs a bitwise AND operation on the given vpin analog value and mask. + * @param vpin1 + * @param mask Binary mask to be ANDed with vpin1 value + */ +#define BITMAP_AND(vpin1,mask) +/** + * @def BITMAP_INC(vpin) + * @brief Increments poesudo analog value by 1 + * @param vpin + */ +#define BITMAP_INC(vpin) +/** + * @def BITMAP_DEC(vpin) + * @brief Decrements poesudo analog value by 1 (to zero) + * @param vpin + */ +#define BITMAP_DEC(vpin) +/** + * @def BITMAP_OR(vpin1,mask) + * @brief Performs a bitwise OR operation on the given vpin analog value and mask. + * @param vpin1 + * @param mask Binary mask to be ORed with vpin1 value + */ +#define BITMAP_OR(vpin1,mask) +/** + * @def BITMAP_XOR(vpin1,mask) + * @brief Performs a bitwise XOR operation on the given vpin analog value and mask. + * @param vpin1 + * @param mask Binary mask to be XORed with vpin1 value + */ +#define BITMAP_XOR(vpin1,mask) /** * @def WAITFOR(vpin) - * @brief WAits for completion of servo movement + * @brief Waits for completion of servo movement * @param vpin */ #define WAITFOR(pin) diff --git a/EXRAILMacros.h b/EXRAILMacros.h index 40cd5d6..d926eff 100644 --- a/EXRAILMacros.h +++ b/EXRAILMacros.h @@ -160,6 +160,8 @@ bool exrailHalSetup() { #define ONBUTTON(vpin) | FEATURE_SENSOR #undef ONSENSOR #define ONSENSOR(vpin) | FEATURE_SENSOR +#undef ONBITMAP +#define ONBITMAP(vpin) | FEATURE_SENSOR #undef ONBLOCKENTER #define ONBLOCKENTER(blockid) | FEATURE_BLOCK #undef ONBLOCKEXIT @@ -481,6 +483,8 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #define IFTTPOSITION(id,position) OPCODE_IFTTPOSITION,V(id),OPCODE_PAD,V(position), #endif #define IFRE(sensor_id,value) OPCODE_IFRE,V(sensor_id),OPCODE_PAD,V(value), +#define IFBITMAP_ALL(vpin,mask) OPCODE_IFBITMAP_ALL,V(vpin),OPCODE_PAD,V(mask), +#define IFBITMAP_ANY(vpin,mask) OPCODE_IFBITMAP_ANY,V(vpin),OPCODE_PAD,V(mask), #define INVERT_DIRECTION OPCODE_INVERT_DIRECTION,0,0, #define JMRI_SENSOR(vpin,count...) #define JOIN OPCODE_JOIN,0,0, @@ -533,6 +537,7 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #define ONTHROW(turnout_id) OPCODE_ONTHROW,V(turnout_id), #define ONCHANGE(sensor_id) OPCODE_ONCHANGE,V(sensor_id), #define ONSENSOR(sensor_id) OPCODE_ONSENSOR,V(sensor_id), +#define ONBITMAP(sensor_id) OPCODE_ONBITMAP,V(sensor_id), #define ONBUTTON(sensor_id) OPCODE_ONBUTTON,V(sensor_id), #define PAUSE OPCODE_PAUSE,0,0, #define PICKUP_STASH(id) OPCODE_PICKUP_STASH,V(id), @@ -595,6 +600,11 @@ int RMFT2::onLCCLookup[RMFT2::countLCCLookup]; #define UNLATCH(sensor_id) OPCODE_UNLATCH,V(sensor_id), #define VIRTUAL_SIGNAL(id) #define VIRTUAL_TURNOUT(id,description...) OPCODE_PINTURNOUT,V(id),OPCODE_PAD,V(0), +#define BITMAP_AND(vpin,mask) OPCODE_BITMAP_AND,V(vpin),OPCODE_PAD,V(mask), +#define BITMAP_INC(vpin) OPCODE_BITMAP_INC,V(vpin), +#define BITMAP_DEC(vpin) OPCODE_BITMAP_DEC,V(vpin), +#define BITMAP_OR(vpin,mask) OPCODE_BITMAP_OR,V(vpin),OPCODE_PAD,V(mask), +#define BITMAP_XOR(vpin,mask) OPCODE_BITMAP_XOR,V(vpin),OPCODE_PAD,V(mask), #define WITHROTTLE(msg) PRINT(msg) #define WAITFOR(pin) OPCODE_WAITFOR,V(pin), #ifndef IO_NO_HAL diff --git a/EXRAILSensor.cpp b/EXRAILSensor.cpp index 218b970..c6ac3e9 100644 --- a/EXRAILSensor.cpp +++ b/EXRAILSensor.cpp @@ -59,7 +59,7 @@ void EXRAILSensor::checkAll() { bool EXRAILSensor::check() { // check for debounced change in this sensor - inputState = RMFT2::readSensor(pin); + inputState = useAnalog?IODevice::readAnalogue(pin):RMFT2::readSensor(pin); // Check if changed since last time, and process changes. if (inputState == active) {// no change @@ -83,18 +83,18 @@ bool EXRAILSensor::check() { return false; } -EXRAILSensor::EXRAILSensor(VPIN _pin, int _progCounter, bool _onChange) { - // Add to the start of the list - //DIAG(F("ONthing vpin=%d at %d"), _pin, _progCounter); +EXRAILSensor::EXRAILSensor(VPIN _pin, int _progCounter, bool _onChange, bool _useAnalog) { + nextSensor = firstSensor; firstSensor = this; pin=_pin; progCounter=_progCounter; onChange=_onChange; + useAnalog=_useAnalog; IODevice::configureInput(pin, true); - active = IODevice::read(pin); + active = useAnalog?IODevice::readAnalogue(pin): IODevice::read(pin); inputState = active; latchDelay = minReadCount; } diff --git a/EXRAILSensor.h b/EXRAILSensor.h index c9929f6..077431e 100644 --- a/EXRAILSensor.h +++ b/EXRAILSensor.h @@ -29,7 +29,8 @@ class EXRAILSensor { public: static void checkAll(); - EXRAILSensor(VPIN _pin, int _progCounter, bool _onChange); + EXRAILSensor(VPIN _pin, int _progCounter, bool _onChange, bool _useAnalog=false); + bool check(); private: @@ -42,9 +43,10 @@ class EXRAILSensor { EXRAILSensor* nextSensor; VPIN pin; int progCounter; - bool active; - bool inputState; + uint16_t active; + uint16_t inputState; bool onChange; + bool useAnalog; byte latchDelay; }; #endif diff --git a/IODeviceList.h b/IODeviceList.h index 2b82e1b..9400ca8 100644 --- a/IODeviceList.h +++ b/IODeviceList.h @@ -20,19 +20,31 @@ This is the list of HAL drivers automatically included by IODevice.h It has been moved here to be easier to maintain than editing IODevice.h */ +#include "IO_AnalogueInputs.h" +#include "IO_DFPlayer.h" +#include "IO_DS1307.h" +#include "IO_duinoNodes.h" +#include "IO_EncoderThrottle.h" +#include "IO_EXFastclock.h" +#include "IO_EXIOExpander.h" +#include "IO_EXSensorCAM.h" +#include "IO_HALDisplay.h" +#include "IO_HCSR04.h" +#include "IO_I2CDFPlayer.h" +#include "IO_I2CRailcom.h" #include "IO_MCP23008.h" #include "IO_MCP23017.h" +#include "IO_NeoPixel.h" +#include "IO_PCA9555.h" +#include "IO_PCA9685pwm.h" #include "IO_PCF8574.h" #include "IO_PCF8575.h" -#include "IO_PCA9555.h" -#include "IO_duinoNodes.h" -#include "IO_EXIOExpander.h" -#include "IO_trainbrains.h" -#include "IO_EncoderThrottle.h" +#include "IO_RotaryEncoder.h" +#include "IO_Servo.h" #include "IO_TCA8418.h" -#include "IO_NeoPixel.h" #include "IO_TM1638.h" -#include "IO_EXSensorCAM.h" -#include "IO_DS1307.h" -#include "IO_I2CRailcom.h" +#include "IO_TouchKeypad.h" +#include "IO_trainbrains.h" +#include "IO_Bitmap.h" +#include "IO_VL53L0X.h" diff --git a/IO_Bitmap.h b/IO_Bitmap.h new file mode 100644 index 0000000..c4e2997 --- /dev/null +++ b/IO_Bitmap.h @@ -0,0 +1,89 @@ +/* + * © 2025, 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_Bitmap_h + #define IO_Bitmap_h +#include +#include "defines.h" +#include "IODevice.h" + +/* +Bitmap provides a set of virtual pins with no hardware. +Bitmap pins are able to be output and input and may be set and tested +as digital or analogue values. +When writing a digital value, the analogue value is set to 0 or 1. +When reading a digital value, the return is LOW for value 0 or HIGH for any other value +or analogue. + +Bitmap pins may be used for any purpose, this is easier to manage than LATCH in EXRAIL +as they can be explicitely set and tested without interfering with underlying hardware. +Bitmap pins may be set, reset and tested in the same way as any other pin. +They are not persistent across reboots, but are retained in the current session. +Bitmap pins may also be monitored by JMRI_SENSOR() and as for any other pin. + +*/ +class Bitmap : public IODevice { + +public: + static void create(VPIN firstVpin, int nPins) { + if (IODevice::checkNoOverlap(firstVpin,nPins)) + new Bitmap( firstVpin, nPins); + } + + Bitmap(VPIN firstVpin, int nPins) : IODevice(firstVpin, nPins) { + _pinValues=(int16_t *) calloc(nPins,sizeof(int16_t)); + // 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; + _display(); + } + + int _read(VPIN vpin) override { + int pin=vpin - _firstVpin; + return _pinValues[pin]?1:0; + } + + void _write(VPIN vpin, int value) override { + int pin = vpin - _firstVpin; + _pinValues[pin]=value!=0; // this is digital write + } + + int _readAnalogue(VPIN vpin) override { + int pin=vpin - _firstVpin; + return _pinValues[pin]; // this is analog read + } + + void _writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) override { + int pin=vpin - _firstVpin; + _pinValues[pin]=value; // this is analog write + } + + void _display() override { + DIAG(F("Bitmap Configured on Vpins:%u-%u"), + (int)_firstVpin, + (int)_firstVpin+_nPins-1); + } + +private: + int16_t* _pinValues; +}; +#endif diff --git a/Release_Notes/IO_Bitmap.md b/Release_Notes/IO_Bitmap.md new file mode 100644 index 0000000..c86383b --- /dev/null +++ b/Release_Notes/IO_Bitmap.md @@ -0,0 +1,58 @@ +Virtual Bitmap device pins. + +a Bitmap device pin is a software representation of a virtual hardware device that has the ability to store a 16bit value. + +This this is easier to manage than LATCH in EXRAIL as they can be explicitely set and tested without interfering with underlying hardware or breaching the 255 limit. + +Virtual pins may be set, reset and tested in the same way as any other pin. Unlike sensors and leds, these device pins are both INPUT and OUTPUT These can be used in many ways: + + As a simple digital flag to assist in inter-thread communication. + A flag or value that can be set from commands and tested in EXRAIL.(e.g. to stop a sequence) + As a counter for looping or occupancy counts such as trains passing over a multi track road crossing. + As a collection of 16 digital bits that can be set, reset, toggled, masked and tested. + + Existing <> and exrail commands for vpins work on these pins. + + Virtual pin creation: + HAL(Bitmap,firstpin,npins) + creates 1 or more virtual pins in software. (RAM requirement approximately 2 bytes per pin) + e.g. HAL(Bitmap,1000,20) creates pins 1000..1019 + + Simple use as flags: + This uses the traditional digital pin commands + SET(1013) RESET(1013) sets value 1 or 0 + SET(1000,20) RESET(1000,20) sets/resets a range of pins + IF(1000) tests if pin value!=0 + + Commands can set 1/0 values using as for any digital output. + BLINK can be used to set them on/off on a time pattern. + + In addition, Exrail sensor comands work as if these pins were sensors + ONBUTTON(1013) triggers when value changes from 0 to something. + ONSENSOR(1013) triggers when value changes to or from 0. + and JMRI_SENSOR(1013) report etc. + + Use as counters: + For loop counting, counters can be incremented by BITMAP_INC(1013) and decremented by BITMAP_DEC(1013) and tested with IF/IFNOT/IFGTE etc. + Counters be used to automate a multi track crossing where each train entering increments the counter and decrements it on clearing the crossing. Crossing gate automation can be started when the value changes from 0, and be stopped when the counter returns to 0. Detecting the first increment from 0 to 1 can be done with ONBUTTON(1013) and the automation can use IF(1013) or IFNOT(1013) to detect when it needs to reopen the road gates. + +Use as binary flag groups: + Virtual pins (and others that respond to an analog read in order to provide bitmapped digital data, such as SensorCam) can be set and tested with new special EXRAIL commands + + IFBITMAP_ALL(vpin,mask) Bitwise ANDs the the vpin value with the mask value and is true if ALL the 1 bits in the mask are also 1 bits in the value. + e.g. IFBITMAP_ALL(1013,0x0f) would be true if ALL the last 4 bits of the value are 1s. + + IFBITMAP_ANY(1013,0x0f) would be true if ANY of the last 4 bits are 1s. + + + Modifying bitmap values: + BITMAP_AND(vpin,mask) performs a bitwise AND operation. + BITMAP_OR(vpin,mask) performa a bitwise OR operation + BITMAP_XOR(vpin,mask) performs a bitwise EXCLUSIVE OR (which is basically a toggle) + + + \ No newline at end of file diff --git a/version.h b/version.h index d87f350..89b322c 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,8 @@ #include "StringFormatter.h" -#define VERSION "5.5.24" +#define VERSION "5.5.25" +// 5.2.25 - IO_Bitmap and assicated Exrail macros // 5.5.24 - SensorCAM in I2C scan and automatically setClock // 5.5.23 - Reminder loop Idle packet optimization // 5.5.22 - (5.4.9) Handle non-compliant decoders returning 255 for cv 20 and confusing with bad consist addresses.