diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b27c19de7..915e095bd1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -652,6 +652,7 @@ set(INCLUDE_FILES components/timer/Timer.h components/alarm/AlarmController.h drivers/Cst816s.h + drivers/Cst816s_registers.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h displayapp/LittleVgl.h @@ -794,23 +795,28 @@ add_definitions(-DTARGET_DEVICE_NAME="${TARGET_DEVICE}") if(TARGET_DEVICE STREQUAL "PINETIME") add_definitions(-DDRIVER_PINMAP_PINETIME) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_DYNAMIC) elseif(TARGET_DEVICE STREQUAL "MOY_TFK5") # P8a add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_GESTURE) elseif(TARGET_DEVICE STREQUAL "MOY_TIN5") # P8a variant 2 add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_GESTURE) elseif(TARGET_DEVICE STREQUAL "MOY_TON5") # P8b add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) + add_definitions(-DDRIVER_TOUCH_REPORT) elseif(TARGET_DEVICE STREQUAL "MOY_UNK") # P8b mirrored add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) add_definitions(-DDRIVER_DISPLAY_MIRROR) + add_definitions(-DDRIVER_TOUCH_REPORT) else() message(FATAL_ERROR "Invalid TARGET_DEVICE") endif() diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index 89893cf79d..3545e8bd42 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -260,11 +260,23 @@ void LittleVgl::CancelTap() { } } +void LittleVgl::SetNewTap(int16_t x, int16_t y) { + touchPoint = {x, y}; + tapped = true; + simulate_tap_release = true; +} + bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) { ptr->point.x = touchPoint.x; ptr->point.y = touchPoint.y; if (tapped) { ptr->state = LV_INDEV_STATE_PR; + if (simulate_tap_release) { + // If a tap consists of only a single event, enqueue a synthetic release state update + tapped = false; + simulate_tap_release = false; + return true; + } } else { ptr->state = LV_INDEV_STATE_REL; } diff --git a/src/displayapp/LittleVgl.h b/src/displayapp/LittleVgl.h index 9a15ae1599..9e5b54ca54 100644 --- a/src/displayapp/LittleVgl.h +++ b/src/displayapp/LittleVgl.h @@ -26,6 +26,7 @@ namespace Pinetime { void SetFullRefresh(FullRefreshDirections direction); void SetNewTouchPoint(int16_t x, int16_t y, bool contact); void CancelTap(); + void SetNewTap(int16_t x, int16_t y); bool GetFullRefresh() { bool returnValue = fullRefresh; @@ -65,6 +66,7 @@ namespace Pinetime { lv_point_t touchPoint = {}; bool tapped = false; bool isCancelled = false; + bool simulate_tap_release = false; }; } } diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp index cf10c895f5..4fba71d135 100644 --- a/src/drivers/Cst816s.cpp +++ b/src/drivers/Cst816s.cpp @@ -1,108 +1,103 @@ #include "drivers/Cst816s.h" +#include "drivers/PinMap.h" #include #include #include #include -#include "drivers/PinMap.h" using namespace Pinetime::Drivers; -/* References : +/* + * References : * This implementation is based on this article : * https://medium.com/@ly.lee/building-a-rust-driver-for-pinetimes-touch-controller-cbc1a5d5d3e9 Touch panel datasheet (weird chinese * translation) : https://wiki.pine64.org/images/5/51/CST816S%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8CV1.1.en.pdf * - * TODO : we need a complete datasheet and protocol reference! + * TODO: We need a complete datasheet and protocol reference! + * For register desciptions, see Cst816s_registers.h. Information was collected from various chinese datasheets and documents. * */ Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} { } bool Cst816S::Init() { + // Reset the touch driver nrf_gpio_cfg_output(PinMap::Cst816sReset); nrf_gpio_pin_clear(PinMap::Cst816sReset); - vTaskDelay(5); + vTaskDelay(10); nrf_gpio_pin_set(PinMap::Cst816sReset); vTaskDelay(50); - // Wake the touchpanel up - uint8_t dummy; - twiMaster.Read(twiAddress, 0x15, &dummy, 1); - vTaskDelay(5); - twiMaster.Read(twiAddress, 0xa7, &dummy, 1); - vTaskDelay(5); - - // TODO This function check that the device IDs from the controller are equal to the ones - // we expect. However, it seems to return false positive (probably in case of communication issue). - // Also, it seems that some users have pinetimes that works correctly but that report different device IDs - // Until we know more about this, we'll just read the IDs but not take any action in case they are not 'valid' - CheckDeviceIds(); - - /* - [2] EnConLR - Continuous operation can slide around - [1] EnConUD - Slide up and down to enable continuous operation - [0] EnDClick - Enable Double-click action - */ - static constexpr uint8_t motionMask = 0b00000101; - twiMaster.Write(twiAddress, 0xEC, &motionMask, 1); - - /* - [7] EnTest - Interrupt pin to test, enable automatic periodic issued after a low pulse. - [6] EnTouch - When a touch is detected, a periodic pulsed Low. - [5] EnChange - Upon detecting a touch state changes, pulsed Low. - [4] EnMotion - When the detected gesture is pulsed Low. - [0] OnceWLP - Press gesture only issue a pulse signal is low. - */ - static constexpr uint8_t irqCtl = 0b01110000; - twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1); + // Chip ID is suspected to be dependent on embedded firmware and factory configuration, + // and not (just) on hardware type and revision. + if (twiMaster.Read(twiAddress, CHIP_ID, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + chipId = 0xFF; + } + // Vendor / project ID and firmware version can vary between devices. + if (twiMaster.Read(twiAddress, PROJ_ID, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + vendorId = 0xFF; + } + if (twiMaster.Read(twiAddress, FW_VERSION, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + fwVersion = 0xFF; + } + + // These configuration settings will be ignored by chips which were + // fused / pre-configured in the factory (GESTURE and REPORT settings). + // This mainly applies to CST716, however there may be CST816S with static configurations as well. + // The other, freely configureable ones (DYNAMIC), are configured in reporting mode here. + + // Configure motion behaviour + static constexpr uint8_t motionMask = MOTION_MASK_EN_DCLICK | MOTION_MASK_EN_CON_UD | MOTION_MASK_EN_CON_LR; + twiMaster.Write(twiAddress, MOTION_MASK, &motionMask, 1); + + // Configure interrupt generating events + static constexpr uint8_t irqCtl = IRQ_CTL_EN_MOTION | IRQ_CTL_EN_CHANGE | IRQ_CTL_EN_TOUCH; + twiMaster.Write(twiAddress, IRQ_CTL, &irqCtl, 1); return true; } Cst816S::TouchInfos Cst816S::GetTouchInfo() { - Cst816S::TouchInfos info; - uint8_t touchData[7]; - - auto ret = twiMaster.Read(twiAddress, 0, touchData, sizeof(touchData)); - if (ret != TwiMaster::ErrorCodes::NoError) { - info.isValid = false; - return info; + // Some chips fail to wake up even though the reset pin has been toggled. + // They only provide an I2C communication window after a touch interrupt, + // so the first touch interrupt is used to force initialisation. + if (firstEvent) { + Init(); + firstEvent = false; + // The data registers should now be reset, so this touch event will be detected as invalid. } - // This can only be 0 or 1 - uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f; - uint8_t xHigh = touchData[touchXHighIndex] & 0x0f; - uint8_t xLow = touchData[touchXLowIndex]; - uint16_t x = (xHigh << 8) | xLow; - uint8_t yHigh = touchData[touchYHighIndex] & 0x0f; - uint8_t yLow = touchData[touchYLowIndex]; - uint16_t y = (yHigh << 8) | yLow; - Gestures gesture = static_cast(touchData[gestureIndex]); - - // Validity check - if (x >= maxX || y >= maxY || - (gesture != Gestures::None && gesture != Gestures::SlideDown && gesture != Gestures::SlideUp && gesture != Gestures::SlideLeft && - gesture != Gestures::SlideRight && gesture != Gestures::SingleTap && gesture != Gestures::DoubleTap && - gesture != Gestures::LongPress)) { - info.isValid = false; + // Read gesture metadata and first touch point coordinate block + Cst816S::TouchInfos info; + uint8_t touchData[P1_Y_POS_L + 1]; + auto ret = twiMaster.Read(twiAddress, 0x00, touchData, sizeof(touchData)); + if (ret != TwiMaster::ErrorCodes::NoError) return info; - } - info.x = x; - info.y = y; - info.touching = (nbTouchPoints > 0); - info.gesture = gesture; - info.isValid = true; + // Assemble 12 bit point coordinates from lower 8 bits and higher 4 bits + info.x = ((touchData[P1_X_POS_H] & POS_H_POS_MASK) << 8) | touchData[P1_X_POS_L]; + info.y = ((touchData[P1_Y_POS_H] & POS_H_POS_MASK) << 8) | touchData[P1_Y_POS_L]; + // Evaluate number of touch points + info.touching = (touchData[TD_STATUS] & TD_STATUS_MASK) > 0; + // Decode gesture ID + info.gesture = static_cast(touchData[GESTURE_ID]); + + // Validity check, verify value ranges + info.isValid = (info.x < maxX && info.y < maxY && + (info.gesture == Gestures::None || info.gesture == Gestures::SlideDown || info.gesture == Gestures::SlideUp || + info.gesture == Gestures::SlideLeft || info.gesture == Gestures::SlideRight || info.gesture == Gestures::SingleTap || + info.gesture == Gestures::DoubleTap || info.gesture == Gestures::LongPress)); + return info; } void Cst816S::Sleep() { - nrf_gpio_pin_clear(PinMap::Cst816sReset); - vTaskDelay(5); - nrf_gpio_pin_set(PinMap::Cst816sReset); - vTaskDelay(50); - static constexpr uint8_t sleepValue = 0x03; - twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1); + // This only controls the CST716, the CST816S will ignore this register. + // The CST816S power state is managed using auto-sleep. + + static constexpr uint8_t sleepValue = PWR_MODE_DEEP_SLEEP; + twiMaster.Write(twiAddress, PWR_MODE_CST716, &sleepValue, 1); + NRF_LOG_INFO("[TOUCHPANEL] Sleep"); } @@ -110,21 +105,3 @@ void Cst816S::Wakeup() { Init(); NRF_LOG_INFO("[TOUCHPANEL] Wakeup"); } - -bool Cst816S::CheckDeviceIds() { - // There's mixed information about which register contains which information - if (twiMaster.Read(twiAddress, 0xA7, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - chipId = 0xFF; - return false; - } - if (twiMaster.Read(twiAddress, 0xA8, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - vendorId = 0xFF; - return false; - } - if (twiMaster.Read(twiAddress, 0xA9, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - fwVersion = 0xFF; - return false; - } - - return chipId == 0xb4 && vendorId == 0 && fwVersion == 1; -} diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h index c50bb73372..9185dc8d89 100644 --- a/src/drivers/Cst816s.h +++ b/src/drivers/Cst816s.h @@ -1,5 +1,6 @@ #pragma once +#include "drivers/Cst816s_registers.h" #include "drivers/TwiMaster.h" namespace Pinetime { @@ -7,14 +8,15 @@ namespace Pinetime { class Cst816S { public: enum class Gestures : uint8_t { - None = 0x00, - SlideDown = 0x01, - SlideUp = 0x02, - SlideLeft = 0x03, - SlideRight = 0x04, - SingleTap = 0x05, - DoubleTap = 0x0B, - LongPress = 0x0C + None = GESTURE_ID_NONE, + SlideDown = GESTURE_ID_SLIDE_DOWN, + SlideUp = GESTURE_ID_SLIDE_UP, + SlideLeft = GESTURE_ID_SLIDE_LEFT, + SlideRight = GESTURE_ID_SLIDE_RIGHT, + SingleTap = GESTURE_ID_SINGLE_TAP, + DoubleTap = GESTURE_ID_DOUBLE_TAP, + LongPress = GESTURE_ID_LONG_PRESS, + Invalid = 0xFF }; struct TouchInfos { @@ -49,21 +51,6 @@ namespace Pinetime { } private: - bool CheckDeviceIds(); - - // Unused/Unavailable commented out - static constexpr uint8_t gestureIndex = 1; - static constexpr uint8_t touchPointNumIndex = 2; - // static constexpr uint8_t touchEventIndex = 3; - static constexpr uint8_t touchXHighIndex = 3; - static constexpr uint8_t touchXLowIndex = 4; - // static constexpr uint8_t touchIdIndex = 5; - static constexpr uint8_t touchYHighIndex = 5; - static constexpr uint8_t touchYLowIndex = 6; - // static constexpr uint8_t touchStep = 6; - // static constexpr uint8_t touchXYIndex = 7; - // static constexpr uint8_t touchMiscIndex = 8; - static constexpr uint8_t maxX = 240; static constexpr uint8_t maxY = 240; @@ -73,6 +60,8 @@ namespace Pinetime { uint8_t chipId; uint8_t vendorId; uint8_t fwVersion; + + bool firstEvent = true; }; } diff --git a/src/drivers/Cst816s_registers.h b/src/drivers/Cst816s_registers.h new file mode 100644 index 0000000000..edec944fde --- /dev/null +++ b/src/drivers/Cst816s_registers.h @@ -0,0 +1,162 @@ +#pragma once + +// CST816(S) / CST716 High-performance self-capacitive touch chip +// Hynitron, www.hynitron.com + +// Manually assembled from auto-translated incomplete datasheets and documents. + +// The device contains an embedded firmware, behaviour may differ. +// Code fragments on how to update the internal firmware exist, but not much is know about +// the internal architecture. No verified compatible binary firmware has been found yet. + +// The "S" suffix stands for speed, i.e. double the sample rate (>100 Hz instead of ~50 Hz (?)). + +// The CST816S has an auto-sleep low-power mode, from which it can wake via a touch event. +// In low-power sleep, the I2C interface is inactive. +// It sends a gesture event while the gesture is still being performed. + +// The CST716 has no auto-sleep functionality, and sends a gesture event after the gesture has been completed. +// Its I2C interface is always active, as it stays in normal mode. + +// Both chips are able to enter a deep-sleep mode, from which they can only wake via a signal on the reset pin. + +// Registers + +// * = Works only on chips which have not been preconfigured (fused) in the factory. +// CST716 are probably always fused, default: reporting mode. +// CST816S can be reconfigureable, but can be fused as well. Some fused ones report with a CST716 chip ID. + +// ** = Auto-sleep related registers. Only on the CST816S. + +#define DEV_MODE 0x00 // readonly. Always 0. +#define GESTURE_ID 0x01 // readonly. Which gesture was detected. +#define TD_STATUS 0x02 // readonly. Number of touch points. (0 - 2). + +#define P1_X_POS_H 0x03 // readonly. Point 1: X touch event flag + X touch coordinate MSB. +#define P1_X_POS_L 0x04 // readonly. Point 1: X touch coordinate LSB. +#define P1_Y_POS_H 0x05 // readonly. Point 1: Y touch event flag + Y touch coordinate MSB. +#define P1_Y_POS_L 0x06 // readonly. Point 1: Y touch coordinate LSB. +#define P1_WEIGHT 0x07 // readonly. Point 1: Touch weight. +#define P1_MISC 0x08 // readonly. Point 1: Touch area. + +#define P2_X_POS_H 0x09 // readonly. Point 2: X touch event flag + X touch coordinate MSB. +#define P2_X_POS_L 0x0A // readonly. Point 2: X touch coordinate LSB. +#define P2_Y_POS_H 0x0B // readonly. Point 2: Y touch event flag + Y touch coordinate MSB. +#define P2_Y_POS_L 0x0C // readonly. Point 2: Y touch coordinate LSB. +#define P2_WEIGHT 0x0D // readonly. Point 2: Touch weight. +#define P2_MISC 0x0E // readonly. Point 2: Touch area. + +#define BPC0_H 0xB0 // unknown. BPC0 value MSB. +#define BPC0_L 0xB1 // unknown. BPC0 value LSB. +#define BPC1_H 0xB2 // unknown. BPC1 value MSB. +#define BPC1_L 0xB3 // unknown. BPC1 value LSB. + +#define CHIP_ID 0xA7 // readonly. Chip / firmware type ID. +#define PROJ_ID 0xA8 // readonly. Vendor / project ID. +#define FW_VERSION 0xA9 // readonly. Firmware version. + +#define MOTION_MASK 0xEC // read-write*. Motion configuration. +#define IRQ_PULSE_WIDTH 0xED // read-write. Interrupt low pulse output width. Unit 0.1ms, possible value: 1~200. The default value is 10. +// read-write. Normal fast detection cycle. This value affects LpAutoWakeTime and AutoSleepTime. Unit 10ms, possible value: 1~30. The +// default value is 1. +#define NOR_SCAN_PER 0xEE +// read-write. Gesture detection sliding partition angle control. Angle=tan(c)*10. c is the angle based on the positive direction of +// the x-axis. +#define MOTION_S1_ANGLE 0xEF + +#define LP_SCAN_RAW1_H 0xF0 // readonly**. Low power scan, MSB of the reference value of channel 1. +#define LP_SCAN_RAW1_L 0xF1 // readonly**. Low power scan, LSB of the reference value of channel 1. +#define LP_SCAN_RAW2_H 0xF2 // readonly**. Low power scan, MSB of the reference value of channel 2. +#define LP_SCAN_RAW2_L 0xF3 // readonly**. Low power scan, LSB of the reference value of channel 2. +// read-write**. Automatic recalibration cycle in low power mode. The unit is 1 minute, and the possible value is 1 to 5. The default +// value is 5. +#define LP_AUTO_WAKE_TIME 0xF4 +// read-write**. Low-power scan wake-up threshold. The smaller the more sensitive. Possible values: 1 to 255. The default value +// is 48. +#define LP_SCAN_TH 0xF5 +// read-write**. Low power scan range. The larger the more sensitive, the higher the power consumption. Possible values: 0, 1, 2, 3. +// The default value is 3. +#define LP_SCAN_WIN 0xF6 +// read-write**. Low power scan frequency. The smaller the more sensitive. Possible values: 1 to 255. The default value is 7. +#define LP_SCAN_FREQ 0xF7 +#define LP_SCAN_I_DAC 0xF8 // read-write**. Low power scan current. The smaller the more sensitive. Possible values: 1 to 255. +// read-write**. Automatically enter low power mode when there is no touch for x seconds. The unit is 1s, the default value is 2. +#define AUTO_SLEEP_TIME 0xF9 +// read-write*. Interrupt configuration. 0x60 = report mode, 0x11 = gesture mode, 0x71 = both. +#define IRQ_CTL 0xFA +// read-write. Automatic reset (cancel) when there is a touch but no valid gesture within x seconds. The unit is 1s. When it is 0, +// this function is not enabled. Default is 5. +#define AUTO_RESET 0xFB +// read-write. Automatic reset (cancel) after long press for x seconds. The unit is 1s. When it is 0, this function is not enabled. +// Default is 10. +#define LONG_PRESS_TIME 0xFC +// read-write. Pin IO configuration. +#define IO_CTL 0xFD +// read-write**. The default is 0, enabling automatic entry into low power mode. When it is a non-zero value, automatic entry into +// low power mode is disabled. +#define DIS_AUTO_SLEEP 0xFE + +#define PWR_MODE_CST816S 0xE5 // read-write. Power state for the CST816S. +#define PWR_MODE_CST716 0xA5 // read-write. Power state for the CST716. + +// Data fields + +// GESTURE_ID + +#define GESTURE_ID_NONE 0x00 +#define GESTURE_ID_SLIDE_DOWN 0x01 +#define GESTURE_ID_SLIDE_UP 0x02 +#define GESTURE_ID_SLIDE_LEFT 0x03 +#define GESTURE_ID_SLIDE_RIGHT 0x04 +#define GESTURE_ID_SINGLE_TAP 0x05 +#define GESTURE_ID_DOUBLE_TAP 0x0B +#define GESTURE_ID_LONG_PRESS 0x0C + +// TD_STATUS + +#define TD_STATUS_MASK 0x0F + +// *_POS_H + +#define POS_H_POS_MASK 0x0F + +#define POS_H_EVENT_MASK 0xC0 +#define POS_H_EVENT0 (1 << 6) +#define POS_H_EVENT1 (1 << 7) + +#define POS_H_EVENT_DOWN (0 << 6) +#define POS_H_EVENT_UP (1 << 6) +#define POS_H_EVENT_CONTACT (2 << 6) +#define POS_H_EVENT_NONE (3 << 6) + +// CHIP_ID + +#define CHIP_ID_CST816S 0xB4 +#define CHIP_ID_CST716 0x20 + +// Control register configurations + +// MOTION_MASK + +#define MOTION_MASK_EN_DCLICK (1 << 0) // Enable double click action +#define MOTION_MASK_EN_CON_UD (1 << 1) // Enable continuous up-down sliding action +#define MOTION_MASK_EN_CON_LR (1 << 2) // Enable continuous left-right sliding action + +// IRQ_CTL + +#define IRQ_CTL_ONCE_WLP (1 << 0) // The long press gesture only emits a low pulse signal. +#define IRQ_CTL_EN_MOTION (1 << 4) // When a gesture is detected, a low pulse is emitted. +#define IRQ_CTL_EN_CHANGE (1 << 5) // A low pulse is emitted when a touch state change is detected. +#define IRQ_CTL_EN_TOUCH (1 << 6) // Periodically emit low pulses when a touch is detected. +#define IRQ_CTL_EN_TEST (1 << 7) // Interrupt pin test, automatically and periodically send low pulses after enabling. + +// IO_CTL + +#define IO_CTL_EN_1V8 (1 << 0) // I2C and IRQ pin voltage level selection, the default is VDD level. 0: VDD, 1: 1.8V. +#define IO_CTL_IIC_OD (1 << 1) // I2C pin drive mode, the default is resistor pull-up. 0: Resistor pull-up 1: OD. +#define IO_CTL_SOFT_RST (1 << 2) // Enable soft reset by pulling down the IRQ pin. 0: Soft reset is disabled. 1: Enable soft reset. + +// PWR_MODE_* + +#define PWR_MODE_ACTIVE 0x00 // Normal state of execution +#define PWR_MODE_DEEP_SLEEP 0x03 // Deep-sleep mode. Touch to wakeup and I2C are disabled. diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index b245e39227..ac6e009989 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -327,7 +327,13 @@ void SystemTask::Work() { // Double Tap needs the touch screen to be in normal mode if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { - touchPanel.Sleep(); +// REPORT and GESTURE mode sensors must be normal mode for single tap as well +#if !defined(DRIVER_TOUCH_DYNAMIC) + if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) +#endif + { + touchPanel.Sleep(); + } } state = SystemTaskState::Sleeping; diff --git a/src/touchhandler/TouchHandler.cpp b/src/touchhandler/TouchHandler.cpp index b29f951fcb..10765e8501 100644 --- a/src/touchhandler/TouchHandler.cpp +++ b/src/touchhandler/TouchHandler.cpp @@ -37,8 +37,40 @@ bool TouchHandler::ProcessTouchInfo(Drivers::Cst816S::TouchInfos info) { if (!info.isValid) { return false; } + + // REPORT configurations (P8b variants) of the fused (usually) Cst716 + // generate multiple "none" gesture events with info.touching == true during the physical gesture. + // The last event is a e.g. "slide" event with info.touching == true. + // gestureReleased state does not have to be computed manually, instead it occurs when event != "none". - // Only a single gesture per touch + // GESTURE configurations (P8a variants) of the fused (usually) Cst716 generate no events during the physical gesture. + // The only event is a e.g. "slide" event with info.touching == true. + // gestureReleased state does not have to be computed manually, instead it occurs everytime. + + // DYNAMIC configurations (PineTime) are configured in reporting mode during initialisation. + // Usually based on the Cst816s, they generate multiple e.g. "slide" gesture events with info.touching == true during the physical + // gesture. The last of these e.g. "slide" events has info.touching == false. gestureReleased state is computed manually by checking for + // the transition to info.touching == false. + + // Unfortunately, there is no way to reliably obtain which configuration is used at runtime. + // In all cases, the event is bubbled up once the gesture is released. + +#if defined(DRIVER_TOUCH_REPORT) + if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { + gesture = ConvertGesture(info.gesture); + info.touching = false; + } +#elif defined(DRIVER_TOUCH_GESTURE) + if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { + gesture = ConvertGesture(info.gesture); + // A new variant configuration behaves in a way such that it generates a gesture event at the start of a physical gesture, + // but does not set the info.touching flag at all. Since gestures are handled separately, special behaviour is only needed + // for the tap event. For the original P8b, which always sets info.touching = true, this operation is idempotent. + if (gesture == TouchEvents::Tap) { + info.touching = true; + } + } +#elif defined(DRIVER_TOUCH_DYNAMIC) if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { if (gestureReleased) { if (info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideDown || @@ -59,8 +91,30 @@ bool TouchHandler::ProcessTouchInfo(Drivers::Cst816S::TouchInfos info) { if (!info.touching) { gestureReleased = true; } +#endif currentTouchPoint = {info.x, info.y, info.touching}; return true; } + +void TouchHandler::UpdateLvglTouchPoint() { + if (info.touching) { +#if defined(DRIVER_TOUCH_GESTURE) + // GESTURE config only generates a single event / state change + // so the LVGL wrapper is used to generate a successive release state update + lvgl.SetNewTap(info.x, info.y); +#else + if (!isCancelled) { + lvgl.SetNewTouchPoint(info.x, info.y, true); + } +#endif + } else { + if (isCancelled) { + lvgl.SetNewTouchPoint(-1, -1, false); + isCancelled = false; + } else { + lvgl.SetNewTouchPoint(info.x, info.y, false); + } + } +}