Synology NAS(DS216+II)에서 FTDI 장치를 C/C++로 제어
지난 글에서 살펴본 FTDI 장치도,
PC에 연결해 동작하는 자신만의 USB 장치 만들어 보기
; https://www.sysnet.pe.kr/2/0/11606
Raspberry PI Zero (W)에 FTDI 장치 연결 후 C/C++로 DTR 제어
; https://www.sysnet.pe.kr/2/0/11716
DS216+II 제품에 그냥 USB 케이블로 연결하면 다음과 같이 "FT232 Serial (UART) IC - Future Technology Devices International, Ltd" 장치로 인식이 됩니다.
연결 및 해제 시 dmesg 로그를 보면 마지막에 다음의 라인이 추가되는데,
[연결했을 때]
usb 1-2: new full-speed USB device number 4 using xhci_hcd
[해제했을 때]
usb 1-2: USB disconnect, device number 4
메시지로 봐서는 USB 장치로써만 인식했을 뿐 Serial 장치로 인식은 안 한 것입니다. 일례로
라즈베리 파이 제로에 연결했을 때는, "FTDI USB Serial Device converter now attached to ttyUSB0"와 같은 메시지로 "ttyUSB0" 장치에 연결되었으므로 명백히 직렬 통신을 할 수 있었지만 "usb 1-2: new full-speed USB device number 4 using xhci_hcd" 이 정도의 메시지로는 그냥 범용 USB 장치가 연결된 것에 불과하므로 직렬 통신 코드를 사용할 수 없습니다.
그런데, 저 장치 정도의 인식만으로 제어를 할 수 있는 라이브러리가 있습니다.
D2XX Direct Drivers
; https://www.ftdichip.com/Drivers/D2XX.htm
FTDI Drivers Installation Guide for Linux - FTDI Chip
; https://www.ftdichip.com/Support/Documents/AppNotes/AN_220_FTDI_Drivers_Installation_Guide_for_Linux.pdf
문서에 따라, 우선 다음의 파일을 내려받아 압축을 해제하고,
~# sudo -i
~# https://www.ftdichip.com/Drivers/D2XX/Linux/libftd2xx-x86_64-1.4.8.gz // DS216+II 모델의 경우 Intel CPU이므로
~# gunzip libftd2xx1.1.12.tar.gz
~# tar -xvf libftd2xx1.1.12.tar
링크를 걸어준 후 실행 옵션을 변경합니다.
~# cp ./releases/build/lib* /usr/local/lib
~# cd /usr/local/lib
~# ln -s libftd2xx.so.1.1.12 libftd2xx.so
~# chmod 0755 libftd2xx.so.1.1.12
그다음 빌드를 해야 하는데 다음의 글에 따라 gcc 환경을 갖춰야 합니다.
Synology NAS(DS216+II)에 gcc 컴파일러 설치
; https://www.sysnet.pe.kr/2/0/11705
Synology NAS(DS216+II)에서 실행한 gcc의 Segmentation fault
; https://www.sysnet.pe.kr/2/0/11706
이와 함께 make 도구도 설치한 다음,
~# opkg install make
Installing make (4.2.1-2) to root...
Downloading http://pkg.entware.net/binaries/x86-64/make_4.2.1-2_x86-64.ipk
Configuring make.
빌드할 디렉터리로 이동해,
cd ./release/examples
Makefile의 내용에 CC를 gcc로 명명해 줍니다.
export CC = gcc
SUBDIRS = \
BitMode \
EEPROM/erase \
EEPROM/read \
EEPROM/write \
EEPROM/user/read \
EEPROM/user/size \
EEPROM/user/write \
Events \
LargeRead \
loopback \
MultiThread \
SetVIDPID \
Simple \
static \
Timeouts \
W32/escapeseq \
W32/events \
W32/simple \
W32/timeouts \
write \
all: subdirs
subdirs:
for n in $(SUBDIRS); do "$(MAKE)" -C $$n || exit 1; done
clean:
rm -f *.o *~
for n in $(SUBDIRS); do "$(MAKE)" -C $$n clean; done
자, 이제 빌드를 하고 ^^
~# make -B
FTDI 장치를 연결한 후 빌드된 예제 중의 하나인 read 프로그램을 수행해 보면,
$ cd ./EEPROM/read
$ ./read
다음과 같은 식의 출력 결과를 확인할 수 있습니다.
~# ./read
Library version = 0x10408
Opening port 0
FT_Open succeeded. Handle is 0x2582910
FT_GetDeviceInfo succeeded. Device is type 5.
FT_EE_Read succeeded.
Signature1 = 0
Signature2 = -1
Version = 2
VendorId = 0x0403
ProductId = 0x6001
Manufacturer = FTDI
ManufacturerId = A9
Description = FT232R USB UART
SerialNumber = A901J4AU
MaxPower = 90
PnP = 0
SelfPowered = 0
RemoteWakeup = 1
232R:
-----
UseExtOsc = 0x0
HighDriveIOs = 0x0
EndpointSize = 0x40
PullDownEnableR = 0x0
SerNumEnableR = 0x1
InvertTXD = 0x0
InvertRXD = 0x0
InvertRTS = 0x0
InvertCTS = 0x0
InvertDTR = 0x0
InvertDSR = 0x0
InvertDCD = 0x0
InvertRI = 0x0
Cbus0 = 0x3
Cbus1 = 0x2
Cbus2 = 0x0
Cbus3 = 0x1
Cbus4 = 0x5
RIsD2XX = 0x0
Returning 0
일단은 좋은 소식입니다. 그런데, 소스 코드를 보면 직렬 통신을 이용하지 않고 FTDI 라이브러리를 직접 사용하는 것을 볼 수 있습니다.
$ cat main.c
/*
To build use the following gcc statement
(assuming you have the d2xx library in the /usr/local/lib directory).
gcc -o read main.c -L. -lftd2xx -Wl,-rpath,/usr/local/lib
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "../../ftd2xx.h"
int main(int argc, char *argv[])
{
FT_STATUS ftStatus;
FT_HANDLE ftHandle0;
int iport;
static FT_PROGRAM_DATA Data;
static FT_DEVICE ftDevice;
DWORD libraryVersion = 0;
int retCode = 0;
ftStatus = FT_GetLibraryVersion(&libraryVersion);
if (ftStatus == FT_OK)
{
printf("Library version = 0x%x\n", (unsigned int)libraryVersion);
}
else
{
printf("Error reading library version.\n");
return 1;
}
if(argc > 1) {
sscanf(argv[1], "%d", &iport);
}
else {
iport = 0;
}
printf("Opening port %d\n", iport);
ftStatus = FT_Open(iport, &ftHandle0);
if(ftStatus != FT_OK) {
/*
This can fail if the ftdi_sio driver is loaded
use lsmod to check this and rmmod ftdi_sio to remove
also rmmod usbserial
*/
printf("FT_Open(%d) failed\n", iport);
return 1;
}
printf("FT_Open succeeded. Handle is %p\n", ftHandle0);
ftStatus = FT_GetDeviceInfo(ftHandle0,
&ftDevice,
NULL,
NULL,
NULL,
NULL);
if (ftStatus != FT_OK)
{
printf("FT_GetDeviceType FAILED!\n");
retCode = 1;
goto exit;
}
// ...[생략]...
FT_Close(ftHandle0);
printf("Returning %d\n", retCode);
return retCode;
}
비록 시리얼 통신으로 제어할 수는 없지만 일단 어떻게든 제어할 수 있게 되었으니 이 정도에서 ^^ 만족하겠습니다.
참고로, FTDI 장치를 연결한 상태에서 lsusb 명령어를 내리면 다음과 같은 출력을 보입니다.
$ lsusb
|__usb1 1d6b:0002:0310 09 2.00 480MBit/s 0mA 1IF (xhci_hcd 0000:00:14.0) hub
|__1-2 0403:6001:0600 00 2.00 12MBit/s 90mA 1IF (FTDI FT232R USB UART A901J4AU)
|__1-5 f400:f400:0100 00 2.00 480MBit/s 200mA 1IF (Synology DiskStation 650076B3CCCA6016)
|__usb2 1d6b:0003:0310 09 3.00 5000MBit/s 0mA 1IF (xhci_hcd 0000:00:14.0) hub
출력 결과의 xxxx:xxxx:xxxx 형식은 각각 device_id:vendor_id:revision을 의미합니다. 예를 들어, usb1의 1-2 장치인 경우 device id = 0x0403, vendor id = 0x6001, revision = 6.0이 됩니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]