tslib 프레임워크 구조
tslib은 터치스크린 입력 데이터를 처리하기 위한 라이브러리로, 모듈 기반의 파이프라인 구조를 사용합니다. 각 모듈은 데이터를 가공하거나 필터링하는 역할을 담당합니다.
핵심 데이터 구조: tsdev
struct tsdev {
struct tslib_module_info *list; // 처리 모듈 연결 리스트
struct tslib_module_info *list_raw; // 원시 데이터 모듈 (변경되지 않음)
// ... 기타 필드
};
설정 파일 처리 방식
ts.conf 파일의 각 라인은 순차적으로 읽혀지며, ts_setup() 호출 시 내부에서 linked list로 변환됩니다. 각 모듈은 info->dev 필드를 통해 자신이 속한 장치 정보를 참조할 수 있습니다.
모듈 연결 과정 (head insertion 방식):
- 첫 번째
input모듈 추가:module_raw타입이므로__ts_attach_raw()호출.ts->list가 NULL일 경우, 이 모듈이ts->list와ts->list_raw모두에 설정됩니다. - 두 번째
pthres pmin=1모듈 추가:__ts_attach()호출. 새 모듈이ts->list의 헤드가 되고, 기존ts->list는 다음 노드로 연결됩니다.
이 방식으로 모든 모듈이 연결되며, ts->list_raw는 항상 첫 번째 module_raw 모듈을 가리킵니다.
크로스 컴파일 설정
크로스 컴파일러를 사용하여 tslib을 타겟 플랫폼용으로 빌드할 수 있습니다. 일반적으로 configure 스크립트에 --host 옵션으로 타겟 아키텍처를 지정합니다.
./configure --host=arm-linux-gnueabihf --prefix=/usr/local/tslib
make
make install
실전 예제: 두 터치 포인트 간 유클리드 거리 계산
구현 단계
- 장치 초기화
ts_setup(NULL, 0)을 호출하여 자동으로 터치스크린 장치를 찾고 연결합니다. 두 번째 인자는 블로킹 모드를 제어하며, 0은 블로킹(데이터가 없으면 대기), 1은 논블로킹(즉시 반환)을 의미합니다. - 멀티터치 지원 확인
ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot)으로 장치의 절대 축 정보를 얻습니다.slot.maximum과slot.minimum을 통해 최대 지원 터치 포인트 수를 계산합니다:max_slots = slot.maximum + 1 - slot.minimum; - 데이터 버퍼 준비
struct ts_sample_mt **samp_mt는 이차원 포인터로, 두 개의 버퍼를 관리합니다:samp_mt[0]: 이전 프레임의 터치 데이터samp_mt[1]: 현재 프레임의 터치 데이터
calloc을 통해max_slots개의struct ts_sample_mt구조체를 저장할 공간을 할당받습니다. - 데이터 읽기 및 거리 계산
ts_read_mt(ts, &samp_mt[1], max_slots, 1)로 현재 터치 데이터를 읽고,valid필드가 1인 활성 포인트를 식별합니다. 두 개의 활성 포인트가 발견되면 유클리드 거리를 계산합니다.
전체 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <tslib.h>
int max_slots;
struct ts_sample_mt **samp_mt;
int compute_distance(struct ts_sample_mt *points)
{
int active_indices[2] = {0};
int count = 0;
for (int i = 0; i < max_slots; i++) {
if (points[i].valid == 1 && points[i].tracking_id != -1) {
if (count < 2)
active_indices[count++] = i;
}
}
int dx = points[active_indices[1]].x - points[active_indices[0]].x;
int dy = points[active_indices[1]].y - points[active_indices[0]].y;
return dx * dx + dy * dy;
}
int main(int argc, char *argv[])
{
struct tsdev *ts;
struct input_absinfo slot;
int ret;
int active_count = 0;
int touch_ids[20];
ts = ts_setup(NULL, 0);
if (!ts) {
fprintf(stderr, "ts_setup failed\n");
return -1;
}
if (ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot) < 0) {
perror("ioctl EVIOCGABS");
ts_close(ts);
return errno;
}
max_slots = slot.maximum + 1 - slot.minimum;
samp_mt = malloc(sizeof(struct ts_sample_mt *));
samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));
if (!samp_mt || !samp_mt[0]) {
ts_close(ts);
return -ENOMEM;
}
samp_mt = realloc(samp_mt, 2 * sizeof(struct ts_sample_mt *));
samp_mt[1] = calloc(max_slots, sizeof(struct ts_sample_mt));
if (!samp_mt[1]) {
free(samp_mt[0]);
free(samp_mt);
ts_close(ts);
return -ENOMEM;
}
for (int i = 0; i < max_slots; i++)
samp_mt[0][i].valid = 0;
while (1) {
ret = ts_read_mt(ts, &samp_mt[1], max_slots, 1);
if (ret < 0) {
fprintf(stderr, "ts_read_mt error\n");
break;
}
memcpy(samp_mt[0], samp_mt[1], max_slots * sizeof(struct ts_sample_mt));
active_count = 0;
for (int i = 0; i < max_slots; i++) {
if (samp_mt[0][i].valid == 1 && samp_mt[0][i].tracking_id != -1)
touch_ids[active_count++] = i;
}
if (active_count == 2) {
int dist = compute_distance(samp_mt[0]);
printf("Distance squared: %08d\n", dist);
}
usleep(10000); // 10ms delay
}
free(samp_mt[0]);
free(samp_mt[1]);
free(samp_mt);
ts_close(ts);
return 0;
}