touch button mode
This commit is contained in:
@@ -10,9 +10,95 @@
|
||||
|
||||
#include "_touch_internal.h"
|
||||
|
||||
// discharge time in ms
|
||||
#define DIS_TIME 1
|
||||
|
||||
static void startNextPhase(struct priv *priv);
|
||||
static void startNextPhase(Unit *unit);
|
||||
|
||||
static void UTOUCH_EventReportJob(Job *job)
|
||||
{
|
||||
Unit *unit = job->unit;
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint8_t buf[8];
|
||||
PayloadBuilder pb = pb_start(buf, 8, NULL);
|
||||
pb_u32(&pb, pinmask_pack_32(~job->data1, priv->all_channels_mask)); // inverted and packed - all pins (pressed state)
|
||||
pb_u32(&pb, pinmask_pack_32(job->data2, priv->all_channels_mask)); // trigger generating pins
|
||||
assert_param(pb.ok);
|
||||
|
||||
EventReport er = {
|
||||
.unit = unit,
|
||||
.type = 0x00,
|
||||
.length = 8,
|
||||
.data = buf,
|
||||
.timestamp = job->timestamp,
|
||||
};
|
||||
|
||||
EventReport_Send(&er);
|
||||
}
|
||||
|
||||
static void UTOUCH_CheckForBinaryEvents(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
uint32_t time_ms = PTIM_GetTime();
|
||||
|
||||
if (priv->last_done_ms == 0) {
|
||||
// avoid bug with trigger on first capture
|
||||
priv->last_done_ms = time_ms;
|
||||
}
|
||||
|
||||
uint64_t ts = PTIM_GetMicrotime();
|
||||
uint32_t eventpins = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
const uint32_t poke = (uint32_t) (1 << i);
|
||||
if (0 == (priv->all_channels_mask & poke)) continue;
|
||||
if (priv->binary_thr[i] == 0) continue; // skip disabled channels
|
||||
|
||||
const bool can_go_up = !(priv->binary_active_bits&poke) && (priv->readouts[i] > (priv->binary_thr[i] + priv->binary_hysteresis));
|
||||
const bool can_go_down = (priv->binary_active_bits&poke) && (priv->readouts[i] < priv->binary_thr[i]);
|
||||
|
||||
if (can_go_up) {
|
||||
priv->bin_trig_cnt[i] += (time_ms - priv->last_done_ms);
|
||||
if (priv->bin_trig_cnt[i] >= priv->binary_debounce_ms) {
|
||||
priv->binary_active_bits |= poke;
|
||||
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
|
||||
|
||||
eventpins |= poke;
|
||||
}
|
||||
}
|
||||
else if (priv->bin_trig_cnt[i] > 0) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
|
||||
if (can_go_down) {
|
||||
priv->bin_trig_cnt[i] -= (time_ms - priv->last_done_ms);
|
||||
if (priv->bin_trig_cnt[i] <= -priv->binary_debounce_ms) {
|
||||
priv->binary_active_bits &= ~poke;
|
||||
priv->bin_trig_cnt[i] = 0; // reset for the other direction of the switch
|
||||
|
||||
eventpins |= poke;
|
||||
}
|
||||
}
|
||||
else if (priv->bin_trig_cnt[i] < 0) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventpins != 0) {
|
||||
Job j = {
|
||||
.timestamp = ts,
|
||||
.data1 = priv->binary_active_bits,
|
||||
.data2 = eventpins,
|
||||
.unit = unit,
|
||||
.cb = UTOUCH_EventReportJob,
|
||||
};
|
||||
|
||||
scheduleJob(&j);
|
||||
}
|
||||
|
||||
priv->last_done_ms = time_ms;
|
||||
}
|
||||
|
||||
void UTOUCH_HandleIrq(void *arg)
|
||||
{
|
||||
@@ -44,7 +130,7 @@ void UTOUCH_HandleIrq(void *arg)
|
||||
if (priv->next_phase == 3 || priv->groups_phase[priv->next_phase] == 0) {
|
||||
priv->next_phase = 0;
|
||||
priv->status = UTSC_STATUS_READY;
|
||||
// we'll stay in READY after the first loop until an error occurs or it's re-inited
|
||||
UTOUCH_CheckForBinaryEvents(unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +160,7 @@ void UTOUCH_updateTick(Unit *unit)
|
||||
if (priv->discharge_delay > 0) {
|
||||
priv->discharge_delay--;
|
||||
} else {
|
||||
startNextPhase(priv);
|
||||
startNextPhase(unit);
|
||||
}
|
||||
|
||||
#if TSC_DEBUG
|
||||
@@ -91,8 +177,10 @@ void UTOUCH_updateTick(Unit *unit)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void startNextPhase(struct priv *priv)
|
||||
static void startNextPhase(Unit *unit)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
if (priv->all_channels_mask == 0) return;
|
||||
|
||||
if (priv->cfg.interlaced) {
|
||||
@@ -102,6 +190,7 @@ static void startNextPhase(struct priv *priv)
|
||||
if (priv->next_phase == 32) {
|
||||
priv->next_phase = 0;
|
||||
priv->status = UTSC_STATUS_READY;
|
||||
UTOUCH_CheckForBinaryEvents(unit);
|
||||
}
|
||||
}
|
||||
TSC->IOGCSR = (uint32_t) (1 << (priv->next_phase >> 2)); // phase divided by 4
|
||||
|
||||
@@ -23,6 +23,8 @@ error_t UTOUCH_preInit(Unit *unit)
|
||||
priv->cfg.sense_timeout = 7;
|
||||
memset(priv->cfg.group_scaps, 0, 8);
|
||||
memset(priv->cfg.group_channels, 0, 8);
|
||||
priv->cfg.binary_hysteresis = 10;
|
||||
priv->cfg.binary_debounce_ms = 20;
|
||||
|
||||
return E_SUCCESS;
|
||||
}
|
||||
@@ -35,6 +37,10 @@ error_t UTOUCH_init(Unit *unit)
|
||||
|
||||
unit->tick_interval = 1; // sample every 1 ms
|
||||
|
||||
// copy from conf
|
||||
priv->binary_debounce_ms = priv->cfg.binary_debounce_ms;
|
||||
priv->binary_hysteresis = priv->cfg.binary_hysteresis;
|
||||
|
||||
TRY(rsc_claim(unit, R_TSC));
|
||||
|
||||
// simple bound checks, just clamp without error
|
||||
|
||||
@@ -39,6 +39,8 @@ struct priv {
|
||||
uint8_t group_scaps[8];
|
||||
uint8_t group_channels[8];
|
||||
bool interlaced;
|
||||
uint16_t binary_debounce_ms;
|
||||
uint16_t binary_hysteresis;
|
||||
} cfg;
|
||||
|
||||
uint8_t next_phase;
|
||||
@@ -46,11 +48,17 @@ struct priv {
|
||||
uint32_t channels_phase[3];
|
||||
uint8_t groups_phase[3];
|
||||
uint16_t readouts[32];
|
||||
int16_t bin_trig_cnt[32];
|
||||
uint16_t binary_debounce_ms;
|
||||
uint16_t binary_hysteresis;
|
||||
uint16_t binary_thr[32];
|
||||
uint32_t binary_active_bits;
|
||||
uint32_t all_channels_mask;
|
||||
uint32_t last_done_ms;
|
||||
bool ongoing;
|
||||
|
||||
enum utsc_status status;
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
extern const char *utouch_group_labels[8];
|
||||
extern const Resource utouch_group_rscs[8][4];
|
||||
|
||||
@@ -50,6 +50,11 @@ void UTOUCH_loadBinary(Unit *unit, PayloadParser *pp)
|
||||
if (version >= 1) {
|
||||
priv->cfg.interlaced = pp_bool(pp);
|
||||
}
|
||||
|
||||
if (version >= 2) {
|
||||
priv->cfg.binary_debounce_ms = pp_u16(pp);
|
||||
priv->cfg.binary_hysteresis = pp_u16(pp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write to a binary buffer for storing in Flash */
|
||||
@@ -57,7 +62,7 @@ void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
{
|
||||
struct priv *priv = unit->data;
|
||||
|
||||
pb_u8(pb, 1); // version
|
||||
pb_u8(pb, 2); // version
|
||||
|
||||
pb_u8(pb, priv->cfg.charge_time);
|
||||
pb_u8(pb, priv->cfg.drain_time);
|
||||
@@ -68,6 +73,8 @@ void UTOUCH_writeBinary(Unit *unit, PayloadBuilder *pb)
|
||||
pb_buf(pb, priv->cfg.group_scaps, 8);
|
||||
pb_buf(pb, priv->cfg.group_channels, 8);
|
||||
pb_bool(pb, priv->cfg.interlaced);
|
||||
pb_u16(pb, priv->cfg.binary_debounce_ms);
|
||||
pb_u16(pb, priv->cfg.binary_hysteresis);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -99,6 +106,12 @@ error_t UTOUCH_loadIni(Unit *unit, const char *key, const char *value)
|
||||
else if (streq(key, "interlaced-pads")) {
|
||||
priv->cfg.interlaced = cfg_bool_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "btn-debounce")) {
|
||||
priv->cfg.binary_debounce_ms = cfg_u16_parse(value, &suc);
|
||||
}
|
||||
else if (streq(key, "btn-hysteresis")) {
|
||||
priv->cfg.binary_hysteresis = cfg_u16_parse(value, &suc);
|
||||
}
|
||||
else {
|
||||
volatile char namebuf[10]; // must be volatile or gcc optimizes out the second compare and fucks it up
|
||||
|
||||
@@ -152,6 +165,11 @@ void UTOUCH_writeIni(Unit *unit, IniWriter *iw)
|
||||
iw_comment(iw, "Optimize for interlaced pads (individual sampling with others floating)");
|
||||
iw_entry(iw, "interlaced-pads", str_yn(priv->cfg.interlaced));
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Button mode debounce (ms) and release hysteresis (lsb)");
|
||||
iw_entry(iw, "btn-debounce", "%d", (int)priv->cfg.binary_debounce_ms);
|
||||
iw_entry(iw, "btn-hysteresis", "%d", (int)priv->cfg.binary_hysteresis);
|
||||
|
||||
iw_cmt_newline(iw);
|
||||
iw_comment(iw, "Each used group must have 1 sampling capacitor and 1-3 channels.");
|
||||
iw_comment(iw, "Channels are numbered 1,2,3,4");
|
||||
|
||||
@@ -11,20 +11,23 @@
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
enum TouchCmd_ {
|
||||
CMD_READ=0
|
||||
CMD_READ=0,
|
||||
CMD_SET_BIN_THR=1,
|
||||
CMD_DISABLE_ALL_REPORTS=2,
|
||||
CMD_GET_CH_COUNT=10,
|
||||
};
|
||||
|
||||
/** Handle a request message */
|
||||
static error_t UTOUCH_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
|
||||
{
|
||||
struct priv* priv = unit->data;
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
|
||||
switch (command) {
|
||||
case CMD_READ:
|
||||
if (priv->status == UTSC_STATUS_BUSY) return E_BUSY;
|
||||
if (priv->status == UTSC_STATUS_FAIL) return E_HW_TIMEOUT;
|
||||
|
||||
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
pb_u16(&pb, priv->readouts[i]);
|
||||
@@ -33,6 +36,39 @@ static error_t UTOUCH_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_SET_BIN_THR:
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
priv->binary_thr[i] = pp_u16(pp);
|
||||
if (priv->readouts[i] >= (priv->binary_thr[i] + priv->binary_hysteresis)) {
|
||||
priv->binary_active_bits |= 1<<i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_DISABLE_ALL_REPORTS:
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
priv->binary_thr[i] = 0;
|
||||
priv->bin_trig_cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
priv->binary_active_bits = 0;
|
||||
return E_SUCCESS;
|
||||
|
||||
case CMD_GET_CH_COUNT:;
|
||||
uint8_t nb = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (priv->all_channels_mask & (1<<i)) {
|
||||
nb++;
|
||||
}
|
||||
}
|
||||
pb_u8(&pb, nb);
|
||||
com_respond_pb(frame_id, MSG_SUCCESS, &pb);
|
||||
return E_SUCCESS;
|
||||
|
||||
default:
|
||||
return E_UNKNOWN_COMMAND;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user