diff --git a/IO_TM1638.h b/IO_TM1638.h
new file mode 100644
index 0000000..e8df926
--- /dev/null
+++ b/IO_TM1638.h
@@ -0,0 +1,88 @@
+ /*
+ * © 2024, Henk Kruisbrink & Chris Harlow. All rights reserved.
+ * © 2023, Neil McKechnie. 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_TM1638_h
+#define IO_TM1638_h
+#include
+#include "IODevice.h"
+#include "I2CManager.h"
+#include "DIAG.h"
+#include "TM1638x.h"
+class TM1638 : public IODevice {
+private:
+
+ TM1638x * tm;
+ uint8_t _buttons;
+ uint8_t _leds;
+ unsigned long _lastLoop;
+ static const int LoopHz=20;
+
+private:
+ // Constructor
+ TM1638(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin){
+ _firstVpin = firstVpin;
+ _nPins = 8;
+ tm=new TM1638x(clk_pin,dio_pin,stb_pin);
+ _buttons=0;
+ _leds=0;
+ _lastLoop=micros();
+ addDevice(this);
+ }
+
+public:
+ static void create(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin) {
+ if (checkNoOverlap(firstVpin,8))
+ new TM1638(firstVpin, clk_pin,dio_pin,stb_pin);
+ }
+
+ void _begin() override {
+ tm->reset();
+ tm->test();
+ _display();
+ }
+
+
+ void _loop(unsigned long currentMicros) override {
+ if (currentMicros - _lastLoop > (1000000UL/LoopHz)) {
+ _buttons=tm->getButtons();// Read the buttons
+ _lastLoop=currentMicros;
+ }
+ // DIAG(F("TM1638 buttons %x"),_buttons);
+ }
+
+ void _display() override {
+ DIAG(F("TM1638 Configured on Vpins:%u-%u"), _firstVpin, _firstVpin+_nPins-1);
+ }
+
+// digital read gets button state
+int _read(VPIN vpin) override {
+ byte pin=vpin - _firstVpin;
+ bool result=bitRead(_buttons,pin);
+ // DIAG(F("TM1638 read (%d) buttons %x = %d"),pin,_buttons,result);
+ return result;
+}
+
+// digital write sets led state
+void _write(VPIN vpin, int value) override {
+ tm->writeLed(vpin - _firstVpin + 1,value!=0);
+ }
+
+};
+#endif // IO_TM1638_h
diff --git a/IO_TM1638.hzz b/IO_TM1638.hzz
new file mode 100644
index 0000000..3f4ce74
--- /dev/null
+++ b/IO_TM1638.hzz
@@ -0,0 +1,186 @@
+ /*
+ * © 2024, Henk Kruisbrink & Chris Harlow. All rights reserved.
+ * © 2023, Neil McKechnie. 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 .
+ */
+
+/*
+ *
+ * Dec 2023, Added NXP SC16IS752 I2C Dual UART
+ * The SC16IS752 has 64 bytes TX & RX FIFO buffer
+ * First version without interrupts from I2C UART and only RX/TX are used, interrupts may not be
+ * needed as the RX Fifo holds the reply
+ *
+ * Jan 2024, Issue with using both UARTs simultaniously, the secod uart seems to work but the first transmit
+ * corrupt data. This need more analysis and experimenatation.
+ * Will push this driver to the dev branch with the uart fixed to 0
+ * Both SC16IS750 (single uart) and SC16IS752 (dual uart, but only uart 0 is enable)
+ *
+ * myHall.cpp configuration syntax:
+ *
+ * I2CRailcom::create(1st vPin, vPins, I2C address);
+ *
+ * myAutomation configuration
+ * HAL(I2CRailcom, 1st vPin, vPins, I2C address)
+ * Parameters:
+ * 1st vPin : First virtual pin that EX-Rail can control to play a sound, use PLAYSOUND command (alias of ANOUT)
+ * vPins : Total number of virtual pins allocated (2 vPins are supported, one for each UART)
+ * 1st vPin for UART 0, 2nd for UART 1
+ * I2C Address : I2C address of the serial controller, in 0x format
+ */
+
+#ifndef IO_TM1638_h
+#define IO_TM1638_h
+#include
+#include "IODevice.h"
+#include "I2CManager.h"
+#include "DIAG.h"
+
+class TM1638 : public IODevice {
+private:
+
+ static const uint8_t
+ INSTRUCTION_WRITE_DATA=0x40,
+ INSTRUCTION_READ_KEY=0x42,
+ INSTRUCTION_ADDRESS_AUTO=0x40,
+ INSTRUCTION_ADDRESS_FIXED=0x44,
+ INSTRUCTION_NORMAL_MODE=0x40,
+ INSTRUCTION_TEST_MODE=0x48,
+ FIRST_DISPLAY_ADDRESS=0xC0,
+ DISPLAY_TURN_OFF=0x80,
+ DISPLAY_TURN_ON=0x88;
+
+ static constexpr uint8_t _digits[16]={ // 7-segment hex
+ 0b00111111,0b00000110,0b01011011,0b01001111,
+ 0b01100110,0b01101101,0b01111101,0b00000111,
+ 0b01111111,0b01101111,0b01110111,0b01111100,
+ 0b00111001,0b01011110,0b01111001,0b01110001
+ };
+
+ uint8_t _clk_pin;
+ uint8_t _stb_pin;
+ uint8_t _dio_pin;
+ uint8_t _buttons;
+ uint8_t _leds;
+ uint8_t _pulse;
+
+
+private:
+ // Constructor
+ TM1638(VPIN firstVpin, byte clk_pin,byte stb_pin,byte dio_pin){
+ _firstVpin = firstVpin;
+ _nPins = 8;
+ _clk_pin=clk_pin;
+ _stb_pin=stb_pin;
+ _dio_pin=dio_pin;
+ _buttons=0;
+ _leds=0;
+ _pulse=4;
+ pinMode(stb_pin, OUTPUT);
+ pinMode(clk_pin, OUTPUT);
+ pinMode(dio_pin, OUTPUT);
+ ArduinoPins::fastWriteDigital(stb_pin, HIGH);
+ ArduinoPins::fastWriteDigital(clk_pin, HIGH);
+ ArduinoPins::fastWriteDigital(dio_pin, HIGH);
+ addDevice(this);
+ }
+
+public:
+ static void create(VPIN firstVpin, byte clk_pin,byte stb_pin,byte dio_pin) {
+ if (checkNoOverlap(firstVpin,8))
+ new TM1638(firstVpin, clk_pin,stb_pin,dio_pin);
+ }
+
+ void _begin() override {
+ _deviceState = DEVSTATE_NORMAL;
+ writeCommand(DISPLAY_TURN_ON | _pulse);
+ _display();
+ }
+
+ void strobe(bool on) {
+ ArduinoPins::fastWriteDigital(_stb_pin, on?LOW:HIGH); // select device
+ delayMicroseconds(1);
+ }
+
+ void _loop(unsigned long currentMicros) override {
+
+ // Read the buttons
+ strobe(true);
+ writeData(INSTRUCTION_READ_KEY);
+ pinMode(_dio_pin, INPUT);
+
+ _buttons=0;
+ for (uint8_t i=0; 4;i++){
+ auto data = readData();
+ _buttons |= ((data>>4) & 0x01) | (data & 0x01);
+ _buttons <<= 2;
+ }
+ pinMode(_dio_pin,OUTPUT);
+ strobe(false);
+ }
+
+ void _display() override {
+ DIAG(F("TM1638 Configured on Vpins:%u-%u"), _firstVpin, _firstVpin+_nPins-1);
+ }
+
+// digital read gets button state
+int _read(VPIN vpin) override {
+ return bitRead(_buttons,vpin - _firstVpin);
+}
+
+// digital write sets led state
+void _write(VPIN vpin, int value) override {
+ auto pin=vpin-_firstVpin;
+ writeCommand(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
+ strobe(true);
+ writeData(FIRST_DISPLAY_ADDRESS + (pin*2+1));
+ writeData(value?0x01:0x00);
+ strobe(false);
+ }
+
+void writeCommand(uint8_t val)
+{
+ strobe(true);
+ writeData(val);
+ strobe(false);
+}
+
+void writeData(uint8_t val)
+{
+ ArduinoPins::fastWriteDigital(_clk_pin, LOW);
+ for (uint8_t i = 0; i < 8; i++) {
+ ArduinoPins::fastWriteDigital(_dio_pin, val & 1);
+ val >>= 1;
+ ArduinoPins::fastWriteDigital(_clk_pin, HIGH);
+ ArduinoPins::fastWriteDigital(_clk_pin, LOW);
+ }
+}
+
+uint8_t readData() {
+ uint8_t value = 0;
+ ArduinoPins::fastWriteDigital(_clk_pin, LOW);
+ for (uint8_t i = 0; i < 8; ++i) {
+ ArduinoPins::fastWriteDigital(_clk_pin, HIGH);
+ value |= ArduinoPins::fastReadDigital(_dio_pin) << i;
+ ArduinoPins::fastWriteDigital(_clk_pin, LOW);
+ }
+ return value;
+}
+
+
+};
+#endif // IO_I2CRailcom_h
diff --git a/TM1638x.cpp b/TM1638x.cpp
new file mode 100644
index 0000000..8ae343c
--- /dev/null
+++ b/TM1638x.cpp
@@ -0,0 +1,139 @@
+#include "Arduino.h"
+#include "TM1638x.h"
+#include "DIAG.h"
+
+bool TM1638x::getButton(button_t s){
+ _buttons = getButtons();
+ return bitRead(_buttons, s);
+}
+
+// buttons K3/KS1-8
+uint8_t TM1638x::getButtons(){
+ digitalWrite(_stb_pin, LOW);
+ writeData(INSTRUCTION_READ_KEY);
+ //Twait 1µs
+ pinMode(_dio_pin, INPUT);
+ digitalWrite(_clk_pin, LOW);
+ uint8_t data[4];
+ for (uint8_t i=0; i7) | (val>15) | (val<0)) return;
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ setDataInstruction(INSTRUCTION_WRITE_DATA| INSTRUCTION_ADDRESS_FIXED);
+ writeDataAt(FIRST_DISPLAY_ADDRESS+14-(digitId*2), _digits[val]);
+}
+
+void TM1638x::displayDig(uint8_t digitId, uint8_t pgfedcba){
+ if (digitId>7) return;
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ setDataInstruction(INSTRUCTION_WRITE_DATA| INSTRUCTION_ADDRESS_FIXED);
+ writeDataAt(FIRST_DISPLAY_ADDRESS+14-(digitId*2), pgfedcba);
+}
+
+void TM1638x::displayClear(){
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ setDataInstruction(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
+ for (uint8_t i=0;i<15;i+=2){
+ writeDataAt(FIRST_DISPLAY_ADDRESS+i,0x00);
+ }
+}
+
+void TM1638x::writeLed(uint8_t num,bool state){
+ //DIAG(F("TM1638x writeLed(%d,%d)"),num,state);
+ if ((num<1) | (num>8)) return;
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ setDataInstruction(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
+ writeDataAt(FIRST_DISPLAY_ADDRESS + (num*2-1), state);
+}
+
+void TM1638x::writeLeds(uint8_t val){
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ setDataInstruction(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
+ for(uint8_t i=1;i<9;i++){
+ writeDataAt(FIRST_DISPLAY_ADDRESS + (i*2-1), val & 0x01);
+ val >>= 1;
+ }
+}
+
+void TM1638x::displayTurnOn(){
+ setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ _isOn = true;
+}
+
+void TM1638x::displayTurnOff(){
+ setDisplayMode(DISPLAY_TURN_OFF | _pulse);
+ _isOn = false;
+}
+
+void TM1638x::displaySetBrightness(pulse_t newpulse){
+ if ((newpulsePULSE14_16)) return;
+ _pulse = newpulse;
+ uint8_t data = (_isOn) ? DISPLAY_TURN_ON : DISPLAY_TURN_OFF;
+ data |= _pulse;
+ setDisplayMode(data);
+}
+
+void TM1638x::writeData(uint8_t data){
+ shiftOut(_dio_pin,_clk_pin,LSBFIRST,data);
+}
+
+void TM1638x::writeDataAt(uint8_t displayAddress, uint8_t data){
+ digitalWrite(_stb_pin, LOW);
+ writeData(displayAddress);
+ writeData(data);
+ digitalWrite(_stb_pin, HIGH);
+ delayMicroseconds(1);
+}
+
+void TM1638x::setDisplayMode(uint8_t displayMode){
+ digitalWrite(_stb_pin, LOW);
+ writeData(displayMode);
+ digitalWrite(_stb_pin, HIGH);
+ delayMicroseconds(1);
+}
+void TM1638x::setDataInstruction(uint8_t dataInstruction){
+ digitalWrite(_stb_pin, LOW);
+ writeData(dataInstruction);
+ digitalWrite(_stb_pin, HIGH);
+ delayMicroseconds(1);
+}
+
+void TM1638x::test(){
+ DIAG(F("TM1638x test"));
+ uint8_t val=0;
+ for(uint8_t i=0;i<5;i++){
+ //setDisplayMode(DISPLAY_TURN_ON | _pulse);
+ displayTurnOn();
+ setDataInstruction(INSTRUCTION_WRITE_DATA| INSTRUCTION_ADDRESS_AUTO);
+ digitalWrite(_stb_pin, LOW);
+ writeData(FIRST_DISPLAY_ADDRESS);
+ for(uint8_t i=0;i<16;i++)
+ writeData(val);
+ digitalWrite(_stb_pin, HIGH);
+ delay(1000);
+ val = ~val;
+ }
+
+}
\ No newline at end of file
diff --git a/TM1638x.h b/TM1638x.h
new file mode 100644
index 0000000..baaa9d6
--- /dev/null
+++ b/TM1638x.h
@@ -0,0 +1,170 @@
+/*!
+ * @file TM1638.h
+ * @brief Arduino library for interface with TM1638 chip.
+ * @n read buttons, switch leds, display on 7segment.
+ * @author [Damien](web@varrel.fr)
+ * @version V1.0.1
+ * @date 2024-02-06
+ * @url https://github.com/dvarrel/TM1638.git
+ * @module https://fr.aliexpress.com/item/32832772646.html
+ */
+
+#ifndef _TM1638_H
+#define _TM1638_H
+#include "Arduino.h"
+
+#ifndef ON
+#define ON 1
+#endif
+#ifndef OFF
+#define OFF 0
+#endif
+
+ typedef enum{
+ PULSE1_16,
+ PULSE2_16,
+ PULSE4_16,
+ PULSE10_16,
+ PULSE11_16,
+ PULSE12_16,
+ PULSE13_16,
+ PULSE14_16
+ } pulse_t;
+
+ typedef enum{
+ S1,S2,S3,S4,
+ S5,S6,S7,S8
+ } button_t;
+
+class TM1638x{
+ private:
+ #define INSTRUCTION_WRITE_DATA 0x40
+ #define INSTRUCTION_READ_KEY 0x42
+ #define INSTRUCTION_ADDRESS_AUTO 0x40
+ #define INSTRUCTION_ADDRESS_FIXED 0x44
+ #define INSTRUCTION_NORMAL_MODE 0x40
+ #define INSTRUCTION_TEST_MODE 0x48
+
+ #define FIRST_DISPLAY_ADDRESS 0xC0
+
+ #define DISPLAY_TURN_OFF 0x80
+ #define DISPLAY_TURN_ON 0x88
+
+ uint8_t _digits[16]={
+ 0b00111111,0b00000110,0b01011011,0b01001111,
+ 0b01100110,0b01101101,0b01111101,0b00000111,
+ 0b01111111,0b01101111,0b01110111,0b01111100,
+ 0b00111001,0b01011110,0b01111001,0b01110001
+ };
+
+ uint8_t _clk_pin;
+ uint8_t _stb_pin;
+ uint8_t _dio_pin;
+ uint8_t _buttons;
+ uint8_t _pulse;
+ bool _isOn;
+
+ public:
+ TM1638x(uint8_t clk_pin, uint8_t dio_pin, uint8_t stb_pin){
+ _clk_pin = clk_pin;
+ _stb_pin = stb_pin;
+ _dio_pin = dio_pin;
+ _pulse = PULSE1_16;
+ _isOn = false;
+
+ pinMode(stb_pin, OUTPUT);
+ pinMode(clk_pin, OUTPUT);
+ pinMode(dio_pin, OUTPUT);
+ digitalWrite(stb_pin, HIGH);
+ digitalWrite(clk_pin, HIGH);
+ digitalWrite(dio_pin, HIGH);
+ }
+
+ /**
+ * @fn getButton
+ * @param s num of button (S1-S8)
+ * @return state of button
+ */
+ bool getButton(button_t s);
+ /**
+ * @fn getButtons
+ * @return state of 8 buttons
+ */
+ uint8_t getButtons();
+
+ /**
+ * @fn writeLed
+ * @brief put led ON or OFF
+ * @param num num of led(1-8)
+ * @param state (true or false)
+ */
+ void writeLed(uint8_t num, bool state);
+
+ /**
+ * @fn writeLeds
+ * @brief set all 8 leds ON or OFF
+ * @param val 8bits
+ */
+ void writeLeds(uint8_t val);
+
+ /**
+ * @fn displayVal
+ * @brief put value on 7 segment display
+ * @param digitId num of digit(0-7)
+ * @param val value(0->F)
+ */
+ void displayVal(uint8_t digitId, uint8_t val);
+
+
+ /**
+ * @fn displayDig
+ * @brief set 7 segment display + dot
+ * @param digitId num of digit(0-7)
+ * @param val value 8 bits
+ */
+ void displayDig(uint8_t digitId, uint8_t pgfedcba);
+
+ /**
+ * @fn displayClear
+ * @brief switch off all leds and segment display
+ */
+ void displayClear();
+
+ /**
+ * @fn displayTurnOff
+ * @brief turn on lights
+ */
+ void displayTurnOff();
+
+ /**
+ * @fn displayTurnOn
+ * @brief turn off lights
+ */
+ void displayTurnOn();
+
+ /**
+ * @fn displaySetBrightness
+ * @brief set display brightness
+ * @param pulse_t (0-7)
+ */
+ void displaySetBrightness(pulse_t pulse);
+
+ /**
+ * @fn reset
+ * @brief switch off all displays-leds
+ */
+ void reset();
+
+ /**
+ * @fn test
+ * @brief blink all displays and leds
+ */
+ void test();
+
+ private:
+ void writeData(uint8_t data);
+ void writeDataAt(uint8_t displayAddress, uint8_t data);
+ void setDisplayMode(uint8_t displayMode);
+ void setDataInstruction(uint8_t dataInstruction);
+};
+#endif
\ No newline at end of file