Add loopbackapp for app debugging using physical TKey with QEMU

This app takes data coming in on any of the normal USB endpoints
like CDC and FIDO (or CCID) and outputs the data on the DEBUG
endpoint.

Using the scripts (tkey_to_udp_linux.py, tkey_to_udp_win.py) in
QEMU (tk1 branch) under tools/tk1, the data from the DEBUG
endpoint can be read and sent over the network to the script
udp_to_qemu_linux.py that feeds it to QEMU.
This commit is contained in:
Jonas Thörnblad 2025-07-08 16:52:02 +02:00
parent 1926d19146
commit 13767ee7df
No known key found for this signature in database
GPG key ID: 2D318AD00A326F95
2 changed files with 159 additions and 3 deletions

View file

@ -0,0 +1,143 @@
// Copyright (C) 2022, 2023 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
#include <stdbool.h>
#include <stdint.h>
#include <tkey/assert.h>
#include <tkey/io.h>
#include <tkey/led.h>
#include <tkey/lib.h>
#define BUFSIZE 256
#define HEADER_SIZE 2
#define HID_PACKET_SIZE 64
#define MAX_PAYLOAD_SIZE 64
#define SLEEPTIME 100000
void sleep(uint32_t n)
{
for (volatile int i = 0; i < n; i++)
;
}
int main(void)
{
uint8_t available = 0;
uint8_t cmdbuf[BUFSIZE] = {0};
enum ioend endpoint = IO_NONE;
bool waiting_for_more_data = false;
uint8_t dest_endpoint = IO_NONE;
uint8_t payload_length = 0;
uint8_t payload_left = 0;
uint8_t payloadbuf[MAX_PAYLOAD_SIZE] = {0};
uint8_t first_packet_len = HID_PACKET_SIZE - HEADER_SIZE;
uint8_t endpoints = IO_DEBUG;
led_set(LED_BLUE);
// Give time to CH552 to settle USB enumeration at power on
sleep(SLEEPTIME * 5);
// Setup available endpoints
endpoints |= IO_CDC | IO_FIDO;
config_endpoints(endpoints);
while (1) {
// Wait for data
if (readselect(endpoints, &endpoint, &available) != 0) {
assert(1 == 2);
}
switch (endpoint) {
case IO_CDC:
cmdbuf[0] = IO_CDC;
cmdbuf[1] = available;
if (read(IO_CDC, cmdbuf + 2, BUFSIZE - 2, available) <
0) {
assert(1 == 2);
}
write(IO_DEBUG, cmdbuf, available + 2);
memset(cmdbuf, 0, BUFSIZE);
break;
case IO_FIDO:
cmdbuf[0] = IO_FIDO;
cmdbuf[1] = available;
if (read(IO_FIDO, cmdbuf + 2, BUFSIZE - 2, available) <
0) {
assert(1 == 2);
}
write(IO_DEBUG, cmdbuf, available + 2);
memset(cmdbuf, 0, BUFSIZE);
break;
case IO_CCID:
cmdbuf[0] = IO_CCID;
cmdbuf[1] = available;
if (read(IO_CCID, cmdbuf + 2, BUFSIZE - 2, available) <
0) {
assert(1 == 2);
}
write(IO_DEBUG, cmdbuf, available + 2);
memset(cmdbuf, 0, BUFSIZE);
break;
case IO_DEBUG:
if (available != HID_PACKET_SIZE) {
led_set(LED_RED);
while (1)
;
}
if (read(IO_DEBUG, cmdbuf, BUFSIZE, available) < 0) {
assert(1 == 2);
}
if (!waiting_for_more_data) {
dest_endpoint = cmdbuf[0];
payload_length = cmdbuf[1];
// Check that destination endpoint is ok
if (dest_endpoint != IO_CDC &&
dest_endpoint != IO_FIDO &&
dest_endpoint != IO_CCID) {
led_set(LED_RED);
while (1)
;
}
// Check payload size
if (payload_length > MAX_PAYLOAD_SIZE) {
led_set(LED_RED);
while (1)
;
}
// Complete payload fits in this packet
if (payload_length <= first_packet_len) {
write(dest_endpoint, cmdbuf + 2,
payload_length);
memset(cmdbuf, 0, BUFSIZE);
} else { // More payload will come in next
// packet
memcpy(payloadbuf, cmdbuf + 2,
first_packet_len);
payload_left =
payload_length - first_packet_len;
waiting_for_more_data = true;
}
} else {
memcpy(payloadbuf + first_packet_len, cmdbuf,
payload_left);
write(dest_endpoint, payloadbuf,
payload_length);
memset(payloadbuf, 0, MAX_PAYLOAD_SIZE);
memset(cmdbuf, 0, BUFSIZE);
waiting_for_more_data = false;
}
break;
default:
break;
}
}
}