Pi IoT In Python Using Linux Drivers - GPIO Using Ioct |
Written by Mike James & Harry Fairhead | |||||||||||||||||||||||||||||||||||||||||
Monday, 29 July 2024 | |||||||||||||||||||||||||||||||||||||||||
Page 2 of 4
The struct module can help you create a buffer of the right length and initialize it with appropriate data, for details see Programmer’s Python: Everything is Data, ISBN:9781871962595. There are many ways to use the struct module but the most efficient is to create a struct object: mystruct = struct(format) where format is a string that defines the type of each part of the buffer and, implicitly, its length. The Python documentation gives a list of allowable format characters but the most useful are:
Notice that int/long int and unsigned int are the same type on most systems, but if in doubt use long and unsigned long to make sure you get 4 bytes of storage. The format you use sets the size of the buffer and the way Python data is loaded into it and unloaded from it. For example, the struct given earlier can be implemented as: gpiochip_info= struct.Struct("32s 32s L") This creates a Struct object with a 68-byte buffer with the first 32 and second 32 bytes regarded as simple character data and the last 4 bytes as a 32-bit unsigned integer. Once you have the Struct object you can transfer data into the buffer using its pack method. For example: buffer = gpiochip_info.pack(b"Hello",b"World",42) returns a buffer with the character codes for Hello packed into the first five bytes, those for World packed into the five bytes starting at byte 32 and the final four bytes set to the binary representation of 42. Notice that the character data has to be specified as a byte data by a leading b and is automatically packed out with zeros to create 32-byte, C-style, null-terminated strings. To get data out of the Struct object you use the unpack method, for example: first,second,third=gpiochip_info.unpack(buffer) If you try printing out the strings, you will discover that they are in fact byte data: print(first) produces: b'Hello\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ i.e. a null-terminated byte character sequence. You can remove the nulls and convert to a standard Python string in a number of ways. For example: print(first.rstrip(b'\0').decode("utf-8")) produces: Hello
Using gpiod With ioctlThe gpiod character device works entirely in terms of the ioctl system call, not by reading or writing the files as was the case with sysfs which it replaces. What you need to know to use the driver directly are the request codes and the structures that are passed. These are not defined for Python in the documentation, but the C linux/gpio.h header contains all of the information necessary. The problem is that you have to read the C to find out what the request constants and structs used actually are. Working with the GPIO chip and the GPIO lines follows the same standard steps:
Getting Chip InfoAs a first simple example, let’s get some information about the GPIO chip. This involves using Python to make an ioctl call that is only documented as a C header file – linux/gpio.h. If you look through the header file you will find the request constant defined as: GPIO_GET_CHIPINFO_IOCTL=0x8044B401 You will also find the definition of a struct which is used to return the information about the GPIO chip: struct gpiochip_info { char name[32]; char label[32]; __u32 lines; }; This is the struct used in the previous examples. Even if you don’t know C, you can probably work out that the struct consists of a name of 32 characters, a label of 32 characters and an unsigned 32-bit integer. This can be implemented using: gpiochip_info= struct.Struct("32s 32s L") With this information we can open the file and make the ioctl call: import fcntl, struct,io GPIO_GET_CHIPINFO_IOCTL=0x8044B401 f = io.open("/dev/gpiochip0", "rb",buffering=0) gpiochip_info= struct.Struct("32s 32s L") buffer=gpiochip_info.pack(b' ',b' ',0) result=fcntl.ioctl(f, GPIO_GET_CHIPINFO_IOCTL,buffer) name,label,lines=gpiochip_info.unpack(result) print(name.rstrip(b'\0').decode("utf-8")) print(label.rstrip(b'\0').decode("utf-8")) print(lines) As with all good, easy-to-understand, examples, error handling has been omitted. If you run this program on any Pi but a Pi 5 you will see: pinctrl-bcm2835 gpiochip0 54 To run it on a Pi 5 change gpiochip0 to gpiochip4 and you will see: gpiochip4 pinctrl-rp1 54 |
|||||||||||||||||||||||||||||||||||||||||
Last Updated ( Tuesday, 30 July 2024 ) |