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);