Usage of atomvm.read_priv

I’ve read this part of the AtomVM guide and I wonder about the usage of the read_priv/2 function AtomVM supports.

I am using ExAtomVM for managing my project and have a project structure like

.
├── README.md
.
├── lib
│   ├── tinker
│   │   ├── blink.ex
│   │   ├── config.ex
│   │   ├── dht.ex
│   │   ├── sensor.ex
│   │   └── sntp.ex
│   └── tinker.ex
.
├── priv
│   └── secret.txt
.

My understanding was that after building/flashing the file should be available to my app in tinker/priv/file.txt.

When I have:

defmodule Tinker.Config do
  def configuration do
    txt = :atomvm.read_priv("tinker", "file.txt")
    :io.format(~c"~p~n", [:erlang.binary_to_list(txt)])
  end
end

and run the app like:

defmodule Tinker do
  @doc """
  Application entry point.
  """
  def start do
    {ok, _Pid} = :logger_manager.start_link(%{log_level: :debug})

    Tinker.Config.configuration()

end

I see garbled output (maybe not handling the binary correctly?).
Tried :tinker instead of “tinker” in the call to read_priv and some other things I don’t recall.
Help? :slight_smile:
My idea was to read a file with simple config format e.g key:value on each line or the like and then parse it and use it later when configuring peripherals/services. Is this possible?

tinker should be :tinker
Should just work.

just tried and it works

:atomvm.read_priv(:my_project, "file.txt")
|> IO.inspect()

think you want this:

:atomvm.read_priv(:atomvm_sim_dev, "file.txt")
|> :binary.split("\n", [:global])
1 Like

Two little problems here. The application name should be an atom, and your file name ”text.txt” does not match the name “secret.txt” that you indicated in the project directory.

Try:
txt = :atomvm.read_priv(:tinker, "secret.txt")

I think that should work for you.

1 Like

This is totally doable. Another convenient place to store configuration options is NVS (non volatile storage).

1 Like

Aha, it does work, Thank you for confirming. Now I have something like:

def configuration(src \\ "secret.txt") do
    lines =
      :atomvm.read_priv(:tinker, src)
      |> IO.inspect()
      |> :binary.split("\n", [:global])
      |> IO.inspect()

    Enum.each(lines, fn line ->
      IO.inspect(line)
      :io.format(~c"format: ~p~n", [line])
    end)
  end

Which prints

Starting application...
<<104, 101, 108, 108, 111, 63, 10>>
["hello?", ""]
"hello?"
format: <<"hello?">>
""
format: <<"">>

that last format output confuses me a little though, its still representing it as a charlist? i.e it is within << and >>

While tinkering around probably messed up my file names, thus user error as expected. :slight_smile:

Can this NVM be flashed beforehand with the data or is it in this case more used as a cache for settings passed to it?

They are all binaries - there is a bit of a learning curve, especially with how IO.inspect works…

E.g you see it output a binary <<104, 101, 108, 108, 111, 63, 10>>, but then when you split it, the binary now is outputable/presentable as a (elixir) string, and you get ["hello?", ""] - eg. try and input <<104, 101, 108, 108, 111, 63>> in an iex terminal and you’ll get back:

iex(1)> <<104, 101, 108, 108, 111, 63>>
"hello?"

but you will most likely encounter charlists elsewhere;-) - but mostly you’ll see binaries.

https://hexdocs.pm/elixir/main/binaries-strings-and-charlists.html

There is this utility for creating the NVS partition from csv: NVS Partition Generator Utility - ESP32 - — ESP-IDF Programming Guide v5.4 documentation - and then you’ll need to flash it to nvs, data, nvs, 0x9000, 0x6000, see AtomVM/src/platforms/esp32/partitions-elixir.csv at main · atomvm/AtomVM · GitHub

But I haven’t tried it yet - so maybe just make it work with priv first, before reaching for python tools and custom flashing;-)

I was going to suggest the same, I have used this and it works great. In fact I plan on adding support for generating the NVS partition if an nvs-partition.cvs file is found in the top level of the esp32 directory to my (still in draft) PR for enhancements to the esp32 build system. This only works of course when building an image, so really only useful for VM developers, or people building custom images.

Perhaps rebar3 and mix tasked could be added, so users using release images could also benefit.

1 Like

This does seem a bit off… I will do some investigating.

FYI, there are still examples the need to be updated, so you might see Elixir apps using the Erlang io module, but examvlib has an Elixir IO module you can use now ;-).

Actualy looks like it behaves the same way in iex. Depends on the control sequences used described in fwrite/3.

Still afaik:
binary: <<>>
charlist: ‘’
string: “”

so the display as <<“123:456”>> just makes me do a double take.