Skip to content

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mix_grisp

Mix tooling for building, deploying, and updating Elixir applications on GRiSP boards. It provides the same GRiSP workflows as rebar3_grisp, adapted to Mix releases and Elixir configuration.

Run mix help grisp.TASK for task-specific help.

Requirements

  • Elixir 1.20 or later
  • A local Erlang/OTP installation whose major version matches the target OTP
  • A GRiSP 2 board and SD card
  • A GRiSP toolchain or Docker when building OTP, eMMC images, or bootloaders

Installation

Add GRiSP and this build-time plugin to mix.exs:

defp deps do
  [
    {:grisp, "~> 2.12"},
    {:mix_grisp, "~> 1.0", runtime: false}
  ]
end

Fetch dependencies with mix deps.get. Print the installed plugin and library versions with:

mix grisp.version

Create a new application

The configure task creates a supervised Mix application with release and GRiSP configuration, plus optional networking files:

mix grisp.configure

For non-interactive use:

mix grisp.configure --no-interactive --name my_grisp_app \
  --ssid mywifi --psk wifipsk

Important options are --name, --otp-version, --jit true|false, --dest, --wifi, --ssid, --psk, --grisp-io, --grisp-io-linking TOKEN, --epmd, and --cookie. The JIT option uses the rebar-compatible explicit values --jit true and --jit false. In non-interactive mode, optional features are disabled when their flags are absent. Ethernet networking is always configured. Wi-Fi is opt-in through --wifi and is also enabled implicitly when either --ssid or --psk is supplied. Supplying --grisp-io-linking TOKEN also enables GRiSP.io integration.

If the target directory already exists, interactive mode asks for confirmation, preserves every existing file, and creates only missing files. Non-interactive mode refuses to configure an existing directory so scripts cannot overwrite a project accidentally.

Configure an existing application

Add GRiSP and release configuration to the project keyword list:

def project do
  [
    app: :my_app,
    version: "0.1.0",
    elixir: "~> 1.20",
    deps: deps(),
    grisp: grisp(),
    releases: releases()
  ]
end

defp grisp do
  [
    platform: :grisp2,
    otp: [version: "29", jit: true],
    deploy: [
      destination: "/path/to/SD-card",
      # pre_script: "rm -rf /path/to/SD-card/*",
      # post_script: "diskutil unmount /path/to/SD-card"
    ]
  ]
end

defp releases do
  [
    my_app: [
      overwrite: true,
      cookie: "replace_with_a_long_random_cookie",
      include_erts: &MixGrisp.Release.erts/0,
      steps: [&MixGrisp.Release.init/1, :assemble],
      include_executables_for: [],
      strip_beams: Mix.env() == :prod
    ]
  ]
end

:platform defaults to :grisp2. The configured OTP version requirement selects a pre-built package unless a :build section enables a custom build. Compile on the development host with the same OTP major version as the target.

Elixir shell and networking

Add grisp/grisp2/common/deploy/files/grisp.ini.mustache. Mix releases need the RELEASE_LIB boot variable. Elixir also expects native UTF-8 filename encoding, so -fnu must be passed to erl.rtems. To boot into IEx, use the Elixir user driver and +iex; -s elixir start_iex is obsolete and fails on current Elixir releases.

[erlang]
args = erl.rtems -C multi_time_warp -fnu -- -mode embedded -home . -pa . -root {{release_name}} -bindir {{release_name}}/erts-{{erts_vsn}}/bin -boot {{release_name}}/releases/{{release_version}}/start -boot_var RELEASE_LIB {{release_name}}/lib -config {{release_name}}/releases/{{release_version}}/sys.config -kernel inetrc "./erl_inetrc" -user elixir -extra +iex --no-halt
shell = none
on_exit = reboot
on_crash = reboot

[network]
ip_self=dhcp
wlan=enable
hostname=GRISP_HOSTNAME
wpa=wpa_supplicant.conf

For Wi-Fi, add wpa_supplicant.conf beside it:

network={
    ssid="WLAN_SSID"
    key_mgmt=WPA-PSK
    psk="WLAN_PASSWORD"
}

Do not commit real credentials. See the GRiSP networking guide. Ethernet is always configured. For Ethernet-only networking, omit the Wi-Fi options; the configure task then leaves out wlan=enable, the wpa setting, and wpa_supplicant.conf.

When --grisp-io is enabled, the generated project also includes the required GRiSP.io dependencies and release applications. Its Logger level is set to :notice to avoid emitting connection-level debug messages on the board.

Deploy a release

Deploy to the configured destination:

mix grisp.deploy
mix grisp.deploy --relname my_app --relvsn 0.1.0
mix grisp.deploy --destination /Volumes/GRISP --force

If more than one release is configured, --relname is required. Use --tar to create _grisp/deploy/grisp2.RELNAME.RELVSN.tar.gz instead of copying to a destination:

mix grisp.deploy --tar

Options are --relname/-n, --relvsn/-v, --tar/-t, --destination/-d, --force/-f, --pre-script, and --post-script. Options after -- are forwarded to mix release:

mix grisp.deploy --tar -- --quiet

The task compiles with GRISP=yes and GRISP_PLATFORM set, resolves or reuses the target OTP package, creates a Mix release with the target ERTS, and applies all application grisp/*/deploy overlays.

Generate GRiSP 2 firmware

The default command generates a system-partition firmware under _grisp/firmware:

mix grisp.firmware

Available outputs are:

  • system firmware (.sys.gz), enabled by default and disabled with --no-system;
  • an eMMC image (.emmc.gz) with --image;
  • bootloader firmware (.boot.gz) with --bootloader.

Examples:

mix grisp.firmware --relname my_app --relvsn 0.1.0
mix grisp.firmware --image --bootloader --force --refresh
mix grisp.firmware --image --no-truncate
mix grisp.firmware --bundle path/to/release.tar.gz

Other options are --[no-]compress, --quiet, and all release-selection options. If no bundle is supplied, the task creates one through grisp.deploy --tar; --refresh recreates it. Image and bootloader generation require a toolchain.

To install firmware, copy it to the GRiSP SD card, unmount the card, open the serial console, insert the card, reset, and interrupt barebox. Write the system firmware to the active partition (/dev/mmc1.0 or /dev/mmc1.1):

uncompress /mnt/mmc/grisp2.RELNAME.RELVSN.sys.gz /dev/mmc1.0

Write an eMMC image or a bootloader image to /dev/mmc1:

uncompress /mnt/mmc/grisp2.RELNAME.RELVSN.emmc.gz /dev/mmc1
uncompress /mnt/mmc/grisp2.RELNAME.RELVSN.boot.gz /dev/mmc1

A truncated image contains only the first system partition. Set the active system to 0 before booting it. Writing system firmware to the inactive A/B partition does not change which partition the board boots.

Build a software update package

Create _grisp/update/grisp2.RELNAME.RELVSN.tar:

mix grisp.pack
mix grisp.pack --with-bootloader
mix grisp.pack --refresh --force
mix grisp.pack --key private_key.pem

The task reuses or generates firmware automatically. Options include --system, --bootloader, --block-size, --key, --with-bootloader, --refresh, --force, and --quiet. If explicit firmware is used, an explicit bootloader must be accompanied by an explicit system firmware.

For A/B updates, include grisp_updater_grisp2 and configure :grisp_updater:

config :grisp_updater,
  signature_check: true,
  signature_certificates: {:priv, :my_app, "certificates/updates"},
  system: {:grisp_updater_grisp2, %{}},
  sources: [
    {:grisp_updater_tarball, %{}},
    {:grisp_updater_http, %{backend: {:grisp_updater_grisp2, %{}}}}
  ]

Extract the package under releases/RELNAME/RELVSN, serve releases over HTTP, then update and validate from IEx:

:grisp_updater.update("http://HOST_IP:8000/RELNAME/RELVSN")
:grisp_updater.validate()

When signature checking is enabled, use --key and install the corresponding public certificate in the configured directory.

List pre-built packages

mix grisp.package list
mix grisp.package list --type toolchain
mix grisp.package list --cached
mix grisp.package list --columns version,hash,url

Use --platform to override the configured platform. OTP columns are version, hash, name, size, etag, url, and last_modified. Toolchain results also provide os, os_version, revision, and latest.

Build OTP for GRiSP

Custom drivers, NIFs, and GRiSP system changes require a custom OTP build. Add a toolchain to the GRiSP configuration:

defp grisp do
  [
    platform: :grisp2,
    otp: [version: "29", jit: true],
    build: [
      toolchain: [
        # Local installation takes precedence:
        directory: "/PATH/TO/grisp2-rtems-toolchain/rtems/VERSION/"
        # Or: docker: "grisp/grisp2-rtems-toolchain"
      ]
    ],
    deploy: [destination: "/PATH/TO/DESTINATION"]
  ]
end

GRISP_TOOLCHAIN overrides the configured directory. Build with:

mix grisp.build
mix grisp.build --no-configure
mix grisp.build --clean
mix grisp.build --tar
mix grisp.build --update-prebuild

The installation is stored under _grisp/otp/VERSION/install. Reconfigure after adding C sources; --no-configure can speed up rebuilds after ordinary source changes.

Bug reports

mix grisp.report
mix grisp.report --tar

Reports are written under _grisp/report. Review them for private information before sharing.

Development checkouts

To test local branches, place both repositories in the consuming project's _checkouts directory:

git clone https://github.com/grisp/mix_grisp.git _checkouts/mix_grisp
git clone https://github.com/grisp/grisp_tools.git _checkouts/grisp_tools

Mix automatically gives checkout dependencies precedence over Hex packages.

Troubleshooting

If boot fails with cannot expand $RELEASE_LIB in bootfile, ensure the -boot_var RELEASE_LIB {{release_name}}/lib option is present. If BEAM files were compiled for a later runtime, switch the development host to the target OTP major and rebuild:

mix clean
mix deps.clean --all --build
mix deps.get
mix grisp.deploy

About

Mix plug-in for GRiSP

Resources

Stars

6 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages