ftd2xx
ftd2xx copied to clipboard
Device status is not handled properly
Describe the bug When a device is opened using open() or openEx() the status always returns to "INVALID_HANDLE", and when the device is closed the status returns to "OK". If the serial number is not corrected an exception error will be raised "DEVICE_NOT_FOUND", it works well in this case, but it could be a case (the function called returns 2). In defines.py there is the enumerator class "Status" that defines the error constants:
@unique
class Status(IntEnum):
OK = 0
INVALID_HANDLE = 1
DEVICE_NOT_FOUND = 2
DEVICE_NOT_OPENED = 3
IO_ERROR = 4
INSUFFICIENT_RESOURCES = 5
INVALID_PARAMETER = 6
INVALID_BAUD_RATE = 7
DEVICE_NOT_OPENED_FOR_ERASE = 8
DEVICE_NOT_OPENED_FOR_WRITE = 9
FAILED_TO_WRITE_DEVICE = 10
EEPROM_READ_FAILED = 11
EEPROM_WRITE_FAILED = 12
EEPROM_ERASE_FAILED = 13
EEPROM_NOT_PRESENT = 14
EEPROM_NOT_PROGRAMMED = 15
INVALID_ARGS = 16
NOT_SUPPORTED = 17
OTHER_ERROR = 18
I tried as follow to see the effect, but it is just an example:
class FTD2XX(AbstractContextManager):
"""Class for communicating with an FTDI device"""
handle: _ft.FT_HANDLE
status: int
def __init__(self, handle: _ft.FT_HANDLE, update: bool = True):
"""Create an instance of the FTD2XX class with the given device handle
and populate the device info in the instance dictionary.
Args:
update (bool): Set False to disable automatic (slow) call to
createDeviceInfoList
"""
self.handle = handle
self.status = 0 # OK
# createDeviceInfoList is slow, only run if update is True
if update:
createDeviceInfoList()
self.__dict__.update(self.getDeviceInfo())
def close(self) -> None:
"""Close the device handle"""
call_ft(_ft.FT_Close, self.handle)
self.status = 3 # DEVICE_NOT_OPENED
To Reproduce
>>> import ftd2xx as ft
>>> from ftd2xx.defines import Status
>>> ft.listDevices()
[b'FT5SAZB5A', b'FT5SAZB5B', b'FT5SAZB5C', b'FT5SAZB5D']
>>> portb = ft.openEx(b'FT5SAZB5B')
>>> portb.status
1
>>> Status(portb.status)
<Status.INVALID_HANDLE: 1>
>>> portb.close()
>>> portb.status
0
>>> Status(portb.status)
<Status.OK: 0>
>>> portb = interface.openEx(b'FT5SAZB')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\...\ftd2xx\ftd2xx.py", line 243, in openEx
call_ft(_ft.FT_OpenEx, id_str, _ft.DWORD(flags), c.byref(h))
File "c:\...\ftd2xx\ftd2xx.py", line 133, in call_ft
raise DeviceError(status)
ftd2xx.ftd2xx.DeviceError: DEVICE_NOT_FOUND
Expected behavior I expect that the current state of the device is described with the right message.
Desktop:
- OS: Windows, Linux (Raspberry Pi)
- OS Version: Windows 10, Raspbian
- Python Version: 3.7.5, 3.10
- FTDI driver version: 2.12.36.4, 1.4.27 ARMv6
Maybe status should be a property that calls FT_GetStatus (doesn't matter too much which function) to return current status.
Thank you @krister-ts! Yes maybe. However if I use getstatus() or getEventStatus() I shouldn’t have an exception to get the event status message. For example, if I closed the connection and I would like to know the status using one of the above mentioned methods, the message 'INVALID_HANDLE' will be the exception message.
>>> import ftd2xx as ft
>>> mydevice = ft.openEx(b'FT5SAZB5B')
mydevice.getEventStatus()
0
>>> mydevice.close()
>>> mydevice.getEventStatus()
Traceback (most recent call last):
...
File "c:\...\ftd2xx\ftd2xx.py", line 133, in call_ft
raise DeviceError(status)
ftd2xx.ftd2xx.DeviceError: INVALID_HANDLE
I would expect instead 'DEVICE_NOT_OPEN', however this way I would capture the exception to know the status. Why? I was hoping I could use the status property to know the status by avoiding exceptions, but it is only used in three cases and in different way.
@PalladinoMarco This is how the library is supposed to work. The handle is invalid after close.
You should use try except block where you know this could raise an exception.
I was saying, this could be done in the status member so that you can avoid the try except in user code.
@krister-ts I wrote an overload method of my ftd2xx child class:
def getEventStatus(self):
"""
Summary
-------
Gets the current device event status.
"""
try:
return Status(self.ftdi.getEventStatus()).name
except ftd2xx.DeviceError as errorMessage:
return str(errorMessage)
Thanks a lot for your support.
@snmishra Should we change the status
member of the class to a @property
that will not raise an exception?
@krister-ts I don't think the current status
field field is very useful. But changing to a property would be a breaking change. May be something like deviceStatus
?
@krister-ts I don't think the current
status
field field is very useful. But changing to a property would be a breaking change. May be something likedeviceStatus
?
I would maybe use snake case so that no one thinks it is a real function from the API (we are keeping camel case on those).
@krister-ts Sounds good. Want to do a PR?