IOW24-DG via Python on Linux

Dies ist das deutsche Forum für alle Themen um den IO-Warrior. Beiträge bitte nur in Deutsch.

Moderator: Guido Körber

Post Reply
ullix
Posts: 14
Joined: Thu Mar 01, 2018 12:27 pm

IOW24-DG via Python on Linux

Post by ullix »

Ich mache gerade meine ersten Schritte mit dem Dongle und hänge bereits fest, weit entfernt vom Auslesen meines Bosch BME280 sensors. Bitte um Hilfe.

Treiber ist installiert, die Library ebenfalls, das Testprogramm iowkittest gibt die gleichen Antworten wie 'lsusb -v' (wenngleich am Dongle nur sehr wenige LEDs leuchten ;-) ). Ich hab mich an den Sourcen für iowkittest und für die Library orientiert, sowie an diesem Post viewtopic.php?f=2&t=1710&p=9565&hilit=p ... 9479#p9565 (der jedoch für Python unter Windows erstellt ist).
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import ctypes
iowl = ctypes.CDLL("libiowkit.so") # <CDLL 'libiowkit.so', handle ...>
iowHandle = iowl.IowKitOpenDevice() # <class 'int'> e.g. -1481109088
iowHandle1 = iowl.IowKitGetDeviceHandle(1) # same as iowHandle
numIows = iowl.IowKitGetNumDevs() # numIows=1 (correct)

ciowHandle = ctypes.c_ulong(iowHandle)
iowKitID = iowl.IowKitGetProductId(ciowHandle) # always zero (=bool False)
iowRev = iowl.IowKitGetRevision(ciowHandle) # always zero (=bool False)
Die ersten Zeilen liefern anscheinend richtige Ergebnisse, aber die letzten beiden liefern nur 0, was nach iowkit.c das boolesche False ist, und auf einen falschen Handle weist. Obwohl der Handle in dem o.g. Post genauso gemacht wurde und funktionierte. Jedoch war der auf Windows.

Ist das auf Linux irgendwie anders zu machen? Was ist falsch an meinem ciowHandle?
User avatar
Christoph Jung
Posts: 670
Joined: Sun Oct 08, 2006 3:43 pm
Location: Germany / Berlin
Contact:

Re: IOW24-DG via Python on Linux

Post by Christoph Jung »

Hallo,

Ehrlich ich weiß gerade nicht, warum die beiden Funktionen 0 zurück geben.
Aber hier ist einmal ein Python Beispiel unter linux (raspi), was bei mir funktioniert:


import ctypes
from ctypes import *
import time, os
import sys


if sys.platform == 'linux2':
iowkit = ctypes.CDLL("libiowkit.so")
else:
NotImplementedError("loading the iowkit library not implemented yet")


#######################################################################
# iowkit definitions and declarations

# TODO: manually declare all function arguments and return types because
# ctypes does not seem to recognize 64bit pointers on its own
iowkit.IowKitOpenDevice.restype = ctypes.c_voidp
iowkit.IowKitVersion.restype = ctypes.c_char_p
iowkit.IowKitGetProductId.argtypes = [ctypes.c_voidp]
iowkit.IowKitGetProductId.restype = ctypes.c_ulong
iowkit.IowKitRead.argtypes = [ctypes.c_voidp, ctypes.c_ulong, ctypes.c_voidp, ctypes.c_ulong]
iowkit.IowKitCloseDevice.argtypes = [ctypes.c_voidp]
iowkit.IowKitGetDeviceHandle.argtypes = [ctypes.c_ulong]
iowkit.IowKitGetDeviceHandle.restype = ctypes.c_voidp
iowkit.IowKitGetNumDevs.restype = ctypes.c_ulong
iowkit.IowKitSetTimeout.argtypes = [ctypes.c_voidp, ctypes.c_ulong]
iowkit.IowKitReadImmediate.argtypes = [ctypes.c_voidp, ctypes.POINTER(ctypes.c_ulong)]
iowkit.IowKitGetSerialNumber.argtypes = [ctypes.c_voidp, ctypes.c_wchar_p]

# TODO: datatypes and definitions
IOW_PIPE_IO_PINS = ctypes.c_ulong(0)
IOW_PIPE_SPECIAL_MODE = ctypes.c_ulong(1)

IOWKIT_PRODUCT_ID_IOW40 = 0x1500
IOWKIT_PRODUCT_ID_IOW24 = 0x1501
IOWKIT_PRODUCT_ID_IOW56 = 0x1503


IOWKIT_MAX_PIPES = ctypes.c_ulong(2)
IOWKIT_MAX_DEVICES = ctypes.c_ulong(16)

IOWKIT_IO_REPORT = ctypes.c_ubyte * 5
IOWKIT_SPECIAL_REPORT = ctypes.c_ubyte * 8

IOWKIT56_IO_REPORT = ctypes.c_ubyte * 8
IOWKIT56_SPECIAL_REPORT = ctypes.c_ubyte * 64


#Open iowarrior
ioHandle = iowkit.IowKitOpenDevice()


if ioHandle == 0:
raise IOError("No device detected, ioHandle: " + str(ioHandle))
else:
#Get number of IOWs
numdevs = iowkit.IowKitGetNumDevs()
print "Numdevs", numdevs


# Get ProductID
pid = iowkit.IowKitGetProductId(ioHandle)
if pid == IOWKIT_PRODUCT_ID_IOW40: print "Device Type: IO-Warrior40"
if pid == IOWKIT_PRODUCT_ID_IOW24: print "Device Type: IO-Warrior24"
if pid == IOWKIT_PRODUCT_ID_IOW56: print "Device Type: IO-Warrior56"


#Write data into IO-Ports
report = IOWKIT_IO_REPORT(0x00,0x00,0x00,0x00,0x10)
iowkit.IowKitWrite(c_ulong(ioHandle), IOW_PIPE_IO_PINS, ctypes.byref(report), sizeof(IOWKIT_IO_REPORT))

#Don't forget to close!
iowkit.IowKitCloseDevice(ioHandle)
Abteilung: Softwareentwicklung
Folge uns auf Twitter
Follow us on twitter
ullix
Posts: 14
Joined: Thu Mar 01, 2018 12:27 pm

Re: IOW24-DG via Python on Linux

Post by ullix »

Treffer! Die "# iowkit definitions and declarations" machen den Unterschied; da hätte ich lange suchen können, danke!

Dazu demnächst mehr, im Augenblick stolpere ich über die Library. Kann es sein, dass für Linux noch immer eine veraltete Library gepackt ist?

Heute nochmals downgeladen, und obgleich es darin "libiowkit-1.5.0" heisst, ist libiowkit.so dann verlinkt zu /usr/lib/libiowkit.so.1.0.5. Dazu kommt dass alle Dateien ein Datum von 2007 bzw 2012 haben, und der Output meines Programms gemäß dem IowKit_V15_API.pdf dokument anders sein müssten. Z.B. erfordert iowkit.IowKitCloseDevice.argtypes = [ctypes.c_voidp] eine Sequenz, während Version 1.5 ganz ohne Eingabe auskommen sollte, so wie das Open Gegenstück.

Wenn der CloseDevice im Raspi Programm funktionieren sollte (bei mir nicht), dann nur weil dort die echte 1.5 Version benutzt wird, und es der egal ist, ob ein handle, eine sequenz oder gar nichts eingeben wird?
User avatar
Christoph Jung
Posts: 670
Joined: Sun Oct 08, 2006 3:43 pm
Location: Germany / Berlin
Contact:

Re: IOW24-DG via Python on Linux

Post by Christoph Jung »

Was heißt noch immer eine veraltete Version? Die API wurde seit 2007 nicht mehr geändert und für IowKitCloseDevice() musste schon seit Version 1.4 ein Parameter mit übergeben werden.
Ich habe eine Raspi mit einem frischen Linux gerade noch einmal mit der bei uns im Download liegenden API bespielt und alles funktioniert so wie es soll. Ja die libiowkit.so hat komischerweise die
Versionsnummer 1.0.5, aber evtl. ist das ein Zahlendreher.
Abteilung: Softwareentwicklung
Folge uns auf Twitter
Follow us on twitter
ullix
Posts: 14
Joined: Thu Mar 01, 2018 12:27 pm

Re: IOW24-DG via Python on Linux

Post by ullix »

Wow, das spricht für eine erfreulich stabile Software!

Ich denke, ich kann jetzt alle Befehle per Python3 geben. Nun möchte ich mit I2C Sensoren kommunizieren, und da hakt es erneut, wie geht denn die Kommunikation?

Konkret für einen ersten Schritt: für einen LM75 Sensor muss ich 'S 90 00 R 02 P' an den Sensor schicken, und kann dann 2 Bytes lesen, in denen der Temperaturwert steckt. Soweit so einfach. Aber wie stelle ich es an, dass "S", "R", "P" übersandt werden? Beim Bosch BME280 wird es dann komplizierter, wenn ein Dutzend Bytes gelesen werden müssen.

Ich suche vergeblich nach einem I2C-Ratgeber-für-Dummies für den IOW24 Dongle - gibt es da einen irgendwo auf Eurer Seite?
User avatar
Christoph Jung
Posts: 670
Joined: Sun Oct 08, 2006 3:43 pm
Location: Germany / Berlin
Contact:

Re: IOW24-DG via Python on Linux

Post by Christoph Jung »

Das Problem was ich habe ist, was ist mit "S", "R" und "P" gemeint? Soll das ein String sein oder die Flags, Start, Reset, Pause/Stop?

Die Start und Stop-Bits werden beim IO-Warrior im Flag eingetragen. Mehr dazu ist im Datenblatt beschrieben, wie ein Report aufgebaut ist.
Man muss an den IO-Warrior also einfach die Bytes (inkl. I2C Adresse) senden und dann den Status zurücklesen und dann einen Lesebefehl senden um die Daten die im Sensor stehen
dann auszulesen.

Beim Lesen mehrerer Bytes ist es so, das man dem IO-Warrior einfach sagt, wie viele Bytes man lesen möchte und dann dem entsprechend die IowKitRead() befehle durchführt.

Ein Konkretes Beispiel in Python haben wir dazu nicht nur etwas, was ich vor langer Zeit einmal für den IOW56 getestet hatte für I2C (unter Windows):

.....

if ioHandle == None:
ioHandle = self.ioHandle

report = IOWKIT56_SPECIAL_REPORT(
0x01, # I2C-Mode
0x01, # Enable
0x08, # flags
0x00, 0x00, 0x00, 0x00, 0x00
)

status = iowkit.IowKitWrite(ioHandle, numPipe, ctypes.byref(report), length)

# set read timeout to 1000 msecs
status = iowkit.IowKitSetTimeout(ioHandle, ctypes.c_ulong(1000));

# set write timeout to 1000 msecs
status = iowkit.IowKitSetWriteTimeout(ioHandle, ctypes.c_ulong(1000));

# Write data to IO-Warrior
report = IOWKIT56_SPECIAL_REPORT(
0x02, # I2C-Write
0xC4, # Start, Stopp, 4 Bytes
0x46 | 0, # 8Bit I2C Address + Write-Bit
0x01, # I2C register
0xFE, # data
0x20, # data
)

iowkit.IowKitWrite(ioHandle, numPipe, ctypes.byref(report), length) #Send Write command
iowkit.IowKitRead(ioHandle, numPipe, ctypes.byref(report), length) #Read Status / ACK



# Read Data from device
report = IOWKIT56_SPECIAL_REPORT(
0x03, #I2C Read command
0x02, #Byte count
0x46 | 1 # 8Bit I2C Address + Read-Bit
)

iowkit.IowKitWrite(c_ulong(ioHandle), IOW_PIPE_SPECIAL_MODE, ctypes.byref(report), sizeof(IOWKIT56_SPECIAL_REPORT)) #Send read command
iowkit.IowKitRead(c_ulong(ioHandle), IOW_PIPE_SPECIAL_MODE, ctypes.byref(report), sizeof(IOWKIT56_SPECIAL_REPORT)) #Read data from IO-Warrior

# Output result
print ("Output(r[1] r[2] r[3]: ", hex(report[1]) + " " + hex(report[2]) + " " + hex(report[3]) + " Loop " + str(i))




# DON'T FORGETT TO CLOSE AT THE END OF THE SCRIPT!!!!!
iowkit.IowKitCloseDevice(ioHandle)


Dieses Skript müsste man ein wenig anpassen aber es ist alles drin was man zum schreiben und lesen benötigt (Halt nur für den IOW56 und nicht für den IOW24).
Abteilung: Softwareentwicklung
Folge uns auf Twitter
Follow us on twitter
ullix
Posts: 14
Joined: Thu Mar 01, 2018 12:27 pm

Re: IOW24-DG via Python on Linux

Post by ullix »

Danke. Nachdem ich dann festgestellt hatte, dass sich in den Tiefen der Datenblätter noch eine I2C Beschreibung findet, ging es dann recht einfach. Eine Python3 Demoversion für den IOW24-Dongle und den LM75 Sensor habe ich auf Sourceforge hochgeladen, hier: https://sourceforge.net/projects/i2cpytools/

Die Voranstellung der Typendeklaration erwies sich als ungemein hilfreich, ich habe sie korrigiert und komplettiert. Es kam aber bei der IowKitGetSerialNumber zu einem Problem: Das IOWkit definiert die Seriennummer als 8-stelligen Unicode String mit 2 bytes pro Character. Python - zumindest meine Python 3.5.2 Version - erwartet aber Unicode mit 4 Bytes pro char. Die versuchte Wandlung mit .value führte dann stets zum Crash. Ein Workaround mit ctypes.create_string_buffer(18) löst das Problem.

Die Definition der Reports und Flags ist ein bisschen frickelig. Ein bisschen Wrapping in Python hilft, könnte aber noch verbessert werden. Etwas komplexer wird es noch, wenn die Datenmengen nicht mehr in einen einzelnen Report passen. Vorerst mal als Demo ok.

Das Auslesen der Temperatur aus dem LM75B Sensor läuft über viele Stunden ohne Fehler. Ein Datensegment ist in der Abb geplottet. Die starken Flattereien betragen bis zu 4 bit der 11bit Auflösung; damit ist der Gewinn durch 11 bit beim neuen LM75B versus 9 bit beim alten LM75 nicht richtig nachvollziehbar, ist aber noch im Rahmen der Specs. Mit der Messrate (linker Teil 1 sek, rechts 10sek) hat es nichts zu tun. Die rote Kurve des gleitenden Mittelwertes zeigt, dass der Sensor "im Mittel" richtig misst. Der Dongle arbeitet korrekt. Der Vorteil des LM75(B) ist, dass er so einfach zu programmieren ist und damit für einen I2C Einstieg gut geeignet ist.
IOW24DG-LM75B.png
IOW24DG-LM75B.png (37.43 KiB) Viewed 12455 times
Guido Körber
Site Admin
Posts: 2856
Joined: Tue Nov 25, 2003 10:25 pm
Location: Germany/Berlin
Contact:

Re: IOW24-DG via Python on Linux

Post by Guido Körber »

Probleme mit Datentypen sind bei Python durch die Sprache verursacht. Der Versuch dem Programmierer da durch inherente Typen die Arbeit zu erleichtern führt zum Gegenteil.

Das Rauschen auf dem Sensor kann durch die Stromversorgung kommen. Da empfiehlt es sich mal ganz detailliert ins Datenblatt zu schauen, möglicherweise sind da Hinweise drin wie man die Stromversorgung auslegen sollte, oder für zusätzliche Filterelemente. Bei A/D Wandlung kann es manchmal schon einen Unterschied machen, ob man die Masseleitung um den Chip oder drunter durch führt, oder wo der Kondensator sitzt.

Wir hatten beim StarterKit für den IOW56 auch viel Spaß den 14 Bit A/D Wandler ruhig zu kriegen :)
ullix
Posts: 14
Joined: Thu Mar 01, 2018 12:27 pm

Re: IOW24-DG via Python on Linux

Post by ullix »

Inzwischen läuft alles bestens, der IOW24-DG Dongle funktioniert gut mit den I2C Sensoren BME280 (Temperatur, Luftdruck, Feuchtigkeit), LM75 Temperatur) und TSL2591 (LIcht Vis+IR), siehe Abb.

Die Software I2Cpytools ist Open Source und kann hier heruntergeladen werden: https://sourceforge.net/projects/i2cpytools/

Mit im Paket ist die Plotting Software pytoolsPlot, die aber auch Stand-Alone zum Plot von CSV (Comma Separated Values) verwendet werden kann; die Abb ist damit gemacht

I2Cpytools unterstützt übrigens auch den USB-I2C Dongle von ELV Elektronik AG mit den gleichen Sensoren.

Image
Post Reply