Zugriff mit Python
Posted: 13 Dec 2016, 04:51
Wie versprochen kommt hier ein Beispiel für den Zugriff mit Python (das Beipiel arbeitet mit einem DIO am Core). Ich habe gleich mal verschiedene Methoden der Konvertierung von Integer zu Byte-Strings eingebaut. Das ist ein nicht grade einfaches Thema und da wird oft viel falsch gemacht. Vor allem gibt es fundamentale unterschiede zwischen Python 3 und Python 2.7.
Das Beispiel enthält auch die schwierigen ioctl-Zugriffe, die für den bitweisen Zugriff aber auch für den Zugriff über symbolische Namen benötigt werden.
Viel Erfolg!
Das Beispiel enthält auch die schwierigen ioctl-Zugriffe, die für den bitweisen Zugriff aber auch für den Zugriff über symbolische Namen benötigt werden.
Viel Erfolg!
Code: Select all
import time # wird für die Delays der Demo gebraucht
import struct # wird für die Verarbeitung von byte-Strings vor allem mit Python 2.7 benötigt
import fcntl # wird für den bitweisen Zugriff auf das Prozessabbild über IOCTL benötigt
a=1; # Integer, in der ein bit über 14 Positionen geshiftet wird, um ein Lauflicht am DIO zu erzeugen
# Zuerst muss immer der Treiber über ein "open" statement geöffnet werden:
f = open("/dev/piControl0","wb+",0);
# Jetzt beginnt die Endlosschleife der Demo...
while 1:
#Phase 1: Lauflicht von Out1 bis Out14 am DIO
# Diese Phase zeigt den Zugriff wie er mit Python 2.7 und Python 3 funktioniert. Es wird die struct-Bibliothek verwendet
# um einen byte-string zu erzeugen, der für die write-Funktion benötigt wird...
for i in range(0,14):
f.seek(70); # hier wird der Offset im Prozessabbild eingestellt: Outputs fangen in dieser Konfiguration ab Byte 70 an
x = struct.pack('<H',(a<<i));
f.write(x); # hier werden 2 byte in das Prozessabbild geschrieben, weil mit 'H' beim der pack-Funktion 2 Byte in x gepackt wurden
time.sleep(0.1);
# Phase 2: Lauflicht von Out14 bis Out1 am DIO
# Diese Phase zeigt den Zugriff wie er mit Python 2.7 und Python 3 funktioniert. Statt mit struct wird mit einem bytearray gearbeitet,
# um einen byte-string zu erzeugen, der für die write-Funktion benötigt wird...
for i in range(13,-1,-1):
f.seek(70);
x1 = 255 & (a<<i); # low byte
x2 = 255 & ((a<<i)>>8); # high byte
x =bytearray([x1,x2]);
f.write(x);
time.sleep(0.1);
# Phase 3: Lauflicht von außen in die Mitte
# Diese Phase zeigt den Zugriff wie er nur mit Python 3 funktioniert. Ab Python 3 verfügen Integer über die Methode "to_bytes",
# mit der sich sehr elegant ein byte-string erzeugen lässt...
for i in range(0,7):
f.seek(70);
x=((a<<i)|(a<<(13-i))).to_bytes(2, 'little'); # wir brauchen little Endian für das Prozessabbild
f.write(x);
time.sleep(0.1);
# Phase 4: Lauflicht von der Mitte nach außen
# Diese Phase zeigt den Zugriff wie er nur mit Python 3 funktioniert. Ab Python 3 kan mit der Funktion "bytes" ein byte array aus integern erzegt werden,
for i in range(6,-1,-1):
f.seek(70);
x1 = 255 & ((a<<i)|(a<<(13-i)));
x2 = 255 & (((a<<i)|(a<<(13-i)))>>8);
x = bytes([x1,x2]);
f.write(x);
time.sleep(0.1);
# Phase 5: die 14 Eingänge werden auf die Ausgänge gespiegelt, wir lesen jetzt Eingänge ein
f.seek(0); # Eingänge stehen ab Offset 0 in dieser Konfiguration
x = f.read(2); # 2 Byte werden eingelsen
#i = x[0] + 256*x[1]; # Diese sehr einfache Konvertierung des Byte-strings in integerwerte geht nur mit Python 3!
s = struct.unpack('<H',x); # so geht es auch mit Python 2.7
i = s[0]; # weil s eine Liste ist, müssen wir den zugriff auf das erste Element beschränken
f.seek(70); # jetzt kommt das Schreiben der grade gelesenen Daten... Ausgänge stehen ab Offset 70 in dieser Konfiguration
#f.write(i.to_bytes(2,'little')); # to_byte geht nur in Python 3
f.write(struct.pack('<H',i)); # bei Python 2.7 brauchen wir die struct-Bibliothek
time.sleep(3);
# Phasen 6: Über IOCTL Zugriff ermitteln wir den Offset und das Bit eines symbolischen Namens (wurde mit PiCtory angelegt),
# um dann ein einzelnes Bit zu lesen und zu schreiben:
# Liste der vorhandenen IOCTL-Funktionen (siehe C-Quellcode von "piTest"):
#define KB_CMD1 _IO(KB_IOC_MAGIC, 10 ) // for test only
#define KB_CMD2 _IO(KB_IOC_MAGIC, 11 ) // for test only
#define KB_RESET _IO(KB_IOC_MAGIC, 12 ) // reset the piControl driver including the config file
#define KB_GET_DEVICE_INFO_LIST _IO(KB_IOC_MAGIC, 13 ) // get the device info of all detected devices
#define KB_GET_DEVICE_INFO _IO(KB_IOC_MAGIC, 14 ) // get the device info of one device
#define KB_GET_VALUE _IO(KB_IOC_MAGIC, 15 ) // get the value of one bit in the process image
#define KB_SET_VALUE _IO(KB_IOC_MAGIC, 16 ) // set the value of one bit in the process image
#define KB_FIND_VARIABLE _IO(KB_IOC_MAGIC, 17 ) // find a varible defined in piCtory
#define KB_SET_EXPORTED_OUTPUTS _IO(KB_IOC_MAGIC, 18 ) // copy the exported outputs from a application process image to the real process image
# erste Funktion: Wir suchen den Offset und das Byte von "Input_Pin_4" mit Hilfe von KB_FIND_VARIABLE
prm = (b'K'[0]<<8) + 17; # der IOCTL-Parameter wird berechnet aus ASCII 'K' um 8 bit geshiftet plus die ID der gewünschten Funktion (=17)
name = struct.pack('37s',b"Input_Pin_4"); # Das Argument für Funktion 17 ist ein gepacktes byte array mit 37 Byte. Die ersten 32 Byte bestehen aus dem symbolischen Namen
ret = fcntl.ioctl(f,prm, name); # Die Ergebniswerte werden in ein Byte-Array geschrieben,
# wobei die ersten 32 Byte der symbolische Name sind, dann 2 Byte für den Offset, dann 1 Byte für die Bitposition und dann 2 Byte für die Länge
# in C sieht das so aus:
# typedef struct
#{
# char strVarName[32]; // Variable name
# uint16_t i16uAddress; // Address of the byte in the process image
# uint8_t i8uBit; // 0-7 bit position, >= 8 whole byte
# uint16_t i16uLength; // length of the variable in bits. Possible values are 1, 8, 16 and 32
#} SPIVariable;
offset = struct.unpack_from('>H',ret,32)[0]; # so geht es auch mit Python 2.7
bit = struct.unpack_from('B',ret,34)[0];
length = struct.unpack_from('H',ret,35)[0];
# jetzt wird mit Funktion 15 ein einzelnes Bit ("Input_Pin_4") der Eingänge ausgelesen...
prm = (b'K'[0]<<8) + 15;
# Das Argument der Funktion ist ein bytearray mit dieser Struktur:
#typedef struct
#{
# uint16_t i16uAddress; // Address of the byte in the process image
# uint8_t i8uBit; // 0-7 bit position, >= 8 whole byte
# uint8_t i8uValue; // Value: 0/1 for bit access, whole byte otherwise
#} SPIValue;
value = bytearray([0,0,0,0]);
struct.pack_into('>H',value,0,offset); # so funktioniert das auch in Python 2.7
struct.pack_into('B',value,2,bit);
fcntl.ioctl(f,prm,value);
bitval = value[3];
# nochmal die Funktion 17. jetzt wollen wir wissen, wo "Output_Pin_4" im Prozessabbiold steht...
prm = (b'K'[0]<<8) + 17;
name = struct.pack('37s',b"Output_Pin_4");
ret = fcntl.ioctl(f,prm, name);
offset = struct.unpack_from('>H',ret,32)[0];
bit = struct.unpack_from('B',ret,34)[0];
length = struct.unpack_from('H',ret,35)[0];
# jetzt wird mit Funktion 16 ein einzelnes Bit ("Output_Pin_4") der Ausgänge geschrieben...
prm = (b'K'[0]<<8) + 16;
value = bytearray([0,0,0,0]);
struct.pack_into('>H',value,0,offset);
struct.pack_into('B',value,2,bit);
struct.pack_into('B',value,3,bitval);
fcntl.ioctl(f,prm,value);
time.sleep(3);