Skip to content

Yocto Layer for Odin Control

Joseph Nobes edited this page Apr 23, 2026 · 28 revisions

Creating a Yocto Layer for an application Odin-Control Instance

The Yocto recipe layer is a directory that specifies how the application-specific code should be baked into the Linux image. This is combined with general layers for the hardware provided by the vendor, as well as additional layers for supporting the LOKI infrastructure. In a typical LOKI application repository, this layer is used to create recipe derived from an odin-control base recipe to install the custom adapter into the image such that resources end up in a predictable place, and everything is executed automatically.

A good example of how this can work is in the BabyD repository.

Contents:

Creating the Yocto Layer

  1. Create the parent directories from your project root. The name meta-<project> is just a convention, but the other directories and files must have the same names to overlay properly.
mkdir meta-<project>
cd meta-<project>
mkdir conf
touch conf/layer.conf
  1. Edit the main config file. layer.conf describes the contents of this layer as well as how it overlays. These settings should work fine, but remember to replace "" with whatever your project's name is.
# layer.conf

# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have recipes-* directories, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
	${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "<project>"
BBFILE_PATTERN_<project> = "^${LAYERDIR}/"
BBFILE_PRIORITY_<project> = "9"
LAYERVERSION_<project> = "1"
LAYERSERIES_COMPAT_<project> = "zeus"    # For 2020 tools
LAYERSERIES_COMPAT_<project> = "langdale"    # For 2023 tools
  1. Create an odin-detector recipe instance (see Creating a Recipe for an Odin-Control Instance), by convention called <project>-detector.

  2. Add the recipe name to the layer.conf so that it will always be brought into the Linux image without being a dependency.

IMAGE_INSTALL_APPENDS = " <project>-detector"        # For 2020 tools
IMAGE_INSTALL:append = " <project>-detector"         # For 2023 tools

Warning

DO NOT try and include these lines in any file aside from layer.conf, no matter what is already present. This leads to confusion due to the way that some petalinux-specific files are overridden between layers.

  1. Update your repository environment file to include the location of the new user layer (see Repository Configuration Files for more information). In repo.env:
yocto_user_layer_0=$(shell pwd)/meta-<project>

Note that you may have to clean and re-build the entire project for this to take effect.

Creating a Recipe For an Odin-Control Instance

An instance of odin-control is the combination of odin-control adapter(s), configuration file(s), sequences for odin-sequencer (optional), and any other supporting files. To make this easier - and to standardise installation locations - a base recipe from which application-specific recipes can be derived has been created. This means that everything to do with automatically starting the process, system outputs and static resource target locations are all handled. Additionally, it includes the the odin-control software, dependencies, and supporting code (odin-devices and odin-sequencer) in the image.

This guide assumes that you have already created an odin-control adapter for your project, and that it is present in the repository's /control directory, or is in another known repository.

Basic File Structure

Note

Throughout this documentation, ensure that <project> is always replaced with the exact same project/detector name

The recipe must be created inside a subdirectory recipes-apps in the user layer. This step takes place assuming the user is CD'ed into /meta-<project>/

mkdir recipes-apps
mkdir recipes-apps/detector
cd recipes-apps/detector

Create a directory for any files that the recipe will need to import later (if applicable):

mkdir files

Create the recipe files themselves (update name to match your project):

touch <project>-adapter.bb
touch <project>.bb

Adding the Control Source

If your control code is in the current repository, create a relative symlink to it (if your control code is in a repository, skip this step).

This way, the logic for moving the control software into the image is kept in the Yocto layer, and the control software is in the toplevel with no required knowledge of how this is done, making it easier to work in in isolation.

ln -s ../../../../control files/control

Edit the Recipe Files

There are two types of recipe files that need to be created, adapter recipe(s) and an application recipe.

An adapter recipe uses <project>-adapter.bb as its naming convention. This recipe is used to install an adapter as a python package that the application recipe will later depend on.

An application recipe uses <project>.bb as its naming convention. This recipe is used to install any UIs, or config files that are required.

Templates

Note

These are generic templates and may not be entirely applicable for your scenario. Please ensure all placeholders are replaced with the revelvant information

Adapter Recipe

You can create this initially by using this template:

SUMMARY = "A recipe for the <project> adapter"

RDEPENDS_${PN} += "odin-control (= 1.6.0)"

SRC_URI = "file://control/* \
          "

inherit setuptools3

do_configure_prepend() {
	cd ${WORKDIR}/<directory_with_setup.py>
}

do_compile_prepend() {
	cd ${WORKDIR}/<directory_with_setup.py>
}

do_install_prepend() {
	cd ${WORKDIR}/<directory_with_setup.py>
}

# This has to be in the format expected in Yocto's license list...
LICENSE = "CLOSED"

Warning

For 2023 tools, _prepend becomes :prepend, _append becomes :append, and _${PN} becomes :${PN}

Application Recipe

You can initially create this file using this template:

inherit odin-control-instance

SUMMARY = "A recipe for the <project> application"

RDEPENDS_${PN} += "<adapter-recipe-name>"

S = "${WORKDIR}"

REACT_UI_TAG = "v0.0.0"

# React UI will end up here
REACT_SOURCE_PATH = "<project>-${REACT_UI_TAG}"

REACT_SOURCE_URL = "<react_UI_download_URL>"

# Repo will be cloned into here
REPO_CLONED_BASE = "git"

# Pull specific commit from repository
SRCREV = "<commit_hash>"
PV = "0.0+git${SRCPV}"

SRC_URI = "git://<github repo URL> \
           file://<project>-config.conf \
           "

# Checksum specifically for the react UI
SRC_URI[react-build-zip.sha256sum] = "<checksum>"

# This has to be in the format expected in Yocto's license list...
LICENSE = "CLOSED"

# Relative repository locations of standard resources
REPO_STATIC_PATH = '${REACT_SOURCE_PATH}'
REPO_SEQUENCES_PATH = 'control/sequences/'
REPO_CONFIG_PATH = 'control/config/config.cfg'

FILES_${PN} += "${base_prefix}/opt/loki-detector/instances/${PN}/*"

Warning

For 2023 tools, _prepend becomes :prepend, _append becomes :append, and _${PN} becomes :${PN}

Note

If using remote complied React resources, REPO_STATIC_PATH must be the same as REACT_SOURCE_PATH

Add the control code to the recipe

  • Your code will need to be staged by the recipe in SRC_URI, but this will depend on where it is stored

    • If (typical) your control code is in the current application repository, specify the local location (this also works with symlink directories). E.g.
    SRC_URI = "file://control/* \
              "
    • If your control code resides in a different repository, you will have to specify it with a git:// URL, as well as a specific tag or commit hash in SRCREV (you cannot simply specify a branch assuming it will pull the latest commit). Note that this is quite different depending on tool version.

      • For 2020 tools:
      SRC_URI = "git://github.com/stfc-aeg/mercury-detector.git;branch=use-loki-carrier \
                "
      
      # Pull specific commit from mercury-detector repository
      SRCREV = "91b2edb93f2a899b4fa2394eaa3444ca7810459c"
      PV = "0.0+git${SRCPV}"
      • For 2023 tools (more complicated due to it not liking hanging references):
      # To build to a tag, update the tag here as well as the commit hash below.
      # You can fetch the git hash with git ls-remote https://github.com/<repository> refs/tags/<tag>
      GIT_TAG = "1.6.0"
      GIT_HASH = "a5a399d21818405c262a1f09cdfe32a944e5f084"
      
      PV = "${GIT_TAG}+git${SRCPV}"
      
      # AUTOREV will just pull latest version
      # SRCREV must now be the git hash of the target tag since Yocto does not like hanging references.
      SRCREV = "${GIT_HASH}"
      
      SRC_URI = "git://github.com/odin-detector/odin-control.git;protocol=http;branch=master"
      SRC_URI[md5sum] = "1af5b49ffe84b3360b23086c7bb06a15"

Some other settings:

  • The RDEPENDS is used to specify any runtime dependencies you need along with your recipe
    • Suggested often-used dependencies are python3-matplotlib and python3-numpy. These were originally always build into the core, but are now only built if the application requires them. You can also add them to layer.conf if they are not specific to the recipe.
  • SUMMARY should be updated for your project ` This example is using a react-based UI, which has already been compiled and made available as a build artifact from a separate repository. This is the recommended way of producing a UI. See below.
  • REPO_STATIC_PATH is used to point the base recipe to static resources from this repository/codebase, if there are any (see UI options below)
  • REPO_SEQUENCES_PATH is used to point the base recipe to odin-sequencer sequences that should be baked into the image
  • REPO_CONFIG_PATH is used to point the base recipe to the odin-control config file for starting the server

Add UI Static Resources - Remote Compiled React (Recommended)

Note

A UI is optional

Add the target repository location so that it will grab a certain tag's build outputs, assuming that the repository has been set up with automation to build tagged versions:

# The react UI tag is a separate repository, used to download pre-built static assets
# This will only accept tags that have been built (releases)
REACT_UI_TAG = "v0.0.4"
REACT_SOURCE_PATH = "babyd-ui-${REACT_UI_TAG}"
REACT_SOURCE_URL = "https://github.com/owner/repo/releases/${REACT_UI_TAG}/build.zip

REACT_UI_SOURCE_URL is the URL of the compiled resources that will be downloaded and unzipped into the directory specified in REACT_SOURCE_PATH.

Advanced - Directly Including Additional Files / Folders

There is a base directory in the LOKI image that is used for including general purpose files and folders. The destination locations are relative to this directory.

To add a files from a local directory (files in the Yocto layer):

# Add the files to the source for the recipe
SRC_URI += " file://control/*"

# Install the target directory into the image
copy_resource_protected 'control/clkgen' 'clkgen'

To add a directory from a cloned source after creating the destination directory:

do_install_append() {
    # Add a directory to the image for the clock configs at the same relative place
    loki_mkdir 'carrier'    # Must create parent
    copy_resource_protected '${MERCURY_REPO_CLONED_BASE}/control/test/carrier/clk_config' 'carrier/clk_config'
}

#TODO there are helpers to build things into the image in known locations, explain them.

Advanced - Building an odin-sequencer UI Alongside the Detector UI

Check that this is still a requirement; it is only used while odin-sequencer is not available as part of odin-react and must therefore be included separately. WARNING: This is hacky.

Essentially this boils down to three steps:

  1. Install the sequencer UI as a static page, using the instructions above
  2. Move the sequencer's index.html to a page with a different name post-install, to clear the way for the React UI:
do_install_prepend() {
    # Rename the original UI index.html to prevent conflict. This means the sequencer
    # can be accessed at <IP>:8888/original.html
    # TEMPORARY UNTIL SEQUENCER IS INCLUDED IN REACT UI
    mv '<sequencer_dir_path>/index.html' '<sequencer_dir_path>/original.html'
}
  1. Copy of the React resources manually, hoping that none of the filenames conflict with filenames of the sequencer UI already added to the same location:
do_install_append() {

    # Directly copy the resources into the default working static location.
    # This is an untidy way of doing things, and relies on a lack of conflicts
    # (apart from the manually handled index.html), but means the two 'separate'
    # UI's can be used a the same time.
    # A better future solution would be to integrate the sequencer UI into react.
    # TEMPORARY UNTIL SEQUENCER IS INCLUDED IN REACT UI
    copy_resource_protected '<sequencer_dir_path>/.' ${LOKI_STATIC_DESTINATION}
}

Application Recipe Configuration Files

There is a default recipe config file located at loki/os/petalinux-custom/project-spec/meta-user/recipes-apps/loki/files/config-default.conf (relative to your top level directory for the detector repository). This config file contains options such as log file locations and a toggle for auto starting instances of Odin control, along with many other options.

To override these default configurations for your application, follow these steps:

  1. Create a file named <project>-config.conf inside the files directory you created.
  2. Assign the desired options a new value (any options that are not changed will still use the default)
  3. Add the following to <project>.bb:
do_install_append() {
    install -d ${D}${base_prefix}/etc/conf.d/loki-config
    install -m 0644 '${WORKDIR}/<project>-config.conf' '${D}${base_prefix}/etc/conf.d/loki-config/<project>-config.conf'
}

FILES_${PN} += "${base_prefix}/etc/conf.d/loki-config/*"

Automatically Starting Intances

By default, all installed instances of odin-control are automatically started on boot. To disable this for an instance of odin-control, add conf_AUTO_START=false to the relevant files/<project>-config.conf file.

Troubleshooting

Generally if all else fails (and your issue is not mentioned below), a make clean && make should sort most issues out. Sometimes the PetaLinux tools just get in a state where things are broken and can't easily be recovered. To save time, try this first in the PetaLinux directory only (cd loki/os/petalinux-custom; make clean && make) before doing the same in the root directory (since the latter will also rebuild the hardware).

In addition, ensure that you are not using the same Yocto cache location (in machine.env) for more than one of the Yocto builds, as they will interfere with each other at some point (traditionally later on, once you've forgotten about this).

Recipe resources not appearing in finished image

This is not really a specific error in itself, but to find out more to aid in debugging, you should attempt to build the recipe on its own. This may allow you to spot errors that were masked during the build process (sometimes errors occur and the PetaLinux build just carriers on anyway...).

  1. Make sure you have the correct PetaLinux tools activated (module load xilinx/2020-1; petalinux_env)
  2. Change directory to the PetaLinux root (cd loki/os/petalinux-custom/)
  3. Build just your recipe's name (e.g. petalinux-build -c <projectname>-detector)

This should build properly by itself, or otherwise print out errors with more information.

not a git repository Error on building detector recipe

If you get the following error, it may not exactly be what it suggests:

'PATCHTOOL = "git" set for source tree that is not a git repository.

This is actually returned by the patch.bbclass when

404 Error When Downloading Compiled React Resources

This is usually because the GitHub repository that the recipe is trying to download the release from is private. In order for releases to be downloaded the repo must be set to public.

If this is not the solution, please ensure that the URL being used is correct.

Clone this wiki locally