Skip to content

Instantly share code, notes, and snippets.

@erictroebs
Last active August 30, 2024 20:03
Show Gist options
  • Save erictroebs/3e6ca8aa2b9ed06e0b5527fd38dd2c2f to your computer and use it in GitHub Desktop.
Save erictroebs/3e6ca8aa2b9ed06e0b5527fd38dd2c2f to your computer and use it in GitHub Desktop.
Arduino Micro (ATmega32U4) Ten Finger Touchscreen Example
#include "Touch.h"
#if defined(_USING_HID)
#define CONTACT_COUNT_MAXIMUM 10
#define REPORTID_TOUCH 0x04
#define LSB(v) ((v >> 8) & 0xff)
#define MSB(v) (v & 0xff)
static const uint8_t _hidReportDescriptor[] PROGMEM = {
0x05, 0x0D, // USAGE_PAGE(Digitizers)
0x09, 0x04, // USAGE (Touch Screen)
0xA1, 0x01, // COLLECTION(Application)
0x85, REPORTID_TOUCH, // REPORT_ID (Touch)
// define the maximum amount of fingers that the device supports
0x09, 0x55, // USAGE (Contact Count Maximum)
0x25, CONTACT_COUNT_MAXIMUM, // LOGICAL_MAXIMUM (CONTACT_COUNT_MAXIMUM)
0xB1, 0x02, // FEATURE (Data,Var,Abs)
// define the actual amount of fingers that are concurrently touching the screen
0x09, 0x54, // USAGE (Contact count)
0x95, 0x01, // REPORT_COUNT(1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
// declare a finger collection
0x09, 0x22, // USAGE (Finger)
0xA1, 0x02, // COLLECTION (Logical)
// declare an identifier for the finger
0x09, 0x51, // USAGE (Contact Identifier)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
// declare Tip Switch and In Range
0x09, 0x42, // USAGE (Tip Switch)
0x09, 0x32, // USAGE (In Range)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT(2)
0x81, 0x02, // INPUT (Data,Var,Abs)
// declare the remaining 6 bits of the first data byte as constant -> the driver will ignore them
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Ary,Abs)
// define absolute X and Y coordinates of 16 bit each (percent values multiplied with 100)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0x10, 0x27, // Logical Maximum (10000)
0x36, 0x00, 0x00, // Physical Minimum (0)
0x46, 0x10, 0x27, // Physical Maximum (10000)
0x66, 0x00, 0x00, // UNIT (None)
0x75, 0x10, // Report Size (16),
0x95, 0x02, // Report Count (2),
0x81, 0x02, // Input (Data,Var,Abs)
0xC0, // END_COLLECTION
0xC0 // END_COLLECTION
// with this declaration a data packet must be sent as:
// byte 1 -> "contact count" (always == 1)
// byte 2 -> "contact identifier" (any value)
// byte 3 -> "Tip Switch" state (bit 0 = Tip Switch up/down, bit 1 = In Range)
// byte 4,5 -> absolute X coordinate (0...10000)
// byte 6,7 -> absolute Y coordinate (0...10000)
};
typedef struct Finger {
int contact;
int16_t x;
int16_t y;
} Finger;
Finger fingers[CONTACT_COUNT_MAXIMUM];
Touch_::Touch_() {
static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
HID().AppendDescriptor(&node);
for (int i = 0; i < CONTACT_COUNT_MAXIMUM; i++) {
fingers[i].contact = 0;
fingers[i].x = 0;
fingers[i].y = 0;
}
}
void Touch_::begin(void) {
}
void Touch_::end(void) {
}
void Touch_::send(uint8_t identifier, uint8_t touch, int16_t x, int16_t y) {
// calculate current contact count
uint8_t contact = 0;
for (int i = 0; i < CONTACT_COUNT_MAXIMUM; i++) {
if (fingers[i].contact) {
contact += 1;
}
}
// create data array
uint8_t data[] = {
contact, // contact count
identifier, // contact identifier
touch, // finger touches display
MSB(x), LSB(x), // x
MSB(y), LSB(y) // y
};
// send packet
HID().SendReport(REPORTID_TOUCH, data, 7);
}
void Touch_::moveFingerTo(uint8_t identifier, int16_t x, int16_t y) {
// change finger record
fingers[identifier].contact = 1;
fingers[identifier].x = x;
fingers[identifier].y = y;
// send update
send(identifier, 1, x, y);
}
void Touch_::releaseFinger(uint8_t identifier) {
// change finger record
fingers[identifier].contact = 0;
fingers[identifier].x = 0;
fingers[identifier].y = 0;
// send update
send(identifier, 0, 0, 0);
}
Touch_ Touch;
#endif
#ifndef Touch_h
#define Touch_h
#include "HID.h"
#if !defined(_USING_HID)
#warning "Using legacy HID core (non pluggable)"
#else
class Touch_ {
private:
void send(uint8_t identifier, uint8_t touch, int16_t x, int16_t y);
public:
Touch_(void);
void begin(void);
void end(void);
void moveFingerTo(uint8_t finger, int16_t x, int16_t y);
void releaseFinger(uint8_t finger);
};
extern Touch_ Touch;
#endif
#endif
#define BUTTON 2
#include "Touch.h"
void setup() {
// initialize touch
Touch.begin();
// setup pins
pinMode(BUTTON, INPUT_PULLUP);
}
void loop() {
if (digitalRead(BUTTON) == LOW) {
int16_t x = 5000;
int16_t y = 5000;
for (; x <= 6000; x+=4) {
for (int i = 0; i < 10; i++) {
Touch.moveFingerTo(i, x + i * 100, y + i * 100);
}
}
for (; y <= 6000; y+=4) {
for (int i = 0; i < 10; i++) {
Touch.moveFingerTo(i, x + i * 100, y + i * 100);
}
}
for (; x >= 5000; x-=4) {
for (int i = 0; i < 10; i++) {
Touch.moveFingerTo(i, x + i * 100, y + i * 100);
}
}
for (; y >= 5000; y-=4) {
for (int i = 0; i < 10; i++) {
Touch.moveFingerTo(i, x + i * 100, y + i * 100);
}
}
for (int i = 0; i < 10; i++) {
Touch.releaseFinger(i);
}
}
}
@erictroebs
Copy link
Author

erictroebs commented Nov 8, 2023

Hi there! It's not working on Android 7.1 neither macOS, any ideas why?

@sobrinho Sorry for the late reply: As @francoisnicolas has mentioned, you have to connect a button to pin 2 and ground. I would not recommend to use the script without a button! Otherwise it could be difficult to flash another sketch from the PC while the Arduino is firing touchscreen input commands.

If this does not work for you, I'm afraid I can not help you. I tested the script with a newer version of Android (probably 11), Windows 10 and Linux Mint, but I do neither have access to MacOS nor such an old version of Android.

@sobrinho
Copy link

It has been a long time now, I'm not in the project anymore. Thanks anyways! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment