Files
qemu-ios/contrib/ipod-emu/tests/test-multitouch.c
T

243 lines
9.4 KiB
C

/* Régressions du protocole tactile : commandes invalides et trames concurrentes. */
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "sysemu/cpus.h"
#include "hw/arm/ipod_touch_multitouch.c"
#include "hw/arm/ipod_touch_gpio.c"
#include "hw/arm/ipod_touch_sysic.c"
#include "hw/arm/ipod_touch_spi.c"
static IPodTouchMultitouchState *new_sensor(void)
{
IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(
object_new(TYPE_IPOD_TOUCH_MULTITOUCH));
ipod_touch_multitouch_realize(SSI_PERIPHERAL(s), &error_abort);
return s;
}
static void destroy_sensor(IPodTouchMultitouchState *s)
{
finish_transfer(s);
timer_free(s->touch_timer);
timer_free(s->touch_end_timer);
g_free(s->next_frame);
g_free(s->read_frame);
object_unref(OBJECT(s));
}
static uint8_t transfer(IPodTouchMultitouchState *s, uint8_t byte)
{
return ipod_touch_multitouch_transfer(SSI_PERIPHERAL(s), byte);
}
static void test_unknown(void)
{
IPodTouchMultitouchState *s = new_sensor();
for (int i = 0; i < 10000; i++) {
g_assert_cmpuint(transfer(s, 0xab), ==, 0xff);
g_assert_cmpuint(s->cur_cmd, ==, 0);
g_assert_null(s->in_buffer);
}
uint8_t out[16];
out[0] = transfer(s, MT_CMD_GET_INTERFACE_VERSION);
for (int i = 1; i < 16; i++) out[i] = transfer(s, 0);
g_assert_cmpuint(out[2], ==, MT_INTERFACE_VERSION);
destroy_sensor(s);
}
static void test_snapshot(void)
{
IPodTouchMultitouchState *s = new_sensor();
MTFrame expected = *s->next_frame;
uint8_t out[sizeof(MTFrame)];
out[0] = transfer(s, MT_CMD_FRAME_READ);
for (int i = 1; i < 16; i++) out[i] = transfer(s, 0);
g_free(s->next_frame);
s->next_frame = get_frame(s, MT_EVENT_TOUCH_START, .4, .6,
100, 660, 580, 150);
g_assert_cmpuint(s->cur_cmd, ==, 0);
out[16] = transfer(s, 0xeb);
out[17] = transfer(s, 0);
out[18] = transfer(s, 1);
for (size_t i = 19; i < sizeof out; i++) out[i] = transfer(s, 0);
expected.frame_packet.unused1 = expected.frame_length.length1;
expected.frame_packet.checksum_pad = -(expected.frame_packet.cmd +
expected.frame_packet.unused1 + expected.frame_packet.length1 +
expected.frame_packet.length2);
g_assert_cmpmem(out, sizeof out, &expected, sizeof expected);
g_assert_cmpuint(s->next_frame->finger_data.event, ==, MT_EVENT_TOUCH_START);
destroy_sensor(s);
}
static void test_reports(void)
{
IPodTouchMultitouchState *s = new_sensor();
uint8_t out[16];
for (int cmd = MT_CMD_GET_REPORT_INFO; cmd <= MT_CMD_SHORT_CONTROL_READ; cmd += 3) {
out[0] = transfer(s, cmd);
out[1] = transfer(s, 0xff);
for (int i = 2; i < 16; i++) out[i] = transfer(s, 0);
g_assert_cmpuint(out[2], ==, 1);
unsigned sum = 0;
for (int i = 0; i < 14; i++) sum += out[i];
g_assert_cmpuint(lduw_le_p(out + 14), ==, sum);
}
transfer(s, MT_CMD_SHORT_CONTROL_READ);
transfer(s, MT_REPORT_SENSOR_DIMENSIONS);
for (int i = 2; i < 16; i++) out[i] = transfer(s, 0);
g_assert_cmpuint(ldl_le_p(out + 3), ==, 5000);
g_assert_cmpuint(ldl_le_p(out + 7), ==, 7500);
destroy_sensor(s);
}
static void test_spi_abort(void)
{
IPodTouchSPIState *spi = IPOD_TOUCH_SPI(object_new(TYPE_IPOD_TOUCH_SPI));
DEVICE(spi)->id = g_strdup("spi-test");
set_spi_base(4);
ipod_touch_spi_realize(DEVICE(spi), &error_abort);
ipod_touch_spi_write(spi, R_TXCNT, 2, 4);
ipod_touch_spi_write(spi, R_RXCNT, 2, 4);
ipod_touch_spi_write(spi, R_TXDATA, MT_CMD_FRAME_READ, 4);
ipod_touch_spi_write(spi, R_TXDATA, 2, 4);
ipod_touch_spi_write(spi, R_CTRL, R_CTRL_RUN, 4);
g_assert_cmpuint(spi->mt->in_buffer_ind, ==, 2);
ipod_touch_spi_write(spi, R_CTRL, R_CTRL_TX_RESET | R_CTRL_RX_RESET, 4);
g_assert_cmpuint(spi->mt->cur_cmd, ==, 0);
g_assert_null(spi->mt->in_buffer);
uint8_t response[16];
response[0] = transfer(spi->mt, MT_CMD_GET_INTERFACE_VERSION);
for (int i = 1; i < 16; i++) response[i] = transfer(spi->mt, 0);
g_assert_cmpuint(response[2], ==, MT_INTERFACE_VERSION);
spi->last_irq = 1;
fifo8_push(&spi->tx_fifo, 0x12);
fifo8_push(&spi->rx_fifo, 0x34);
device_cold_reset(DEVICE(spi));
g_assert_cmpuint(spi->last_irq, ==, 0);
g_assert_true(fifo8_is_empty(&spi->tx_fifo));
g_assert_true(fifo8_is_empty(&spi->rx_fifo));
g_assert_cmpuint(ipod_touch_spi_read(spi, R_TXCNT, 4), ==, 0);
timer_free(spi->mt->touch_timer);
timer_free(spi->mt->touch_end_timer);
g_free(spi->mt->next_frame);
fifo8_destroy(&spi->tx_fifo);
fifo8_destroy(&spi->rx_fifo);
object_unref(OBJECT(spi));
}
static void test_hbpp(void)
{
IPodTouchMultitouchState *s = new_sensor();
uint8_t bad[10] = {MT_CMD_HBPP_DATA_PACKET, 0, 0, 4};
for (int i = 0; i < 10; i++) transfer(s, bad[i]);
g_assert_cmpuint(s->cur_cmd, ==, 0);
uint8_t good[10] = {MT_CMD_HBPP_DATA_PACKET, 0, 0, 4, 0, 0, 0, 0, 0, 4};
for (int i = 0; i < 10; i++) transfer(s, good[i]);
for (int i = 1; i < 21; i++) transfer(s, 0);
g_assert_cmpuint(s->cur_cmd, ==, 0);
destroy_sensor(s);
}
static void test_velocity(void)
{
IPodTouchMultitouchState *s = new_sensor();
MTFrame *f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .6, 1, 1, 1, 1);
g_free(f);
f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .7, 1, 1, 1, 1);
g_assert_cmpint(f->finger_data.velX, ==, 0);
g_assert_cmpint(f->finger_data.velY, >, 0);
g_free(f);
f = get_frame(s, MT_EVENT_TOUCH_MOVED, .4, .7, 1, 1, 1, 1);
g_assert_cmpint(f->finger_data.velX, ==, 0);
g_assert_cmpint(f->finger_data.velY, ==, 0);
g_free(f);
destroy_sensor(s);
}
static void test_buttons(void)
{
IPodTouchGPIOState *s = IPOD_TOUCH_GPIO(object_new(TYPE_IPOD_TOUCH_GPIO));
g_assert_cmpuint(GPIO2PAD(GPIO_BUTTON_HOME), <, NUM_GPIO_PADS);
gpio_set_on(s->gpio_state, GPIO_BUTTON_HOME);
gpio_set_on(s->gpio_state, GPIO_BUTTON_POWER);
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_HOME));
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_POWER));
gpio_set_off(s->gpio_state, GPIO_BUTTON_HOME);
g_assert_true(gpio_is_off(s->gpio_state, GPIO_BUTTON_HOME));
g_assert_true(gpio_is_on(s->gpio_state, GPIO_BUTTON_POWER));
object_unref(OBJECT(s));
}
static void test_gpio_ranges(void)
{
IPodTouchSYSICState *s = IPOD_TOUCH_SYSIC(object_new(TYPE_IPOD_TOUCH_SYSIC));
uint32_t arrays[4][GPIO_NUMINTGROUPS];
s->gpio_int_level[0] = 0x1234;
memcpy(arrays[0], s->gpio_int_level, sizeof arrays[0]);
memcpy(arrays[1], s->gpio_int_status, sizeof arrays[1]);
memcpy(arrays[2], s->gpio_int_enabled, sizeof arrays[2]);
memcpy(arrays[3], s->gpio_int_type, sizeof arrays[3]);
/* Les quatre trous entre groupes ne doivent pas accéder au tableau suivant. */
for (int addr = GPIO_INTLEVEL; addr <= GPIO_INTTYPE; addr += 0x20) {
ipod_touch_sysic_write(s, addr + GPIO_NUMINTGROUPS * 4, 0xffffffff, 4);
g_assert_cmpuint(ipod_touch_sysic_read(s, addr + GPIO_NUMINTGROUPS * 4, 4), ==, 0);
}
g_assert_cmpmem(arrays[0], sizeof arrays[0], s->gpio_int_level, sizeof arrays[0]);
g_assert_cmpmem(arrays[1], sizeof arrays[1], s->gpio_int_status, sizeof arrays[1]);
g_assert_cmpmem(arrays[2], sizeof arrays[2], s->gpio_int_enabled, sizeof arrays[2]);
g_assert_cmpmem(arrays[3], sizeof arrays[3], s->gpio_int_type, sizeof arrays[3]);
object_unref(OBJECT(s));
}
static void test_reset(void)
{
IPodTouchMultitouchState *s = new_sensor();
IPodTouchSYSICState *sysic = IPOD_TOUCH_SYSIC(object_new(TYPE_IPOD_TOUCH_SYSIC));
s->sysic = sysic;
ipod_touch_multitouch_on_touch(s);
/* Capture d'une trame, puis interruption au milieu d'une autre commande. */
transfer(s, MT_CMD_FRAME_READ);
for (int i = 1; i < 16; i++) transfer(s, 0);
transfer(s, MT_CMD_GET_INTERFACE_VERSION);
s->hbpp_atn_ack_response[0] = 0xaa;
g_assert_true(timer_pending(s->touch_timer));
g_assert_nonnull(s->read_frame);
g_assert_nonnull(s->out_buffer);
device_cold_reset(DEVICE(s));
g_assert_false(timer_pending(s->touch_timer));
g_assert_false(timer_pending(s->touch_end_timer));
g_assert_false(s->touch_down);
g_assert_null(s->read_frame);
g_assert_null(s->in_buffer);
g_assert_null(s->out_buffer);
g_assert_cmpuint(s->cur_cmd, ==, 0);
g_assert_cmpuint(s->hbpp_atn_ack_response[0], ==, 0);
g_assert_cmpuint(sysic->gpio_int_status[3], ==, 0);
g_assert_cmpuint(s->next_frame->finger_data.event, ==, MT_EVENT_TOUCH_FULL_END);
transfer(s, MT_CMD_GET_INTERFACE_VERSION);
transfer(s, 0);
g_assert_cmpuint(transfer(s, 0), ==, MT_INTERFACE_VERSION);
destroy_sensor(s);
object_unref(OBJECT(sysic));
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
module_call_init(MODULE_INIT_QOM);
qemu_init_main_loop(&error_abort);
qemu_init_cpu_loop();
qemu_mutex_lock_iothread();
g_test_add_func("/ipod-multitouch/unknown", test_unknown);
g_test_add_func("/ipod-multitouch/snapshot", test_snapshot);
g_test_add_func("/ipod-multitouch/hbpp", test_hbpp);
g_test_add_func("/ipod-multitouch/spi-abort", test_spi_abort);
g_test_add_func("/ipod-multitouch/reports", test_reports);
g_test_add_func("/ipod-multitouch/velocity", test_velocity);
g_test_add_func("/ipod-multitouch/reset", test_reset);
g_test_add_func("/ipod-input/buttons", test_buttons);
g_test_add_func("/ipod-input/gpio-ranges", test_gpio_ranges);
return g_test_run();
}