I have a very limited Python / C skill set and I found the python version of the code a bit easier for me to understand the then C counterpart.
Code: Select all
#!/usr/bin/env python
"""FLYFISH TECHNOLOGIES Ltd.
http://www.flyfish-tech.com/FF32/index.php
FF32 Python 2.7 module
Ported from the FF32 demo 'C' code to Python 2.7 by Douglas Otwell
This code is in the Public Domain. Use it at your own risk.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
# pyudev is required; install with 'sudo apt-get install python-pyudev' (on debian/raspian)
import pyudev
__version__ = "0.3.0"
class FF32:
PRODUCT_NAME = "FF32"
CMD_SET_ADDRESS = 0x10
CMD_GET_ADDRESS = 0x11
CMD_SET_VENDOR = 0x12
CMD_GET_VENDOR = 0x13
CMD_SET_PRODUCT = 0x14
CMD_GET_PRODUCT = 0x15
CMD_SET_SERIAL_NUMBER = 0x16
CMD_GET_SERIAL_NUMBER = 0x17
CMD_SET_DIGITAL_OUTPUT = 0x20
CMD_SET_BLOCK_DIGITAL_OUTPUTS = 0x30
CMD_READ_DIGITAL_INPUT = 0x21
CMD_READ_BLOCK_DIGITAL_INPUTS = 0x31
CMD_SET_PWM_OUTPUT = 0x22
CMD_READ_ANALOG_INPUT = 0x23
CMD_CONFIG_SPI_BUS = 0x24
CMD_WRITE_SPI_BUS = 0x25
CMD_READ_SPI_BUS = 0x26
CMD_CONFIG_I2C_BUS = 0x27
CMD_WRITE_I2C_BUS = 0x28
CMD_READ_I2C_BUS = 0x29
CMD_CONFIG_1WIRE_BUS = 0x2A
CMD_WRITE_1WIRE_BUS = 0x2B
CMD_READ_1WIRE_BUS = 0x2C
CMD_GET_CHIP_INFO = 0x71
def __init__(self, device_num=1):
self.path = None
self.file = None
self.device_num = device_num
def __enter__(self):
self.getPath()
self.openComm()
return self
def __exit__(self, type, value, traceback):
self.closeComm()
def getChipInfo(self):
"""Return the chip version as (major, minor)."""
version = None
bytes = bytearray([0x00, FF32.CMD_GET_CHIP_INFO])
bytes = self.sendData(bytes)
if bytes[1] == 0x0F and bytes[2] == 0x0B:
version = (bytes[3], bytes[4]);
return version
def setAddress(self, addr):
"""Set the chip address."""
bytes = bytearray([0x00, FF32.CMD_SET_ADDRESS, addr])
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error setting the chip address; error code: 0x%02X" % (bytes[0]))
def getAddress(self):
"""Get the chip address as a byte."""
bytes = bytearray([0x00, FF32.CMD_GET_ADDRESS])
bytes = self.sendData(bytes)
return bytes[1]
def setVendor(self, vendor):
"""Set the board vendor string."""
bytes = bytearray([0x00, FF32.CMD_SET_VENDOR])
bytes += bytearray(vendor[:30].ljust(31, chr(0)), 'utf-8')
self.sendData(bytes)
def getVendor(self):
"""Get the board vendor string."""
bytes = bytearray([0x00, FF32.CMD_GET_VENDOR])
bytes = self.sendData(bytes)
vendor = bytes[1:bytes.index(0)].decode()
return vendor
def setProduct(self, product):
"""Set the board product string."""
bytes = bytearray([0x00, FF32.CMD_SET_PRODUCT])
bytes += bytearray(product[:30].ljust(31, chr(0)), 'utf-8')
bytes = self.sendData(bytes)
def getProduct(self):
"""Get the board product string."""
bytes = bytearray([0x00, FF32.CMD_GET_PRODUCT])
bytes = self.sendData(bytes)
product = bytes[1:bytes.index(0)].decode()
return product
def setSerialNumber(self, serial):
"""Set the board serial number string."""
bytes = bytearray([0x00, FF32.CMD_SET_SERIAL_NUMBER])
bytes += bytearray(serial[:30].ljust(31, chr(0)), 'utf-8')
bytes = self.sendData(bytes)
def getSerialNumber(self):
"""Get the board serial number string."""
bytes = bytearray([0x00, FF32.CMD_GET_SERIAL_NUMBER])
bytes = self.sendData(bytes)
serial = bytes[1:bytes.index(0)].decode()
return serial
def setDigitalOutput(self, xxx_todo_changeme, state):
"""Set a pin high (1) or low (0)."""
(pin_block, pin_num) = xxx_todo_changeme
self.__validatePin(pin_block, pin_num)
bytes = bytearray([0x00, FF32.CMD_SET_DIGITAL_OUTPUT, self.convert_str_byte_int(pin_block), pin_num,state])
#print(bytes)
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error setting PWM output; error code: 0x%02X" % (bytes[0]))
def setBlockDigitalOutputs(self, pin_block, bitmask, states):
"""Set a block of pins at a time, with a bitmask"""
self.__validateBlock(pin_block, states)
mask_hi = bitmask >> 8
mask_low = bitmask - (mask_hi << 8)
states_hi = states >> 8
states_low = states - (states_hi << 8)
bytes = bytearray(
[0x00, FF32.CMD_SET_BLOCK_DIGITAL_OUTPUTS, self.convert_str_byte_int(pin_block), mask_hi, mask_low,
states_hi, states_low])
bytes = self.sendData(bytes)
if bytes[0] != 0x0e:
raise FF32Error("Error setting digital inputs; error code: 0x%02X" % (bytes[0]))
def readDigitalInput(self, xxx_todo_changeme1):
"""Read the state of a pin, return an integer."""
(pin_block, pin_num) = xxx_todo_changeme1
self.__validatePin(pin_block, pin_num)
bytes = bytearray([0x00, FF32.CMD_READ_DIGITAL_INPUT, self.convert_str_byte_int(pin_block), pin_num])
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_DIGITAL_INPUT:
raise FF32Error("Error reading a digital pin; error code: 0x%02X" % (bytes[0]))
return int(bytes[1])
def readBlockDigitalInputs(self, pin_block, bitmask):
mask_hi = bitmask >> 8
mask_low = bitmask - (mask_hi << 8)
bytes = bytearray(
[0x00, FF32.CMD_READ_BLOCK_DIGITAL_INPUTS, self.convert_str_byte_int(pin_block), mask_hi, mask_low])
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_BLOCK_DIGITAL_INPUTS:
raise FF32Error("Error reading digital inputs; error code: 0x%02X" % (bytes[0]))
value = int(bytes[1] * 256 + bytes[2])
return value
def setPWMOutput(self, xxx_todo_changeme2, duty_cycle):
"""Set PWM output, 0 - 100."""
(pin_block, pin_num) = xxx_todo_changeme2
self.__validatePin(pin_block, pin_num)
bytes = bytearray([0x00, FF32.CMD_SET_PWM_OUTPUT, self.convert_str_byte_int(pin_block), pin_num, duty_cycle])
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error setting PWM output; error code: 0x%02X" % (bytes[0]))
def readAnalogInput(self, xxx_todo_changeme3):
"""Read an analog pin and return tuple (an int representing Vcc: '3'=3V3 or '5'=5V, an int: 0-1023)."""
(pin_block, pin_num) = xxx_todo_changeme3
self.__validatePin(pin_block, pin_num)
bytes = bytearray([0x00, FF32.CMD_READ_ANALOG_INPUT, self.convert_str_byte_int(pin_block), pin_num])
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_ANALOG_INPUT:
raise FF32Error("Error reading an analog pin; error code: 0x%02X" % (bytes[0]))
vcc = int(bytes[1])
value = int(bytes[2] * 256 + bytes[3])
return vcc, value
def setSPIPins(self, xxx_todo_changeme4, xxx_todo_changeme5, xxx_todo_changeme6, xxx_todo_changeme7):
"""Configure SPI pins."""
(cs_pin_block, cs_pin_num) = xxx_todo_changeme4
(sck_pin_block, sck_pin_num) = xxx_todo_changeme5
(mosi_pin_block, mosi_pin_num) = xxx_todo_changeme6
(miso_pin_block, miso_pin_num) = xxx_todo_changeme7
self.__validatePin(cs_pin_block, cs_pin_num)
self.__validatePin(sck_pin_block, sck_pin_num)
self.__validatePin(mosi_pin_block, mosi_pin_num)
self.__validatePin(miso_pin_block, miso_pin_num)
bytes = bytearray(
[0x00, FF32.CMD_CONFIG_SPI_BUS, self.convert_str_byte_int(cs_pin_block), cs_pin_num,
self.convert_str_byte_int(sck_pin_block), sck_pin_num, self.convert_str_byte_int(mosi_pin_block),
mosi_pin_num, self.convert_str_byte_int(miso_pin_block), miso_pin_num])
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error configuring I2C bus; error code: 0x%02X" % (bytes[0]))
def writeSPIBus(self, data):
"""Write a bytarray to SPI bus."""
if len(data) > 60:
raise FF32Error("Error writing SPI data; write data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_WRITE_SPI_BUS, len(data)])
bytes += data
bytes = self.sendData(bytes)
def readSPIBus(self, read_len, data):
"""Write and read bytearray to SPI buss."""
if read_len > 60:
raise FF32Error("Error writing SPI data; read data length > 60 bytes")
if len(data) > 60:
raise FF32Error("Error writing SPI data; write data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_READ_SPI_BUS, len(data), read_len])
bytes += data
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_SPI_BUS:
raise FF32Error("Error reading SPI data; error code: 0x%02X" % (bytes[0]))
return bytes[2:]
def setI2CPins(self, xxx_todo_changeme8, xxx_todo_changeme9):
"""Configure I2C pins."""
(scl_pin_block, scl_pin_num) = xxx_todo_changeme8
(sda_pin_block, sda_pin_num) = xxx_todo_changeme9
self.__validatePin(scl_pin_block, scl_pin_num)
self.__validatePin(sda_pin_block, sda_pin_num)
bytes = bytearray([0x00, FF32.CMD_CONFIG_I2C_BUS, self.convert_str_byte_int(scl_pin_block), scl_pin_num, self.convert_str_byte_int(sda_pin_block), sda_pin_num])
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error configuring I2C bus; error code: 0x%02X" % (bytes[0]))
def writeI2CBus(self, data):
"""Write a bytarray to I2C bus."""
if len(data) > 60:
raise FF32Error("Error writing I2C data; write data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_WRITE_I2C_BUS, len(data)])
bytes += data
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error writing I2C data; error code: 0x%02X" % (bytes[0]))
def readI2CBus(self, read_len, data):
"""Write and read bytearray to I2C bus."""
if read_len > 60:
raise FF32Error("Error writing I2C data; read data length > 60 bytes")
if len(data) > 60:
raise FF32Error("Error writing I2C data; write data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_READ_I2C_BUS, len(data), read_len])
bytes += data
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_I2C_BUS:
raise FF32Error("Error writing I2C data; error code: 0x%02X" % (bytes[0]))
return bytes[2:]
def set1WirePin(self, xxx_todo_changeme10):
"""Configure 1-wire pins."""
(dq_pin_block, dq_pin_num) = xxx_todo_changeme10
self.__validatePin(dq_pin_block, dq_pin_num)
bytes = bytearray([0x00, FF32.CMD_CONFIG_1WIRE_BUS, self.convert_str_byte_int(dq_pin_block), dq_pin_num])
bytes = self.sendData(bytes)
if bytes[0] != 0x0E:
raise FF32Error("Error configuring 1-Wire bus; error code: 0x%02X" % (bytes[0]))
def write1WireBus(self, data):
"""Write a bytarray to 1-Wire bus."""
if len(data) > 60:
raise FF32Error("Error writing 1-Wire data; data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_WRITE_1WIRE_BUS, len(data)])
bytes = self.sendData(bytes + data)
if bytes[0] != 0x0E:
raise FF32Error("Error writing 1-Wire data; error code: 0x%02X" % (bytes[0]))
def read1WireBus(self, read_len, data):
"""Write and read bytearray to 1-Wire bus."""
if read_len > 60:
raise FF32Error("Error writing 1-Wire data; read data length > 60 bytes")
if len(data) > 60:
raise FF32Error("Error writing 1-Wire data; write data length > 60 bytes")
bytes = bytearray([0x00, FF32.CMD_READ_1WIRE_BUS, len(data), read_len])
bytes += data
bytes = self.sendData(bytes)
if bytes[0] != FF32.CMD_READ_1WIRE_BUS:
raise FF32Error("Error writing 1-Wire data; error code: 0x%02X" % (bytes[0]))
return bytes[2:]
def writeByteI2C(self, addr, byte):
"""Write a byte to a slave address"""
addr = addr * 2
data = bytearray([addr, byte])
bytes = self.writeI2CBus(data)
def writeBlockI2C(self, addr, bytes):
"""Write a bytearray to a slave address"""
addr = addr * 2
data = bytearray([addr])
data += bytes
bytes = self.writeI2CBus(data)
def readByteI2C(self, addr):
"""Read a byte from a slave address"""
addr = (addr * 2) + 1
data = bytearray([addr])
bytes = self.readI2CBus(1, data)
return bytes[0]
def readWordI2C(self, addr):
"""Read a (two byte) word from a slave address (little-endian)"""
addr = (addr * 2) + 1
data = bytearray([addr])
bytes = self.readI2CBus(2, data)
little_byte = bytes[0]
big_byte = bytes[1]
word = big_byte * 256 + little_byte
return word
def readBlockI2C(self, addr, read_len):
"""Read a bytearray from a slave address"""
addr = (addr * 2) + 1
data = bytearray([addr])
bytes = self.readI2CBus(read_len, data)
return bytes[0:read_len]
#
# these are internal methods, but are left public for flexibility
#
def sendData(self, bytes):
"""Send a bytarray to the device and return a bytearray response."""
self.file.write(bytes)
str = self.file.read(64)
bytes = bytearray(str)
if len(bytes) == 0:
raise FF32Error("No response from chip")
return bytes
def openComm(self):
"""Open the device."""
self.file = open(self.path, "r+b", buffering=0)
def closeComm(self):
"""Close the device."""
self.file.close()
def getPath(self):
"""Return the path name of the device"""
count = 1
context = pyudev.Context()
for device in context.list_devices(subsystem="hidraw"):
path = device.device_node;
parentDevice = device.find_parent("usb", device_type="usb_device")
# print("test")
# print(parentDevice)
# print(parentDevice.__getitem__("ID_MODEL"))
# for attributes in parentDevice:
# # print(attributes)
# print(parentDevice.__getitem__(attributes))
try:
product = parentDevice.__getitem__("ID_MODEL")
if (product == FF32.PRODUCT_NAME):
if (count == self.device_num):
self.path = path;
print(path)
return
count += 1
except KeyError:
pass
raise FF32Error("Error locating FF32 USB device. Check USB cable.")
#
# private methods
#
def __validatePin(self, pin_block, pin_num):
if pin_block != "A" and pin_block != "B":
raise FF32Error("Invalid pin block; must be 'A' or 'B'")
if pin_block == "A":
if pin_num < 1 or pin_num > 6:
raise FF32Error("Invalid pin number for block A; must be between 1 and 6")
if pin_block == "B":
if pin_num < 1 or pin_num > 12:
raise FF32Error("Invalid pin number for block B; must be between 1 and 12")
def __validateBlock(self, pin_block, states):
if pin_block != "A" and pin_block != "B":
raise FF32Error("Invalid pin block; must be 'A' or 'B'")
if pin_block == "A":
if states < 0 or states > 63:
raise FF32Error("Invalid pin states for block A; must be between 0 and 63")
if pin_block == "B":
if states < 0 or states > 4095:
raise FF32Error("Invalid pin states for block B; must be between 0 and 4095")
def convert_str_byte_int(self, value):
return int.from_bytes(value.encode('utf-8'), byteorder='little')
class FF32Error(Exception):
pass
if __name__ == "__main__":
with FF32() as ff32:
print(("pyff32 module version is %s" % __version__))
version = ff32.getChipInfo()
if version:
print(("Chip is FF32, silicon version %d.%d" % version))
else:
print("Chip is not FF32")
Which from the looks of it on linux I have to use libusb?
I found this
Code: Select all
https://www.purebasic.fr/german/viewtopic.php?f=8&t=27047
Code: Select all
https://freakscorner.de/owncloud/index.php/s/HwkXCDHLNASPSAT
Code: Select all
Version: 1.0.22.11312琀潯洠湡⁹潣普杩牵瑡潩獮搀獥牴祯搠癥捩搥┮d敮 (瑨灴⼺氯扩獵湩潦)
䥌啂䉓卟䍕䕃卓⼠䰠䉉单彂剔乁䙓剅䍟䵏䱐呅䑅
*context = 94641999562272
Bus 004 Device 013: ID 04E8:6860 䅓卍乕G 䅓卍乕彇湁牤楯d
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 004 Device 002: ID 8087:0024
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 004 Device 001: ID 1D6B:0002
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 003 Device 006: ID 5986:02D5
Bus 003 Device 005: ID 0A5C:21E6 牂慯捤浯䌠牯p 䍂㉍㜰㈰ぁ
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 003 Device 004: ID 147E:2020
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 003 Device 037: ID 04D8:F8B9
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 003 Device 002: ID 8087:0024
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 003 Device 001: ID 1D6B:0002
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 002 Device 001: ID 1D6B:0003
[ERR] LIBUSB::openDevice: 䥌啂䉓䕟剒剏䅟䍃卅S䥌啂䉓䕟剒剏也彏䕄䥖䕃䰀䉉单
Bus 001 Device 001: ID 1D6B:0002
So if anyone can help me, point me in the right direction, tell me if it is isnt possible to do with PB, or howto do it would greatly appreciate it.
Thanks