Python is a widely used interpreted language. Despite the performance gap when compared to a compiled solution, it is still suitable for some applications.
This article focuses on the BSP Layers and Reference Images for Yocto Project. If you want to learn how to use Python on Torizon, read the article Python development on TorizonCore.
Note: Python might be already added in certain versions of our Reference Multimedia Image: BSP Layers and Reference Images for Yocto Project Software. You can quickly check by running the python
command on the command line.
A set of python packages can be added to an OpenEmbedded Linux build for inclusion into the image's root file system. After establishing the image build configuration, additionally append the following line to the oe-core/build/conf/local.conf file:
local.conf
IMAGE_INSTALL_append = "python"
You may also want to install other packages as python-pip
and dependencies to the Python packages you plan to use.
You can search related Python packages using the OpenEmbedded recipes index or by searching the layers
directory of your build environment. An example is provided to search for the pyserial package:
user@host:~$ cd <openembedded-setup-directory>user@host:~/oe-core$ lsbuild deploy export layersuser@host:~/oe-core$ find ./layers -name "*python*pyserial*bb"./layers/meta-openembedded/meta-python/recipes-devtools/python/python3-pyserial_3.4.bb./layers/meta-openembedded/meta-python/recipes-devtools/python/python-pyserial_3.4.bb
Even if you are starting with OpenEmbedded, writing recipes for Python modules is usually straightforward. There are many recipes out there that do it for you to use as examples and their structure looks very alike.
A possible path for writing a recipe is provided below. We use the TinyDB 3.7.0 release for illustration:
We will create three files:
Note: Follow the dash, underscore and case standard provided, since those matter for OpenEmbedded. See the project documentation for further details.
For our example:
First create a new layer (recommended) to hold all your OpenEmbedded customizations, or you can do it in an existing layer also for studying purposes.
# assuming you have a meta-mylayer already setup and working.user@host:~/oe-core$ mkdir -p layers/meta-mylayer/recipes-devtools/python-tinydbuser@host:~/oe-core$ cd layers/meta-mylayer/recipes-devtools/python-tinydb
Create the files provided below:
python-tinydb.inc
# Add the package description here.
DESCRIPTION = "TinyDB is a lightweight document oriented database optimized \
for your happiness :) It's written in pure Python and has no external \
dependencies. The target are small apps that would be blown away by a SQL-DB \
or an external database server."
SECTION = "devel/python"
# Add the license type found in step 3 of previous section
LICENSE = "MIT"
# Add the license md5sum found in step 6 of previous section
LIC_FILES_CHKSUM = "file://${S}/PKG-INFO;md5=8e3a385933697d0374af36db8ee0319d"
PYPI_PACKAGE = "tinydb"
PYPI_PACKAGE_EXT = "tar.gz"
BBCLASSEXTEND = "native"
# Add the compressed package md5 and sha256 checksums generated in step 4 of previous section
SRC_URI[md5sum] = "e28a5650ef8796ab6b7892591edfbae8"
SRC_URI[sha256sum] = "071105c339b44f928968cb4e62f7340a568beb9962a3dcda66eb82da9cab0b0a"
inherit pypi
python-tinydb_3.7.0.bb
inherit setuptools
require python-tinydb.inc
# Uncomment the lines below and add runtime dependencies if any. Our example does not have any dependencies.
#RDEPENDS_${PN} += ""
#RDEPENDS_${PN}_class-native = ""
python3-tinydb_3.7.0.bb
inherit setuptools3
require python-tinydb.inc
# Uncomment the lines below and add runtime dependencies if any. Our example does not have any dependencies.
#RDEPENDS_${PN} += ""
#RDEPENDS_${PN}_class-native = ""
Now you can add the package to your image, e.g. for TinyDB:
local.conf
IMAGE_INSTALL_append = "python-tinydb"
# or
IMAGE_INSTALL_append = "python3-tinydb"
Tests results are pending; however, Python is expected to perform at least an order of magnitude slower than equivalent compiled C/C++ code due to Python's run-time interpreted nature. Use of a Just-in-Time or Ahead-of-Time compiler should improve performance; however, such compilers have not been tested with our Linux images.
Regardless, Python is still a viable alternative for performing lighter processing tasks. It can be effective for low level IO operations as well as high level applications such as web services. Furthermore, Python code can be rapidly modified and tested without the need to recompile.
Blinking a LED using GPIO access through sysfs.
#!/usr/bin/env python import time import os.path import traceback GPIO_RESET = False; # Whether GPIOs should be re-exported GPIO_PATH = "/sys/class/gpio"; GPIO_DIR_OUT = "out"; GPIO_VAL_HI = "1"; GPIO_VAL_LO = "0"; GPIO_CHAN_NUM = "146"; # GPIO1 on Apalis T30 BLINK_PERIOD = 500; # Blink period (milliseconds) BLINK_DUTY = 0.25; # Blink duty cycle (fraction) def main(): try: ### Initialize GPIO - optionally reset if already initialized ## Note: GPIOs which are already used in the drivers can not be controlled from sysfs, ## unless a driver explicitly exported that particular pins GPIO. # Open GPIO export & unexport files exportFile = open(GPIO_PATH+'/export', 'w') unexportFile = open(GPIO_PATH+'/unexport', 'w') # Unexport GPIO if it exists and GPIO_RESET is enabled exportExists = os.path.isdir(GPIO_PATH+'/gpio'+GPIO_CHAN_NUM) if exportExists and GPIO_RESET: unexportFile.write(GPIO_CHAN_NUM) unexportFile.flush() # Export GPIO if not exportExists or GPIO_RESET: exportFile.write(GPIO_CHAN_NUM) exportFile.flush() # Open GPIO direction file to set direction directionFile = open(GPIO_PATH+'/gpio'+GPIO_CHAN_NUM+'/direction','w') # Set GPIO direction to "out" directionFile.write(GPIO_DIR_OUT) directionFile.flush() # Open GPIO value file to set value valueFile = open(GPIO_PATH+'/gpio'+GPIO_CHAN_NUM+'/value','w') # Loop indefinitely while True: # Set GPIO value to HI valueFile.write(GPIO_VAL_HI) valueFile.flush() # Sleep for blink on duration time.sleep(BLINK_PERIOD*BLINK_DUTY/1000.0) # Set GPIO value to LO valueFile.write(GPIO_VAL_LO) valueFile.flush() # Sleep for blink off duration time.sleep(BLINK_PERIOD*(1.0-BLINK_DUTY)/1000.0) except Exception: print(traceback.format_exc()) return if __name__ == "__main__": main()
Note: The modules fcntl and glob are provided by the packages 'python-fcntl' and 'python-shell' respectively.
#!/usr/bin/env python import fcntl, struct, glob RTC_RD_TIME=0x80247009 # Identify RTCs rtcList = glob.glob('/dev/rtc[0-9]') print "RTCs: ", rtcList, "\n" # Read each RTC for rtc in rtcList # struct rtc_time { # int tm_sec; # int tm_min; # int tm_hour; # int tm_mday; # int tm_mon; # int tm_year; # int tm_wday; # int tm_yday; # int tm_isdst; # }; a=struct.pack('iiiiiiiii', 0,0,0,0,0,0,0,0,0) fo=open(rtc) input=fcntl.ioctl(fo.fileno(), RTC_RD_TIME, a) result=struct.unpack('iiiiiiiii', input) print rtc + ": " + str(1900+result[5]) + "-" + str(1+result[4]) + "-" + str(result[3]) + " " + \ str(result[2]) + ":" + str(result[1]) + ":" + str(result[0]) + " UTC"