Skip to content

Commit

Permalink
Touch: Add support for CST716
Browse files Browse the repository at this point in the history
The touch driver now automatically detects whether
a CST816s (pinetime) or CST716 (some p8 watches) chip
is used, and adjusts the decoding logic accordingly.

For more information, see the discussion on
InfiniTimeOrg#492
  • Loading branch information
StarGate01 committed Mar 25, 2022
1 parent a728d51 commit 9065272
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 29 deletions.
14 changes: 12 additions & 2 deletions src/displayapp/screens/SystemInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ namespace {
return "BMA425";
case Pinetime::Controllers::MotionController::DeviceTypes::Unknown:
return "???";
char CstUnknown[4] = {0};
const char* ToString(const Pinetime::Drivers::Cst816S::Variant variant, uint8_t chipId) {
switch (variant) {
case Pinetime::Drivers::Cst816S::Variant::Cst816S:
return "Cst816S";
case Pinetime::Drivers::Cst816S::Variant::Cst716:
return "Cst716";
case Pinetime::Drivers::Cst816S::Variant::Unknown:
snprintf(CstUnknown, 4, "?%x", chipId);
return CstUnknown;
}
return "???";
}
Expand Down Expand Up @@ -146,7 +156,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
"#444444 Backlight# %s\n"
"#444444 Last reset# %s\n"
"#444444 Accel.# %s\n"
"#444444 Touch.# %x.%x.%x\n",
"#444444 Tch.# %s-%x.%x\n",
dateTimeController.Day(),
static_cast<uint8_t>(dateTimeController.Month()),
dateTimeController.Year(),
Expand All @@ -162,7 +172,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen2() {
brightnessController.ToString(),
resetReason,
ToString(motionController.DeviceType()),
touchPanel.GetChipId(),
ToString(touchPanel.GetVariant(), touchPanel.GetChipId()),
touchPanel.GetVendorId(),
touchPanel.GetFwVersion());
lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
Expand Down
44 changes: 32 additions & 12 deletions src/drivers/Cst816s.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,15 @@ bool Cst816S::Init() {
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();
// Read the device ids, and use the chip ID to know which variant is used.
ReadDeviceIds();

/*
[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;
static constexpr uint8_t motionMask = 0b00000111;
twiMaster.Write(twiAddress, 0xEC, &motionMask, 1);

/*
Expand All @@ -52,6 +49,10 @@ bool Cst816S::Init() {
[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.
This configures the chip in report mode (regular interrupts), instead of gesture mode.
Although the CST18S supports mode switching, the CST716 can only done one (permanently configured by the factory).
CST716 default is report mode.
*/
static constexpr uint8_t irqCtl = 0b01110000;
twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1);
Expand Down Expand Up @@ -102,12 +103,29 @@ Cst816S::TouchInfos Cst816S::GetTouchInfo() {
}

void Cst816S::Sleep() {
// The Cst816S ignores this sleep command, as is has an auto-sleep function.
// During this auto-sleep, it can wake up by touch but has its I2C interface disabled.
// The Cst716 cannot wake up by touch, and can only come out of sleep by resetting it.
// The accelerometer can be used instead to generate wakeup events.

// Force a reset in case the chip went into auto-sleep mode
nrf_gpio_pin_clear(PinMap::Cst816sReset);
vTaskDelay(5);
nrf_gpio_pin_set(PinMap::Cst816sReset);
vTaskDelay(50);

// The CST816 and CST716 differ in their sleep register addresses
uint8_t sleepRegister = 0;
if(variant == Variant::Cst816S) {
sleepRegister = 0xE5;
} else if(variant == Variant::Cst716) {
sleepRegister = 0xA5;
}
static constexpr uint8_t sleepValue = 0x03;
twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1);
if(variant != Variant::Unknown) {
twiMaster.Write(twiAddress, sleepRegister, &sleepValue, 1);
}

NRF_LOG_INFO("[TOUCHPANEL] Sleep");
}

Expand All @@ -116,20 +134,22 @@ void Cst816S::Wakeup() {
NRF_LOG_INFO("[TOUCHPANEL] Wakeup");
}

bool Cst816S::CheckDeviceIds() {
void Cst816S::ReadDeviceIds() {
// 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;
variant = Variant::Unknown;
if(chipId == 0xB4) {
variant = Variant::Cst816S;
} else if(chipId == 0x20) {
variant = Variant::Cst716;
}
}
11 changes: 10 additions & 1 deletion src/drivers/Cst816s.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ namespace Pinetime {
namespace Drivers {
class Cst816S {
public:
enum class Variant : uint8_t {
Unknown = 0,
Cst816S = 1, // Used in Pinetime
Cst716 = 2 // Used in some P8(b) variants
};
enum class Gestures : uint8_t {
None = 0x00,
SlideDown = 0x01,
Expand Down Expand Up @@ -44,8 +49,11 @@ namespace Pinetime {
uint8_t GetFwVersion() const {
return fwVersion;
}
Variant GetVariant() const {
return variant;
}
private:
bool CheckDeviceIds();
void ReadDeviceIds();

// Unused/Unavailable commented out
static constexpr uint8_t gestureIndex = 1;
Expand All @@ -69,6 +77,7 @@ namespace Pinetime {
uint8_t chipId;
uint8_t vendorId;
uint8_t fwVersion;
Variant variant;
};

}
Expand Down
45 changes: 31 additions & 14 deletions src/touchhandler/TouchHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,42 @@ bool TouchHandler::GetNewTouchInfo() {
return false;
}

if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) {
if (gestureReleased) {
if (info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideDown ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideLeft ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideUp ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideRight ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::LongPress) {
if (info.touching) {
// Cst716 (P8 variants) generates multiple "none" gesture events with info.touching == true during the physical gesture.
// The last event is a "slide" event with info.touching == true.
// gestureReleased state does not have to be computed manually, instead it occurs when event != "none".

// Cst816s (PineTime) generates multiple "slide" gesture events with info.touching == true during the physical gesture.
// The last of these "slide" events has info.touching == false.
// gestureReleased state is computed manually by checking for the transition to info.touching == false.

// In both cases, the event is bubbled up once the gesture is released.

if(touchPanel.GetVariant() == Pinetime::Drivers::Cst816S::Variant::Cst716) {
if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) {
gesture = info.gesture;
info.touching = false;
}
} else if(touchPanel.GetVariant() == Pinetime::Drivers::Cst816S::Variant::Cst816S) {
if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) {
if (gestureReleased) {
if (info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideDown ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideLeft ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideUp ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideRight ||
info.gesture == Pinetime::Drivers::Cst816S::Gestures::LongPress) {
if (info.touching) {
gesture = info.gesture;
gestureReleased = false;
}
} else {
gesture = info.gesture;
gestureReleased = false;
}
} else {
gesture = info.gesture;
}
}
}

if (!info.touching) {
gestureReleased = true;
if (!info.touching) {
gestureReleased = true;
}
}

return true;
Expand Down

0 comments on commit 9065272

Please sign in to comment.