안경잡이개발자

728x90
반응형

  제가 최근에 참여하고 있는 프로젝트에서 USB 디바이스 개발을 요구하고 있습니다. 그래서 USB 관련 장치(Device)를 직접 개발하기 위한 목적으로 사용할 수 있는 보드를 정리하고자 합니다. USB 디바이스 개발에 있어서 더 편리한 보드가 있을 수도 있습니다. 혹시 다른 좋은 보드를 아시는 분이 있다면 댓글로 남겨주시면 감사하겠습니다.

 

1. Teensy

 

  ▶ 링크: https://www.pjrc.com/store/teensy41.html

 

  Teensy는 USB 기반의 마이크로컨트롤러 개발 시스템입니다. 나만의 USB 장치를 새롭게 만들어 보거나 할 때 좋습니다. 최신 버전의 Teensy는 Teensy 4.1 (가격: $26.85)인데요. 이 보드(Board)의 특징은 다음과 같습니다.

 

 

  - USB 2.0 High Speed (최대 480Mbit/sec)
  - ARM Cortex-M7 processor at 600MHz
  - SD Socket
  - 8Mbyte Flash Memory
  - 아두이노 개발 환경과 연동 가능
  - 외부 센서 연동에 유리

 

  최신 Teensy 버전인 Teensy 4.1에서는 SD 소켓(Socket)을 포함하고 있어서, 간단히 Micro SD 카드만 있으면 이를 부착하여 사용할 수 있습니다. Native SDIO 프로토콜을 이용할 수 있어 SPI를 이용했을 때보다 훨씬 빠릅니다.

  이러한 SD 카드를 활용하면 더욱 다양한 예시를 만들 수 있습니다. 예를 들어 Teensy를 활용하여 임시 저장소, 키보드, 마우스 등의 USB 장치를 만들 수 있는데, 그와 동시에 사용자가 입력한 모든 정보를 Teensy에 부착된 SD 카드에 기록하거나 할 수도 있을 것입니다.

 

 

  참고로 Teensy 4.1은 USB 호스트 포트 또한 지원합니다. 다시 말해 Teensy를 호스트 PC처럼 사용할 수 있습니니다. 예를 들어 Teensy와 키보드를 서로 연결하여 키보드에 입력한 정보가 Teensy에 임시적으로 기록되었다가, Teensy에서 다시 실제 호스트(Host) PC로 데이터를 넘겨 주는 것도 가능할 것입니다. 이를 위해서는 별도로 USB 호스트 케이블이 필요하다고 하네요. 다음과 같은 케이블을 산 뒤에 Teensy 4.1의 5핀에 꽂아서 사용할 수 있습니다. 실제로 USB 호스트 포트를 이용하는 경우는 다음의 그림과 같습니다.

 

 

  그리고 Teensy의 가장 큰 특징은 아두이노(Arduino) 개발 환경을 그대로 이용할 수 있다는 점입니다. Teensy 공식 홈페이지에서 제공하는 Teensyduino를 설치하면 다음과 같이 아두이노 개발 환경에서 사용 가능한 보드로 Teensy가 보이게 됩니다. 이 경우 아두이노 개발 환경을 이용하되 코어 라이브러리의 코드는 Teensy 전용 코드로 이용할 수 있습니다.

 

 

2. ODROID

 

  ▶ 링크: https://www.hardkernel.com/ko/shop/odroid-c2/

 

  오드로이드(ODROID)하드커널(Hardkernel) 회사에서 만든 개발용 보드입니다. 라즈베리파이처럼 유사하게 사실상 소형 컴퓨터나 다름 없습니다. 그러면서도 성능이 좋은 편입니다. 실제로 성능을 확인해 보시면 기가비트 속도의 이더넷(Ethernet), 2기가 바이트 DDR3 SDRAM, HDMI 포트 또한 있으며 USB 포트도 5개나 있습니다. 그리고 우분투 16.04가 올라갈 수 있습니다.

 

  참고로 라즈베리파이나 틴시(Teensy) 같은 보드는 마이크로 USB를 통해서 전원을 공급 받지만, 오드로이드의 경우 별도의 2.5mm 어댑터를 이용해 전원을 공급해야 합니다.

 

  오드로이드 제품군 중에서 ODROID-C2 (가격: $52,900)는 2020년 기준으로 가장 인기 있는 제품 중 하나입니다.

 

 

  - USB OTG 지원: USB 2.0 High Speed (최대 480Mbit/sec) 
  - Amlogic ARM® Cortex®-A53(ARMv8) 1.5GHz quad-core CPUs 
  - 2Gbyte DDR3 SDRAM 
  - Ubuntu 16.04 설치 가능
  - Devier Driver (Gadget)를 활용한 Mass Storage Device 등으로도 활용 가능

 

  가장 일반적인 사용 형태는 다음과 같을 것입니다. 아래 이미지는 ODROID 사에서 제공하는 동영상을 캡처한 것입니다. 확인해 보시면 전원은 별도로 연결해 주고 HDMI에 모니터를 연결하여 사용하는 것을 알 수 있습니다.

 

 

  이후에 동작 과정은 일반적인 리눅스 기반 컴퓨터와 같습니다. 예를 들어 우분투 OS를 설치했다면 미니 서버용 컴퓨터로 사용할 수도 있을 것입니다. 예를 들어 단순히 나만의 파일 저장용 서버로 사용할 수도 있을 것이고, 사용 예시는 매우 다양합니다.

 

  ODROID-C2의 또 다른 큰 장점은 USB 포트를 매우 많이 제공한다는 점입니다. 이는 USB 디바이스 개발 목적으로도 활용도가 높습니다. 특히 USB OTG(USB On-The-Go)를 제공한다는 점에서 ODROID-C2를 마우스나 키보드와 같이 동작하도록 만들 수도 있습니다.

 

  참고로 ODROID-C2는 잘 팔리는 제품이라서 품절이 발생할 수 있습니다. 만약 품절이라면 입고 알림 메시지를 받도록 할 수 있습니다.

 

 

  만약 ODROID-C2가 품절 상태라면 ODROID-C1+를 구매할 수도 있습니다. ODROID-C1+ 또한 USB OTG 포트와, 4개의 USB Host 포트를 가지고 있기 때문에 USB Device 개발 목적으로 적합합니다. 다만 컴퓨팅 파워는 ODROID-C2에 비해서 떨어지는 편이고 가격은 조금 더 저렴합니다.

 

  성능을 비교하면 다음과 같습니다.

 

 

  참고로 주문하실 때에는 배송지를 [대한민국]으로 설정하시지 않으면 아주 큰 요금으로 설정될 수 있습니다. 그러므로 처음에 배송비가 너무 크게 찍혀 있다고 놀라지 마세요. ODROID는 국내 기업 제품이라서, 배송지를 국내로 변경하면 일반적인 배송비가 나옵니다.

 

3. Raspberry Pi

 

  ▶ 링크: https://www.raspberrypi.org/products/raspberry-pi-zero-w/

 

  라즈베리파이(Raspberry Pi)는 아두이노(Arduino)와 더불어 매우 유명한 보드 중 하나입니다. 일종의 소형 컴퓨터로 볼 수 있으며, 매우 저렴한 가격으로도 좋은 컴퓨팅 파워를 제공합니다. 작은 웹 서버를 운용하는 프로젝트 등에서 자주 나오는 보드이기도 합니다. 실제 보드 크기는 학생증 카드보다 조금 더 큰 크기입니다.

 

  라즈베리파이 보드 중에서도 가성비가 매우 높은 것으로 알려진 보드는 Raspberry Pi Zero W입니다.  이 Raspberry Pi Zero W (가격: $10)는 가격이 매우 저렴하고, 해외 주문을 고려해도 굉장히 쌉니다. 특히 크기가 매우 작아서 휴대성이 뛰어납니다. 학생증보다도 훨씬 작아요. 원래 Raspberry Pi Zero 모델이 출시가 되었는데, 여기에 Wireless LAN과 Bluetooth를 추가하여 Raspberry Pi Zero W라는 이름으로 출시가 되었습니다.

 

  - 1GHz single-core ARMv6 CPU (BCM2835)
  - SD Socket
  - 512MB RAM
  - Linux, Windows 등 다양한 OS 설치 가능
  - USB OTG 지원: 단, 사용 예시를 찾아보니 Mass Storage Class로 5~6MB/s 정도의 속도만 나온다고 함

  - Micro USB로 전원 공급
  - Devier Driver (Gadget)를 활용한 Mass Storage Device 등으로도 활용 가능

  - 802.11 b/g/n wireless LAN

 

  그래서 라즈베리파이 제로 W 버전 또한 사실상 운영체제(OS)를 올릴 수 있는 소형 컴퓨터와 마찬가지입니다. SD 카드를 부착할 수 있기 때문에 SD 카드에 우분투와 같은 운영체제(OS)를 설치해 놓고, 이를 라즈베리파이 제로 W에 연결하여 SD 카드로부터 바로 부팅을 진행할 수 있습니다. 당연히 미니 HDMI 케이블도 있기 때문에 모니터와 연결하여 화면을 볼 수도 있습니다.

 

  또한 라즈베리파이 제로 W는 USB OTG 기능을 지원하기 때문에 USB 디바이스를 개발할 때에도 유용합니다. 아래와 같이 라즈베리파이 제로 W가 있으면 USB 포트 하나로 전원을 공급하고, 다른 USB 포트 하나를 더 써서 호스트(Host) PC와 데이터를 주고 받는 목적으로도 쓸 수 있습니다.

 

 

  참고로 Raspberry Pi Zero W는 원래 $10의 저렴한 가격이지만, 국내에서 구매하려고 하면 굉장히 비쌉니다. 따라서 일반적으로 해외에서 직구하는 경우가 많습니다. (다만, 배송하는 물품의 개수가 많지 않다면 배송비 때문에 오히려 더 비싸질 수 있습니다.) 캐나다 기업인 CanaKit에서 구매할 수 있는데, 여기에서 주문하면 통상 3주 안에는 도착한다고 합니다. 저도 여기에서 구매를 해보았습니다.

 

   ▶ CanaKit 라즈베리파이 구매 경로: www.canakit.com/raspberry-pi-zero-wireless.html

 

Raspberry Pi Zero W (Wireless)

 

www.canakit.com

 

  CanaKit에 접속하면 다음과 같이 Raspberry Pi Zero W를 찾으실 수 있습니다. 일반적으로 Basic Kit이나 Starter Kit을 이용하는 편입니다. Starter Kit을 이용하면 Power Supply, USB OTG Cable 등의 구성을 함께 받으실 수 있습니다.

 

 

  상세한 물품 구성은 다음과 같습니다. Raspberry Pi Zero W 단품만 구매하는 경우에는 사람당 1개씩으로 개수를 한정하는 것 같습니다. 온전한 하나의 미니 컴퓨터 형태를 원한다면 Start Kit을 이용하시면 됩니다.

 

 

  최종적으로 다음과 같이 장바구니에 담은 물품을 구매하실 수 있습니다.

 

 

  다만, 실제로 구매할 때는 배송비가 상당히 비싸네요.

 

 

  아무튼 결제 카드를 이용하여 구매하게 되면 결제 정보가 이메일로 도착하여, 이를 확인하실 수 있습니다.

728x90
반응형

728x90
반응형

  시리얼(Serial)은 말 그대로 직렬이라는 의미를 가지고 있습니다.

 

  일반적인 시리얼 통신 방식은 UART (Universal Asynchronous serial Receiver and Transmitter) 방식을 의미합니다. UART는 하드웨어적으로 구현이 간단한 편이며, 대표적인 비동기 통신 방식입니다. 다시 말해 통신을 수행하는 두 기기가 클럭(Clock)을 공유하지 않습니다. 그래서 두 기기가 동일한 속도를 가지도록 추가적으로 속도를 맞추어 주어야 합니다.

 

  시리얼 통신 속도 (Speed)는 여러 개의 BPS (Bits Per Second) 중에서 하나를 선택해야 합니다. 4800, 9600, 19200 등이 있는데요. 대표적인 것이 바로 9600입니다. 당연히 호스트(Host) 컴퓨터와 USB 장치랑 이러한 BPS를 맞추지 않으면 통신이 안 되겠죠? 그러한 작업은 기본적으로 수행됩니다.

 

  다른 시리얼 통신 방법으로는 SPI (Serial Peripheral Interface)가 있습니다. SPI는 라인이 더 많아 데이터 송수신을 동시에 할 수 있으며 UART에 비해서 훨씬 빠릅니다.  또한 두 기기가 같은 클럭(Clock)을 사용하여 통신을 하므로 시작 단계부터 동기화 작업이 수행됩니다.

 

  한 번 예시 코드를 확인해 보겠습니다. Serial.begin() 함수를 이용하여 초기화를 수행할 수 있습니다. 다만 기본적으로 Serial 객체가 초기화 될 때까지 기다려야 합니다. 초기화 된 이후에는 바로 Serial.println() 함수를 이용하여 원하는 문자열을 호스트(Host) 쪽으로 보내어 출력할 수 있습니다.

 

void setup() {
    // 시리얼 통신을 열고 포트가 열릴 때까지 기다립니다.
    Serial.begin(9600);
    while (!Serial) {
        ; // 시리얼 포트가 연결될 때까지 기다립니다.
    }
    Serial.println("Setup이 완료되었습니다.");
}

void loop() {
    Serial.println("Loop 함수를 호출합니다.");
    delay(1000);
}

 

  코드를 작성한 뒤에 USB Type으로는 [Serial]을 선택합니다.

 

 

  업로드를 해보시면 1초에 한 번씩 Serial 통신이 수행되어 문자열이 출력됩니다.

 

 

※ 유의할 점 ※

 

  Teensy에서는 기본적으로 Serial 통신을 이용할 때 Serial을 포함하는 USB Type을 설정했는지 확인할 필요가 있습니다. 만약에 RawHID와 Serial 통신을 같이 사용해야 할 때에는 RawHID를 선택할 수 있는데요. 다만 RawHID는 기본적으로 Serial 통신을 메인으로 사용하지 않으며, setup() 함수에 포함되어 있는 Serial 작업은 무시될 수 있습니다. 이 점을 유의하셔야 합니다.

 

 

  예를 들어 이와 같이 USB TypeRaw HID로 설정하여 동일한 코드를 실행하면 다음과 같이 setup() 함수에 정의되어 있던 출력 구문은 출력되지 않는 것을 알 수 있습니다.

 

728x90
반응형

728x90
반응형

  Teensy는 USB 장치(Device) 개발용 키트로, 새로운 USB 장치를 개발하고자 할 때 아두이노(Arduino) IDE를 기반으로 하여 개발을 진행할 수 있습니다. Teensy는 USB 장치 개발용 키트라는 점에서 원하는 USB Type으로 해당 보드를 이용할 수 있습니다. 저는 Teensy 3.6 보드를 사용하고 있는데, Teensyduino를 설치한 뒤에 다음과 같이 다양한 기본적인 USB 타입들을 확인할 수 있습니다.

 

 

  Teensy는 동시에 여러 개의 인터페이스를 제공하기에 용이하다는 점에서 다목적의 USB 장치를 만들 수 있습니다. 예를 들어 동시에 마우스이면서 키보드인 USB 장치를 만들 수 있습니다. 다만 기본적으로 제공하는 USB Type이 아니라, 자신만의 USB Type을 만들고자 한다면 어떻게 해야 할까요? 새로운 보드를 추가하고 개발하는 방법을 소개합니다.

 

※ 새로운 USB 타입 정의하기 ※

 

  자신만의 USB Type을 정의하고자 할 때는 가장 먼저 boards.txt 파일을 수정해야 합니다. 일반적으로 boards.txt 파일을 열어서 수정할 때는 에디터(Editor) 프로그램을 관리자 권한으로 실행하셔야 합니다.

 

  ▶ Boards.txt 파일 경로: C:\Program Files (x86)\Arduino\hardware\teensy\avr\cores\teensy3

 

 

  boards.txt를 열면 각 Teensy 보드 버전에 따라서 다양한 보드 타입과 기타 내용들이 정의되어 있는 것을 확인할 수 있습니다. 가볍게 다음과 같은 내용을 추가하여 새로운 USB Type으로 "USB_TEST"를 추가할 수 있습니다.

 

teensy36.menu.usb.test=Test
teensy36.menu.usb.test.build.usbtype=USB_TEST
teensy36.menu.usb.test.fake_serial=teensy_gateway

 

  그러면 다음과 같은 형태로 들어가게 될 겁니다.

 

 

  이제 boards.txt를 저장한 뒤에 아두이노 IDE를 관리자 권한으로 실행합니다. 그러면 다음과 같이 새로운 USB Type으로 "Test"가 추가되어 있는 것을 확인할 수 있습니다.

 

 

※ USB Description 정의하기 ※

 

  (참고: 아두이노 IDE를 관리자 권한으로 실행했다면, 소스코드 편집기도 관리자 권한으로 실행해야 합니다.)

 

  USB 장치는 기본적으로 우리의 컴퓨터 (Host)에 꽂았을 때 기본적인 Description 정보를 보냅니다. "나는 어떤 기능을 제공하는 USB 장치야."라는 의미라고 보시면 됩니다. 당연히 새로운 USB 장치를 개발한다면 Description 정보를 수정할 필요가 있을 것입니다.

 

  Teensy 3.6 버전에서는 usb_desc.h 파일에서 그러한 정보를 담고 있습니다. 이 소스코드를 수정하면 알아서 Teensy 보드가 연결될 때 호스트(Host)에게 자신의 수정된 Description 정보를 보냅니다.

 

 

  예를 들어 다음과 같이 작성할 수 있습니다. 저는 간단히 키보드와 마우스의 기능만을 포함하고 있는 새로운 USB Type을 정의했습니다. 참고로 KEYBOARD_INTERFACE나 MOUSE_INTERFACE 등은 usb_keyboard.h와 usb_mouse.h 코드를 사용할 수 있도록 해주는 전처리 구문입니다. 다시 말해, 일단 저는 이미 Teensy 코어(Core)에 정의되어 있는 키보드와 마우스 기능을 그대로 사용하고자 합니다. (만약 이러한 코어 코드까지 다 새롭게 만드시고 싶을 수 있는데요. 이 또한 원하신다면 처음부터 다 만드실 수 있습니다.)

 

#elif defined(USB_TEST)
  /* USB 장치의 기본적인 ID와 클래스 정보 */
  #define VENDOR_ID 0x16C0
  #define PRODUCT_ID 0x0707
  #define DEVICE_CLASS 0xEF // 기타 USB 클래스 (Miscellaneous) 
  #define DEVICE_SUBCLASS 0x02 // 기타 USB 클래스 (Miscellaneous)의 서브 클래스 
  #define DEVICE_PROTOCOL 0x01 // 다양한 인터페이스 사용 (Interface Association Descriptor)

  /* USB 장치의 이름 정보 */ 
  #define MANUFACTURER_NAME {'T','e','e','n','s','y','d','u','i','n','o'}
  #define MANUFACTURER_NAME_LEN 11
  #define PRODUCT_NAME {'M','y',' ','T','e','s','t',' ','B','o','a','r','d'}
  #define PRODUCT_NAME_LEN 13

  /* USB 장치의 엔드포인트 및 인터페이스 정보 */
  // 엔드포인트 0번은 Control Transfer 목적으로 고정 
  #define EP0_SIZE 64
  #define NUM_ENDPOINTS 6
  #define NUM_USB_BUFFERS 30
  #define NUM_INTERFACE 5

  /* CDC 관련 정보 */
  #define CDC_IAD_DESCRIPTOR 1
  #define CDC_STATUS_INTERFACE 0
  #define CDC_DATA_INTERFACE 1 // 시리얼 (Serial) 
  #define CDC_ACM_ENDPOINT 1
  #define CDC_RX_ENDPOINT 2
  #define CDC_TX_ENDPOINT 3
  #define CDC_ACM_SIZE 16
  #define CDC_RX_SIZE 64
  #define CDC_TX_SIZE 64

  /* 키보드 (Keyboard) */
  #define KEYBOARD_INTERFACE 2
  #define KEYBOARD_ENDPOINT 4
  #define KEYBOARD_SIZE 8
  #define KEYBOARD_INTERVAL 1

  /* 키보드 미디어 키 (Keyboard Media Keys) */
  #define KEYMEDIA_INTERFACE 3
  #define KEYMEDIA_ENDPOINT 5
  #define KEYMEDIA_SIZE 8
  #define KEYMEDIA_INTERVAL 4

  /* 마우스 (Mouse) */
  #define MOUSE_INTERFACE 4
  #define MOUSE_ENDPOINT 6
  #define MOUSE_SIZE 8
  #define MOUSE_INTERVAL 2

  /* 각 엔드포인트의 데이터 송수신 관련 정보 */
  #define ENDPOINT1_CONFIG ENDPOINT_TRANSMIT_ONLY // CDC ACM
  #define ENDPOINT2_CONFIG ENDPOINT_RECEIVE_ONLY // CDC RX
  #define ENDPOINT3_CONFIG ENDPOINT_TRANSMIT_ONLY // CDC TX
  #define ENDPOINT4_CONFIG ENDPOINT_TRANSMIT_ONLY // 키보드 TX (전송만) 
  #define ENDPOINT5_CONFIG ENDPOINT_TRANSMIT_ONLY // 키보드 미디어 키 TX (전송만) 
  #define ENDPOINT6_CONFIG ENDPOINT_TRANSMIT_ONLY // 마우스 TX (전송만)

 

  또한 USB Function Driver에는 HID (Human Interface Device), CDC (Communication Device Class), MSC (Mass Storage Class) 등이 포함됩니다. 이 때 Mouse, Keyboard 등은 기본적으로 HID에 속하며, 시리얼(Serial) 통신은 CDC에 속합니다.  그래서 usb_desc.h에서 CDC 부분을 빼버리면 아두이노에서 Serial 라이브러리를 사용할 수 없습니다.  마찬가지로 Mouse나 Keyboard 부분을 빼버리면 아두이노에서 Mouse, Keyboard 라이브러리를 사용할 수 없답니다.

 

  참고로 usb_desc.h 부분의 코드가 잘못되어 있으면 호스트(Host)에서 USB 장치로 인식조차 안 할 수 있습니다. 만약에 usb_desc.h 파일을 수정한 뒤에 Teensy 보드로 업로드를 했는데, 아예 인식을 안 하는 경우 (특히 포트조차 못 잡는 경우) Teensy 보드에 있는 작은 버튼을 눌러서 초기화 해주셔야 합니다. 

 

※ 예제 소스코드 ※

 

  예제 소스코드는 다음과 같습니다. Mouse, Keyboard, Serial 라이브러리를 모두 사용합니다.

 

void setup() {

}

void loop() {
    int i;
    for (i = 0; i < 40; i++) {
        Mouse.move(2, -1);
        delay(100);
    }
    delay(1000);
    Serial.println("Hello");
    Keyboard.print("Hello World");
}

 

※ 실행 결과 ※

 

  컴파일 이후에 Teensy 보드에 업로드를 하면 성공적으로 USB 장치가 동작합니다. 반복적으로 마우스를 움직이며, 키보드로 "Hello World"를 입력하고, 시리얼 통신으로 "Hello"라는 문자열을 전송합니다. 리눅스 환경에서 lsusb 명령어를 이용해 USB 장치의 상세 Description을 확인하면 다음과 같습니다.

 

  사실 Vendor ID로 사용한 0x16c0는 이미 정의되어 있네요. 이 값 또한 원래는 바꿔주어야 합니다. 

 

 

  또한 이어서 인터페이스(Interface) 정보를 확인해 보시면, 인터페이스마다 CDC, Keyboard, Mouse 등의 각기 다른 기능이 제공되는 것을 알 수 있습니다. CDC를 이용한 시리얼 통신은 Bulk Transfer를 기반으로 하고 있으며, HID를 이용한 Keyboard 기능은 Interrupt Transfer를 기반으로 하고 있네요. 각각 패킷 크기도 64 바이트와 8 바이트로 다릅니다. 사실 이 내용들도 대부분 usb_desc.h 파일에 정의되어 있습니다.

 

728x90
반응형

728x90
반응형

  Teensy Board를 이용하는 경우 다양한 오류를 만날 수 있는데요. 해결하기 어려운 오류는 포럼(Forum)에 글을 남김으로써 다른 개발자에게 도움을 받을 수 있습니다. Teensy 포럼 웹 사이트의 링크는 다음과 같습니다.

 

  ▶ PJRC 포럼(Forum) 웹 사이트: https://forum.pjrc.com/

 

  만약 회원가입을 아직 안 하신 분이라면 다음과 같이 [Register] 버튼을 눌러서 회원가입을 진행할 수 있습니다.

 

 

  회원가입을 진행할 때에는 아이디, 비밀번호, 이메일 등 다양한 정보를 기입한 뒤에 [Complete Registration] 버튼을 눌러서 회원가입 요청을 할 수 있습니다.

 

 

  회원가입 이후에는 자신이 회원가입을 할 때 기입했던 이메일 주소로 등록 완료 메일이 옵니다. 여기에서 링크를 눌러 주시면 실제로 회원가입이 완료됩니다.

 

 

  회원가입이 완료되면 이제 포럼에 글을 작성할 수 있게 됩니다.

 

 

  저는 개발 관련 이슈가 있어서 [Technical Support & Questions] 경로로 이동하였습니다.

 

 

  다음과 같이 [Post New Thread] 버튼을 눌러서 게시판에 글을 작성할 수 있습니다.

 

 

 

  이후에 다음과 같이 글을 작성하시면 됩니다. 가능하면 이미지와 소스코드 및 설명을 최대한 자세하게 첨부하는 것이 좋은 답변을 받기에 유리합니다.

 

 

  이렇게 글을 쓴 뒤에 이메일로 알림을 받도록 설정하면, 누군가 댓글을 달았을 때 다음과 같이 댓글이 달렸다는 이메일이 도착합니다.

 

 

  이후에 댓글에 대하여 다시 댓글을 다는 방법은 다음과 같습니다. [Reply With Quote] 버튼을 눌러서 다른 사람의 글에서 인용할 부분을 설정합니다. 그리고 글의 내용을 작성하면 됩니다. [Post Quick Reply] 버튼을 눌러서 댓글을 등록할 수 있습니다.

 

728x90
반응형

728x90
반응형

  이번 시간에는 Teensy 보드(Board) 위에서 동작하는 HID 소프트웨어를 개발하는 방법을 소개하고자 합니다. 단, HID 코어(Core) 라이브러리를 처음부터 만드는 방법을 소개합니다. 즉, 자신만의 USB 프로토콜을 만들어 보고 싶은 사람에게 도움이 될 만한 글입니다. 본 예시는 RawHID 소스코드를 기반으로 하지만, 특히 HID가 아닌 본인만의 USB 클래스를 정의하고 싶으신 분들에게도 도움이 될 것입니다.

 

※ Teensy USB 디바이스 개발하기 ※

 

  일단 Teensy의 경우에는 아두이노 IDE 위에서 동작한다는 특징이 있는데요. 사용자 라이브러리는 다음의 경로에 만들어 주면 됩니다.

 

  ▶ 아두이노 사용자 라이브러리(스케치북) 경로: C:\Users\{사용자명}\Documents\Arduino\libraries

 

 

  기본적인 HID 기능을 이용할 수 있도록 MyHID라는 이름의 사용자 라이브러리를 생성하도록 하겠습니다. 폴더 구성은 다음과 같이 해주시면 됩니다. 일반적으로 다음과 같이 하나의 헤더 파일(.h)과 하나의 C++ 소스 코드(.cpp)로 라이브러리를 작성할 수 있습니다. 그리고 자신의 라이브러리를 어떻게 사용할 수 있을지를 간략히 보여주는 examples 폴더를 만드시면 됩니다.

 

 

  먼저 MyHID.h를 작성해 보겠습니다. 기본적으로 2개의 함수가 존재하도록 작성할 수 있는데요. 바로 hid_recv()와 hid_send()입니다. 하나는 HID 프로토콜을 이용해 데이터를 받는 함수, 하나는 보내는 함수입니다.

 

  ▶ hid_recv(): 호스트(Host)로부터 buffer만큼의 데이터를 받아 옵니다.

  ▶ hid_send(): 호스트(Host)로부터 buffer만큼의 데이터를 전송합니다.

 

  USB 디바이스(Device)는 기본적으로 여러 개의 인터페이스(Interface)를 포함할 수 있는데요. 개발 단계에서부터 어떠한 인터페이스를 HID 목적으로 사용할 지 설정할 수 있습니다. 구체적으로 Teensy 쪽의 usb_desc.h에 그러한 기본적인 인터페이스 번호를 포함한 설정 정보가 적혀 있습니다. (조금 있다가 다시 언급하겠습니다.) 아무튼 그러한 usb_desc.h를 불러와 이용하는 방식으로 소스코드가 작성됩니다.

 

#ifndef MyHID_H
#define MyHID_H

#include "usb_desc.h" // for contants (RAWHID_INTERFACE, RAWHID_RX_ENDPOINT, RAWHID_TX_ENDPOINT, ...)

#if defined(RAWHID_INTERFACE)

#include <inttypes.h>

int available(void);
int hid_recv(void *buffer, uint32_t timeout);
int hid_send(const void *buffer, uint32_t timeout);

#endif // RAWHID_INTERFACE
#endif // MyHID_H

 

  이제 MyHID.cpp를 작성할 수 있습니다. hid_recv() 함수와 hid_send() 함수를 실제로 구현하는 부분입니다. 구현을 위해서 usb_dev.h를 이용하는데요, 기본적으로 usb_dev.h 헤더 파일에는 usb_rx()나 usb_tx()와 같은 기본적인 기능들이 구현되어 있습니다. 그러한 코어 USB 기능을 이용하여 실제로 HID 관련 라이브러리를 구현하게 됩니다. 확인해 보시면 전송을 위한 timeout이 있어서, 너무 오랫동안 전송이 안 되는 데이터는 버리게 됩니다.

 

  데이터를 주고 받는 usb_rx()나 usb_tx()를 확인해 보시면, 특정한 엔드포인트(Endpoint)를 이용하는 것을 알 수 있습니다. 엔드포인트데이터를 주고 받기 위한 주소와 같은 것이라고 보시면 됩니다.

 

#include "usb_dev.h" // for USB core functions (usb_rx, usb_tx, ...)
#include "core_pins.h" // for yield(), millis()
#include <string.h> // for memcpy()
#include "MyHID.h"

#ifdef RAWHID_INTERFACE
#if F_CPU >= 20000000

int available(void)
{
	uint32_t count;

	if (!usb_configuration) return 0;
	count = usb_rx_byte_count(RAWHID_RX_ENDPOINT);
	return count;
}

int hid_recv(void *buffer, uint32_t timeout)
{
	usb_packet_t *rx_packet;
	uint32_t begin = millis();

	while (1) {
		if (!usb_configuration) return -1;
		rx_packet = usb_rx(RAWHID_RX_ENDPOINT);
		if (rx_packet) break;
		if (millis() - begin > timeout || !timeout) return 0;
		yield();
	}
	memcpy(buffer, rx_packet->buf, RAWHID_RX_SIZE);
	usb_free(rx_packet);
	return RAWHID_RX_SIZE;
}

// Maximum number of transmit packets to queue so we don't starve other endpoints for memory
#define TX_PACKET_LIMIT 4

int hid_send(const void *buffer, uint32_t timeout)
{
	usb_packet_t *tx_packet;
	uint32_t begin = millis();

	while (1) {
		if (!usb_configuration) return -1;
		if (usb_tx_packet_count(RAWHID_TX_ENDPOINT) < TX_PACKET_LIMIT) {
			tx_packet = usb_malloc();
			if (tx_packet) break;
		}
		if (millis() - begin > timeout) return 0;
		yield();
	}
	memcpy(tx_packet->buf, buffer, RAWHID_TX_SIZE);
	tx_packet->len = RAWHID_TX_SIZE;
	usb_tx(RAWHID_TX_ENDPOINT, tx_packet);
	return RAWHID_TX_SIZE;
}

#endif // F_CPU
#endif // RAWHID_INTERFACE

 

  이제 이러한 라이브러리를 이용하는 실질적인 USB 디바이스의 아두이노 코드를 작성할 수 있습니다.

 

 

  소스코드는 다음과 같이 작성할 수 있습니다. 소스코드를 간단히 설명하자면, 앞서 정의한 HID 코어 라이브러리를 이용해서 데이터를 보내고 받도록 작성되어 있습니다. 일단 코드의 앞 부분에서는 데이터를 받아서 이를 바로 출력하는 부분이 작성되어 있으며, 코드의 뒷 부분에서는 2초마다 한 번씩 64바이트의 데이터를 보내는 부분이 작성되어 있습니다.

 

#include <MyHID.h>

void setup() {
}

// RawHID packets are always 64 bytes.
byte buffer[64];
elapsedMillis msUntilNextSend;

void loop() {
  int n;
  n = hid_recv(buffer, 0); // 0 timeout = do not wait
  if (n > 0) {
    String received = String((char*)buffer);
    Serial.println(received);
  }
  // every 2 seconds, send a packet to the computer (Host PC)
  if (msUntilNextSend > 2000) {
    msUntilNextSend = msUntilNextSend - 2000;
    buffer[0] = 0x12;
    buffer[1] = 0x34;
    for (int i = 2; i < 62; i++) {
      buffer[i] = 0;
    }
    buffer[62] = 0x56;
    buffer[63] = 0x78;
    // send the packet
    n = RawHID.send(buffer, 100);
    if (n > 0) {
      Serial.println("Transmit packet ");
    } else {
      Serial.println("Unable to transmit packet");
    }
  }
}

 

  실제로 USB Device의 설정 정보는 Teensy 코어 라이브러리 위치의 usb_desc.h 헤더 파일에 정의되어 있습니다. 우리가 Teensy 장치를 RawHID로 설정하게 되면, 다음과 같이 각각의 Description 정보가 구성됩니다. 확인해 보시면, 기본적으로 Vendor ID로 0x16C0을, Product ID로 0x0486을 사용하도록 되어 있네요.

 

 

  여기에서 핵심이 되는 내용은 Vendor ID, Product ID인데요. 이 값을 통해서 Host OS가 USB Device를 정확히 찾아 접근할 수 있습니다. 또한 Product Name은 "Teensyduino RawHID"인데요, 이게 나중에 Host OS에서 출력될 USB Device의 이름이 됩니다.

 

  또한 HID 통신을 위해서 데이터를 주고 받으려면 데이터를 받는 엔드포인트(Endpoint)와 데이터를 보내는 엔드포인트(Endpoint)를 정확히 정의해야 합니다. 확인해 보시면 송신(Transmit)을 위한 엔드포인트는 3번이고, 수신(Receive)을 위한 엔드포인트는 4번으로 정의된 것을 확인할 수 있습니다. 이러한 정보는 실제로 Description 정보가 되어 Host PC로 전송됩니다. Host는 이후에 이러한 엔드포인트를 이용해서 HID 통신을 진행하게 되는 것이죠.

 

  이제 최종적으로 만들어진 HelloWorld.ino 파일을 Teensy에 업로드 해주세요.

 

 

  그럼 이제 성공적으로 우리의 Teensy는 HID 기능을 위한 목적으로 동작하게 됩니다.

 

※ Host 프로그램 개발하기 ※

 

  Host 프로그램의 소스코드는 다음과 같이 구성됩니다.

 

  ▶ hid_WINDOWS.c: HID 기능을 위한 기본 라이브러리 (윈도우 전용)

  hid_LINUX.c: HID 기능을 위한 기본 라이브러리 (리눅스 전용)

   hid.h: HID 라이브러리를 위한 헤더 파일

   Makefile: 컴파일을 진행하기 위한 설정 파일

   my_hid.c: 메인 함수가 포함된 실제 소스코드

 

  먼저 hid_WINDOWS.c와 hid_LINUX.c의 소스코드는 다음의 경로에서 찾아보실 수 있습니다. (참고로 소스코드를 가져오신 뒤에, printf() 함수를 보이지 않도록 처리한 부분을 제거하시면 디버깅에 도움이 됩니다.)

 

  https://github.com/ndb796/Teensy-RawHID-SD/tree/master/host

 

  먼저 hid.h는 다음과 같이 작성할 수 있습니다. Host OS 쪽에서도 마찬가지로 USB 디바이스로부터 데이터를 받을 수 있어야 하기 때문에, 송신(Send) 함수와 수신(Receive) 함수로 구성됩니다.

 

int rawhid_open(int max, int vid, int pid, int usage_page, int usage);
int rawhid_recv(int num, void *buf, int len, int timeout);
int rawhid_send(int num, void *buf, int len, int timeout);
void rawhid_close(int num);

 

  그리고 Makefile은 다음과 같이 작성할 수 있습니다. 참고로 빌드(Build)는 리눅스 OS에서 진행하셔야 합니다. 리눅스 OS에서 윈도우 전용 실행 파일(.exe)도 만들 수 있습니다. 일단 아래 Makefile은 LINUX 환경에서 실행할 수 있는 실행 파일이 나오도록 작성되어 있습니다. 윈도우용 실행 파일을 만드실 때는 OS의 값으로 WINDOWS를 넣어주시면 됩니다.

 

OS = LINUX
# OS = WINDOWS
PROG = my_hid

ifeq ($(OS), LINUX)
TARGET = $(PROG)
CC = gcc
STRIP = strip
CFLAGS = -Wall -O2 -DOS_$(OS)
LIBS = -lusb
else ifeq ($(OS), WINDOWS)
TARGET = $(PROG).exe
CC = i686-w64-mingw32-gcc
STRIP = i686-w64-mingw32-strip
CFLAGS = -Wall -O2 -DOS_$(OS)
LIBS = -lhid -lsetupapi
endif

OBJS = $(PROG).o hid.o

all: $(TARGET)

$(PROG): $(OBJS)
	$(CC) -o $(PROG) $(OBJS) $(LIBS)
	$(STRIP) $(PROG)

$(PROG).exe: $(PROG)
	cp $(PROG) $(PROG).exe

hid.o: hid_$(OS).c hid.h
	$(CC) $(CFLAGS) -c -o $@ $<

clean:
	rm -f *.o $(PROG) $(PROG).exe $(PROG).dmg
	rm -rf tmp

 

  이제 my_hid.c는 다음과 같이 작성할 수 있습니다. 확인해 보시면 계속해서 데이터를 받고, 보내는 작업이 수행되는 것을 확인할 수 있는데요. 기본적으로 타임아웃(Timeout)이 걸려 있어서 무한정 대기하지는 않기 때문에, 데이터를 잘 주고 받으며 동작하게 되는 것입니다.

 

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#if defined(OS_LINUX)
#include <sys/ioctl.h>
#include <termios.h>
#elif defined(OS_WINDOWS)
#include <conio.h>
#endif

#include "hid.h"

static char get_keystroke(void);

int main()
{
	int i, r, num;
	char c, buf[64];

	// C-based example is 16C0:0480:FFAB:0200
	r = rawhid_open(1, 0x16C0, 0x0480, 0xFFAB, 0x0200);
	if (r <= 0) {
		// Arduino-based example is 16C0:0486:FFAB:0200
		r = rawhid_open(1, 0x16C0, 0x0486, 0xFFAB, 0x0200);
		if (r <= 0) {
			printf("no rawhid device found\n");
			return -1;
		}
	}
	printf("found rawhid device\n");

	while (1) {
		// check if any Raw HID packet has arrived
		num = rawhid_recv(0, buf, 64, 220);
		if (num < 0) {
			printf("\nerror reading, device went offline\n");
			rawhid_close(0);
			return 0;
		}
		if (num > 0) {
			printf("\nrecv %d bytes:\n", num);
			for (i=0; i<num; i++) {
				printf("%02X ", buf[i] & 255);
				if (i % 16 == 15 && i < num-1) printf("\n");
			}
			printf("\n");
		}
		// check if any input on stdin
		while ((c = get_keystroke()) >= 32) {
			printf("\ngot key '%c', sending...\n", c);
			buf[0] = c;
			for (i=1; i<64; i++) {
				buf[i] = 0;
			}
			rawhid_send(0, buf, 64, 100);
		}
	}
}

#if defined(OS_LINUX)
static int _kbhit() {
	static const int STDIN = 0;
	static int initialized = 0;
	int bytesWaiting;

	if (!initialized) {
		// Use termios to turn off line buffering
		struct termios term;
		tcgetattr(STDIN, &term);
		term.c_lflag &= ~ICANON;
		tcsetattr(STDIN, TCSANOW, &term);
		setbuf(stdin, NULL);
		initialized = 1;
	}
	ioctl(STDIN, FIONREAD, &bytesWaiting);
	return bytesWaiting;
}
static char _getch(void) {
	char c;
	if (fread(&c, 1, 1, stdin) < 1) return 0;
	return c;
}
#endif

static char get_keystroke(void)
{
	if (_kbhit()) {
		char c = _getch();
		if (c >= 32) return c;
	}
	return 0;
}

 

  결과적으로 리눅스 Host PC 입장에서 전체 소스코드는 다음과 같이 구성됩니다.

 

 

  이제 Teensy Board를 리눅스 OS에 연결합니다. 저는 가상 머신(Virtual Machine)에서 실습을 진행하고 있으므로, PC에 꽂혀 있는 USB를 가상 머신에서 인식할 수 있도록 USB 장치 설정을 해주었습니다.

 

 

  이제 소스코드를 컴파일하고, my_hid 프로그램을 실행하시면 됩니다. 참고로 리눅스에서는 알 수 없는 USB 장치와 통신하기 위해서는 루트(Root) 권한이 필요합니다. 결과적으로 다음과 같이 프로그램이 실행됩니다.

 

 

  이후에 다음과 같이 2초마다 한 번씩 USB 장치로부터 64 바이트의 데이터가 날라오는 것을 확인할 수 있습니다. 또한 Host 입장에서도 어떠한 알파벳 키를 누르면 해당 데이터가 USB 장치로 전달됩니다. 서로 데이터를 주고 받는 것을 알 수 있습니다.

 

 

  또한 Makefile 코드에서 빌드 대상(Target)을 윈도우로 설정하여 컴파일하면 다음과 같이 윈도우 호스트 실행 파일이 생성됩니다. (만약에 이미 리눅스 버전으로 컴파일을 해서 my_hid 실행 파일이 존재한다면, 이를 모두 삭제한 뒤에 다시 컴파일을 진행하셔야 합니다.)

 

 

  다음과 같이 윈도우 호스트에서 실행을 해도 정상적으로 동작하는 것을 확인할 수 있습니다.

 

 

  최종적으로 호스트(Host)와 USB 장치가 통신하는 내용을 출력한 사진은 다음과 같습니다.

 

 

  이제 이러한 소스코드 예시를 조금씩 수정해서 자신만의 USB 프로토콜 상에서 동작하는 USB 장치를 개발할 수 있게 되었습니다. 현재 예시는 RawHID를 토대로 하여 작성된 예시이지만, HID가 아닌 본인만의 USB 클래스를 정의하고 출시할 때에도 이와 비슷한 과정을 거칠 것이라는 것을 알 수 있습니다.

728x90
반응형

728x90
반응형

※ 쓰레드(Thread) 사용 방법 ※

 

  Teensy 버전 3과 4에서는 쓰레드(Thread) 기능을 제공한다. 쓰레드를 이용하기 위해서는 아두이노 IDE에서 [스케치] - [라이브러리 포함하기]를 확인하자.

 

 

  여기에서 TeensyThreads를 선택하여 TeensyThread 라이브러리를 불러 올 수 있다.

 

 

  이후에 다음과 같은 예시 소스코드를 작성하여 실행해보자.

 

#include <TeensyThreads.h>

volatile int count = 0;

void thread_function(int data){
  while(1) {
    count += data;
  }
}

void setup() {
  threads.addThread(thread_function, 1);
}

void loop() {
  Serial.println(count);
}

 

  실제로 업로드하여 프로그램을 실행하면, 다음과 같이 count 변수의 값이 증가하며 출력된다.

 

 

※ 라이브러리가 없는 경우 ※

 

  혹시나 TeensyThread 라이브러리가 없다는 오류가 나온다면, 해당 라이브러리를 아두이노 라이브러리로 등록해주면 된다. 라이브러리 경로(https://github.com/ndb796/python-for-coding-test)로 접속하여 프로젝트 소스코드를 다운로드 할 수 있다. 아래와 같이 TeensyThreads.zip을 확인할 수 있다.

 

 

  압축 파일(zip)을 라이브러리로 포함시킬 때에도 마찬가지로 [스케치] - [라이브러리 포함하기]로 이동하면 된다.

 

 

  다음과 같은 경로의 압축 파일을 등록하면 된다.

 

 

728x90
반응형

728x90
반응형

  Teensy는 Teensyduino를 이용하여, 아두이노 IDE 상에서 프로그램을 작성할 수 있도록 지원하고 있습니다. 기본적으로 HalfKay 부트로더(Bootloader)가 동작하고 있을 때, Teensy Loader 프로그램이 Teensy Board와 통신하게 됩니다.

 

  ▶ Teensy Loader 다운로드 경로: https://www.pjrc.com/teensy/loader.html

 

  따라서 Teensy Loader 프로그램을 설치해야 합니다. Teensy Loader는 다양한 운영체제를 지원하고 있습니다. 자신의 운영체제에 맞는 프로그램을 설치하시면 됩니다. 저는 윈도우(Windows)를 이용하고 있기 때문에, 윈도우 프로그램을 다운로드 받았습니다. 

 

 

  운영체제별 Teensy Loader 설치 페이지에서는, 제공해주는 두 개의 파일을 모두 받도록 합니다.

 

 

  USB를 이용해 Teensy Board를 컴퓨터와 연결하면, 1초에 한 번씩 LED가 깜빡이는 프로그램이 동작하는 것을 확인할 수 있는데요. 이 상태에서 Teensy Loader 프로그램을 실행하면 다음과 같은 화면이 나옵니다.

 

 

  이 때 자신의 Teensy Board에 있는 버튼(Button)을 눌러 보시면, 프로그램 모드로 진입할 수 있습니다. 저는 Teensy Board 3.6을 사용하고 있는데요. 버전과 상관없이 Teensy Board에는 모두 버튼이 존재할 겁니다. 아무튼 버튼을 누르게 되면, Teensy Loader 프로그램도 다음과 같이 화면이 바뀝니다. 이것은 HalfKay가 동작하고 있다는 의미입니다.

 

 

  그리고 함께 다운로드 받은 Blink 프로그램 예제 압축파일의 압축을 풀어주시면, 다음과 같이 자신의 Teensy 버전에 맞는 프로그램 파일(.hex)을 확인하실 수 있습니다.

 

 

  이제 해당 파일을 우리의 Teensy Board에 업로드 해봅시다.

 

 

  업로드 이후에는 프로그램(Program) 버튼과 재부팅(Reboot) 버튼을 차례대로 클릭해 주시면, 우리가 업로드 한 프로그램 파일(.hex)이 정상적으로 Teensy Board 위에서 실행됩니다.

 

 

  실행 결과, 매우 빠르게 LED가 깜빡이는 프로그램 예제가 정상적으로 Teensy Board에서 실행되는 것을 확인할 수 있었습니다. 가장 먼저 아두이노 IDE를 실행해서 [보드]에서 자신의 버전에 맞는 Teensy Board를 선택합니다.

 

 

  이후에 Teensy 예제 프로젝트 소스코드를 확인하실 수 있습니다. 가장 기본적인 Blink 프로젝트를 열어 봅시다.

 

 

  프로젝트를 확인하신 이후에는 소스코드를 확인 하시고 [확인/컴파일] 버튼을 눌러서 컴파일 해볼 수 있습니다.

 

 

  이후에 소스코드를 업로드 하기 전에 USB를 이용해 Teensy Board와 컴퓨터를 연결하고, 해당 포트를 선택합니다.

 

 

  최종적으로 코드를 업로드하면, 우리가 작성한 코드에 맞게 정상적으로 Teensy Board가 동작합니다.

 

 

※ 소스코드 수정해보기 ※

 

  다음과 같이 소스코드를 수정해서 다시 [스케치] - [확인/컴파일]을 진행합니다. 그리고 [스케치] - [업로드]에 들어가면 됩니다.

 

 

  그러면 이제 우리의 Teensy 보드가 3초 동안 LED를 빛냈다가, 0.5초 동안 껐다가를 반복하게 됩니다.

 

※ 추가 예시 ① Serial 통신 예시

 

  기본적으로 앞으로의 예시들을 수행할 때는 다음과 같이 [툴] - [USB Type]에서 적절한 타입(Type)을 설정해주어야 합니다. USB Type을 제대로 설정해야 관련 라이브러리들을 불러오기 때문에, Type이 제대로 설정되어 있지 않으면 소스코드 오류가 발생할 수 있습니다.

 

 

  바로 기본적인 Teensy 예제에서 [USB Serial] - [HelloWorld]를 확인할 수 있습니다.

 

 

  이 예제는 업로드 이후에 [시리얼 모니터]를 확인하면 됩니다.

 

 

  시리얼 모니터를 통해서 Teensy가 보내는 시리얼 메시지를 확인할 수 있습니다.

 

 

※ 추가 예시 ② 키보드 예시 ※

 

  또한 키보드(Keyboard) 예시도 한 번 실행해보면 좋습니다. 이 예시는 우리의 Teensy 보드를 키보드처럼 인식하고, Teensy 보드가 특정한 문자열을 입력한 것처럼 인식이 되도록 해줍니다.

 

 

  소스코드를 보면, 우리의 Teensy 보드가 5초에 한 번씩 "Hello World"라는 문장을 입력하는 키보드가 되는 것을 알 수 있습니다. 사실 이런 특징을 이용하면 꽂기만 하면 특정 작업을 수행하는 물리적 장치를 만드는 것도 가능할 것으로 보이네요. 예를 들어 꽂기만 하면 윈도우(Windows) 키를 누르거나 하는 작업도 가능할 것입니다.

 

 

※ 추가 예시 ③ 마우스 예시 ※

 

  또한 마우스 예시도 있습니다.

 

 

  소스코드를 실행하면 삼각형 형태로 반복적으로 마우스가 움직이게 됩니다.

 

 

728x90
반응형