diff --git a/.gitignore b/.gitignore index 61eb52e..acffd00 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ build/ .vscode/ *.user *code-workspace -library.json +.pio diff --git a/.gitmodules b/.gitmodules index ae14b99..3def47a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "IMU_Sensor_Fusion"] - path = 3rdparty/IMU_Sensor_Fusion - url = https://github.com/malloch/IMU_Sensor_Fusion +[submodule "3rdparty"] + path = 3rdparty + url = git@github.com:Puara/3rdparty.git diff --git a/3rdparty b/3rdparty new file mode 160000 index 0000000..05f8b16 --- /dev/null +++ b/3rdparty @@ -0,0 +1 @@ +Subproject commit 05f8b169e07ed528f469969c2a3d574835e5b383 diff --git a/3rdparty/IMU_Sensor_Fusion b/3rdparty/IMU_Sensor_Fusion deleted file mode 160000 index 9412e64..0000000 --- a/3rdparty/IMU_Sensor_Fusion +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9412e6423e2e07d88573cd8d4fe9b19f09fedcc7 diff --git a/exampleProjects/touch/README.md b/exampleProjects/touch/README.md new file mode 100644 index 0000000..b446577 --- /dev/null +++ b/exampleProjects/touch/README.md @@ -0,0 +1,7 @@ +# Touch Project + +This project is part of the Puara Framework and demonstrates high-level gestural descriptor functions using a touchscreen. It showcases the integration of `puara-gestures` with a touchscreen to detect and display touch interactions. You can use the built-in wokwi diagram.json to simulate the project. + +## License + +This project is licensed under the MIT License. diff --git a/exampleProjects/touch/diagram.json b/exampleProjects/touch/diagram.json new file mode 100644 index 0000000..ec7beb4 --- /dev/null +++ b/exampleProjects/touch/diagram.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "author": "Vincent Berthiaume", + "editor": "wokwi", + "parts": [ + { "type": "wokwi-tinypico", "id": "esp", "top": -0.7, "left": 81.4, "attrs": {} }, + { + "type": "board-ili9341-cap-touch", + "id": "lcd1", + "top": -143.24, + "left": -230.78, + "attrs": {} + } + ], + "connections": [ + [ "esp:TX0", "$serialMonitor:RX", "", [] ], + [ "esp:RX0", "$serialMonitor:TX", "", [] ], + [ "lcd1:GND", "esp:GND.1", "black", [ "v67.2", "h240", "v-105.4" ] ], + [ "esp:3V3", "lcd1:VCC", "red", [ "h-38.4", "v134.1", "h-240" ] ], + [ "lcd1:LED", "esp:3V3", "red", [ "v28.8", "h76.8", "v-86.4", "h134.4" ] ], + [ "lcd1:CS", "esp:14", "orange", [ "v57.6", "h211.2", "v-133.8" ] ], + [ "lcd1:RST", "esp:15", "gold", [ "v48", "h192", "v-124.8" ] ], + [ "lcd1:D/C", "esp:27", "green", [ "v19.2", "h172.8", "v-114.9" ] ], + [ "lcd1:MOSI", "esp:23", "green", [ "v38.4", "h288" ] ], + [ "lcd1:MISO", "esp:19", "green", [ "v105.6", "h278.4", "v-153.6" ] ], + [ "lcd1:SCK", "esp:18", "green", [ "v86.4", "h307.2", "v9.6" ] ], + [ "lcd1:SDA", "esp:25", "violet", [ "v9.6", "h96", "v-124.8" ] ], + [ "lcd1:SCL", "esp:26", "green", [ "v28.8", "h115.2", "v-134.4" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/exampleProjects/touch/include/README b/exampleProjects/touch/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/exampleProjects/touch/include/README @@ -0,0 +1,39 @@ + +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 usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +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/exampleProjects/touch/lib/README b/exampleProjects/touch/lib/README new file mode 100644 index 0000000..2593a33 --- /dev/null +++ b/exampleProjects/touch/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 executable file. + +The source code of each library should be placed in an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, 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 + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/exampleProjects/touch/platformio.ini b/exampleProjects/touch/platformio.ini new file mode 100644 index 0000000..889af0e --- /dev/null +++ b/exampleProjects/touch/platformio.ini @@ -0,0 +1,29 @@ +; 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:tinypico] +platform = espressif32 +board = tinypico +framework = arduino +lib_deps = + tinypico/TinyPICO Helper Library + adafruit/Adafruit GFX Library + adafruit/Adafruit ILI9341 + adafruit/Adafruit FT6206 Library +build_flags = + -I../../include/ + -I../../3rdparty/ + -std=gnu++2a +build_unflags = + -std=gnu++11 + -std=gnu++14 + -std=gnu++17 +; enable this to debug wokwi in vscode, see https://docs.wokwi.com/vscode/debugging +; build_type = debug diff --git a/exampleProjects/touch/src/TinyTouch.hpp b/exampleProjects/touch/src/TinyTouch.hpp new file mode 100644 index 0000000..125c484 --- /dev/null +++ b/exampleProjects/touch/src/TinyTouch.hpp @@ -0,0 +1,163 @@ +#include + +#include + +#include +#include // Core graphics library +#include // Hardware-specific library for ST7789 +#include + +/** + * @class TinyTouch + * @brief A class to handle touchscreen interactions using the Adafruit ILI9341 and FT6206 libraries. + * + * This class is designed to test the Puara gesture framework by providing a simple interface + * for initializing the screen, displaying introductory messages, detecting touch events, and + * drawing rectangles on the screen. It uses the Puara library to handle gesture recognition. + */ +class TinyTouch +{ +public: + //======================== TinyPICO pins ======================= + static constexpr int PIN_CS{14}; ///< Chip select pin for the display + static constexpr int PIN_DC{27}; ///< Data/command pin for the display + static constexpr int PIN_SDA{25}; ///< Serial data pin for the touchscreen + static constexpr int PIN_SCL{26}; ///< Serial clock pin for the touchscreen + + /** + * @brief Initializes the touchscreen and display. + */ + void initScreen() + { + tft.begin(); + screenHeight = tft.height(); + screenWidth = tft.width(); + rectangleHeight = screenHeight / RECT_COUNT; + Serial.println(F("Touchscreen is initialized")); + + if(!ctp.begin()) + { + Serial.println("Couldn't start touchscreen controller"); + while(1) + ; + } + Serial.println("touchscreen started"); + } + + /** + * @brief Prints an introductory message to the screen. + */ + void printIntro() + { + tft.fillScreen(ILI9341_BLACK); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(2); + tft.setCursor(10, 100); + tft.println("Puara Gesture Test!"); + tft.setTextSize(1); + tft.setCursor(10, 130); + tft.println("Touch the screen to begin."); + } + + /** + * @brief Checks if the touchscreen is currently being touched. + * @return True if the touchscreen is being touched, false otherwise. + */ + bool touched() { return ctp.touched(); } + + /** + * @brief Draws rectangles on the screen. + * + * This function divides the screen into a series of rectangles and draws them. These + * discrete rectangles will be used by puara to calculate various touch gestures. + */ + void drawRectangles() + { + // Draw rectangles + tft.fillScreen(ILI9341_BLACK); + for(int i = 0; i < RECT_COUNT; i++) + tft.drawRect(0, i * rectangleHeight, screenWidth, rectangleHeight, ILI9341_WHITE); + } + + /** + * @brief Updates the touch state of rectangles and redraws them on the screen. + * + * This function resets the current touch states, checks for new touch inputs, + * and updates the screen and internal state to reflect changes. Touched + * rectangles are filled with white, while untapped ones are filled with black + * and outlined in white. + * + * @pre `ctp` must be initialized, and rectangle dimensions must match screen setup. + * @post The screen reflects the updated touch states. + */ + void updateRectangles() + { + // Reset the current touch array + std::fill_n(touchedRectangles, RECT_COUNT, 0); + + // Check for touches + if(ctp.touched()) + { + TS_Point p{ctp.getPoint()}; + p.x = map(p.x, 0, 240, 240, 0); + p.y = map(p.y, 0, 320, 320, 0); + + // Determine which rectangle is touched + const int rectIndex{p.y / rectangleHeight}; + if(rectIndex >= 0 && rectIndex < RECT_COUNT) + touchedRectangles[rectIndex] = 1; + } + + // Update the screen based on touch states + for(int i = 0; i < RECT_COUNT; i++) + { + if(touchedRectangles[i] == 1 && previouslyTouchedRectangles[i] == 0) + { + // Rectangle is touched - make it white + tft.fillRect(0, i * rectangleHeight, screenWidth, rectangleHeight, ILI9341_WHITE); + } + else if(touchedRectangles[i] == 0 && previouslyTouchedRectangles[i] == 1) + { + // Rectangle no longer touched - make it black + tft.fillRect(0, i * rectangleHeight, screenWidth, rectangleHeight, ILI9341_BLACK); + tft.drawRect(0, i * rectangleHeight, screenWidth, rectangleHeight, ILI9341_WHITE); + } + } + + // Calculate current touch values and cache them for the next loop + touch.updateTouchArray(touchedRectangles, RECT_COUNT); + std::copy(touchedRectangles, touchedRectangles + RECT_COUNT, previouslyTouchedRectangles); + } + + /** + * @brief Prints the current touch values to the serial monitor. + */ + void printUpdate() + { + if(touch.brush != prev_brush || touch.rub != prev_rub) + { + Serial.println("brush;" + String(touch.brush, 6) + ";rub;" + String(touch.rub, 6)); + prev_brush = touch.brush; + prev_rub = touch.rub; + } + } + +private: + //======================== setup screen ======================= + int screenHeight{-1}; + int screenWidth{-1}; + int rectangleHeight{-1}; + + Adafruit_ILI9341 tft{TinyTouch::PIN_CS, TinyTouch::PIN_DC}; + Adafruit_FT6206 ctp; + + //======================== setup puara ======================= + static constexpr int RECT_COUNT{16}; + int touchedRectangles[RECT_COUNT] = {0}; + puara_gestures::Touch touch; + + // Keep track of previous values + int previouslyTouchedRectangles[RECT_COUNT] = {0}; + float prev_brush{-1.0f}; + float prev_rub{-1.0f}; +}; \ No newline at end of file diff --git a/exampleProjects/touch/src/main.cpp b/exampleProjects/touch/src/main.cpp new file mode 100644 index 0000000..4c04749 --- /dev/null +++ b/exampleProjects/touch/src/main.cpp @@ -0,0 +1,31 @@ +#include "Arduino.h" + +#include + +TinyTouch tinyTouch; + +void setup(void) +{ + //initialize serial monitoring + Serial.begin(9600); + Serial.println(F("Touch Puara Gesture Test!")); + + //initialize i2c + Wire.setPins(TinyTouch::PIN_SDA, TinyTouch::PIN_SCL); + Wire.begin(); + + tinyTouch.initScreen(); + tinyTouch.printIntro(); + + // Wait for a touch before proceeding + while(!tinyTouch.touched()) + delay(50); + + tinyTouch.drawRectangles(); +} + +void loop() +{ + tinyTouch.updateRectangles(); + tinyTouch.printUpdate(); +} diff --git a/exampleProjects/touch/test/README b/exampleProjects/touch/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/exampleProjects/touch/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 diff --git a/exampleProjects/touch/wokwi.toml b/exampleProjects/touch/wokwi.toml new file mode 100644 index 0000000..58ebe52 --- /dev/null +++ b/exampleProjects/touch/wokwi.toml @@ -0,0 +1,5 @@ +[wokwi] +version = 1 +elf = ".pio/build/tinypico/firmware.elf" +firmware = ".pio/build/tinypico/firmware.bin" +gdbServerPort = 3333