Qt를 활용한 USB 통신 개요
IoT와 임베디드 시스템 발전에 따라 USB 통신은 장치 간 연결의 핵심 기술로 부상했습니다. Qt 프레임워크에서 USB 장치 접근 및 데이터 전송을 구현하는 방법을 실제 사례와 코드 분석을 통해 살펴보겠습니다.
1. QtUsb 모듈 개요
QtUsb는 libusb-1.0과 libhidapi 기반의 크로스플랫폼 USB 솔루션으로 다음 기능을 제공합니다:
- 벌크 전송: 대용량 데이터 처리에 적합(프린터, 스캐너)
- 인터럽트 전송: 실시간 데이터 교환 보장(HID 장치)
- 핫플러그 감지: 장치 연결/해제 자동 인식
- 장치 필터링: VID/PID 기반 대상 장치 식별
2. 개발 환경 구성
하드웨어 준비
- USB 3.0 지원 개발 보드(STM32F4 시리즈 추천)
- 차폐 처리된 USB 2.0/3.0 케이블(5m 이내)
소프트웨어 설정
# 프로젝트 파일(.pro) 설정
QT += core gui
LIBS += -lusb-1.0 # Linux
win32: LIBS += -L"path/to/libusb" -llibusb-1.0
의존성 관리
# Ubuntu
sudo apt install libusb-1.0-0-dev
# Windows
vcpkg install libusb
3. 핵심 기능 구현
장치 검색 및 식별
class UsbController : public QObject {
Q_OBJECT
public:
UsbController() {
connect(QPeripheral::instance(), &QPeripheral::deviceAttached,
this, &UsbController::handleDeviceAttached);
}
private slots:
void handleDeviceAttached(const QPeripheralPtr &dev) {
if (dev->vendorId() == 0x1234 && dev->productId() == 0xABCD) {
qDebug() << "Target device detected:" << dev->serial();
}
}
};
비동기 데이터 전송
void transmitAsync(QPeripheralPtr dev, const QByteArray &payload) {
QPeripheralEndpoint outEndpoint(QPeripheralEndpoint::BulkOut, 0x01);
auto dataTransfer = dev->createTransfer(outEndpoint);
QObject::connect(dataTransfer.data(), &QPeripheralTransfer::completed,
[](quint64 bytesSent) {
qDebug() << bytesSent << "bytes transmitted";
});
dataTransfer->submit(payload);
}
동기 데이터 수신
QByteArray receiveSync(QPeripheralPtr dev) {
QPeripheralEndpoint inEndpoint(QPeripheralEndpoint::BulkIn, 0x81);
QByteArray buffer(128, 0);
auto dataTransfer = dev->createTransfer(inEndpoint);
dataTransfer->submit(buffer);
dataTransfer->waitForFinished();
return buffer.left(dataTransfer->bytesTransferred());
}
4. 성능 최적화 기법
- 데이터 패킷 병합: 작은 패킷을 대형 패킷으로 결합
- 이중 버퍼링: 전송과 준비 과정 병렬 처리
- USB 3.0+ 컨트롤러 활용: 5Gbps 이상 대역폭 확보
오류 처리 구현
void handleTransferErrors(QPeripheralTransfer* transfer) {
QObject::connect(transfer, &QPeripheralTransfer::transferFailed,
[](QPeripheralTransfer::Error errCode) {
switch(errCode) {
case QPeripheralTransfer::StallError:
qCritical() << "Endpoint stalled";
break;
case QPeripheralTransfer::Timeout:
qWarning() << "Transfer timeout";
break;
}
});
}
5. 실습: USB 프린터 제어
프린터 식별
bool locatePrinter() {
auto devices = QPeripheral::listDevices();
for (auto &dev : devices) {
if (dev->deviceClass() == 0x07 && dev->subclass() == 0x01) {
return true;
}
}
return false;
}
인쇄 작업 전송
void printImage(QPeripheralPtr printer, const QImage &img) {
QByteArray printCmd;
printCmd.append("\x1B@"); // 프린터 초기화
// 이미지 데이터 변환 (실제 프로토콜 구현 필요)
for (int row = 0; row < img.height(); row += 8) {
// 픽셀 데이터 처리 로직
}
// 청크 단위 전송
const int CHUNK = 4096;
for (int pos = 0; pos < printCmd.size(); pos += CHUNK) {
transmitAsync(printer, printCmd.mid(pos, CHUNK));
}
}
6. 문제 해결 가이드
장치 인식 실패
- 드라이버 설치 확인 (Zadig 툴 활용)
- 전원 공급 상태 점검 (USB 2.0: 500mA, USB 3.0: 900mA)
Linux 권한 설정
# /etc/udev/rules.d/99-usb.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", MODE="0666"
7. 고급 개발 전략
- 상태 머신 활용: 복잡한 통신 프로토콜 파싱
- 실시간 모니터링: 데이터 전송률 및 오류율 시각화
- AES 암호화: 민감 데이터 보안 강화