스토리
나는 과학 카메라 용 드라이버를 프로그래밍하고있어 후 비동기 TRANSFER_NO_DEVICE 상태. Cypress FX3 USB 주변기기 컨트롤러를 사용합니다. 그것과 통신하기 위해서 저는 파이썬, 특히 모듈 usb1에 libusb1을 사용하고 있습니다. 내 OS는 우분투 16.04 LTS입니다. 카메라가 구성파이썬 libusb1 : 단지 성공 syncronous 전송
:
통신은 두 단계를 갖는다. 컴퓨터는 카메라를 프로그래밍하기위한 명령을 동 기적으로 전송하고 각 명령 후에 카메라는 동 기적으로 읽힌 상태 어로 응답합니다.
사진을 찍습니다. 컴퓨터가 동 기적으로 단일 명령을 보내고 카메라가 스트리밍 데이터를 시작합니다. 컴퓨터는 비동기 방식으로이 데이터를 읽습니다.
비동기 통신은 주 스레드에서 수행됩니다. 따라서 통신 자체가 비동기 일지라도 작업이 차단됩니다.
문제
난 그냥 구성 단계에서 카메라와 통신 것으로 주어진 이상한 각 비동기 전송에 대한 TRANSFER_NO_DEVICE 상태를 얻고있다. Windows에서 Cypress 라이브러리를 사용하는 C#에서 비슷한 코드를 사용 했으므로 제대로 작동하므로 카메라를 제외 할 수 있습니다. 또한 사진 데이터를 가져 와서 FX3 버퍼에 이미지 데이터의 일부가 나타납니다.이 이미지는 cypress에서 제공하는 예제 응용 프로그램을 사용하여 복구 할 수 있습니다.
최소 예제 스크립트를 만들었습니다. 구성 및 take_picture 기능에 주목 : 여기
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# StackOverflow.py
import usb1 as usb1 # Libusb, needed to provide a usb context
import GuideCamLib.binary as binary # Handles bytecode formatting
import GuideCamLib.ccd as ccd # Generates configuration information
import GuideCamLib.usb as usb # Manages communication
# Camera usb parameters
vid = 0x04B4;
pid = 0x00F1;
read_addr = 0x81;
write_addr = 0x01;
interface = 0;
success = [0x55, 0x55, 0x55, 0x55] + [0]*(512 - 4); # A successful response
# Objects that generate instructions for the camera
ccd0 = ccd.CCD_47_10();
formatter = binary.ByteCode();
def configure(context):
# Generating bytes to transfer, outputs a list of int lists
bytecode_lines = ccd0.create_configuration_bytecode(formatter);
# Opens device
with usb.Device(vid=vid, pid=pid, context= context) as dev:
# Opens read/write ports
port_write = dev.open_port(write_addr);
port_read = dev.open_port(read_addr);
print(" Start configuration...")
# Transfer synchronously
for line in bytecode_lines:
written_bytes = port_write.write_sync(line);
response = port_read.read_sync(512);
if(response != success):
raise RuntimeError(" Configuration failed. (" + str(response) + ")");
print(" End configuration")
def take_picture(context):
# Generating bytes to transfer, generates a list of ints
take_photo_bytecode = formatter.seq_take_photo(ccd0.get_take_photo_mode_address());
# Opens device
with usb.Device(vid=vid, pid=pid, context= context) as dev:
# Opens read/write ports
port_write = dev.open_port(write_addr);
port_read = dev.open_port(read_addr, 10000); # 10 sec timeout
# Prepare asynchronous read
print(" Prepare read")
with port_read.read_async(512) as data_collector:
print(" Writing")
written_bytes = port_write.write_sync(take_photo_bytecode); # Write synchronously
print(" Reading...")
recieved_image = data_collector(); # Read asynchronously (but in a blocking manner)
print " Recieved: " + str(len(recieved_image)) + " bytes.";
with usb1.USBContext() as context:
print "Configuring camera:"
configure(context); # Configure camera
print "Taking picture:"
take_picture(context); # Take picture
print "Done."
이 필요한 상황화에 대한/usb.py GuideCamLib입니다. _AsyncReader는 상태가있는 함수 일뿐 아니라 _TransferCollector 클래스가 대부분의 작업을 수행합니다.
이
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# GuideCamLib/usb.py
import usb1 as usb
import six as six
import traceback
# For human-readable printing
transfer_status_dict = \
{ \
usb.TRANSFER_COMPLETED : "TRANSFER_COMPLETED",
usb.TRANSFER_ERROR : "TRANSFER_ERROR",
usb.TRANSFER_TIMED_OUT : "TRANSFER_TIMED_OUT",
usb.TRANSFER_CANCELLED : "TRANSFER_CANCELLED",
usb.TRANSFER_STALL : "TRANSFER_STALL",
usb.TRANSFER_NO_DEVICE : "TRANSFER_NO_DEVICE",
usb.TRANSFER_OVERFLOW : "TRANSFER_OVERFLOW" \
};
# Callback to accumulate succesive transfer calls
class _AsyncReader:
def __init__(self):
self.transfers = [];
def __call__(self, transfer):
print "Status: " + transfer_status_dict[transfer.getStatus()]; # Prints the status of the transfer
if(transfer.getStatus() != usb.TRANSFER_COMPLETED):
return;
else:
self.transfers.append(transfer.getBuffer()[:transfer.getActualLength()]);
transfer.submit();
# A collector of asyncronous transfer's data.
# Stops collection after port.timeout time of recieving the last transfer.
class _TransferCollector:
# Prepare data collection
def __init__(self, transfer_size, pararell_transfers, port):
self.interface_handle = port.device.dev.claimInterface(port.interface);
self.reader = _AsyncReader();
self.port = port;
transfers = [];
# Queue transfers
for ii in range(pararell_transfers):
transfer = port.device.dev.getTransfer();
transfer.setBulk(
port.address,
transfer_size,
callback=self.reader,
timeout=port.timeout);
transfer.submit();
transfers.append(transfer);
self.transfers = transfers;
def __enter__(self):
self.interface_handle.__enter__();
return self;
def __exit__(self, exception_type, exception_value, traceback):
self.interface_handle.__exit__(exception_type, exception_value, traceback);
# Activate data collection
def __call__(self):
# Collect tranfers with _AsyncReader while there are active transfers.
while any(x.isSubmitted() for x in self.transfers):
try:
self.port.device.context.handleEvents();
except usb.USBErrorInterrupted:
pass;
return [six.byte2int(d) for data in self.reader.transfers for d in data];
# Port class for creating syncronous/asyncronous transfers
class Port:
def __init__(self, device, address, timeout = None):
self.device = device;
self.address = address;
self.interface = self.device.interface;
self.timeout = timeout;
if(timeout is None):
self.timeout = 0;
def read_sync(self, length):
with self.device.dev.claimInterface(self.interface):
data = self.device.dev.bulkRead(self.address, length, timeout=self.timeout);
return [six.byte2int(d) for d in data];
def write_sync(self, data):
data = [six.int2byte(d) for d in data];
with self.device.dev.claimInterface(self.interface):
return self.device.dev.bulkWrite(self.address, data, timeout=self.timeout);
# Make asyncronous transfers blocking. Collects data as long as the device
# sends data more frecuently than self.timeout or all the transfers fails
def read_async(self, length, pararell_transfers = 32):
return _TransferCollector(length, pararell_transfers, self);
# Device class for creating ports
class Device:
def __init__(self, vid = None, pid = None, context = None, interface = 0):
if(not context):
self.backend = usb.USBContext();
context = self.backend.__enter__();
self.context = context;
self.interface = interface;
self.dev = context.openByVendorIDAndProductID(vid, pid, skip_on_error = False);
if self.dev is None:
raise RuntimeError('Device not found');
def __enter__(self):
return self;
def __exit__(self, exception_type, exception_value, traceback):
if(hasattr(self, "backend")):
self.backend.__exit__(exception_type, exception_value, traceback);
def open_port(self, address, timeout = None):
return Port(self, address, timeout);
스크립트는 명확하게 동기 전송이 성공하지만, 대기중인 비동기 전송의 각각 NO_DEVICE 실패 보여줍니다 다음을 출력합니다 : 포트 및 장치는 각각의 전송에서 상용구 코드를 줄이기 위해, 단지 헬퍼 클래스이다
>>> python StackOverflow.py
Configuring camera:
Start configuration...
End configuration
Taking picture:
Prepare read
Writing
Reading...
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Status: TRANSFER_NO_DEVICE
Traceback (most recent call last):
File "StackOverflow.py", line 70, in <module>
take_picture(context); # Take picture
File "StackOverflow.py", line 62, in take_picture
recieved_image = data_collector();
File "/media/jabozzo/Data/user_data/jabozzo/desktop/sigmamin/code/workspace_Python/USB/USB wxglade libusb1/GuideCamLib/usb.py", line 62, in __exit__
self.interface_handle.__exit__(exception_type, exception_value, traceback);
File "/home/jabozzo/.local/lib/python2.7/site-packages/usb1.py", line 1036, in __exit__
self._handle.releaseInterface(self._interface)
File "/home/jabozzo/.local/lib/python2.7/site-packages/usb1.py", line 1171, in releaseInterface
libusb1.libusb_release_interface(self.__handle, interface),
File "/home/jabozzo/.local/lib/python2.7/site-packages/usb1.py", line 121, in mayRaiseUSBError
raiseUSBError(value)
File "/home/jabozzo/.local/lib/python2.7/site-packages/usb1.py", line 117, in raiseUSBError
raise STATUS_TO_EXCEPTION_DICT.get(value, USBError)(value)
usb1.USBErrorNotFound: LIBUSB_ERROR_NOT_FOUND [-5]
장치가 openned 때 인터페이스가 열릴 수 있도록 내가 장치 및 포트 클래스를 변경 한
업데이트. 그렇게하면 인터페이스는 열려있는 포트의 수와 관계없이 한 번 열리고 닫힙니다.
여전히 같은 오류가 있습니다. 그러나 인쇄 나 표시는 이전 읽기 준비에 실패 : 나는 의심하기 시작하고있어
>>> python StackOverflow.py
Configuring camera:
Start configuration...
End configuration
Taking picture:
Prepare read
Traceback (most recent call last):
...
내가 비동기 전송을 수행하기 위해 인터페이스를 열 필요가 없습니다.
나는 완전히 내가 파이썬를 유창하게 구사하지 않다 원인 내가 두려워 코드를 이해하지 않습니다. 그러나 끝에있는 오류는 장치가 이미 사라 졌음을 분명히 말합니다. 장치가 해제되기 전에 전송이 데이터를 반환 할 때까지 기다릴 것입니까? C#을 알고 있기 때문에 이미 배치 된 객체와 동일한 파이썬이라고 제안합니다. 내가 읽었을 때'recieved_image'는받은 데이터가 아닌 _TransferCollector의 인스턴스입니다.하지만 파이썬이 어떻게 처리하는지 오해 할 수도 있습니다. – dryman
@dryman 당신은 아마 맞을 것입니다. 이제는 인터페이스에 대해 두 번 언급하고 있습니다. 'with port_read' 그리고'port_write.write_sync'에서 우선. 그런 다음 두 번째 호출이 완료되고'data_collector()'가 호출되기 전에 인터페이스를 닫습니다 (이는'data_collector .__ call __()'과 동일합니다). 지금 나는 카메라가 아니다. 나는 결과와 함께 돌아올 것이다. – jabozzo
위의 수정을 시도했지만 작동하지 않았습니다. 나는 내 질문을 업데이트 할 것이다. – jabozzo