How do I start GPS on boot?

With the modem connected to my laptop, I have setup and saved settings in the modem with AT commands to start the GPS at boot.

When I connect the modem to my STM32MP1 based board I get no NMEA data on GPS port (ttyUSB1). If I enable GPS with:

mmcli -m 0 --location-enable-gps-nmea

I get the GPS output on port so I think ModemManager is the one that stop it on boot.

How do I make ModemManager to autostart my GPS on boot?

I have tried to set UDEV rules to run above mmcli command to start GPS when modem is added to the system but it doesn’t notice. Maybe it’s to early for the GPS to receive those commands.
My UDEV rule looked like this:

ACTION==“add”, ATTRS{idVendor}==“1bc7”, ATTRS{idProduct}==“1201”, RUN+=“mmcli -m 0 --location-enable-gps-nmea”

One solution could be to create a cronjob or add those mmcli commands in the startup script. But then I have no control if GPS is initialized or even connected.

I usually use supervisord in my Docker images to manage supporting processes like this. I find it fairly straightforward to work with.

I will have a look at that. Thanks.

Hey @Ankan, I found another forum post with similar use case here: Modem Manager GPS issue

We also have a blog post that show cases how this is done with different hadware: Create a GPS tracking system with cell connectivity and minimal bandwidth

Please take a look at these to see if the solutions work for you as well. Let us know if we could help with anything further.

Hi,

I read that forum post earlier and it looked promising except that my modem doesn’t accept commands. But using DBUS is anyway a good start as I can control ModemManager with it.
How do I send enum values to ModemManager Location Setup on dbus?

https://www.freedesktop.org/software/ModemManager/api/latest/gdbus-org.freedesktop.ModemManager1.Modem.Location.html#gdbus-method-org-freedesktop-ModemManager1-Modem-Location.Setup

I can send a integer as source argument but it would look more cleaner if I could send for example MM_MODEM_LOCATION_SOURCE_GPS_NMEA instead.

https://www.freedesktop.org/software/ModemManager/api/latest/ModemManager-Flags-and-Enumerations.html#MMModemLocationSource

Hi Ankan,

I think you are on the right path with approaching this through the ModemManager API. I would not use raw D-Bus though, but use the libmm-glib wrapper library instead for convenience. Here is an example modem watcher in Python: ModemManager/examples/modem-watcher-python at master · freedesktop/ModemManager · GitHub. I am pointing it out as it could serve as a good base for your code which you may built on top. There is a JS example there as well.

While I do not have experience with libmm-glib nor the ModemManager D-Bus API, I used the libnm wrapper library for NetworkManager and it makes things much easier.

The docs for libmm-glib are located here: libmm-glib Reference Manual: libmm-glib Reference Manual

Also mmcli should be using libmm-glib as well, so you may check the particular sources of the --location-enable-gps-nmea command and you will see what calls in particular are used there.

If I install mmcli into my container I can control mmcli in host os by changing
DBUS_SYSTEM_BUS_ADDRESS to unix:path=/host/run/dbus/system_bus_socket and run mmcli with sudo.
But how do I do this as non-root?

What I try to do is to control mmcli in host os from my application in my container.

My code look like this:

#include <gio/gio.h>
#include <libmm-glib.h>

int main(int argc, char** argv) {

     GError* error = NULL;

     // Set DBUS SYSTEM BUS PATH
     setenv("DBUS_SYSTEM_BUS_ADDRESS", "unix:path=/host/run/dbus/system_bus_socket", true);

     // Get Gdbus Connection
     GDBusConnection* connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);

     if (!connection)
     {
	     DLog::WriteDebug(2, "GetModemState : Failed to get gdbus connection");
	     g_error_free(error);
	     return;
     }

     // Get MMModemManager
     MMManager* manager = mm_manager_new_sync(connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, NULL, &error);

     if (!manager)
     {
	     DLog::WriteDebug(2, "GetModemState : Failed to get MMManager");
	     g_error_free(error);
	     g_object_unref(connection);
	     return;		
     }

     // Get list of Modems.
     GList* modem_list = g_dbus_object_manager_get_objects(G_DBUS_OBJECT_MANAGER(manager));

     if (!modem_list)
     {
	     DLog::WriteDebug(2, "GetModemState : No modems detected");
	     g_object_unref(manager);
	     g_object_unref(connection);
	     return;
     }

     // Select first modem. and set it as MMObject.
     MMObject* object = MM_OBJECT(modem_list->data);

     // Get MMModem. (peek)
     MMModem* modem = mm_object_peek_modem(object);

     // Get MMModemState
     MMModemState modem_state = mm_modem_get_state(modem);

     // Free glist modems.
     g_list_free_full(modem_list, (GDestroyNotify)g_object_unref);

     // Clear pointer referances.
     g_object_unref(manager);
     g_object_unref(connection);

}

connection == NULL and the error is:

message = 0xb5b0ce00 Exhausted all available authentication mechanisms (tried: EXTERNAL) (available: EXTERNAL) {0x45 ‘E’}

It seams like my problem is in my created ssh user in the container.

In Balena cloud I can access mmcli from the container but not by connect directly to my container via ssh. In that case I have to sudo the mmcli command.

So, what is wrong with my created ssh server and user? This image is only for development.

My Dockerfile look like this:

FROM balenalib/armv7hf-ubuntu:focal-build
RUN apt-get update && apt-get install -y openssh-server sudo
RUN mkdir -p /var/run/sshd
RUN echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config && ssh-keygen -A
RUN useradd -rm -d /home/test -s /bin/bash -g root -G sudo,dialout -u 1000 test
RUN echo 'test:test' | chpasswd

…But how do I do this as non-root?

in your entrypoint/cmd:

chown ${USER} /host/run/dbus/system_bus_socket