rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
touch_merge.h File Reference

Two touch controllers, one contact set: the glass's GT911 at 0x5D and a touch injector at 0x14 (testbench/touch-injector), merged into the frame the tracker sees. Pure C; the panel compiles the I/O around it in a build with RCBENCH_TOUCH_INJECTOR (the default), and the host suite tests it. More...

#include <stdbool.h>
#include <stdint.h>
#include "touch_map.h"
#include "touch_types.h"

Go to the source code of this file.

Data Structures

struct  touch_merge_t
 The two sources' last sets and the injector's health. More...

Macros

#define TOUCH_MERGE_GLASS_ADDR   0x5Du
 The glass's GT911 address; the GT911's first strap address.
#define TOUCH_MERGE_INJECT_ADDR   0x14u
 The touch injector's address; the GT911's second strap address, which the glass latches instead when its INT line is low at the end of its reset.
#define TOUCH_MERGE_INJECT_PRODUCT   "9INJ"
 The product ID the touch injector reports at 0x8140..0x8143: 4 ASCII bytes, no NUL.
#define TOUCH_MERGE_INJECT_ID   0x80u
 Set in the track id of every injected contact.
#define TOUCH_MERGE_FAIL_DROP   3u
 Failed injector reads in a row before its contacts are dropped.
#define TOUCH_MERGE_RETRY_MS   100u
 Once dropped, the injector is asked again after this many ms.
#define TOUCH_MERGE_DETACH_MS   1000u
 An injector with no good read for this many ms is detached.
#define TOUCH_MERGE_PROBE_MS   1000u
 A detached injector is probed at most once in this many ms.

Enumerations

enum  touch_role_t { TOUCH_ROLE_NONE , TOUCH_ROLE_GLASS , TOUCH_ROLE_INJECTOR }
 What a controller found at start-up is to the touch task. More...

Functions

bool touch_merge_is_injector (const char *product_id)
 Whether product_id is the touch injector's.
touch_role_t touch_merge_role (uint16_t addr, bool glass_found, const char *product_id)
 The role of a controller that answered as a GT911 at start-up.
touch_map_t touch_merge_role_map (touch_role_t role, const touch_map_t *glass, const touch_map_t *inject, bool turned)
 The map for one report of a controller with role role.
void touch_merge_reset (touch_merge_t *m)
 Forget both sets: no contacts, the injector attached at 0ms.
void touch_merge_attach (touch_merge_t *m, uint32_t now_ms)
 Reset, with the injector attached and answering at now_ms.
void touch_merge_start (touch_merge_t *m, bool answered, uint32_t now_ms)
 The start-up look for the injector.
bool touch_merge_attached (const touch_merge_t *m)
 Whether the injector is attached: false once detached, until a probe.
bool touch_merge_expire (touch_merge_t *m, uint32_t now_ms)
 Detach the injector when its last good read is TOUCH_MERGE_DETACH_MS or more old. Detaching drops its contacts.
bool touch_merge_probe_due (const touch_merge_t *m, uint32_t now_ms)
 Whether a detached injector is due to be probed: TOUCH_MERGE_PROBE_MS after the detach and after every probe. Never for an absent one.
bool touch_merge_probe (touch_merge_t *m, bool answered, uint32_t now_ms)
 A detached injector was probed.
void touch_merge_glass (touch_merge_t *m, const touch_point_t *pts, int n)
 The glass reported a new contact set (0 points when every finger lifted). Injected contacts the frame no longer has room for are cut.
bool touch_merge_inject_due (const touch_merge_t *m, uint32_t now_ms)
 Whether the injector is due to be asked: on every poll while it answers, and every TOUCH_MERGE_RETRY_MS once it has failed TOUCH_MERGE_FAIL_DROP times in a row.
bool touch_merge_inject (touch_merge_t *m, const touch_point_t *pts, int n, bool fresh, uint32_t now_ms)
 The injector answered at now_ms.
bool touch_merge_inject_failed (touch_merge_t *m, uint32_t now_ms)
 An injector read failed.
int touch_merge_frame (const touch_merge_t *m, touch_point_t *out, int max)
 The merged set: the glass's contacts, then the injector's that are not cut, TOUCH_MAX_POINTS at most.
int touch_merge_mark_cut (const touch_merge_t *m, touch_event_t *evts, int n)
 Mark the UP of every cut injected contact TOUCH_FLAG_NO_TAP.
static uint32_t touch_merge_age (uint32_t glass_age_ms, uint32_t inject_age_ms)
 How old touch is: the older of the two sources' ages.
static uint32_t touch_merge_inject_age (bool attached, uint32_t ok_ms, uint32_t now_ms)
 The injector's share of touch age.

Detailed Description

Two touch controllers, one contact set: the glass's GT911 at 0x5D and a touch injector at 0x14 (testbench/touch-injector), merged into the frame the tracker sees. Pure C; the panel compiles the I/O around it in a build with RCBENCH_TOUCH_INJECTOR (the default), and the host suite tests it.

Rules:

  • The glass's contacts come first, unchanged. A frame holds at most TOUCH_MAX_POINTS contacts, so an injected contact is the one left out when the two together have more; a contact on the glass, STOP among them, never is.
  • The injected contact left out is cut: the newest first, then the last in the injector's report. A cut contact stays out until the injector lifts it, so a finger lifting from the glass never brings it back as a new press. The UP the tracker makes for it carries TOUCH_FLAG_NO_TAP (touch_merge_mark_cut()): it did not lift, and only a control that stops what the bench drives acts on it.
  • An injected contact's track id has TOUCH_MERGE_INJECT_ID set, so it never shares an id with a finger on the glass, whatever the two report and wherever they are: a finger and an injected contact on the same pixel are two contacts.
  • A source with no new report keeps its last set.
  • An injector that fails TOUCH_MERGE_FAIL_DROP reads in a row loses its contacts: the tracker then sends an UP for each, as for a finger the glass stops reporting. After that it is asked once every TOUCH_MERGE_RETRY_MS, so a dead injector costs the glass's poll at most one failed read in that time.
  • Touch is as old as the older of the two sources (touch_merge_age()): an injector that stops answering is touch that stops answering, and the bench goes SAFE as it does for the glass.
  • An injector with no good read for TOUCH_MERGE_DETACH_MS is detached (touch_merge_expire()): its contacts are dropped, it is no longer read, and its age no longer counts (touch_merge_inject_age()), so the glass alone decides how old touch is. By then touch has read as dead and the bench has disarmed; nothing arms again without a new arm.
  • The injector is looked for once, at start-up (touch_merge_start()). One that does not answer then is absent until the next start: it is never read, probed or counted, whatever the bus does later, and the glass is the only touch.
  • A detached injector is probed once every TOUCH_MERGE_PROBE_MS. The first probe it answers re-attaches it with no contacts and an age of 0 (touch_merge_probe()). Its age stays under TOUCH_MERGE_DETACH_MS whatever it does, so an injector that answers and falls silent by turns withholds touch for at most the span from touch reading as dead to the detach.

SPDX-License-Identifier: MIT

Macro Definition Documentation

◆ TOUCH_MERGE_INJECT_PRODUCT

#define TOUCH_MERGE_INJECT_PRODUCT   "9INJ"

The product ID the touch injector reports at 0x8140..0x8143: 4 ASCII bytes, no NUL.

A Goodix controller reports its part number there, digits with at most one trailing letter: "911" and a NUL on the GT911 the panel's glass carries, "9271", "917S". This ID has letters from its second byte on, so no glass reports it. '9' first keeps the GT911 driver's probe, which wants a '9' there, accepting it. testbench/touch-injector reports it (GT911_EMU_PRODUCT_ID).

Enumeration Type Documentation

◆ touch_role_t

What a controller found at start-up is to the touch task.

Enumerator
TOUCH_ROLE_NONE 

not read

TOUCH_ROLE_GLASS 

the glass: mirrors, rotation, and the turn

TOUCH_ROLE_INJECTOR 

the injector: logical pixels, never turned

Function Documentation

◆ touch_merge_age()

uint32_t touch_merge_age ( uint32_t glass_age_ms,
uint32_t inject_age_ms )
inlinestatic

How old touch is: the older of the two sources' ages.

Parameters
glass_age_msThe glass's age, in ms.
inject_age_msThe injector's share (touch_merge_inject_age()).
Returns
The older, in ms.

◆ touch_merge_attach()

void touch_merge_attach ( touch_merge_t * m,
uint32_t now_ms )

Reset, with the injector attached and answering at now_ms.

Parameters
mThe merge.
now_msThe clock.

◆ touch_merge_attached()

bool touch_merge_attached ( const touch_merge_t * m)

Whether the injector is attached: false once detached, until a probe.

Parameters
mThe merge.
Returns
Whether it is attached.

◆ touch_merge_expire()

bool touch_merge_expire ( touch_merge_t * m,
uint32_t now_ms )

Detach the injector when its last good read is TOUCH_MERGE_DETACH_MS or more old. Detaching drops its contacts.

Parameters
mThe merge.
now_msThe clock.
Returns
True when this call detached it.

◆ touch_merge_frame()

int touch_merge_frame ( const touch_merge_t * m,
touch_point_t * out,
int max )

The merged set: the glass's contacts, then the injector's that are not cut, TOUCH_MAX_POINTS at most.

Parameters
mThe merge.
outWhere the set goes.
maxThe room in out.
Returns
The number written.

◆ touch_merge_glass()

void touch_merge_glass ( touch_merge_t * m,
const touch_point_t * pts,
int n )

The glass reported a new contact set (0 points when every finger lifted). Injected contacts the frame no longer has room for are cut.

Parameters
mThe merge.
ptsThe points, in panel pixels.
nHow many; a count outside 0..TOUCH_MAX_POINTS is clamped.

◆ touch_merge_inject()

bool touch_merge_inject ( touch_merge_t * m,
const touch_point_t * pts,
int n,
bool fresh,
uint32_t now_ms )

The injector answered at now_ms.

A contact it reports keeps its cut by track id; a new one is cut when the frame has no room for it. A cut contact the injector lifts is forgotten, and its id is free again.

Parameters
mThe merge.
ptsThe points, in panel pixels; not read when fresh is false.
nHow many.
freshFalse when it had no new report.
now_msThe clock.
Returns
True when the merged set changed.

◆ touch_merge_inject_age()

uint32_t touch_merge_inject_age ( bool attached,
uint32_t ok_ms,
uint32_t now_ms )
inlinestatic

The injector's share of touch age.

Parameters
attachedWhether it is attached.
ok_msIts last good read.
now_msThe clock.
Returns
The time since ok_ms, in ms, while it is attached and that time is under TOUCH_MERGE_DETACH_MS; 0 otherwise, so the glass alone decides.

◆ touch_merge_inject_due()

bool touch_merge_inject_due ( const touch_merge_t * m,
uint32_t now_ms )

Whether the injector is due to be asked: on every poll while it answers, and every TOUCH_MERGE_RETRY_MS once it has failed TOUCH_MERGE_FAIL_DROP times in a row.

Parameters
mThe merge.
now_msThe clock.
Returns
Whether to read it.

◆ touch_merge_inject_failed()

bool touch_merge_inject_failed ( touch_merge_t * m,
uint32_t now_ms )

An injector read failed.

Parameters
mThe merge.
now_msThe clock.
Returns
True when this failure dropped injected contacts, which changes the merged set.

◆ touch_merge_is_injector()

bool touch_merge_is_injector ( const char * product_id)

Whether product_id is the touch injector's.

Parameters
product_idThe 4 bytes read at 0x8140; NULL is not the injector.
Returns
True for TOUCH_MERGE_INJECT_PRODUCT exactly.

◆ touch_merge_mark_cut()

int touch_merge_mark_cut ( const touch_merge_t * m,
touch_event_t * evts,
int n )

Mark the UP of every cut injected contact TOUCH_FLAG_NO_TAP.

Called on the tracker's events for the frame touch_merge_frame() gave. A contact cut to make room for the glass's did not lift; its UP ends the press as TOUCH_FLAG_NO_TAP says. Every other event is left as it is.

Parameters
mThe merge.
evtsThe events.
nHow many.
Returns
How many UPs were marked.

◆ touch_merge_probe()

bool touch_merge_probe ( touch_merge_t * m,
bool answered,
uint32_t now_ms )

A detached injector was probed.

Parameters
mThe merge.
answeredTrue when it answered as a GT911.
now_msThe clock.
Returns
True when this re-attached it.

◆ touch_merge_probe_due()

bool touch_merge_probe_due ( const touch_merge_t * m,
uint32_t now_ms )

Whether a detached injector is due to be probed: TOUCH_MERGE_PROBE_MS after the detach and after every probe. Never for an absent one.

Parameters
mThe merge.
now_msThe clock.
Returns
Whether to probe.

◆ touch_merge_reset()

void touch_merge_reset ( touch_merge_t * m)

Forget both sets: no contacts, the injector attached at 0ms.

Parameters
mThe merge; NULL does nothing.

◆ touch_merge_role()

touch_role_t touch_merge_role ( uint16_t addr,
bool glass_found,
const char * product_id )

The role of a controller that answered as a GT911 at start-up.

  • At TOUCH_MERGE_GLASS_ADDR: the glass, whatever its product ID.
  • At TOUCH_MERGE_INJECT_ADDR with TOUCH_MERGE_INJECT_PRODUCT: the injector, beside a glass at 0x5D or alone.
  • At TOUCH_MERGE_INJECT_ADDR with any other product ID: the glass when nothing answered at 0x5D (glass_found false); not read when the glass answered at 0x5D, so 0x5D wins.
  • At any other address: not read.
Parameters
addrThe address it answered at.
glass_foundWhether a glass answered at TOUCH_MERGE_GLASS_ADDR before it.
product_idIts 4-byte product ID; NULL when the read failed.
Returns
Its role.

◆ touch_merge_role_map()

touch_map_t touch_merge_role_map ( touch_role_t role,
const touch_map_t * glass,
const touch_map_t * inject,
bool turned )

The map for one report of a controller with role role.

Parameters
roleIts role.
glassThe glass's map: its resolution, mirrors and rotation.
injectThe injector's map (logical pixels).
turnedWhether the turned picture is on the glass (gfx_turn_shown()); false again after the turn falls back.
Returns
glass turned by turned for TOUCH_ROLE_GLASS; inject, never turned, for TOUCH_ROLE_INJECTOR; a zeroed map for TOUCH_ROLE_NONE or a NULL map.

◆ touch_merge_start()

void touch_merge_start ( touch_merge_t * m,
bool answered,
uint32_t now_ms )

The start-up look for the injector.

An answer is touch_merge_attach(). No answer makes the injector absent until the next start: nothing in this header attaches, reads or probes it, and touch_merge_attached() stays false.

Parameters
mThe merge.
answeredTrue when 0x14 answered as a GT911.
now_msThe clock.