blob: 19173c5b8ee0c3aeef481585faee3afbf35b2d35 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gt92xx.h"
#include <lib/fake_ddk/fake_ddk.h>
#include <lib/mock-i2c/mock-i2c.h>
#include <atomic>
#include <ddk/metadata.h>
#include <ddk/metadata/buttons.h>
#include <ddktl/protocol/gpio.h>
#include <hid/gt92xx.h>
#include <mock/ddktl/protocol/gpio.h>
#include <zxtest/zxtest.h>
namespace goodix {
class Gt92xxTest : public Gt92xxDevice {
public:
Gt92xxTest(ddk::I2cChannel i2c, ddk::GpioProtocolClient intr, ddk::GpioProtocolClient reset)
: Gt92xxDevice(fake_ddk::kFakeParent, i2c, intr, reset) {}
void Running(bool run) { Gt92xxDevice::running_.store(run); }
zx_status_t Init() { return Gt92xxDevice::Init(); }
void Trigger() { irq_.trigger(0, zx::time()); }
zx_status_t StartThread() {
EXPECT_OK(zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq_));
auto thunk = [](void* arg) -> int { return reinterpret_cast<Gt92xxTest*>(arg)->Thread(); };
Running(true);
int ret = thrd_create_with_name(&test_thread_, thunk, this, "gt92xx-test-thread");
return (ret == thrd_success) ? ZX_OK : ZX_ERR_BAD_STATE;
}
zx_status_t StopThread() {
Running(false);
irq_.trigger(0, zx::time());
int ret = thrd_join(test_thread_, NULL);
return (ret == thrd_success) ? ZX_OK : ZX_ERR_BAD_STATE;
}
thrd_t test_thread_;
};
static std::atomic<uint8_t> rpt_ran = 0;
void rpt_handler(void* ctx, const void* buffer, size_t size, zx_time_t time) {
gt92xx_touch_t touch_rpt = {};
touch_rpt.rpt_id = GT92XX_RPT_ID_TOUCH;
touch_rpt.fingers[0] = {0x01, 0x110, 0x100};
touch_rpt.fingers[1] = {0x05, 0x220, 0x200};
touch_rpt.fingers[2] = {0x09, 0x330, 0x300};
touch_rpt.fingers[3] = {0x0d, 0x440, 0x400};
touch_rpt.fingers[4] = {0x11, 0x550, 0x500};
touch_rpt.contact_count = 5;
ASSERT_BYTES_EQ(buffer, &touch_rpt, size);
EXPECT_EQ(size, sizeof(touch_rpt));
rpt_ran.store(1);
}
TEST(GoodixTest, Init) {
ddk::MockGpio reset_mock;
ddk::MockGpio intr_mock;
mock_i2c::MockI2c mock_i2c;
zx::interrupt irq;
reset_mock.ExpectConfigOut(ZX_OK, 0).ExpectWrite(ZX_OK, 1);
intr_mock.ExpectConfigOut(ZX_OK, 0).ExpectConfigIn(ZX_OK, 0).ExpectGetInterrupt(
ZX_OK, ZX_INTERRUPT_MODE_EDGE_LOW, std::move(irq));
const gpio_protocol_t* reset = reset_mock.GetProto();
const gpio_protocol_t* intr = intr_mock.GetProto();
ddk::I2cChannel i2c(mock_i2c.GetProto());
Gt92xxTest device(i2c, intr, reset);
mock_i2c
.ExpectWrite({static_cast<uint8_t>(GT_REG_FIRMWARE >> 8),
static_cast<uint8_t>(GT_REG_FIRMWARE & 0xff)})
.ExpectReadStop({GT_FIRMWARE_MAGIC})
.ExpectWriteStop(Gt92xxDevice::GetConfData())
.ExpectWriteStop({static_cast<uint8_t>(GT_REG_TOUCH_STATUS >> 8),
static_cast<uint8_t>(GT_REG_TOUCH_STATUS & 0xff), 0x00});
EXPECT_OK(device.Init());
ASSERT_NO_FATAL_FAILURES(reset_mock.VerifyAndClear());
ASSERT_NO_FATAL_FAILURES(intr_mock.VerifyAndClear());
}
TEST(GoodixTest, TestReport) {
ddk::MockGpio reset_mock;
ddk::MockGpio intr_mock;
mock_i2c::MockI2c mock_i2c;
mock_i2c
.ExpectWrite({static_cast<uint8_t>(GT_REG_TOUCH_STATUS >> 8),
static_cast<uint8_t>(GT_REG_TOUCH_STATUS & 0xff)})
.ExpectReadStop({0x85})
.ExpectWrite(
{static_cast<uint8_t>(GT_REG_REPORTS >> 8), static_cast<uint8_t>(GT_REG_REPORTS & 0xff)})
.ExpectReadStop({0x00, 0x00, 0x01, 0x10, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00,
0x02, 0x20, 0x02, 0x01, 0x01, 0x00, 0x02, 0x00, 0x03, 0x30,
0x03, 0x01, 0x01, 0x00, 0x03, 0x00, 0x04, 0x40, 0x04, 0x01,
0x01, 0x00, 0x04, 0x00, 0x05, 0x50, 0x05, 0x01, 0x01, 0x00})
.ExpectWriteStop({static_cast<uint8_t>(GT_REG_TOUCH_STATUS >> 8),
static_cast<uint8_t>(GT_REG_TOUCH_STATUS & 0xff), 0x00});
ddk::I2cChannel i2c(mock_i2c.GetProto());
Gt92xxTest device(i2c, intr_mock.GetProto(), reset_mock.GetProto());
EXPECT_OK(device.StartThread());
zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
hidbus_ifc_protocol_ops_t ops = {};
ops.io_queue = rpt_handler;
hidbus_ifc_protocol_t protocol = {};
protocol.ops = &ops;
device.HidbusStart(&protocol);
zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
device.Trigger();
while (!rpt_ran.load()) {
zx_nanosleep(zx_deadline_after(ZX_MSEC(10)));
}
EXPECT_OK(device.StopThread());
}
} // namespace goodix