This article presents two options to setup Python:
There are no guarantees that the same Python packages will be available using both methods, since they are maintained by different third parties.
The pre-built Linux image provided by Toradex is built on top of the Ångström distribution. It comes with a package manager (opkg) and the Ångström feeds already configured, which enables the installation of packages in an existing image. It is a good starting point for quick prototypes and tests.
To see a list of relevant packages, enter the following commands:
opkg update
opkg list | grep python
Python (and any additional packages) may be installed with the following command:
opkg install python [optionally list additional packages...]
The same applies for Python 3. The packages are usually referred as python3-package, for instance python3-pyserial.
PIP is the Python package manager, which enables you to install packages unavailable from the distribution feeds. Nevertheless you have to install at least Python and PIP:
opkg updateopkg install python python-pip
You may also need a native SDK if the package builds native (C/C++) code. Please refer to the article Native Compilation for information how to setup the native SDK:
Then you can install a package using PIP:
pip install <package># for instancepip install pyserial
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"
Then execute (or re-execute) 'bitbake' for the image (ie. 'bitbake angstrom-lxde-image'). For more information about building a Linux image, see OpenEmbedded (core).
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 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: exception.printStackTrace() 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"