diff --git a/units/touch/_touch_core.c b/units/touch/_touch_core.c index 76f8ebb..7d25922 100644 --- a/units/touch/_touch_core.c +++ b/units/touch/_touch_core.c @@ -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 diff --git a/units/touch/_touch_init.c b/units/touch/_touch_init.c index 4321b4f..bb897f3 100644 --- a/units/touch/_touch_init.c +++ b/units/touch/_touch_init.c @@ -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 diff --git a/units/touch/_touch_internal.h b/units/touch/_touch_internal.h index ffc6d39..432c29a 100644 --- a/units/touch/_touch_internal.h +++ b/units/touch/_touch_internal.h @@ -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]; diff --git a/units/touch/_touch_settings.c b/units/touch/_touch_settings.c index 9c2b244..a213e51 100644 --- a/units/touch/_touch_settings.c +++ b/units/touch/_touch_settings.c @@ -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"); diff --git a/units/touch/unit_touch.c b/units/touch/unit_touch.c index dd42aee..a7d9a7e 100644 --- a/units/touch/unit_touch.c +++ b/units/touch/unit_touch.c @@ -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<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<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<all_channels_mask & (1<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<