ftd2xx
ftd2xx copied to clipboard
Asyncio transports, enumerated openEx flags
I added the asyncio transports (somewhat based on pyserial-asyncio). I broke it up into base, read and write transports (as the asyncio lib shows) to get fewer methods per class. Read-only or write-only might be useful to someone.
Something to look at: My chain of super()._shutdown(), etc is probably NOT the best way to glue these together.
I made the openEx flags enumerated so that a bad flag will be easier to debug. That also gives me something to put as a typehint and make it easy to generate docs down the road.
@snmishra I have tested this last commit (you can review now). Do you have any device for testing?
Ya, I suppose there are some tests we could do. I think just opening and closing is a good start. Not sure what else can be done right now.
Hmm. @krister-ts I feel the API needs to be a bit more hashed out before we're ready to merge. What do you think?
Doesn't hurt to hold off. It is harder to take back if people start using it...
@krister-ts Glad we're in agreement on this. I think may be an example usage and a test will clarify it. Are you using this transport function?
I am using the create_ftd2xx_connection factory. It works well so far but I have not done much testing.
@snmishra I basically do the same as this example: https://pyserial-asyncio.readthedocs.io/en/latest/shortintro.html#protocol-example
open_ftd2xx_connection keeps the loop and protocol_factory args, the rest are replaced with open/openEx args. I don't really use the openEx args but I did test them. For now, I just want the first device.
Should we add more kwargs like baud? I guess adding later will not break compatibility though.
@krister-ts We can think about configuration later. I don't understand asyncio at all. If you could add an example for may be reading the serial number or anything else, it will make it clear how to use it.
@snmishra Pretty much what it does is allow you to make a protocol to handle the connection. In my case, I am just processing bytes into packets. My protocol object is passed a Queue object in its init which gets filled when a valid packet is received.
class Direct(asyncio.Protocol):
"""Direct connection to COMPANY device."""
__slots__ = (
"transport",
"packetizer",
"is_connected",
)
def __init__(self, queue: Queue, is_connected: Event):
super().__init__()
self.transport = None
self.packetizer = Packetizer(queue)
self.is_connected = is_connected
def connection_made(self, transport):
self.transport = transport
self.is_connected.set()
print("Connected")
def data_received(self, data):
self.packetizer.process(data)
def connection_lost(self, exc):
self.is_connected.clear()
print("Disconnected")
With the transport/protocol support for ftd2xx, I can use this protocol (which I already use for tcp and bluetooth) for usb connections.
@snmishra This class reminded me about using slots in the transports. I'm not sure why pyserial did not use them but I think we should lock our classes from dynamically assigning members (like the asyncio lib). The user should subclass if they want to add members, in my opinion. What do you think?
@krister-ts May be the ctypes cleanup could be a separate PR? This seems unrelated to the asyncio transport, and perhaps could be merged sooner?
I have finally had a chance to make a PR for this. I will probably not have time to put into aio for awhile, but the ctypes should be the priority anyways since there has been an issue in linux.
Created ftd2xx-aio project. No longer need aio module.