ref: e5b73212f6addcfdb5e306df63d7135e543c4f8d
src/drivers/Cst816s.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
#include "drivers/Cst816s.h" #include <FreeRTOS.h> #include <legacy/nrf_drv_gpiote.h> #include <nrfx_log.h> #include <task.h> #include "drivers/PinMap.h" using namespace Pinetime::Drivers; /* 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! * */ Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} { } bool Cst816S::Init() { nrf_gpio_cfg_output(PinMap::Cst816sReset); nrf_gpio_pin_clear(PinMap::Cst816sReset); vTaskDelay(5); 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); 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; } // 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<Gestures>(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; return info; } info.x = x; info.y = y; info.touching = (nbTouchPoints > 0); info.gesture = gesture; info.isValid = true; 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); NRF_LOG_INFO("[TOUCHPANEL] Sleep"); } 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; } |