From 24cbad3257d3d26826766fd587f81fe9fa9d2453 Mon Sep 17 00:00:00 2001 From: Vic Date: Mon, 4 Jan 2021 14:57:32 +0100 Subject: [PATCH 1/7] more diagnostics --- tasmota/.xdrv_47_ftc532.ino.kate-swp | Bin 0 -> 710 bytes tasmota/xdrv_47_ftc532.ino | 99 ++++++++++++++++----------- 2 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 tasmota/.xdrv_47_ftc532.ino.kate-swp diff --git a/tasmota/.xdrv_47_ftc532.ino.kate-swp b/tasmota/.xdrv_47_ftc532.ino.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..46ab3cc1996b17b4471ee761f28e803930b1f42e GIT binary patch literal 710 zcmZ9}J4*vW5C`zx_zGx@im&)$F~)R~J2i#cNZ5$@Bzq`UN5B&f!eMbi?X2?|Y%Kj6 zehO1D(@2@8_M>XXok;mRH6g_OZ|~Kse7v9B^nQ}J zueE+Y3XyuY(lA?I(Kz6mUo}#>r*#$UZPs1s@2z%@qxUT@fyVw0kZ8Vgw)41~)R@|nE_(}rk1q(JjFnk{TI>^8&wW?!4ztiGbnVDb?q@X4~9 zk;vS0MGlVGBk%)z6wWRW6UX4}^5AjU>7RfV_vgulX3*H*^+OXJ2Rh`n1=Kd!i|`eD x3BF)2!`JK*e9m5hHG35f*lR=U>#%dy4RTI72{oL+%h<=j-@A_i_a9?V{{fF>QeprA literal 0 HcmV?d00001 diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 5c076faa4..e88a80312 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -54,105 +54,122 @@ #define XDRV_47 47 #define FTC532_KEYS_MAX 8 +#define FTC532_RETRY 8 // number of reads before discarding #define FTC532_STATE_WAITING false #define FTC532_STATE_READING true // Rising edge timing in microseconds #define FTC532_BIT 377 +#define FTC532_NOISE (FTC532_BIT * 3 / 2) #define FTC532_SHORT (FTC532_BIT * 2) #define FTC532_LONG (FTC532_BIT * 4) #define FTC532_IDLE (FTC532_BIT * 10) #define FTC532_MAX (FTC532_BIT * 58) +#define DEBUG_FTC532 //@@@@@@@@@@@@@@@@ + struct FTC532 { volatile uint32_t rxtime; // ISR timer memory - volatile uint16_t sample = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t tsmp = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t sample = 0xF0F0; // complete samples volatile uint16_t rxbit; // ISR bit counter uint8_t keys = 0; // bitmap of active keys uint8_t old_keys = 0; // previously active keys volatile bool state; // ISR state - bool present = false; -#ifdef DEBUG_TASMOTA_DRIVER - volatile uint16_t errors; // error counter - volatile bool valid; // did we ever receive valid data? -#endif // DEBUG_TASMOTA_DRIVER + bool present = false; // driver active +#ifdef DEBUG_FTC532 + volatile uint16_t errors = 0; // inv. key error counter + volatile uint16_t frame = 0; // frame error counter + volatile uint16_t noise = 0; // noise detection counter + volatile bool valid = 0; // did we ever receive valid data? +#endif // DEBUG_FTC532 } Ftc532; const char ftc532_json[] PROGMEM = "\"FTC532\":{\"KEYS\":\""; -void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge +void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge uint32_t time = micros(); uint32_t time_diff = time - Ftc532.rxtime; Ftc532.rxtime = time; if (Ftc532.state == FTC532_STATE_WAITING) { - if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame + if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame Ftc532.rxbit = 0; Ftc532.state = FTC532_STATE_READING; } return; } // FTC532_STATE_READING starts here if (time_diff > FTC532_LONG + FTC532_BIT) { -#ifdef DEBUG_TASMOTA_DRIVER - ++Ftc532.errors; // frame error -#endif // DEBUG_TASMOTA_DRIVER +#ifdef DEBUG_FTC532 + ++Ftc532.frame; // frame error +#endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; } if (time_diff > FTC532_SHORT + FTC532_BIT) { - Ftc532.sample |= (1 << Ftc532.rxbit); // LONG + Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG + } else if (time_diff < FTC532_NOISE) { // noise detector +#ifdef DEBUG_FTC532 + ++Ftc532.noise; +#endif // DEBUG_FTC532 + Ftc532.state = FTC532_STATE_WAITING; + return; } else { - Ftc532.sample &= ~(1 << Ftc532.rxbit); // SHORT + Ftc532.tsmp &= ~(1 << Ftc532.rxbit); // SHORT } ++Ftc532.rxbit; - if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + Ftc532.sample = Ftc532.tsmp; // copy frame Ftc532.rxbit = 0; -#ifdef DEBUG_TASMOTA_DRIVER - Ftc532.valid = true; -#endif // DEBUG_TASMOTA_DRIVER Ftc532.state = FTC532_STATE_WAITING; +#ifdef DEBUG_FTC532 + Ftc532.valid = true; +#endif // DEBUG_FTC532 } } -void ftc532_init(void) { // Initialize +void ftc532_init(void) { // Initialize if (!PinUsed(GPIO_FTC532)) { return; } -#ifdef DEBUG_TASMOTA_DRIVER - Ftc532.errors = 0; - Ftc532.valid = false; -#endif // DEBUG_TASMOTA_DRIVER Ftc532.state = FTC532_STATE_WAITING; - Ftc532.rxtime = micros(); pinMode(Pin(GPIO_FTC532), INPUT_PULLUP); + Ftc532.rxtime = micros(); attachInterrupt(Pin(GPIO_FTC532), ftc532_ISR, RISING); Ftc532.present = true; } -void ftc532_update(void) { // Usually called every 50 ms -#ifdef DEBUG_TASMOTA_DRIVER -// WARNING: Reduce callback frequency if this code is enabled -// if ((Ftc532.sample & 0xF) != ((~Ftc532.sample >> 4) & 0xF) || ((Ftc532.sample >> 8) & 0xF) != ((~Ftc532.sample >> 12) & 0xF)) { -// AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: inverted sample does not match %x %x %x %x"), -// Ftc532.sample & 0xF, (~Ftc532.sample >> 4) & 0xF, (Ftc532.sample >> 8) & 0xF, (~Ftc532.sample >> 12) & 0xF); -// } -#endif // DEBUG_TASMOTA_DRIVER - Ftc532.keys = (Ftc532.sample & 0xF) | ((Ftc532.sample >> 4) & 0xF0); - if (Ftc532.keys != Ftc532.old_keys) { -#ifdef DEBUG_TASMOTA_DRIVER - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%02X OLD=%02X ERR=%u OK=%u TIME=%lu Pin=%u"), - Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.errors, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); -#endif // DEBUG_TASMOTA_DRIVER - ftc532_publish(); - Ftc532.old_keys = Ftc532.keys; +void ftc532_update(void) { // Usually called every 50 ms + uint16_t smp; + uint16_t i; + + while (i++ < FTC532_RETRY) { // fix 'ghost' keys from bad hardware + smp = Ftc532.sample; + if ((smp & 0xF0F0) != ((~smp & 0x0F0F) << 4)) { // inverted keys don't match + ++Ftc532.errors; +#ifdef DEBUG_FTC532 + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), smp); +#endif // DEBUG_FTC532 + } else { + Ftc532.keys = (smp & 0xF) | ((smp >> 4) & 0xF0); + if (Ftc532.keys != Ftc532.old_keys) { +#ifdef DEBUG_FTC532 + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%02X OLD=%02X ERR=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), + Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.errors, Ftc532.noise, Ftc532.frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); +#endif // DEBUG_FTC532 + ftc532_publish(); + Ftc532.old_keys = Ftc532.keys; + } + break; + } } } void ftc532_show() { - ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes + ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); } void ftc532_publish(void) { - Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes + Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); MqttPublishTeleSensor(); } From 22734fe8bbeac0580ec87482554d2d370e0374e9 Mon Sep 17 00:00:00 2001 From: Vic Date: Mon, 4 Jan 2021 19:25:24 +0100 Subject: [PATCH 2/7] add debouncing code for noisy environments --- tasmota/.xdrv_47_ftc532.ino.kate-swp | Bin 710 -> 0 bytes tasmota/xdrv_47_ftc532.ino | 87 ++++++++++++++------------- 2 files changed, 46 insertions(+), 41 deletions(-) delete mode 100644 tasmota/.xdrv_47_ftc532.ino.kate-swp diff --git a/tasmota/.xdrv_47_ftc532.ino.kate-swp b/tasmota/.xdrv_47_ftc532.ino.kate-swp deleted file mode 100644 index 46ab3cc1996b17b4471ee761f28e803930b1f42e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 710 zcmZ9}J4*vW5C`zx_zGx@im&)$F~)R~J2i#cNZ5$@Bzq`UN5B&f!eMbi?X2?|Y%Kj6 zehO1D(@2@8_M>XXok;mRH6g_OZ|~Kse7v9B^nQ}J zueE+Y3XyuY(lA?I(Kz6mUo}#>r*#$UZPs1s@2z%@qxUT@fyVw0kZ8Vgw)41~)R@|nE_(}rk1q(JjFnk{TI>^8&wW?!4ztiGbnVDb?q@X4~9 zk;vS0MGlVGBk%)z6wWRW6UX4}^5AjU>7RfV_vgulX3*H*^+OXJ2Rh`n1=Kd!i|`eD x3BF)2!`JK*e9m5hHG35f*lR=U>#%dy4RTI72{oL+%h<=j-@A_i_a9?V{{fF>QeprA diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index e88a80312..d9dbca660 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -25,7 +25,7 @@ select pin (GPIO_FTC532) attach interrupt to pin DONE ISR updating all 8 inputs DONE - de-bouncing for 50 ms NOT REQUIRED + de-bouncing for 50 ms DONE change report every 250 ms REPORTS EVERY 50MS Webserver display "00001001" DONE & REMOVED MQTT message DONE @@ -53,11 +53,13 @@ #define XDRV_47 47 -#define FTC532_KEYS_MAX 8 -#define FTC532_RETRY 8 // number of reads before discarding +#define FTC532_KEYS 4 // number of key pins on chip +#define FTC532_KEYS_MAX 8 // number of slots in protocol +#define FTC532_DEBOUNCE 2 // number of consecutive cycles until key accepted -#define FTC532_STATE_WAITING false -#define FTC532_STATE_READING true +#define FTC532_STATE_WAITING 0x1 +#define FTC532_STATE_READING 0x2 +#define FTC532_STATE_COMPLETE 0x4 // Rising edge timing in microseconds #define FTC532_BIT 377 @@ -71,17 +73,18 @@ struct FTC532 { volatile uint32_t rxtime; // ISR timer memory - volatile uint16_t tsmp = 0xF0F0; // buffer for bit-coded time samples - volatile uint16_t sample = 0xF0F0; // complete samples + volatile uint16_t tsmp = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t sample = 0xF0F0; // valid samples volatile uint16_t rxbit; // ISR bit counter - uint8_t keys = 0; // bitmap of active keys - uint8_t old_keys = 0; // previously active keys - volatile bool state; // ISR state + volatile uint16_t state; // ISR state + uint8_t keys = 0; // bitmap of active keys + uint8_t old_keys = 0; // previously active keys + uint8_t key_cnt = 0; // used to de-bounce bool present = false; // driver active #ifdef DEBUG_FTC532 - volatile uint16_t errors = 0; // inv. key error counter - volatile uint16_t frame = 0; // frame error counter - volatile uint16_t noise = 0; // noise detection counter + volatile uint16_t e_inv = 0; // inv. key error counter + volatile uint16_t e_frame = 0; // frame error counter + volatile uint16_t e_noise = 0; // noise detection counter volatile bool valid = 0; // did we ever receive valid data? #endif // DEBUG_FTC532 } Ftc532; @@ -93,16 +96,25 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigg uint32_t time_diff = time - Ftc532.rxtime; Ftc532.rxtime = time; - if (Ftc532.state == FTC532_STATE_WAITING) { + if (Ftc532.state & (FTC532_STATE_WAITING | FTC532_STATE_COMPLETE)) { if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame Ftc532.rxbit = 0; + if (Ftc532.state & FTC532_STATE_COMPLETE) { + Ftc532.sample = Ftc532.tsmp; // copy complete frame +#ifdef DEBUG_FTC532 + Ftc532.valid = true; +#endif // DEBUG_FTC532 + } Ftc532.state = FTC532_STATE_READING; + } else { + Ftc532.state = FTC532_STATE_WAITING; } return; - } // FTC532_STATE_READING starts here + } + // FTC532_STATE_READING starts here if (time_diff > FTC532_LONG + FTC532_BIT) { #ifdef DEBUG_FTC532 - ++Ftc532.frame; // frame error + ++Ftc532.e_frame; // frame error #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; @@ -111,7 +123,7 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigg Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG } else if (time_diff < FTC532_NOISE) { // noise detector #ifdef DEBUG_FTC532 - ++Ftc532.noise; + ++Ftc532.e_noise; #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; @@ -120,16 +132,11 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigg } ++Ftc532.rxbit; if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete - Ftc532.sample = Ftc532.tsmp; // copy frame - Ftc532.rxbit = 0; - Ftc532.state = FTC532_STATE_WAITING; -#ifdef DEBUG_FTC532 - Ftc532.valid = true; -#endif // DEBUG_FTC532 + Ftc532.state = FTC532_STATE_COMPLETE; } } -void ftc532_init(void) { // Initialize +void ftc532_init(void) { // Initialize if (!PinUsed(GPIO_FTC532)) { return; } Ftc532.state = FTC532_STATE_WAITING; pinMode(Pin(GPIO_FTC532), INPUT_PULLUP); @@ -138,30 +145,28 @@ void ftc532_init(void) { // Initialize Ftc532.present = true; } -void ftc532_update(void) { // Usually called every 50 ms - uint16_t smp; - uint16_t i; - - while (i++ < FTC532_RETRY) { // fix 'ghost' keys from bad hardware - smp = Ftc532.sample; - if ((smp & 0xF0F0) != ((~smp & 0x0F0F) << 4)) { // inverted keys don't match - ++Ftc532.errors; +void ftc532_update(void) { // Usually called every 50 ms + if ((Ftc532.sample & 0xF0F0) == ((~Ftc532.sample & 0x0F0F) << 4) && (Ftc532.sample >> 8) == 0xF0) { + Ftc532.keys = Ftc532.sample & 0xF; + if (Ftc532.keys != Ftc532.old_keys) { + if (++Ftc532.key_cnt >= FTC532_DEBOUNCE) { #ifdef DEBUG_FTC532 - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), smp); -#endif // DEBUG_FTC532 - } else { - Ftc532.keys = (smp & 0xF) | ((smp >> 4) & 0xF0); - if (Ftc532.keys != Ftc532.old_keys) { -#ifdef DEBUG_FTC532 - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%02X OLD=%02X ERR=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), - Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.errors, Ftc532.noise, Ftc532.frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%X OLD=%X INV=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), + Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); #endif // DEBUG_FTC532 ftc532_publish(); Ftc532.old_keys = Ftc532.keys; + Ftc532.key_cnt = 0; } - break; + } else { + Ftc532.key_cnt = 0; } +#ifdef DEBUG_FTC532 + } else { + ++Ftc532.e_inv; + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), Ftc532.sample); } +#endif // DEBUG_FTC532 } void ftc532_show() { From 2426dbf8e592946dd1c891191b53b2fc08395dc5 Mon Sep 17 00:00:00 2001 From: Vic Date: Mon, 4 Jan 2021 20:26:00 +0100 Subject: [PATCH 3/7] debounce selectable --- tasmota/xdrv_47_ftc532.ino | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index d9dbca660..98a7ddf18 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -54,8 +54,8 @@ #define XDRV_47 47 #define FTC532_KEYS 4 // number of key pins on chip -#define FTC532_KEYS_MAX 8 // number of slots in protocol -#define FTC532_DEBOUNCE 2 // number of consecutive cycles until key accepted +#define FTC532_KEYS_MAX 8 // number of key slots in protocol +#define FTC532_DEBOUNCE 0 // number of consecutive cycles until key accepted #define FTC532_STATE_WAITING 0x1 #define FTC532_STATE_READING 0x2 @@ -79,7 +79,9 @@ struct FTC532 { volatile uint16_t state; // ISR state uint8_t keys = 0; // bitmap of active keys uint8_t old_keys = 0; // previously active keys +#if FTC532_DEBOUNCE > 1 uint8_t key_cnt = 0; // used to de-bounce +#endif // FTC532_DEBOUNCE > 1 bool present = false; // driver active #ifdef DEBUG_FTC532 volatile uint16_t e_inv = 0; // inv. key error counter @@ -91,7 +93,7 @@ struct FTC532 { const char ftc532_json[] PROGMEM = "\"FTC532\":{\"KEYS\":\""; -void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge +void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, triggers on rising edge uint32_t time = micros(); uint32_t time_diff = time - Ftc532.rxtime; Ftc532.rxtime = time; @@ -100,7 +102,7 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigg if (time_diff > FTC532_LONG + FTC532_SHORT) { // new frame Ftc532.rxbit = 0; if (Ftc532.state & FTC532_STATE_COMPLETE) { - Ftc532.sample = Ftc532.tsmp; // copy complete frame + Ftc532.sample = Ftc532.tsmp; // copy completed frame #ifdef DEBUG_FTC532 Ftc532.valid = true; #endif // DEBUG_FTC532 @@ -149,20 +151,25 @@ void ftc532_update(void) { // Usually called every 50 ms if ((Ftc532.sample & 0xF0F0) == ((~Ftc532.sample & 0x0F0F) << 4) && (Ftc532.sample >> 8) == 0xF0) { Ftc532.keys = Ftc532.sample & 0xF; if (Ftc532.keys != Ftc532.old_keys) { +#if FTC532_DEBOUNCE > 1 if (++Ftc532.key_cnt >= FTC532_DEBOUNCE) { +#endif // FTC532_DEBOUNCE > 1 #ifdef DEBUG_FTC532 AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%X OLD=%X INV=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); #endif // DEBUG_FTC532 ftc532_publish(); Ftc532.old_keys = Ftc532.keys; +#if FTC532_DEBOUNCE > 1 Ftc532.key_cnt = 0; } } else { Ftc532.key_cnt = 0; +#endif // FTC532_DEBOUNCE > 1 } + } #ifdef DEBUG_FTC532 - } else { + else { ++Ftc532.e_inv; AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), Ftc532.sample); } From 11921eb92863b5a54e7e95d65d6c2a0b23b7d992 Mon Sep 17 00:00:00 2001 From: Vic Date: Tue, 5 Jan 2021 10:42:50 +0100 Subject: [PATCH 4/7] One more ISR improvement --- tasmota/xdrv_47_ftc532.ino | 58 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 98a7ddf18..6a50ba9b1 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -49,13 +49,41 @@ Timing of an ALL OFF frame in clock cycles T=377µs, triggering on rising edge: IDLE-2222444422224444-IDLE + + ********************* + * About this driver * + ********************* + + This driver implements the reverse engineered protocol of the FTC532 touch controller. + The protocol encodes the bitmap of touched keys in variable length pulses comprising a + fixed length frame. These frames are then sent out continuously from the FTC532 chip. + The first version of this driver was working fine on well behaved hardware. After being + released to the field and installed on crappy hardware in noisy environments it developed + a habit of random 'ghost' switchings at night, much to the chagrin of some users. + This is almost a re-write containing a lot more timing (and other) checks in order to + detect and mitigate various incarnations of noise. + If you should still experience 'ghost switching' issues a solution may be increasing + FTC532_DEBOUNCE to 2 or higher. That will enable the de-bouncing code, at the expense of + 'snappiness' of touch reactions. Higher values will accumulate more samples in 50 ms steps + before actually firing the rules trigger. It will eat a few bytes off your RAM and Flash + budget, too. + + Usage: + ------ + This driver does not actually switch anything. It is a pure "rules" driver that solely emits + {"FTC532":{"KEYS":"XX"}} JSON messages to be used in a rule or by an MQTT broker. "XX" stands + for the hexadecimal (big endian) representation of a bitmap of keys currently touched, where + e.g. "00" means "no key touched" while "03" means "keys 1 and 2 touched simultaneously". + Selecting "FTC532" on a GPIO will awake the driver. This driver can only be selected once. + + \*********************************************************************************************/ #define XDRV_47 47 +#define FTC532_DEBOUNCE 0 // no. of cycles, < 2 disables the code #define FTC532_KEYS 4 // number of key pins on chip #define FTC532_KEYS_MAX 8 // number of key slots in protocol -#define FTC532_DEBOUNCE 0 // number of consecutive cycles until key accepted #define FTC532_STATE_WAITING 0x1 #define FTC532_STATE_READING 0x2 @@ -79,15 +107,15 @@ struct FTC532 { volatile uint16_t state; // ISR state uint8_t keys = 0; // bitmap of active keys uint8_t old_keys = 0; // previously active keys + bool present = false; // driver active #if FTC532_DEBOUNCE > 1 uint8_t key_cnt = 0; // used to de-bounce #endif // FTC532_DEBOUNCE > 1 - bool present = false; // driver active #ifdef DEBUG_FTC532 - volatile uint16_t e_inv = 0; // inv. key error counter + volatile uint16_t e_inv = 0; // inverted key error counter volatile uint16_t e_frame = 0; // frame error counter volatile uint16_t e_noise = 0; // noise detection counter - volatile bool valid = 0; // did we ever receive valid data? + volatile bool valid = 0; // did we ever receive valid data? #endif // DEBUG_FTC532 } Ftc532; @@ -108,37 +136,36 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigger #endif // DEBUG_FTC532 } Ftc532.state = FTC532_STATE_READING; + Ftc532.tsmp = 0; } else { Ftc532.state = FTC532_STATE_WAITING; } return; } - // FTC532_STATE_READING starts here + // FTC532_STATE_READING starts here if (time_diff > FTC532_LONG + FTC532_BIT) { #ifdef DEBUG_FTC532 - ++Ftc532.e_frame; // frame error + ++Ftc532.e_frame; // frame error #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; } if (time_diff > FTC532_SHORT + FTC532_BIT) { - Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG - } else if (time_diff < FTC532_NOISE) { // noise detector + Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG + } else if (time_diff < FTC532_NOISE) { // NOISE #ifdef DEBUG_FTC532 ++Ftc532.e_noise; #endif // DEBUG_FTC532 Ftc532.state = FTC532_STATE_WAITING; return; - } else { - Ftc532.tsmp &= ~(1 << Ftc532.rxbit); // SHORT } ++Ftc532.rxbit; - if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete + if (Ftc532.rxbit == FTC532_KEYS_MAX * 2) { // frame complete Ftc532.state = FTC532_STATE_COMPLETE; } } -void ftc532_init(void) { // Initialize +void ftc532_init(void) { // Initialize if (!PinUsed(GPIO_FTC532)) { return; } Ftc532.state = FTC532_STATE_WAITING; pinMode(Pin(GPIO_FTC532), INPUT_PULLUP); @@ -147,7 +174,7 @@ void ftc532_init(void) { // Initialize Ftc532.present = true; } -void ftc532_update(void) { // Usually called every 50 ms +void ftc532_update(void) { // Usually called every 50 ms if ((Ftc532.sample & 0xF0F0) == ((~Ftc532.sample & 0x0F0F) << 4) && (Ftc532.sample >> 8) == 0xF0) { Ftc532.keys = Ftc532.sample & 0xF; if (Ftc532.keys != Ftc532.old_keys) { @@ -156,7 +183,8 @@ void ftc532_update(void) { // Usually called every 50 ms #endif // FTC532_DEBOUNCE > 1 #ifdef DEBUG_FTC532 AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X KEY=%X OLD=%X INV=%u NOI=%u FRM=%u OK=%u TIME=%lu Pin=%u"), - Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); + Ftc532.sample, Ftc532.keys, Ftc532.old_keys, Ftc532.e_inv, Ftc532.e_noise, Ftc532.e_frame, + Ftc532.valid, Ftc532.rxtime, Pin(GPIO_FTC532)); #endif // DEBUG_FTC532 ftc532_publish(); Ftc532.old_keys = Ftc532.keys; @@ -171,7 +199,7 @@ void ftc532_update(void) { // Usually called every 50 ms #ifdef DEBUG_FTC532 else { ++Ftc532.e_inv; - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: SAM=%04X"), Ftc532.sample); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); } #endif // DEBUG_FTC532 } From c8822628042755af776edaddfc606c463ccec71f Mon Sep 17 00:00:00 2001 From: Vic Date: Tue, 5 Jan 2021 12:44:53 +0100 Subject: [PATCH 5/7] final version for PR --- tasmota/xdrv_47_ftc532.ino | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 6a50ba9b1..27cb8056d 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -97,11 +97,9 @@ #define FTC532_IDLE (FTC532_BIT * 10) #define FTC532_MAX (FTC532_BIT * 58) -#define DEBUG_FTC532 //@@@@@@@@@@@@@@@@ - struct FTC532 { volatile uint32_t rxtime; // ISR timer memory - volatile uint16_t tsmp = 0xF0F0; // buffer for bit-coded time samples + volatile uint16_t tsmp = 0; // buffer for bit-coded time samples volatile uint16_t sample = 0xF0F0; // valid samples volatile uint16_t rxbit; // ISR bit counter volatile uint16_t state; // ISR state @@ -152,7 +150,7 @@ void ICACHE_RAM_ATTR ftc532_ISR(void) { // Hardware interrupt routine, trigger } if (time_diff > FTC532_SHORT + FTC532_BIT) { Ftc532.tsmp |= (1 << Ftc532.rxbit); // LONG - } else if (time_diff < FTC532_NOISE) { // NOISE + } else if (time_diff < FTC532_NOISE) { // NOISE (SHORT now implicitly default) #ifdef DEBUG_FTC532 ++Ftc532.e_noise; #endif // DEBUG_FTC532 From faeb80fbffe80e720db1377363a5a1f3a4e4df8a Mon Sep 17 00:00:00 2001 From: Vic Date: Wed, 6 Jan 2021 15:45:50 +0100 Subject: [PATCH 6/7] tested, ready --- tasmota/xdrv_47_ftc532.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index 27cb8056d..eaaa2e924 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -60,8 +60,8 @@ The first version of this driver was working fine on well behaved hardware. After being released to the field and installed on crappy hardware in noisy environments it developed a habit of random 'ghost' switchings at night, much to the chagrin of some users. - This is almost a re-write containing a lot more timing (and other) checks in order to - detect and mitigate various incarnations of noise. + This is almost a re-write containing more timing (and other) checks in order to detect + and mitigate various incarnations of noise. If you should still experience 'ghost switching' issues a solution may be increasing FTC532_DEBOUNCE to 2 or higher. That will enable the de-bouncing code, at the expense of 'snappiness' of touch reactions. Higher values will accumulate more samples in 50 ms steps @@ -197,13 +197,13 @@ void ftc532_update(void) { // Usually called every 50 m #ifdef DEBUG_FTC532 else { ++Ftc532.e_inv; - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); // Hex keys need JSON quotes } #endif // DEBUG_FTC532 } void ftc532_show() { - ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); + ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes } void ftc532_publish(void) { From 8fc44336cc889c295120be78fcbdbeb7a23cffde Mon Sep 17 00:00:00 2001 From: Vic Date: Wed, 6 Jan 2021 16:04:35 +0100 Subject: [PATCH 7/7] formatting --- tasmota/xdrv_47_ftc532.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/xdrv_47_ftc532.ino b/tasmota/xdrv_47_ftc532.ino index eaaa2e924..277ba73e6 100644 --- a/tasmota/xdrv_47_ftc532.ino +++ b/tasmota/xdrv_47_ftc532.ino @@ -197,17 +197,17 @@ void ftc532_update(void) { // Usually called every 50 m #ifdef DEBUG_FTC532 else { ++Ftc532.e_inv; - AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); // Hex keys need JSON quotes + AddLog_P(LOG_LEVEL_DEBUG, PSTR("FTC: ILL SAM=%04X"), Ftc532.sample); } #endif // DEBUG_FTC532 } void ftc532_show() { - ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes + ResponseAppend_P(PSTR(",%s%02X\"}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes } void ftc532_publish(void) { - Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); + Response_P(PSTR("{%s%02X\"}}"), ftc532_json, Ftc532.keys); // Hex keys need JSON quotes MqttPublishTeleSensor(); }