Browser in Nerves (kiosk-mode)

Hi all
We’d like to use a raspi3 as a host for a full screen browser app.
Theres a project on github with just this intention:

But I just get it running. It fails with the error

Status 404 Not Found

This seems to be a problem, which was solved in nerves already, so I changed the nerves dependency to the newest version. It didn’t solve the problem though.
Latest commit is from jan 22, so it seems to be maintained, but an open issue wasn’t resolved by the maintainer.
Anybody has a hint, where I could get a functioning example or find an experienced person, who could help?
Thanks in advance!

Did you checkout the v1.10.0 tag?
It looks like the checksum for the download doesn’t match the one in the releases.
Take a look at Nerves Package Configuration (especially 2 and 7).

Thanks a lot for your input!
What I saw the is module Mix.Tasks.Nerves.Artifact.Get, which calculates the checksum out of the list of package files provided in mix.exs.
But I don’t know yet, how the checksum on github is built and why it differs from the calculated checksum. Maybe the list of files has changed?
Is there a standard-method which github uses?
I don’t know and have to check this out.

If you checked out the master branch, the checksum differs, because the files used for the checksum changed since the v1.10.0 release.

The checksum calculation has nothing to do with GitHub. It is done by Nerves.

Just run git checkout v1.10.0 and try again!

@moogle19 : You’re my hero! Thanks a lot!
It’s so obvious but I didn’t get it before you pointed me to it.

I still can’t build the example from GitHub - nerves-web-kiosk/kiosk_system_rpi3: Nerves QtWebEngine Kiosk system for Raspberry Pi 3, but this seems to be an issue already reported by someone else.
It hangs now when trying to download the artifacts.

When I try to bump the version of the nerves dependency myself from 1.6.0 to 1.7.11 I’m changing the mix.exs and then the checksum doesn’t match any more :crazy_face: .
I tried to rebuild the dependencies of KioskSystemRpi3 which resulted in a 3 hour build of buildroot which then finally failed on my Mac.
What would be the the path to successfully upgrading the dependencies of nerves?
Because a mix deps.get after changing the version will always fail (different checksum).

@daniel_frey Do you have access to a Linux machine? Building the kiosk code is very time consuming. When I did it, I used a 32-core Linux machine and it still took a while. I think it was around 30-40 minutes for a full build.

There has been some recent work on Raspberry Pi 4-based kiosks if that’s an option. @elcritch presented his work on it at NervesConf last week. I’m hoping he’s on the forum so that he can give an update here.

@fhunleth We have a build server with 16 cores. We use it with docker images only though. So installing the needed packages for building the kiosk is not really an option I’d prefer.
I have some VM’s, but rather low cores. But if I’d know the build runs through I wouldn’t mind if it takes several hours. If it fails after 4 hours it is a bit more annoying :wink:

A Raspberry Pi 4-based kiosk would definitely be great!

You could run mix deps.update —all which gives you the newest version which match the requirements in your mix.exs (e.g the newest 1.6 of nerves). This only changes the mix.lock so the checksum stays the same.

I tried to build GitHub - nerves-web-kiosk/kiosk_system_rpi3: Nerves QtWebEngine Kiosk system for Raspberry Pi 3 from scatch, but failed.
What I did: I pulled the repository above on an Ubuntu 20.04.
I went into the “example” directory and made a

export MIX_TARGET=rpi3
mix deps.clean 
mix deps.compile

To install the build infrastructure I installed the following packages:

build-essential autoconf m4 libncurses5-dev libwxgtk3.0-gtk3-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libssh-dev unixodbc-dev xsltproc fop libxml2-utils libncurses-dev openjdk-11-jdk 
 gcc-multilib automake libwxgtk3.0-gtk3-dev qtwebengine5-dev qtmultimedia5-dev qt5-default

I got errors though but managed the get further with the ENV set FORCE_UNSAFE_CONFIGURE=1

It finally fails with an error message from ninja. The last message is this

ninja: error: WriteFile(__services_network_public_mojom_mutable_network_traffic_annotation_interface_shared_cpp_sources__jumbo_merge__root_dev_kiosk_system_rpi3_example_deps_kiosk_system_rpi3_.nerves_artifacts_kiosk_system_rpi3-portable-1.10.0_build_qt5webengine-5.15.0_src_toolchain_target__rule.rsp): Unable to create file. File name too long
ninja: build stopped: .

I tried various different approaches. My goal is to compile kiosk_system_rpi3 with the latest release of nerves, then push it to my clone repository on github as an artifact.

I’m somehow stuck. As I understand the nerves project generates their precompiled packages with buildroot included, so that the build process for depending projects don’t take that long.

Is there a somewhere description how I can build an artifact for kiosk_system_rpi3 from scratch?
Any help is appreciated!

I can successfully build kiosk for rpi3.
Ubunut 20.04 LTS.

asdf install erlang
asdf global erlang
asdf install elixir 1.11.4-otp-22
asdf global elixir 1.11.4-otp-22
mix local.rebar
mix local.hex
mix archive.install hex nerves_bootstrap

create a project with mix and to export MIX_TARGET=rpi3.

diff --git a/mix.exs b/mix.exs
index d8481f7..7bd212d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -45,15 +45,7 @@ defmodule Kiosk.MixProject do
       # bumps to Nerves systems. Since these include Linux kernel and Erlang
       # version updates, please review their release notes in case
       # changes to your application are needed.
-      {:nerves_system_rpi, "~> 1.17", runtime: false, targets: :rpi},
-      {:nerves_system_rpi0, "~> 1.17", runtime: false, targets: :rpi0},
-      {:nerves_system_rpi2, "~> 1.17", runtime: false, targets: :rpi2},
-      {:nerves_system_rpi3, "~> 1.17", runtime: false, targets: :rpi3},
-      {:nerves_system_rpi3a, "~> 1.17", runtime: false, targets: :rpi3a},
-      {:nerves_system_rpi4, "~> 1.17", runtime: false, targets: :rpi4},
-      {:nerves_system_bbb, "~> 2.12", runtime: false, targets: :bbb},
-      {:nerves_system_osd32mp1, "~> 0.8", runtime: false, targets: :osd32mp1},
-      {:nerves_system_x86_64, "~> 1.17", runtime: false, targets: :x86_64}
+      {:kiosk_system_rpi3, "~> 1.0"}
mix deps.update --all
mix firmware
mix firmware.burn

EDIT: hangs at boot :frowning:

Thank a lot @Sebb. Your instructions lead me finally to a working sample!
Great help in this forum.
I had to compile it under Ubuntu, on my Mac it wouldn’t work.
Before your post I tried to use a newer erlang, but this forced me the compile the
kiosk_system_rpi3 myself, which I failed.

At last I have now a working sample. QTWebengine looks a bit old fashioned though, so I don’t know if I could use it for production.
But I’m still curious how I could build from scratch a nerves_system :slight_smile:
Again, thanks a lot for your help!

Thats odd … did you try with the exact same versions on the Mac?

QTWebengine is always up-to-date with Chromium when Qt is released, so it depends on Qt-Version, see:

You won’t find anything better in the embedded world.

I dug out a rpi3 and followed the process. Yes, it does hang at boot. Any clues on how to get past that?

No, sorry. It worked once, all I can say right now.

Hi Sebb and others,

I went back and reproduced your build. I connected a serial console to the rpi3 gpio and I see the kernel boot on the serial console and the nerves splash screen on the hdmi. The iex shell starts and the console displays the following error.

erl_child_setup: failed with error 32 on line 253

Any ideas/advice on what to look at?

No idea, this seem to be the source of the error (from OTP master, so not really)

How did you setup the serial console?

I setup the serial console by using a ftdi usb to serial dongle in 3.3v mode on pins 6, 8, 10 of the gpio header. You must be careful to ensure that any dongle you use is or can be put into 3.3 volt (TTL) mode, or you may lose the RXD pin on the pi. The dongle I use has a genuine FTDI FT232RL chip on. I find those the most reliable. Beware clones.

Errno 32 is a broken pipe error, so I am guessing that it tried to launch something that either does not exist or failed.

I suspect the code that is earlier version than the one you sent me a link to. I would expect line 253 to be a line like the one at line 323.


Thanks, I’ll try to look into it with the serial console.

The system now crashing in OTP is beyond my knowledge. I’m also just starting with nerves, but I want to understand the thing, so I hope I’ll eventually be able to fix this. Kiosk is not an immediate priority for me, I first have to be able to build a normal system with some adjustments in buildroot. After that I’ll look into Kiosk and hopefully can make the systems work again.

No, errno is set by some C-stdlib funtion somewhere before the log message is generated. But could still be another version.

I have to disagree on that. Please excuse me if I am teaching my grandmother to suck eggs.

The blob we are looking at is a C programme. To produce that particular error message.The sequence of calls is as follows.

Execution starts at the main function at line 421. At line 546 in this function the following happens.

            os_pid = fork();
            if (os_pid == 0)

The fork function creates a duplicate of this process. So after it returns two processes are executing the same piece of code in parallel. So the next thing that happens is they both check the os_pid value. In the child process this is set to zero and in the parent(original) process it is set to the pid of that process. So the child process calls the start_new_child function and the parent process continues to the next line.

So up to the the start_new_child function at line 147. The first reference to child_error is at line 176. So looking at that code
do {
    res = read(pipes[0], (char*)&size, sizeof(size));
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));

if (res <= 0) {
    errln = __LINE__;
    goto child_error;
Errno is nothing to do with the C library. It is a number that is set by the linux kernel on before returning from a system call. In this case the system call is read and system always return less than zero whenever errno is set.
So the line number in the source code is saved to errln and goto child_error: is executed. This literally jumps the to child_error: label at line 351. This prints errln and the current value of errno which will still be whatever the read system call set it to.

I hope that makes sense.