안경잡이개발자

728x90
반응형

  USB 장치(device)는 태생적으로 하나의 장치가 여러 개의 기능(function)을 제공할 수 있도록 만들어졌다. 참고로 여기에서 기능(function)이란 USB 프로토콜 상에서 인터페이스(interface)를 의미한다. 예를 들어 마우스(mouse), 키보드(keyboard), HID 장치, 대용량 저장소(mass storage) 등은 각각 하나의 기능(function)이다. 이후에 각 기능은 한 개 이상의 엔드포인트(endpoint)를 가질 수 있으며, 이를 통해 호스트(host) PC와 USB 프로토콜에 맞게 데이터를 주고받는다.

 

출처: Texas Instruments 교육 자료

 

  이번 포스팅에서는 Raspberry Pi Zero W를 이용해 멀티 가젯(multi-gadget) USB 장치를 만드는 방법을 소개하고자 한다. 우리의 라즈베리 파이를 일종의 USB 장치로 쓰면서, 동시에 대용량 저장소나 마우스 등의 다양한 기능을 제공하는 기기가 될 수 있도록 하는 것이다.

 

※ 기초 환경 설정 ※

 

  가장 먼저 USB OTG 기능을 제공하기 위해 라즈베리 파이의 /boot/config.txt 파일을 열어서 제일 마지막 줄에 다음의 코드를 추가한다. dwc2 USB 드라이버를 사용할 수 있도록 하는 것이다.

 

dtoverlay=dwc2

 

  Raspberry Pi Zero W를 기준으로 다음과 같다.

 

 

  이어서 /etc/modules의 마지막 줄에 다음 두 개의 커널 모듈을 넣어주자. 부팅 과정에서 아래의 두 모듈을 자동으로 로드하여 사용할 수 있도록 한다. 만약 부팅과 동시에 멀티 가젯 기능을 제공하지는 않고 수동적으로 필요할 때마다 기능을 제공하고 싶다면 libcomposite는 빼고 넣어주도록 하자.

dwc2 
libcomposite 

 

 

  이때 libcomposite 커널 모듈이 핵심적인 역할을 수행한다. 이 모듈은 여러 개의 가젯(gadget)을 한꺼번에 활성화 할 수 있도록 해준다. 일반적으로 USB 가젯(gadget) 모드란, 리눅스 시스템을 호스트 컴퓨터의 입장에서 보았을 때 USB 장치(device)인 것처럼 보이게 하는 방법을 의미한다. 우리의 Raspberry Pi를 HID 장치나 Mass Storage Class (MSC)처럼 보이게 만들 수 있다.

 

  이러한 배경에서 USB 가젯 기능을 제공하되, 한 번에 여러 개의 USB 디바이스 기능을 제공하려면 libcomposite 모듈을 사용할 수 있다. 이를 이용하면 나의 Raspberry Pi Zero W가 동시에 3개의 USB 대용량 저장소이면서, 그와 동시에 마우스와 키보드의 역할을 수행하도록 만들 수 있다. 이처럼 간단하게 여러 개의 USB 장치 역할을 수행하도록 만들 수 있다.

 

※ 멀티 가젯(Multi-gadget) 모드 확인 ※

 

  이제 /sys/kernel/config/usb_gadget/ 폴더를 활성화해야 한다. 이 폴더 안에서 규칙에 맞게 생성된 파일들을 통해 실제로 multi-gadget 역할을 수행할 수 있다. 이 폴더는 libcomposite 모듈을 커널에 적재함으로써 활성화할 수 있다. 앞서 우리는 재부팅을 했을 때 리눅스 커널 모듈 중에서 libcomposite이 불러와지도록 만들었다. 자동으로 모듈을 불러오도록 설정하지 않았다면 modprobe 명령을 이용해 수동으로 적재하자.

 

  modprobe 명령어커널 모듈(kernel module)을 리눅스 커널에 추가하거나 커널로부터 제거할 때 사용할 수 있다. 원래 모듈을 추가하거나 제거할 때는 insmod나 rmmod를 사용할 수 있는데, modprobe는 더욱 다양한 기능을 제공한다. modprobe는 모듈을 올릴 때 여러 개의 모듈을 한꺼번에 올릴 수 있으며, 의존성이 있는 모듈도 같이 적재할 수 있다.

 

  재부팅하지 않고 바로 libcomposite을 적재하기 위해서는 다음과 같은 명령어를 입력하면 된다. (/etc/modules에 libcomposite을 추가했다면 sudo reboot 명령을 통해 재부팅 하자.)

 

sudo modprobe libcomposite

 

  이후에 /sys/kernel/config/usb_gadget 경로가 생긴 것을 확인할 수 있다. 이제 이 경로에 각종 환경 설정 파일을 생성하여 우리의 라즈베리 파이가 USB 가젯으로 동작하게 만들 수 있다.

 

 

※ 환경 설정 스크립트 만들기 ※

 

  Texas Instruments 교육 자료를 보면 USB 멀티 가젯(multi-gadget) 구조를 쉽게 확인할 수 있다. 바로 다음과 같은 형태로 파일을 배치하면 그에 맞게 다양한 기능(function)이 동작한다.

 

출처: Texas Instruments 교육 자료

 

  따라서 이러한 구조에 맞게 파일을 생성하는 하나의 환경 설정 스크립트를 작성하는 것이 좋다.

 

sudo touch /usr/bin/my_usb # 파일 생성
sudo chmod +x /usr/bin/my_usb # 실행할 수 있도록 만들기

 

 

  이제 이러한 환경 설정 스크립트를 작성해보자.

 

sudo nano /usr/bin/my_usb # 스크립트 작성하기

 

가장 먼저 global configuration에 대하여 작성할 필요가 있다. 앞서 말했듯이 하나의 configuration 안에 여러 개의 기능(function)이 들어가 있는 형태로 동작한다. 따라서 일단 기능(function) 부분은 제외하고 configuration 관련 내용을 작성하여 전체적인 틀을 잡도록 하자.

 

#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p my_usb
cd my_usb

# 기본적인 USB 클래스 명시
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2

# 내가 만들 USB 장치의 기본적인 이름
mkdir -p strings/0x409
echo "0123456789abcdef" > strings/0x409/serialnumber
echo "Dongbin Na" > strings/0x409/manufacturer
echo "My USB" > strings/0x409/product

# 하나의 Configuration 정보 작성
mkdir -p configs/c.1/strings/0x409
echo "My USB Config 1" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

# 실질적으로 USB 기능(function)들이 들어갈 공간

# UDC (Usb Device Controller)
ls /sys/class/udc > UDC

 

※ 대용량 저장소(Mass Storage) 기능 추가하기 ※

 

  필자는 개인적으로 Mass Storage Class (MSC) 기능이 필요한 상황이다. 따라서 Mass Storage 기능을 추가하는 방법을 소개한다. 일단 가장 먼저 블록 장치(block device)를 만들 필요가 있다. 라즈베리파이를 USB 대용량 저장소로 보이도록 만들고 싶다면, 호스트(host) PC 입장에서는 블록 단위로 접근할 필요가 있기 때문이다.

 

  필자는 다음과 같이 2개의 이미지를 만들었다. 이미지 내에서 하나의 블록 크기(block size)는 1,048,576 바이트(1Mb)로 설정했다. 이후에 mkdosfs 명령어를 이용해 파일 시스템 형태로 포맷(format)할 수 있도록 한다.

 

mkdir -p /home/pi/images

# 1Gb 이미지 생성
dd if=/dev/zero of=/home/pi/images/usbdisk1.img bs=1048576 count=1024
mkdosfs /home/pi/images/usbdisk1.img

# 500Mb 이미지 생성
dd if=/dev/zero of=/home/pi/images/usbdisk2.img bs=1048576 count=512
mkdosfs /home/pi/images/usbdisk2.img

 

 

  이제 기능(function) 부분에 다음과 같은 코드를 추가하자. 필자는 다음과 같이 총 2개의 Mass Storage를 제공할 수 있도록 2개의 기능을 명시했다.

 

################# Mass Storage 1 #################
# 첫 번째 이미지 지정하기
FILE1=/home/pi/images/usbdisk1.img

# 해당 이미지에 마운트(mount) 진행하기
mkdir -p ${FILE1/img/d}
mount -o loop,ro, -t vfat $FILE1 ${FILE1/img/d} # 라즈베리 파이 입장에서는 읽기 전용(read-only)

# USB 기능(function) 작성하기 (kernel.org reference 참고하기)
mkdir -p functions/mass_storage.usb0
echo 1 > functions/mass_storage.usb0/stall
echo 0 > functions/mass_storage.usb0/lun.0/cdrom
echo 0 > functions/mass_storage.usb0/lun.0/ro # 호스트 입장에서는 쓰기 가능
echo 0 > functions/mass_storage.usb0/lun.0/nofua
echo $FILE1 > functions/mass_storage.usb0/lun.0/file # 이미지 파일 명시하기

# 만들어진 기능(function) 사용할 수 있도록 설정
ln -s functions/mass_storage.usb0 configs/c.1/

################# Mass Storage 2 #################
# 두 번째 이미지 지정하기
FILE2=/home/pi/images/usbdisk2.img

# 해당 이미지에 마운트(mount) 진행하기
mkdir -p ${FILE2/img/d}
mount -o loop,ro, -t vfat $FILE2 ${FILE2/img/d} # 라즈베리 파이 입장에서는 읽기 전용(read-only)

# USB 기능(function) 작성하기 (kernel.org reference 참고하기)
mkdir -p functions/mass_storage.usb1
echo 1 > functions/mass_storage.usb1/stall
echo 0 > functions/mass_storage.usb1/lun.0/cdrom
echo 0 > functions/mass_storage.usb1/lun.0/ro # 호스트 입장에서는 쓰기 가능
echo 0 > functions/mass_storage.usb1/lun.0/nofua
echo $FILE2 > functions/mass_storage.usb1/lun.0/file # 이미지 파일 명시하기

# 만들어진 기능(function) 사용할 수 있도록 설정
ln -s functions/mass_storage.usb1 configs/c.1/

 

※ 두 개의 Mass Storage 장치 전체 스크립트 ※

 

  두 개의 Mass Storage를 이용하는 예제의 전체 /usr/bin/my_usb 스크립트 최종본은 다음과 같다.

 

#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p my_usb
cd my_usb

# 기본적인 USB 클래스 명시
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2

# 내가 만들 USB 장치의 기본적인 이름
mkdir -p strings/0x409
echo "0123456789abcdef" > strings/0x409/serialnumber
echo "Dongbin Na" > strings/0x409/manufacturer
echo "My USB" > strings/0x409/product

# 하나의 Configuration 정보 작성
mkdir -p configs/c.1/strings/0x409
echo "My USB Config 1" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

################# Mass Storage 1 #################
# 첫 번째 이미지 지정하기
FILE1=/home/pi/images/usbdisk1.img

# 해당 이미지에 마운트(mount) 진행하기
mkdir -p ${FILE1/img/d}
mount -o loop,ro, -t vfat $FILE1 ${FILE1/img/d} # 라즈베리 파이 입장에서는 읽기 전용(read-only)

# USB 기능(function) 작성하기 (kernel.org reference 참고하기)
mkdir -p functions/mass_storage.usb0
echo 1 > functions/mass_storage.usb0/stall
echo 0 > functions/mass_storage.usb0/lun.0/cdrom
echo 0 > functions/mass_storage.usb0/lun.0/ro # 호스트 입장에서는 쓰기 가능
echo 0 > functions/mass_storage.usb0/lun.0/nofua
echo $FILE1 > functions/mass_storage.usb0/lun.0/file # 이미지 파일 명시하기

# 만들어진 기능(function) 사용할 수 있도록 설정
ln -s functions/mass_storage.usb0 configs/c.1/

################# Mass Storage 2 #################
# 두 번째 이미지 지정하기
FILE2=/home/pi/images/usbdisk2.img

# 해당 이미지에 마운트(mount) 진행하기
mkdir -p ${FILE2/img/d}
mount -o loop,ro, -t vfat $FILE2 ${FILE2/img/d} # 라즈베리 파이 입장에서는 읽기 전용(read-only)

# USB 기능(function) 작성하기 (kernel.org reference 참고하기)
mkdir -p functions/mass_storage.usb1
echo 1 > functions/mass_storage.usb1/stall
echo 0 > functions/mass_storage.usb1/lun.0/cdrom
echo 0 > functions/mass_storage.usb1/lun.0/ro # 호스트 입장에서는 쓰기 가능
echo 0 > functions/mass_storage.usb1/lun.0/nofua
echo $FILE2 > functions/mass_storage.usb1/lun.0/file # 이미지 파일 명시하기

# 만들어진 기능(function) 사용할 수 있도록 설정
ln -s functions/mass_storage.usb1 configs/c.1/

# UDC (Usb Device Controller)
ls /sys/class/udc > UDC

 

  최종적으로 대략 다음과 같이 작성된다. (후반부 생략)

 

 

  이제 이러한 스크립트를 sudo 권한으로 실행하면 곧바로 USB 멀티 가젯 기능이 제공된다.

 

 

  이후에 호스트(host) PC에 연결하면 다음과 같이 정상적으로 대용량 저장소로 인식된다. 윈도우(Windows)와 우분투(Ubuntu) 모두에서 정상적으로 인식되는데, 윈도우 장치 관리자로 보았을 때는 다음과 같다.

 

 

  앞서 만들었던 두 개의 이미지(image)가 정상적으로 인식된다.

 


※ 내 스크립트가 자동으로 실행될 수 있도록 하기 ※

 

  또한 라즈베리파이가 재부팅되면 곧바로 스크립트가 실행되도록 설정할 수 있다. (단, 이게 정상적으로 동작하려면 앞서 /etc/modules에 libcomposite을 추가한 상태여야 한다.) /etc/rc.local을 수정하자. 리눅스는 부팅을 진행하는 과정에서 /etc/rc.local 스크립트를 자동으로 실행한다.

 

sudo nano /etc/rc.local

 

  이후에 exit 0 위쪽 라인에 /usr/bin/my_usb를 추가하자. 라즈베리파이 구동 이후에 자동으로 우리가 작성했던 스크립트를 구동하도록 만드는 것이다.

 

 

  이제 재부팅(reboot)을 진행한다.

 

 

  그러면 재부팅 이후에는 라즈베리파이를 연결만 하면 자동으로 Mass Storage 형태로 인식이 된다.

 

 

  다만 간혹 두 개의 Mass Storage를 이용하도록 했으나 하나만 인식되는 문제가 발생하거나, 연결이 되었다가 안 되었다가 하는 문제가 발생할 수 있다. 이럴 때는 데이터 공급선(USB OTG)이 정상적으로 연결되어 있는지를 다시 한 번 체크해보도록 하자. 혹은 호스트(host) PC의 다른 포트로 연결하면 잘 동작하는 경우가 있다.

 

※ 동적으로 Mass Storage 이미지 변경하기 ※

 

  Mass Storage 목적으로 리눅스 가젯(gadget) 드라이버를 활용한다면, 다양한 기능에 대하여 추가적으로 알아 두면 좋다. 참고로 Mass Storage의 경우 동적으로 블록 장치(block device)를 변경할 수 있다. 동적으로 블록 장치를 변경해 보기 위하여 하나의 블록 장치를 만들어 보자.

 

# 500Mb 이미지 생성
dd if=/dev/zero of=/home/pi/images/usbdisk3.img bs=1048576 count=512
mkdosfs /home/pi/images/usbdisk3.img

 

  이후에 Mass Storage 기능이 제공되고 있는 상황에서 다음과 같은 명령어를 입력하여 동적으로 블록 장치 이미지를 변경할 수 있다.

 

sudo bash -c 'echo "/home/pi/usbdisk3.img" > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb0/lun.0/file'

 

※ 동적으로 멀티 가젯(Gadget) 기능 올리거나 내리기 ※

 

  라즈베리파이를 호스트(host) PC에 연결한 상태에서 원할 때 멀티 가젯 기능을 열거나 닫는 작업도 가능하다. 다음과 같이 예시로 2개의 Mass Storage 기능을 제공하는 라즈베리파이가 있다고 해보자.

 

 

  가젯(gadget) 기능을 enabling 하기 위해서는 UDC(USB Device Controller)에 바운딩을 시킬 필요가 있다. 같은 원리로 disabling을 할 때는 바운딩을 해제하면 되는 것이다. 따라서 다음과 같은 명령을 실행하면 전원은 공급된 상태에서 가젯 기능만 뺄 수 있다.

 

sudo bash -c 'echo "" > /sys/kernel/config/usb_gadget/my_usb/UDC'

 

 

  다음의 명령어를 입력하면 다시 가젯 기능이 활성화된다.

 

sudo bash -c 'ls /sys/class/udc > /sys/kernel/config/usb_gadget/my_usb/UDC'

 

※ 동적으로 특정 가젯(Gadget) 올리거나 내리기 ※

 

  1) 동적으로 특정한 가젯을 새롭게 올리기

 

  그렇다면 라즈베리파이호스트(host) PC에 연결한 상태에서 원할 때 특정한 가젯 기능만을 열거나 닫고자 한다면 어떻게 할 수 있을까? 사실 우리가 Mass Storage USB를 이용할 때는, 그냥 물리적으로 USB를 PC에서 빼면 연결이 해제된다. 하지만 라즈베리파이에서 여러 개의 가젯(gadget) 기능을 제공하고 있을 때는 어떻게 하나의 기능만 제거할 수 있을지 알아보자. 현재의 라즈베리파이가 다음과 같이 2개의 MSC를 제공한다고 해보자.

 

 

  이제 간단히 하나의 블록 장치를 만들어 보자.

 

# 500Mb 이미지 생성
dd if=/dev/zero of=/home/pi/images/usbdisk4.img bs=1048576 count=512
mkdosfs /home/pi/images/usbdisk4.img

 

  이후에 라즈베리파이에서 다음의 코드를 실행해보자.

 

# 특정 이미지에 마운트(mount) 진행하기
sudo mkdir -p /home/pi/images/usbdisk4.d
sudo mount -o loop,ro, -t vfat /home/pi/images/usbdisk4.img /home/pi/images/usbdisk4.d # 라즈베리 파이 입장에서는 읽기 전용(read-only)

# USB 기능(function) 작성하기 (kernel.org reference 참고하기)
sudo mkdir -p /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2
sudo bash -c 'echo 1 > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2/stall'
sudo bash -c 'echo 0 > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2/lun.0/cdrom'
sudo bash -c 'echo 0 > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2/lun.0/ro' # 호스트 입장에서는 쓰기 가능
sudo bash -c 'echo 0 > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2/lun.0/nofua'
sudo bash -c 'echo /home/pi/images/usbdisk4.img > /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2/lun.0/file' # 이미지 파일 명시하기

# 만들어진 기능(function) 사용할 수 있도록 설정
sudo ln -s /sys/kernel/config/usb_gadget/my_usb/functions/mass_storage.usb2 /sys/kernel/config/usb_gadget/my_usb/configs/c.1/

 

  단순히 위 코드를 실행하는 것으로는 동적으로 반영되지 않는 것을 알 수 있다. 다음의 두 코드를 추가적으로 실행하여 UDC를 재동작 시켰을 때 비로소 정상적으로 동작한다. 참고로 단순히 호스트(Host) PC와 라즈베리파이 사이의 데이터 케이블을 연결을 해제하고 다시 연결하는 작업만으로는 정상적으로 새 기능이 추가되지 않는다.

 

  반면에 /sys/kernel/config/usb_gadget/my_usb/UDC의 값을 공백으로 바꾸었다가 다시 정상적인 UDC 값을 기입하면 새 기능이 추가되어 재연결 된 것을 확인할 수 있다.

 

sudo bash -c 'echo "" > /sys/kernel/config/usb_gadget/my_usb/UDC'
sudo bash -c 'ls /sys/class/udc > /sys/kernel/config/usb_gadget/my_usb/UDC'

 

  아무튼 케이블을 뺐다가 다시 끼지 않더라도 기능을 변경할 수 있다는 점은 확실하다.

 

 

  2) 동적으로 특정한 가젯을 내리기

 

  특정한 가젯을 내릴 때에도 비슷하다. configuration에서 바운딩 된 mass_storage.usb2 기능(function)을 다음과 같은 명령어로 동적으로 제거할 수 있다.

 

sudo rm /sys/kernel/config/usb_gadget/my_usb/configs/c.1/mass_storage.usb2

 

  물론 이 명령을 실행하면 configuration 정보가 바뀌기 때문에 UDC의 값이 자동으로 공백으로 바뀌어 호스트(Host) PC와의 연결이 해제될 수 있다. 따라서 가젯을 제거한 뒤에는 다음과 같이 UDC 값을 갱신할 필요가 있다.

 

sudo bash -c 'ls /sys/class/udc > /sys/kernel/config/usb_gadget/my_usb/UDC'

 

  결과적으로 호스트 PC는 다시 USB를 인식하고, 하나의 Mass Storage 기능이 정상적으로 제거된 것을 알 수 있다.

 

 

※ (추가) Serial로 터미널 접속하기 ※

 

  Serial을 열어서 터미널로 접속할 수도 있다. (사실 굳이 사용할 이유가 없는 경우가 많다.) 이를 위해 다음과 같은 내용을 환경 설정 파일에 추가한다. 그리고 재부팅을 하면 라즈베리파이에 /dev/ttyGS0 디바이스가 생성된다. 이 디바이스를 이용하여 통신이 가능하다.

 

mkdir -p functions/acm.usb0
ln -s functions/acm.usb0 configs/c.1/

 

  이어서 라즈베리파이에서 USB 시리얼 콘솔 접속을 활성화 해주자.

 

sudo systemctl enable getty@ttyGS0.service

 

  호스트(host) PC 입장에서는 다음과 같이 PuTTY를 이용하여 접속할 수 있다. 윈도우(Windows)의 경우 장치 관리자에서 COM 포트 번호를 확인한 뒤에 115200 레이트로 접속하면 된다.

 

 

  그러면 다음과 같이 성공적으로 접속된다.

 

 

※ (추가) Serial로 통신하기 ※

 

  Serial을 터미널 접속용이 아니라 데이터 주고 받기용으로 사용할 수도 있다. 설정 파일에 다음의 내용을 추가하고 재부팅 해보자.

 

mkdir -p functions/acm.usb1
ln -s functions/acm.usb1 configs/c.1/

 

  그러면 라즈베리파이에서는 /dev/ttyGS1이 추가적으로 생성된다. 이제 이걸로 데이터를 주고 받아보도록 하자.

 

  1) 호스트가 데이터를 보낼 때

 

  호스트의 파이썬 3.7 프로그램은 다음과 같다.

 

import serial

values = [1, 2, 3, 4, 5, 6, 7, 8, 9]

s = serial.Serial("COM7", 115200)
s.write(b'Hello\n')
s.close()

 

  라즈베리파이 쪽에서는 다음과 같이 /dev/ttyGS1에 적힌 내용을 확인하면 된다.

 

 

  2) 호스트가 데이터를 받을 때

 

  호스트의 파이썬 3.7 프로그램은 다음과 같다.

 

import serial

s = serial.Serial("COM7", 115200)

while True:
    data = s.readline()
    print(data)

s.close()

 

  라즈베리파이 쪽에서는 다음과 같이 /dev/ttyGS1를 통해 데이터를 전송하면 된다.

 

 

  그러면 다음과 같이 호스트 쪽에서는 데이터를 받을 수 있게 된다.

 

 

  이어서 라즈베리파이가 보내는 데이터를 있는 대로 계속 받아서 파일에 바이트 스트림(byte stream)으로 저장하려면 다음과 같이 하면 된다.

 

import serial

s = serial.Serial("COM7", 115200)
total = 0

while True:
    len = s.inWaiting()
    if len == 0:
        continue
    f = open("log.dat", "ab")
    data = s.read(len)
    f.write(data)
    f.close()
    total += len
    print(f"total length:", total)

s.close()

 

  그러면 파이썬 프로그램이 계속 실행되고, 라즈베리파이로부터 받은 데이터를 그대로 log.dat에 계속 쓴다.

 

 

  (참고) Serial을 데이터 송수신 목적으로 사용하는 경우에는 raw 모드로 데이터를 전송할 필요가 있다. 그렇지 않으면 \b10을 보냈을 때 \b13\b10의 형태로 보내지는 문제가 발생할 수 있다.

 

※ Mass Storage Class를 Boot Device로 사용할 때 ※

 

  이 케이스는 흔한 케이스는 아니지만, 필자는 연구 목적으로 Raspberry Pi의 Mass Storage Class를 Boot Device로 사용해 본 경험이 있다. 만약 Raspberry Pi Zero W를 부팅 디스크로 사용한다고 하면, 호스트(host) PC의 UEFI 단계에서 Raspberry Pi를 부팅 디스크로 잡아 OS를 부팅하게 된다. 다만 이때 Multi Composite Gadget을 이용하면 OS 부팅 단계에서 오류가 발생할 수 있다.

 

  구체적으로 필자는 g_mass_storage를 올릴 때만 동작하고, Multi Composite Gadget을 사용했을 때 Booting이 안 되는 문제가 발생했었다. g_mass_storage 모듈을 이용했을 때 USB 장치의 기본 Vendor ID는 0x0525, Product ID는 0xA4A5이다. 반면에 Composite Gadget은 일반적으로 Vendor ID 0x1D6B, Product ID 0x0104를 사용한다.

 

  100% 확신하는 것은 아니지만, OS 부팅 과정에서 Well-known이 아닌 Identifier를 사용하면 OS를 올리는 과정에서 USB Reconnection이 이루어지며, 이 과정에서 Mass Storage와의 연결이 일시적으로 해제되어 부팅이 안 되었던 것으로 보인다. 그래서 기존의 Raspberry Pi의 config 파일에서 Vendor ID와 Product ID를 g_mass_storage와 동일하게 맞추어 실행했더니 문제가 해결된 적이 있었다. 이렇게 해도 Multi Composite Gadget의 기능을 가지며 정상 동작하는 것을 확인했다.

728x90
반응형