Skip to content

Commit

Permalink
Add Touch Example Project for Puara Gestures (#24)
Browse files Browse the repository at this point in the history
This PR introduces a new example project demonstrating the use of the Puara Gestures library with a touchscreen interface. Key additions include:

Added a new 3rdparty submodule, which includes a copy of the Boost 1.86.0 library, as well as the IMU_Sensor_Fusion submodule
added a new example project using these dependencies and demonstrating the touch puara gesture in exampleProjects/touch.
the touch project includes a working Wokwi diagram.json to run a project simulation
  • Loading branch information
vberthiaume authored Dec 24, 2024
1 parent 5c0cdbf commit f19ab5f
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ build/
.vscode/
*.user
*code-workspace
library.json
.pio
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions 3rdparty
Submodule 3rdparty added at 05f8b1
1 change: 0 additions & 1 deletion 3rdparty/IMU_Sensor_Fusion
Submodule IMU_Sensor_Fusion deleted from 9412e6
7 changes: 7 additions & 0 deletions exampleProjects/touch/README.md
Original file line number Diff line number Diff line change
@@ -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.
31 changes: 31 additions & 0 deletions exampleProjects/touch/diagram.json
Original file line number Diff line number Diff line change
@@ -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": {}
}
39 changes: 39 additions & 0 deletions exampleProjects/touch/include/README
Original file line number Diff line number Diff line change
@@ -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
46 changes: 46 additions & 0 deletions exampleProjects/touch/lib/README
Original file line number Diff line number Diff line change
@@ -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 <Foo.h>
#include <Bar.h>

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
29 changes: 29 additions & 0 deletions exampleProjects/touch/platformio.ini
Original file line number Diff line number Diff line change
@@ -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
163 changes: 163 additions & 0 deletions exampleProjects/touch/src/TinyTouch.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include <algorithm>

#include <puara/gestures.h>

#include <Adafruit_FT6206.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ILI9341.h> // Hardware-specific library for ST7789
#include <SPI.h>

/**
* @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};
};
31 changes: 31 additions & 0 deletions exampleProjects/touch/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "Arduino.h"

#include <TinyTouch.hpp>

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();
}
11 changes: 11 additions & 0 deletions exampleProjects/touch/test/README
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions exampleProjects/touch/wokwi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[wokwi]
version = 1
elf = ".pio/build/tinypico/firmware.elf"
firmware = ".pio/build/tinypico/firmware.bin"
gdbServerPort = 3333

0 comments on commit f19ab5f

Please sign in to comment.