From 4808d9bc2480284ac72b21136659f1c9af5b0542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20T=C3=B3th?= Date: Wed, 29 Oct 2025 08:58:43 +0100 Subject: [PATCH] Software Upload 1 Erste Funktionen zur Firmware erstellt. Keyboard auslesen im Warteschlangen Prinzip. Test-Programm mit 3x4-Matrix Tastatur --- dev/digital/Firmware_TEST/.gitignore | 5 + .../Firmware_TEST/.vscode/extensions.json | 10 + dev/digital/Firmware_TEST/include/FIRMWARE.h | 62 +++++++ .../Firmware_TEST/include/FIRMWARE_DEF.h | 29 +++ dev/digital/Firmware_TEST/include/README | 37 ++++ dev/digital/Firmware_TEST/lib/README | 46 +++++ dev/digital/Firmware_TEST/platformio.ini | 16 ++ dev/digital/Firmware_TEST/src/FIRMWARE.cpp | 172 ++++++++++++++++++ dev/digital/Firmware_TEST/src/main.cpp | 34 ++++ dev/digital/Firmware_TEST/test/README | 11 ++ 10 files changed, 422 insertions(+) create mode 100644 dev/digital/Firmware_TEST/.gitignore create mode 100644 dev/digital/Firmware_TEST/.vscode/extensions.json create mode 100644 dev/digital/Firmware_TEST/include/FIRMWARE.h create mode 100644 dev/digital/Firmware_TEST/include/FIRMWARE_DEF.h create mode 100644 dev/digital/Firmware_TEST/include/README create mode 100644 dev/digital/Firmware_TEST/lib/README create mode 100644 dev/digital/Firmware_TEST/platformio.ini create mode 100644 dev/digital/Firmware_TEST/src/FIRMWARE.cpp create mode 100644 dev/digital/Firmware_TEST/src/main.cpp create mode 100644 dev/digital/Firmware_TEST/test/README diff --git a/dev/digital/Firmware_TEST/.gitignore b/dev/digital/Firmware_TEST/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/dev/digital/Firmware_TEST/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/dev/digital/Firmware_TEST/.vscode/extensions.json b/dev/digital/Firmware_TEST/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/dev/digital/Firmware_TEST/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/dev/digital/Firmware_TEST/include/FIRMWARE.h b/dev/digital/Firmware_TEST/include/FIRMWARE.h new file mode 100644 index 0000000..f14456e --- /dev/null +++ b/dev/digital/Firmware_TEST/include/FIRMWARE.h @@ -0,0 +1,62 @@ +/* + @file: FIRMARE.h + @author: Erik Tóth + @contact: etoth@tsn.at + @date: 2025-10-26 + @brief: Header for FIRMWARE.cpp +*/ +#include +#include +#include + +#ifndef FIRMWARE_H +#define FIRMWARE_H + +#define N_MAX_QUEUE 10 +#define N_MAX_ROWS 8 +#define N_MAX_COLS 8 +#define MS_DEBOUNCE 20 + +struct Key +{ + int row; + int col; +}; + +const Key NOT_A_KEY = {-1, -1}; + +bool isNotKey(Key k); +bool isEqualKey(Key k1, Key k2); + +class Keyboard +{ + public: + Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol); + void begin(); + void update(); + int getQueueLength(); + Key getQueue(uint8_t index); + + private: + uint8_t _nRows; + uint8_t _nCols; + uint8_t *_pinsRow; + uint8_t *_pinsCol; + + bool _keyState[N_MAX_COLS][N_MAX_ROWS]; + bool _keyStateLatest[N_MAX_COLS][N_MAX_ROWS]; + unsigned long _lastChangeTime[N_MAX_COLS][N_MAX_ROWS]; + + Key _activeKeys[N_MAX_QUEUE]; + uint8_t _nActiveKeys; + uint8_t _nSticky; + + void _addActiveKey(uint8_t row, uint8_t col); + void _removeActiveKey(uint8_t row, uint8_t col); + bool _inQueue(uint8_t row, uint8_t col); + bool _inQueue(Key k); + bool _isNotKey(Key k); + bool _isEqualKey(Key k1, Key k2); +}; + +#endif \ No newline at end of file diff --git a/dev/digital/Firmware_TEST/include/FIRMWARE_DEF.h b/dev/digital/Firmware_TEST/include/FIRMWARE_DEF.h new file mode 100644 index 0000000..52e16b2 --- /dev/null +++ b/dev/digital/Firmware_TEST/include/FIRMWARE_DEF.h @@ -0,0 +1,29 @@ +/* + @file: FIRMARE_DEF.h + @author: Erik Tóth + @contact: etoth@tsn.at + @date: 2025-10-26 + @brief: Header for constant definitions +*/ + +#ifndef FIRMWARE_DEF_H +#define FIRMWARE_DEF_H +#include +#include +// CONSTANTS DEFINITONS +#define N_KEYBOARD_ROW 4 +#define N_KEYBOARD_COL 3 +#define BAUDRATE 115200 +// PIN DEFENTITIONS +// I2C PINS +#define PIN_SDA 15 +#define PIN_SCL 16 +// KEYBOARD PINS +#define PIN_K_R0 7 +#define PIN_K_R1 8 +#define PIN_K_R2 9 +#define PIN_K_R3 10 +#define PIN_K_C0 1 +#define PIN_K_C1 2 +#define PIN_K_C2 4 +#endif \ No newline at end of file diff --git a/dev/digital/Firmware_TEST/include/README b/dev/digital/Firmware_TEST/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/dev/digital/Firmware_TEST/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/dev/digital/Firmware_TEST/lib/README b/dev/digital/Firmware_TEST/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/dev/digital/Firmware_TEST/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/dev/digital/Firmware_TEST/platformio.ini b/dev/digital/Firmware_TEST/platformio.ini new file mode 100644 index 0000000..53d7357 --- /dev/null +++ b/dev/digital/Firmware_TEST/platformio.ini @@ -0,0 +1,16 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32-s3-devkitm-1] +platform = espressif32 +board = esp32-s3-devkitm-1 +framework = arduino +build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_JTAG_ON_BOOT=1 +lib_deps = adafruit/Adafruit MCP4728@^1.0.10 diff --git a/dev/digital/Firmware_TEST/src/FIRMWARE.cpp b/dev/digital/Firmware_TEST/src/FIRMWARE.cpp new file mode 100644 index 0000000..225a574 --- /dev/null +++ b/dev/digital/Firmware_TEST/src/FIRMWARE.cpp @@ -0,0 +1,172 @@ +/* + @file: FIRMWARE.cpp + @author: Erik Tóth + @contact: etoth@tsn.at + @date: 2025-10-26 + @brief: Firmware for MCU +*/ + +#include "FIRMWARE.h" + +bool isNotKey(Key k) +{ + if((k.row == NOT_A_KEY.row) && (k.col == NOT_A_KEY.col)) return true; + else return false; +} + +bool isEqualKey(Key k1, Key k2) +{ + if((k1.row == k2.row) && (k1.col == k2.col)) return true; + else return false; +} + +Keyboard::Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol) +{ + _nRows = nRows; + _nCols = nCols; + _pinsRow = pinsRow; + _pinsCol = pinsCol; + + _nActiveKeys = 0; + _nSticky = 2; + + for(uint8_t i = 0; i < _nRows; i++) + { + for(uint8_t j = 0; j < _nCols; j++) + { + _keyState[i][j] = false; + _keyStateLatest[i][j] = false; + _lastChangeTime[i][j] = 0; + } + } +} + +void Keyboard::begin() +{ + for(int i = 0; i < _nRows; i++) pinMode(_pinsRow[i], INPUT_PULLDOWN); + for(int i = 0; i < _nCols; i++) pinMode(_pinsCol[i], OUTPUT); +} + +void Keyboard::update() +{ + unsigned long now = millis(); + for(uint8_t i = 0; i < _nCols; i++) + { + digitalWrite(_pinsCol[i], HIGH); + for(uint8_t j = 0; j < _nRows; ++j) + { + bool reading = (digitalRead(_pinsRow[j]) == HIGH); + + if(reading != _keyStateLatest[i][j]) + { + _keyStateLatest[i][j] = reading; + _lastChangeTime[i][j] = now; + } + + if((now - _lastChangeTime[i][j]) > MS_DEBOUNCE) + { + if(reading != _keyState[i][j]) + { + _keyState[i][j] = reading; + + if(reading) _addActiveKey(i, j); + else _removeActiveKey(i, j); + } + } + } + digitalWrite(_pinsCol[i], LOW); + } + if((_nActiveKeys == 1) && _inQueue(NOT_A_KEY)) _nActiveKeys = 0; +} + +int Keyboard::getQueueLength() +{ + return _nActiveKeys; +} + +Key Keyboard::getQueue(uint8_t index) +{ + if(index < _nActiveKeys) return _activeKeys[index]; + else return NOT_A_KEY; +} + +bool Keyboard::_inQueue(uint8_t row, uint8_t col) +{ + for(uint8_t i = 0; i < _nActiveKeys; i++) + { + if((_activeKeys[i].row == row) && (_activeKeys[i].col == col)) return true; + } + return false; +} + +bool Keyboard::_inQueue(Key k) +{ + for(uint8_t i = 0; i < _nActiveKeys; i++) + { + if(_isEqualKey(_activeKeys[i], k)) return true; + } + return false; +} + +bool Keyboard::_isNotKey(Key k) +{ + return isNotKey(k); +} + +bool Keyboard::_isEqualKey(Key k1, Key k2) +{ + return isEqualKey(k1, k2); +} + +void Keyboard::_addActiveKey(uint8_t row, uint8_t col) +{ + if(_inQueue(NOT_A_KEY)) + { + for(int i = 0; i < _nSticky; i++) + { + if(_isNotKey(_activeKeys[i])) + { + _activeKeys[i] = {row, col}; + return; + } + } + } + else if((_nActiveKeys < N_MAX_QUEUE) && !(_inQueue(row, col))) + { + _activeKeys[_nActiveKeys++] = {row, col}; + } + else return; +} + +void Keyboard::_removeActiveKey(uint8_t row, uint8_t col) +{ + bool notKeyReplaced = true; + + for(uint8_t i = 0; i < _nActiveKeys; i++) + { + if((_activeKeys[i].row == row) && (_activeKeys[i].col == col)) + { + if(i < _nSticky) + { + _activeKeys[i] = NOT_A_KEY; + notKeyReplaced = false; + } + + if((_isNotKey(_activeKeys[i])) && (_nActiveKeys-1 >= _nSticky)) + { + _activeKeys[i] = _activeKeys[_nSticky]; + notKeyReplaced = true; + } + + for(uint8_t j = i; j < _nActiveKeys-1; j++) + { + if(j >= _nSticky) _activeKeys[j] = _activeKeys[j + 1]; + } + + if(notKeyReplaced || (i > _nSticky)) _nActiveKeys--; + else if(_isNotKey(_activeKeys[_nSticky-1])) _nActiveKeys--; + + return; + } + } +} \ No newline at end of file diff --git a/dev/digital/Firmware_TEST/src/main.cpp b/dev/digital/Firmware_TEST/src/main.cpp new file mode 100644 index 0000000..f24adf6 --- /dev/null +++ b/dev/digital/Firmware_TEST/src/main.cpp @@ -0,0 +1,34 @@ +#include "FIRMWARE_DEF.h" +#include "FIRMWARE.h" + +static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3}; +static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2}; + +Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col); + +void setup() +{ + Serial.begin(BAUDRATE); + //Wire.begin(PIN_SDA, PIN_SCL); + keyboard.begin(); +} + +void loop() +{ + keyboard.update(); + + int n = keyboard.getQueueLength(); + + if(n > 0) + { + Serial.printf("\n\rCurrent queue length: %i", n); + for(int i = 0; i < n; i++) + { + Key k = keyboard.getQueue(i); + if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i); + else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col); + } + } + + delay(50); +} \ No newline at end of file diff --git a/dev/digital/Firmware_TEST/test/README b/dev/digital/Firmware_TEST/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/dev/digital/Firmware_TEST/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html