blob: 15e32e969d74a2454476927bfebfd010923e8ed9 [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "ft6236/device.h"
#include <chrono>
#include <cstddef>
#include <cstdint>
#define PW_LOG_MODULE_NAME "ft6236"
#define PW_LOG_LEVEL PW_LOG_LEVEL_DEBUG
#include "pw_bytes/bit.h"
#include "pw_bytes/endian.h"
#include "pw_i2c/address.h"
#include "pw_i2c/register_device.h"
#include "pw_log/log.h"
#include "pw_status/status.h"
using namespace std::chrono_literals;
using pw::Status;
using pw::bytes::ReadInOrder;
namespace pw::ft6236 {
namespace {
enum Ft62xxRegister : uint8_t {
kThreshhold = 0x80,
kPointrate = 0x88,
kChipid = 0xA3,
kFirmvers = 0xA6,
kVendid = 0xA8,
};
constexpr pw::i2c::Address kAddress = pw::i2c::Address::SevenBit<0x38>();
} // namespace
Device::Device(pw::i2c::Initiator& initiator)
: initiator_(initiator),
device_(initiator,
kAddress,
endian::little,
pw::i2c::RegisterAddressSize::k1Byte) {}
Device::~Device() = default;
Status Device::Enable() {
Result<std::byte> vendor_id_result = device_.ReadRegister(
Ft62xxRegister::kVendid, pw::chrono::SystemClock::for_at_least(10ms));
if (vendor_id_result.value_or(std::byte{0}) != std::byte{0x11}) {
return Status::NotFound();
}
SetThreshhold(128);
return OkStatus();
}
Status Device::SetThreshhold(uint8_t threshhold) {
PW_TRY(device_.WriteRegister(Ft62xxRegister::kThreshhold,
std::byte{threshhold},
pw::chrono::SystemClock::for_at_least(10ms)));
return OkStatus();
}
Status Device::Probe() {
pw::Status probe_result(initiator_.ProbeDeviceFor(
kAddress, pw::chrono::SystemClock::for_at_least(10ms)));
if (probe_result != pw::OkStatus()) {
PW_LOG_DEBUG("FT6236 Probe Failed");
} else {
PW_LOG_DEBUG("FT6236 Probe Ok");
}
return probe_result;
}
void Device::LogControllerInfo() {
Result<std::byte> result = device_.ReadRegister(
Ft62xxRegister::kVendid, pw::chrono::SystemClock::for_at_least(10ms));
PW_LOG_DEBUG("Vend ID: 0x%x", (uint8_t)result.value_or(std::byte{0}));
result = device_.ReadRegister(Ft62xxRegister::kChipid,
pw::chrono::SystemClock::for_at_least(10ms));
PW_LOG_DEBUG("Chip ID: 0x%x (0x36==FT6236)",
(uint8_t)result.value_or(std::byte{0}));
result = device_.ReadRegister(Ft62xxRegister::kFirmvers,
pw::chrono::SystemClock::for_at_least(10ms));
PW_LOG_DEBUG("Firmware Version: %u", (uint8_t)result.value_or(std::byte{0}));
result = device_.ReadRegister(Ft62xxRegister::kPointrate,
pw::chrono::SystemClock::for_at_least(10ms));
PW_LOG_DEBUG("Point Rate Hz: %u", (uint8_t)result.value_or(std::byte{0}));
result = device_.ReadRegister(Ft62xxRegister::kThreshhold,
pw::chrono::SystemClock::for_at_least(10ms));
PW_LOG_DEBUG("Threshhold: %u", (uint8_t)result.value_or(std::byte{0}));
}
void Device::LogTouchInfo() {
if (touch_count_ == 0) {
return;
}
for (int i = 0; i < touch_count_; i++) {
PW_LOG_DEBUG("Touch%d: (x,y)=(%d, %d) weight=%d area=%d",
i + 1,
touches_[i].x,
touches_[i].y,
touches_[i].weight,
touches_[i].area);
}
}
int Device::TouchCount() { return touch_count_; }
pw::ft6236::Touch Device::Touch1() { return touches_[0]; }
pw::ft6236::Touch Device::Touch2() { return touches_[1]; }
Result<bool> Device::ReadData() {
// Read 16 registers starting from 0x00.
std::array<std::byte, 16> rx_buffer;
PW_TRY(device_.ReadRegisters(
0, rx_buffer, pw::chrono::SystemClock::for_at_least(10ms)));
// Number of touches (0, 1 or 2) is at 0x02.
touch_count_ = ReadInOrder<uint8_t>(endian::big, &rx_buffer[0x02]);
// Return false if no new touches are present.
if (touch_count_ == 0) {
return false;
}
// Read Touch #1 X coordinate high (0x03) and low (0x04) registers.
touches_[0].x = ReadInOrder<uint16_t>(endian::big, &rx_buffer[0x03]) & 0xFFF;
// Read Touch #1 Y coordinate high (0x05) and low (0x06) registers.
touches_[0].y = ReadInOrder<uint16_t>(endian::big, &rx_buffer[0x05]) & 0xFFF;
// Read Touch #1 Misc data
touches_[0].weight = ReadInOrder<uint8_t>(endian::big, &rx_buffer[0x07]);
touches_[0].area = ReadInOrder<uint8_t>(endian::big, &rx_buffer[0x08]) & 0x0F;
// Read Touch #2 X coordinate high (0x09) and low (0x0A) registers.
touches_[1].x = ReadInOrder<uint16_t>(endian::big, &rx_buffer[0x09]) & 0xFFF;
// Read Touch #2 Y coordinate high (0x0B) and low (0x0C) registers.
touches_[1].y = ReadInOrder<uint16_t>(endian::big, &rx_buffer[0x0B]) & 0xFFF;
// Read Touch #2 Misc data
touches_[1].weight = ReadInOrder<uint8_t>(endian::big, &rx_buffer[0x0D]);
touches_[1].area = ReadInOrder<uint8_t>(endian::big, &rx_buffer[0x0E]) & 0x0F;
return true;
}
} // namespace pw::ft6236