Skip to main content

Software Version & Hardware Version

info

This document describes the version identifiers used by Memfault. For information on which values are permitted in each of the version specifiers, see the documentation here:

https://api-docs.memfault.com/#memfault-resources

Hardware Version#

The Hardware Version is used to identify the type of hardware on which software is running. In Memfault, a device always has exactly one Hardware Version. It can be used to identify different device types being tracked in the same Project (i.e. smart-toaster and smart-oven) and different board revisions of the same device type (i.e. smart-toaster-evt, smart-toaster-pvt, etc.).

Android#

On Android, Memfault uses the ro.product.board system property as the device's Hardware Version by default. From the Android product documentation:

The board/device layer represents [...] the bare schematics of a product. These include the peripherals on the board and their configuration.

Software Type#

The Software Type is used to identify the separate pieces of software running on a given device. This can be images running on different MCUs (i.e main-mcu-app & bluetooth-mcu) or different images running on the same MCU (i.e main-mcu-bootloader & main-mcu-app). You can also use Software Types to distinguish between build variants (i.e. main-mcu-dvt & main-mcu-evt).

MCU#

The software running on your devices will need to report its Software Type correctly such that it matches with what has been configured in the Project. Please see the core/device info component of the Firmware SDK for details on how to set this up on the device's software side.

Android#

Memfault uses the Software Type android-build to identify the system software running on the device.

Applications have a Software Type equal to their application ID, e.g. com.acme.smartsink.

Software Version#

A Software Version is a single build of a particular Software Type. Software Versions are used in Memfault in a variety of ways, including but not limited to:

  • Displaying Issue distributions by version.
  • Determining regressions: re-opening an Issue if a defect recurs in a newer Software Version after the Issue was marked as resolved.
  • Checking if a device is up to date: if your Project uses Memfault to deploy firmware, the firmware's Software Version is used to determine if a device requires an update.

Version Schemes#

Comparison between versions is a fundamental input to Memfault's OTA system. Consult the section Updating Behavior on our OTA documentation to see how the rules below are applied to OTA.

Ordering#

We recommend using a SemVer for your Software Versions, see details here. If you do not use SemVer, we fallback to using natural sort, as implemented by natsort to resolve ordering.

Memfault uses a slight tweak on top of natsort to support rc or dev versioning schemes. This is achieved by appending a character z.

For example, these versions are sorted from oldest to newest:

1.0.0rc1
1.0.0
1.0.1-dev
1.0.1-rc2
1.0.1
1.0.12
1.0.20

To implement a "release candidate" or "alpha/beta" versioning scheme, the recommended option is to follow the semver 2.0 specification, for example:

1.0.0-alpha.1
1.0.0-alpha.2

Or:

1.0.0-rc.0
1.0.0-rc.1

Be cautious about more exotic versioning schemes! natsort will only handle the common scenarios.

For example, the semver 2.0 spec permits appending build metadata to a version number:

1.0.0+092ced197518c8e304232239315c611af6ff2404

But natsort will apply lexical ordering (under the default settings), which may not result in the expected OTA response (see "Disable Version Checking").

Recommended Versioning Scheme#

Memfault recommends using Semver 2.0 for versioning. Specifically, using these forms will result in the least confusion:

  1. for official releases, strict semver ("normal version number" per the spec):

    1.0.0

    Exactly 3 digit groups, leading zeros permitted, delimited by periods (see the spec for details).

  2. "beta" or "release candidate", etc., pre-release versions:

    1.0.0-beta.0
    1.0.0-rc.0
  3. automated nightly builds that are deployed over Memfault OTA to a cohort:

    # using a build number (eg CI build number, or monontonically incrementing
    # based on git tag, etc.)
    1.0.0-nightly.0
    # using a calendar version. always increments, and can be generated without
    # context (assuming only 1 build is deployed per day)
    1.0.0-nightly.20220123
  4. development builds generated locally (using git sha or other identifier):

    1.2.3+092ced197518c8e304232239315c611af6ff2404

    And set the "Disable Version Checking" setting for the cohort.

info

Note that for these schemes, the device_info.software_version field may need to be populated at build time by the build script. For example, you might have a C preprocessor token that holds the string for the software version, where the value is populated by a build script:

# a C compiler option setting the SOFTWARE_VERSION token to a string
-DSOFTWARE_VERSION=\"1.0.0-nightly-20220123\"`

Some potentially useful things to consider:

  • if using git tags, see information on git rev-parse for generating tag strings
  • if using a calendar version, the unix date command could be used, for example date --utc +%Y%m%d.

Testing#

To test version ordering, two approaches are recommended:

  1. locally, using the natsort command line utility:

    ❯ natsort 2022.04.01 2022.10.02 2022.05.05 2022.05.04
    2022.04.01
    2022.05.04
    2022.05.05
    2022.10.02

    Note: For exotic versioning schemes, to mimic the way Memfault's system operates, it may be necessary to append a z to the versions being compared

  2. using Memfault's API, test using a dummy device (assign it to the appropriate cohort you are testing):

    # use --get and --data-urlencode to encode the query params correctly
    ❯ curl --silent -i -X GET --get \
    --header "Memfault-Project-Key: ${MEMFAULT_PROJECT_KEY}" \
    'https://device.memfault.com/api/v0/releases/latest/url' \
    --data-urlencode device_serial=OTA_TEST_DEVICE \
    --data-urlencode hardware_version=${HARDWARE_VERSION} \
    --data-urlencode software_type=${SOFTWARE_TYPE} \
    --data-urlencode current_version=${SOFTWARE_VERSION}

    See details on the Releases API for more information.

Platform-Specific Considerations#

MCU#

A single Software Version is associated with one Symbol Software Artifact (.elf file).

β”œβ”€β”€ main-fw # Software Type
β”‚ β”œβ”€β”€ 1.0.0 # Software Version
β”‚ β”œβ”€β”€ 1.1.0
β”‚ β”œβ”€β”€ 1.1.1
| ...
└── wifi-fw
β”œβ”€β”€ 11.0
β”œβ”€β”€ 12.0
β”œβ”€β”€ 12.1
...

The software running on your devices will need to report its Software Version correctly such that it matches with what has been configured in the Project. Please see the core/device info component of the Firmware SDK for details on how to set this up on the device's software side.

Android#

Memfault supports extracting the Software Version for the android-build Software Type from several different sources in order to suit different build configurations.

By default, irrespective of the source, the Software Version will be ordered per Version Schemes.

Recommended: Build Fingerprint and System Property#

We recommend using both the build fingerprint and a custom system property for situations where the build fingerprint does not contain a meaningful identifier; for example, if the incremental and ID parts of the fingerprint are set by the ODM and have no semantic meaning for your internal software versioning.

The full Software Version stored in Memfault will have the form:

${fingerprint}::${property}

This provides the additional functionality enabled by using the build fingerprint, while also using a system property of your choice for display and comparison purposes.

The fingerprint must uniquely identify the build, and the specified system property must also uniquely identify the build.

Recommended: Build Fingerprint Only#

Memfault supports using the Android build fingerprint as the Software Version. In recent AOSP builds, the build fingerprint can be found in out/target/product/$DEVICE/build_fingerprint.txt.

If the fingerprint is used to specify the Software Version, the fingerprint must be unique for each build.

We recommend using the fingerprint instead of a single system property because it enables additional functionality such as the ability to filter traces based on fingerprint properties like the build type.

Because the build fingerprint is usually a very long string, the Memfault UI will show only the most relevant part. By default, the "incremental" component is used for display and ordering; this can be customized to instead use e.g. the "ID" component.

System Property Only#

The Software Version can be sourced from any system property. The specified property must be able to uniquely identify the build (the value must be unique for each build).

Android Applications#

For an Android application, Memfault stores both the versionCode and versionName; the versionCode is used to compare Software Versions.