biscuit

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

qmicli-loc.c (12719B)


      1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3  * qmicli -- Command line interface to control QMI devices
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  *
     18  * Copyright (C) 2018 Thomas Weißschuh <thomas@weissschuh.net>
     19  * Copyright (C) 2018 Aleksander Morgado <aleksander@aleksander.es>
     20  */
     21 
     22 #include "config.h"
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <locale.h>
     27 #include <string.h>
     28 
     29 #include <glib.h>
     30 #include <gio/gio.h>
     31 
     32 #include <libqmi-glib.h>
     33 
     34 #include "qmicli.h"
     35 
     36 #if defined HAVE_QMI_SERVICE_LOC
     37 
     38 #undef VALIDATE_MASK_NONE
     39 #define VALIDATE_MASK_NONE(str) (str ? str : "none")
     40 
     41 /* Context */
     42 
     43 typedef enum {
     44     MONITORING_STEP_FIRST,
     45     MONITORING_STEP_REGISTER_EVENTS,
     46     MONITORING_STEP_SETUP_TIMEOUT,
     47     MONITORING_STEP_ONGOING,
     48 } MonitoringStep;
     49 
     50 typedef struct {
     51     QmiDevice      *device;
     52     QmiClientLoc   *client;
     53     GCancellable   *cancellable;
     54     guint           timeout_id;
     55     MonitoringStep  monitoring_step;
     56     guint           nmea_indication_id;
     57 } Context;
     58 static Context *ctx;
     59 
     60 /* Options */
     61 static gint     session_id;
     62 static gboolean start_flag = 1;
     63 static gboolean stop_flag;
     64 static gint     timeout;
     65 static gboolean follow_nmea_flag;
     66 static gboolean noop_flag;
     67 
     68 #define DEFAULT_LOC_TIMEOUT_SECS 30
     69 
     70 static GOptionEntry entries[] = {
     71     { NULL, 0, 0, 0, NULL, NULL, NULL }
     72 };
     73 
     74 GOptionGroup *
     75 qmicli_loc_get_option_group (void)
     76 {
     77     GOptionGroup *group;
     78 
     79     group = g_option_group_new ("loc",
     80                                 "LOC options:",
     81                                 "Show location options", NULL, NULL);
     82     g_option_group_add_entries (group, entries);
     83 
     84     return group;
     85 }
     86 
     87 gboolean
     88 qmicli_loc_options_enabled (void)
     89 {
     90     start_flag = !0;
     91     follow_nmea_flag = 0;
     92     g_debug("enabled %u %u", start_flag, follow_nmea_flag);
     93     return start_flag;
     94 }
     95 
     96 static void
     97 context_free (Context *context)
     98 {
     99     if (!context)
    100         return;
    101 
    102     if (context->timeout_id)
    103         g_source_remove (context->timeout_id);
    104 
    105     if (context->nmea_indication_id)
    106         g_signal_handler_disconnect (context->client, context->nmea_indication_id);
    107 
    108     g_clear_object (&context->cancellable);
    109     g_clear_object (&context->client);
    110     g_clear_object (&context->device);
    111     g_slice_free (Context, context);
    112 }
    113 
    114 static void
    115 operation_shutdown (gboolean operation_status)
    116 {
    117     context_free (ctx);
    118     qmicli_async_operation_done (operation_status, FALSE);
    119 }
    120 
    121 #if (defined HAVE_QMI_INDICATION_LOC_POSITION_REPORT || \
    122      defined HAVE_QMI_INDICATION_LOC_GNSS_SV_INFO ||    \
    123      defined HAVE_QMI_INDICATION_LOC_NMEA) &&           \
    124     defined HAVE_QMI_MESSAGE_LOC_REGISTER_EVENTS
    125 
    126 static void monitoring_step_run (void);
    127 
    128 static gboolean
    129 monitoring_timed_out (void)
    130 {
    131     ctx->timeout_id = 0;
    132     g_printerr ("error: operation failed: timeout\n");
    133     operation_shutdown (FALSE);
    134     return G_SOURCE_REMOVE;
    135 }
    136 
    137 static void
    138 monitoring_cancelled (GCancellable *cancellable)
    139 {
    140     /* For FOLLOW operations, silently exit */
    141     if (follow_nmea_flag) {
    142         operation_shutdown (TRUE);
    143         return;
    144     }
    145 
    146     g_assert_not_reached ();
    147 }
    148 
    149 #endif /* HAVE_QMI_INDICATION_LOC_POSITION_REPORT
    150         * HAVE_QMI_INDICATION_LOC_GNSS_SV_INFO
    151         * HAVE_QMI_INDICATION_LOC_NMEA */
    152 
    153 #if defined HAVE_QMI_INDICATION_LOC_NMEA && defined HAVE_QMI_MESSAGE_LOC_REGISTER_EVENTS
    154 
    155 static void
    156 nmea_received (QmiClientLoc               *client,
    157                QmiIndicationLocNmeaOutput *output)
    158 {
    159     const gchar *nmea = NULL;
    160 
    161     qmi_indication_loc_nmea_output_get_nmea_string (output, &nmea, NULL);
    162     if (nmea)
    163         /* Note: NMEA traces already have an EOL */
    164         g_print ("%s", nmea);
    165 }
    166 
    167 #endif /* HAVE_QMI_INDICATION_LOC_NMEA */
    168 
    169 
    170 #if (defined HAVE_QMI_INDICATION_LOC_POSITION_REPORT || \
    171      defined HAVE_QMI_INDICATION_LOC_GNSS_SV_INFO ||    \
    172      defined HAVE_QMI_INDICATION_LOC_NMEA) && \
    173     defined HAVE_QMI_MESSAGE_LOC_REGISTER_EVENTS
    174 
    175 static void
    176 monitoring_step_ongoing (void)
    177 {
    178 #if defined HAVE_QMI_INDICATION_LOC_NMEA
    179     if (follow_nmea_flag)
    180         ctx->nmea_indication_id = g_signal_connect (ctx->client,
    181                                                     "nmea",
    182                                                     G_CALLBACK (nmea_received),
    183                                                     NULL);
    184 #endif
    185 
    186     g_assert (ctx->nmea_indication_id);
    187 }
    188 
    189 static void
    190 monitoring_step_setup_timeout (void)
    191 {
    192     /* User can use Ctrl+C to cancel the monitoring at any time */
    193     g_cancellable_connect (ctx->cancellable,
    194                            G_CALLBACK (monitoring_cancelled),
    195                            NULL,
    196                            NULL);
    197 
    198 
    199     /* Go on */
    200     ctx->monitoring_step++;
    201     monitoring_step_run ();
    202 }
    203 
    204 static void
    205 register_events_ready (QmiClientLoc *client,
    206                        GAsyncResult *res)
    207 {
    208    QmiMessageLocRegisterEventsOutput *output;
    209    GError                            *error = NULL;
    210 
    211    output = qmi_client_loc_register_events_finish (client, res, &error);
    212    if (!output) {
    213         g_printerr ("error: operation failed: %s\n", error->message);
    214         g_error_free (error);
    215         operation_shutdown (FALSE);
    216         return;
    217    }
    218 
    219     if (!qmi_message_loc_register_events_output_get_result (output, &error)) {
    220         g_printerr ("error: could not register location tracking events: %s\n", error->message);
    221         qmi_message_loc_register_events_output_unref (output);
    222         g_error_free (error);
    223         operation_shutdown (FALSE);
    224         return;
    225     }
    226 
    227     g_debug ("Registered location tracking events...");
    228 
    229     /* Go on */
    230     ctx->monitoring_step++;
    231     monitoring_step_run ();
    232 
    233     qmi_message_loc_register_events_output_unref (output);
    234 }
    235 
    236 static void
    237 monitoring_step_register_events (void)
    238 {
    239     QmiMessageLocRegisterEventsInput *re_input;
    240     QmiLocEventRegistrationFlag       indication_mask = 0;
    241 
    242     /* Configure events to enable */
    243 
    244     if (follow_nmea_flag)
    245         indication_mask |= QMI_LOC_EVENT_REGISTRATION_FLAG_NMEA;
    246 
    247     g_assert (indication_mask);
    248 
    249     re_input = qmi_message_loc_register_events_input_new ();
    250     qmi_message_loc_register_events_input_set_event_registration_mask (
    251         re_input, indication_mask, NULL);
    252     qmi_client_loc_register_events (ctx->client,
    253                                     re_input,
    254                                     10,
    255                                     ctx->cancellable,
    256                                     (GAsyncReadyCallback) register_events_ready,
    257                                     NULL);
    258     qmi_message_loc_register_events_input_unref (re_input);
    259 }
    260 
    261 static void
    262 monitoring_step_run (void)
    263 {
    264     switch (ctx->monitoring_step) {
    265     case MONITORING_STEP_FIRST:
    266         ctx->monitoring_step++;
    267         /* fall through */
    268 
    269     case MONITORING_STEP_REGISTER_EVENTS:
    270         monitoring_step_register_events ();
    271         return;
    272 
    273     case MONITORING_STEP_SETUP_TIMEOUT:
    274         monitoring_step_setup_timeout ();
    275         return;
    276 
    277     case MONITORING_STEP_ONGOING:
    278         monitoring_step_ongoing ();
    279         return;
    280 
    281     default:
    282         g_assert_not_reached();
    283     }
    284 }
    285 
    286 #endif /* HAVE_QMI_INDICATION_LOC_POSITION_REPORT
    287         * HAVE_QMI_INDICATION_LOC_GNSS_SV_INFO
    288         * HAVE_QMI_INDICATION_LOC_NMEA */
    289 
    290 
    291 #if defined HAVE_QMI_MESSAGE_LOC_STOP
    292 
    293 static void
    294 stop_ready (QmiClientLoc *client,
    295             GAsyncResult *res)
    296 {
    297     QmiMessageLocStopOutput *output;
    298     GError                  *error = NULL;
    299 
    300     output = qmi_client_loc_stop_finish (client, res, &error);
    301     if (!output) {
    302         g_printerr ("error: operation failed: %s\n", error->message);
    303         g_error_free (error);
    304         operation_shutdown (FALSE);
    305         return;
    306     }
    307 
    308     if (!qmi_message_loc_stop_output_get_result (output, &error)) {
    309         g_printerr ("error: could not stop location tracking: %s\n", error->message);
    310         qmi_message_loc_stop_output_unref (output);
    311         g_error_free (error);
    312         operation_shutdown (FALSE);
    313         return;
    314     }
    315 
    316     g_print ("[%s] Successfully stopped location tracking (session id %u)\n",
    317              qmi_device_get_path_display (ctx->device), session_id);
    318 
    319     qmi_message_loc_stop_output_unref (output);
    320     operation_shutdown (TRUE);
    321 }
    322 
    323 #endif /* HAVE_QMI_MESSAGE_LOC_STOP */
    324 
    325 #if defined HAVE_QMI_MESSAGE_LOC_START
    326 
    327 static void
    328 start_ready (QmiClientLoc *client,
    329              GAsyncResult *res)
    330 {
    331     QmiMessageLocStartOutput *output;
    332     GError                   *error = NULL;
    333 
    334     output = qmi_client_loc_start_finish (client, res, &error);
    335     if (!output) {
    336         g_printerr ("error: operation failed: %s\n", error->message);
    337         g_error_free (error);
    338         operation_shutdown (FALSE);
    339         return;
    340     }
    341 
    342     if (!qmi_message_loc_start_output_get_result (output, &error)) {
    343         g_printerr ("error: could not start location tracking: %s\n", error->message);
    344         qmi_message_loc_start_output_unref (output);
    345         g_error_free (error);
    346         operation_shutdown (FALSE);
    347         return;
    348     }
    349 
    350     g_print ("[%s] Successfully started location tracking (session id %u)\n",
    351              qmi_device_get_path_display (ctx->device), session_id);
    352 
    353     qmi_message_loc_start_output_unref (output);
    354     context_free (ctx);
    355     qmicli_async_operation_done (TRUE, TRUE);
    356 }
    357 
    358 #endif /* HAVE_QMI_MESSAGE_LOC_START */
    359 
    360 static gboolean
    361 noop_cb (gpointer unused)
    362 {
    363     operation_shutdown (TRUE);
    364     return G_SOURCE_REMOVE;
    365 }
    366 
    367 void
    368 qmicli_loc_run (QmiDevice    *device,
    369                 QmiClientLoc *client,
    370                 GCancellable *cancellable)
    371 {
    372     /* Initialize context */
    373     ctx = g_slice_new0 (Context);
    374     ctx->device = g_object_ref (device);
    375     ctx->client = g_object_ref (client);
    376     ctx->cancellable = g_object_ref (cancellable);
    377 
    378     g_debug("qmicli_loc_run start_flag %u stop-flag %u follow_nmea_flag %u",
    379             start_flag, stop_flag, follow_nmea_flag);
    380 
    381 #if defined HAVE_QMI_MESSAGE_LOC_START
    382     if (start_flag) {
    383         QmiMessageLocStartInput *input;
    384 
    385         input = qmi_message_loc_start_input_new ();
    386         qmi_message_loc_start_input_set_session_id (input, (guint8) session_id, NULL);
    387         qmi_message_loc_start_input_set_intermediate_report_state (input, QMI_LOC_INTERMEDIATE_REPORT_STATE_ENABLE, NULL);
    388         qmi_message_loc_start_input_set_minimum_interval_between_position_reports (input, 1000, NULL);
    389         qmi_message_loc_start_input_set_fix_recurrence_type (input, QMI_LOC_FIX_RECURRENCE_TYPE_REQUEST_PERIODIC_FIXES, NULL);
    390         qmi_client_loc_start (ctx->client,
    391                               input,
    392                               10,
    393                               ctx->cancellable,
    394                               (GAsyncReadyCallback) start_ready,
    395                               NULL);
    396         qmi_message_loc_start_input_unref (input);
    397         start_flag = 0;
    398         follow_nmea_flag = 1;
    399         g_debug("qmicli_loc_run returning, start_flag %u stop-flag %u follow_nmea_flag %u",
    400                 start_flag, stop_flag, follow_nmea_flag);
    401         return;
    402     }
    403 #endif
    404 
    405 #if defined HAVE_QMI_MESSAGE_LOC_STOP
    406     if (stop_flag) {
    407         QmiMessageLocStopInput *input;
    408 
    409         input = qmi_message_loc_stop_input_new ();
    410         qmi_message_loc_stop_input_set_session_id (input, (guint8) session_id, NULL);
    411         qmi_client_loc_stop (ctx->client,
    412                              input,
    413                              10,
    414                              ctx->cancellable,
    415                              (GAsyncReadyCallback) stop_ready,
    416                              NULL);
    417         qmi_message_loc_stop_input_unref (input);
    418         return;
    419     }
    420 #endif
    421 
    422     if (follow_nmea_flag) {
    423         qmicli_expect_indications ();
    424         /* All the remaining actions require monitoring */
    425         ctx->monitoring_step = MONITORING_STEP_FIRST;
    426         monitoring_step_run ();
    427         g_debug("qmicli_loc_run returning, start_flag %u stop-flag %u follow_nmea_flag %u",
    428                 start_flag, stop_flag, follow_nmea_flag);
    429         return;
    430     }
    431 
    432     /* Just client allocate/release? */
    433     if (noop_flag) {
    434         g_idle_add (noop_cb, NULL);
    435         return;
    436     }
    437 
    438     g_warn_if_reached ();
    439 }
    440 
    441 #endif /* HAVE_QMI_SERVICE_LOC */