Package: amfiprot
Amfiprot is a communication protocol for embedded devices used and developed by Amfitech. The protocol can be extended with plugins for specific devices implementing the Amfiprot protocol (e.g. the AmfiTrack).PrerequisitesPython 3.6 or higher.libusbin order to communicate with USB devices throughpyusbInstallationWindowsGet a libusb Windows binary fromhttps://libusb.info/. From the downloaded archive, copy the following two files:VS2015-x64\dll\libusb-1.0.dlltoC:\Windows\System32VS2015-Win32\dll\libusb-1.0.dlltoC:\Windows\SysWOW64Install (or update)amfiprotwithpip:pipinstall-UamfiprotLinux (Ubuntu)Installlibusb:sudoaptinstalllibusb-1.0-0-devMake sure that your user has access to USB devices. For example, give theplugdevgroup access to USB devices by creating a udev rule:echo'SUBSYSTEM=="usb", MODE="660", GROUP="plugdev"'|sudotee/etc/udev/rules.d/50-pyusb.rules
sudoudevadmcontrol--reload
sudoudevadmtriggerCheck whether you are a member ofplugdevwith:groups<username>If not, add yourself to the group with:sudousermod-aGplugdev<username>Finally, install (or update)amfiprotwithpip:pipinstall-UamfiprotQuick startThe basic workflow when using the library is:Create aConnectionto a device connected directly to the host machine (we call this the "root node").Search forNodes on theConnection(i.e. nodes connected through the root node)Create aDeviceusing one of the discoveredNodes.Start theConnection.Communicate with theDevice.Example:importamfiprotVENDOR_ID=0xC17PRODUCT_ID=0xD12if__name__=="__main__":conn=amfiprot.USBConnection(VENDOR_ID,PRODUCT_ID)nodes=conn.find_nodes()print(f"Found{len(nodes)}node(s).")fornodeinnodes:print(f"[{node.tx_id}]{node.name}")dev=amfiprot.Device(nodes[0])conn.start()cfg=dev.config.read_all()whileTrue:ifdev.packet_available():print(dev.get_packet())The following sections provide a more in-depth explanation.Discovering and connecting to a root nodeAfter attaching a device to your host machine, you can scan for connected devices (e.g. connected via USB) with:phys_devs=amfiprot.USBConnection.discover()fordevinphys_devs:print(dev)A connection can then be created using a specific physical device:conn=amfiprot.USBConnection(dev['vid'],dev['pid'],dev['serial_number'])Usingserial_numberis optional. If none is given, the first device matching the given vendor and product ID is used.Finding nodesAfter creating a connection, we can search for nodes that are connected to the root node (e.g. via RF or UART):nodes=conn.find_nodes()find_nodes()returns a list ofNodeinstances. ANodeprovides a low-level interface to the physical device and can be used to retrieve theuuid,tx_idandnameof the device, and send/receive raw packets. It is not recommended to use theNodedirectly, but rather attach it to aDeviceinstance.Creating a deviceADeviceis an abstraction layer on top of aNodeand is created by injecting aNodein the constructor:dev=amfiprot.Device(node)TheDeviceprovides a higher-level interface allowing the user to easily:Update the firmwareReboot the deviceRead/write configurationsRead decoded packetsWe are still able to access theNodethrough theDeviceif necessary:tx_id=dev.node.tx_idStarting the connection and interacting with the deviceBefore interacting with theDevice, theConnectionmust be started:conn.start()This creates a child process that asynchronously sends and receives packets on the specified interface. We can now interact with theDevicein the main process without worrying about blocking:device_name=dev.name()print(f"Reading packets from{device_name}...")whileTrue:ifdev.packet_available():print(dev.get_packet())We can access the device configuration through aConfiguratorinstance which is automatically created as a member (dev.config) of theDevice:# Read the entire configuration as a JSON-like object (a list of dicts)cfg=dev.config.read_all()# Print all parametersforcategoryincfg:print(f"CATEGORY:{category['name']}")forparameterincategory['parameters']:print(parameter)The configuration can be easily saved to and loaded from a.jsonfile:importjson# Write configuration to filewithopen("config.json","w")asoutfile:json.dump(cfg,outfile,indent=4)# Read configuration from file and send to devicewithopen("config.json","r")asinfile:new_cfg=json.load(infile)dev.config.write_all(new_cfg)Contributions and bug reportingThe Amfiprot Python package is open-source and the source code can be found on ourGithub repository. Contributions can be made through pull requests to thedevelopmentbranch. Bug reports and feature requests can be created in theIssuestab.