Hi,
My overriding comment here is to try to combine this with the existing
ublox plugin. That said, there are some comments below.
/Jonas
On 15/02/2019 13:11, philippedeswert(a)gmail.com wrote:
From: Philippe De Swert <philippe.deswert(a)digitalistgroup.com>
Add support for ublox modems that are used over the serial port.
(tested on SARA-R410M and R412M)
---
plugins/ublox-serial.c | 393 +++++++++++++++++++++++++++++++++++++++++
plugins/udevng.c | 1 +
2 files changed, 394 insertions(+)
create mode 100644 plugins/ublox-serial.c
diff --git a/plugins/ublox-serial.c b/plugins/ublox-serial.c
new file mode 100644
index 00000000..4f0cf5f3
--- /dev/null
+++ b/plugins/ublox-serial.c
@@ -0,0 +1,393 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2014 Philip Paeps. All rights reserved.
+ * Copyright (C) 2018-2019 Treon oy. All rights reserved.
+ *
+ * Inspired on the Ublox driver by Philip Paeps
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gatchat.h>
+#include <gattty.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/modem.h>
+#include <ofono/devinfo.h>
+#include <ofono/netreg.h>
+#include <ofono/sim.h>
+#include <ofono/gprs.h>
+#include <ofono/gprs-context.h>
+#include <ofono/netmon.h>
+#include <ofono/lte.h>
+
+#include <drivers/atmodem/atutil.h>
+#include <drivers/atmodem/vendor.h>
+
+static const char *none_prefix[] = { NULL };
+
+struct ublox_data {
+ GIOChannel *device;
+ GAtChat *modem;
+ GAtChat *dlc;
+ int model_id;
+ enum ofono_vendor vendor_family;
+ guint frame_size;
+};
+
+static void ublox_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ ofono_info("%s%s", prefix, str);
+}
+
+static int ublox_probe(struct ofono_modem *modem)
+{
+ struct ublox_data *data;
+
+ DBG("%p", modem);
+
+ data = g_try_new0(struct ublox_data, 1);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ofono_modem_set_data(modem, data);
+
+ return 0;
+}
+
+static void ublox_remove(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ ofono_modem_set_data(modem, NULL);
+ g_at_chat_unref(data->modem);
+ g_free(data);
+}
+
Your implementation of open_device is the same as the implementation in
ublox.c with the addition of communication settings. You could easily
add this as open_serial_device in the ublox.c and call it for serial modems.
+static GAtChat *open_device(struct ofono_modem *modem,
+ const char *key, char *debug)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ const char *device;
+ GAtSyntax *syntax;
+ GIOChannel *channel;
+ GAtChat *chat;
+ GHashTable *options;
+
+ device = ofono_modem_get_string(modem, key);
+ if (device == NULL)
+ {
+ DBG("device = NULL");
+ return NULL;
+ }
+ DBG("%s %s", key, device);
+
+ options = g_hash_table_new(g_str_hash, g_str_equal);
+ if (options == NULL)
+ return NULL;
+
+ g_hash_table_insert(options, "Baud", "115200");
+ g_hash_table_insert(options, "Parity", "none");
+ g_hash_table_insert(options, "StopBits", "1");
+ g_hash_table_insert(options, "DataBits", "8");
+ g_hash_table_insert(options, "XonXoff", "on");
+ g_hash_table_insert(options, "Local", "on");
+ g_hash_table_insert(options, "RtsCts", "off");
+ g_hash_table_insert(options, "Read", "on");
+
+ channel = g_at_tty_open(device, options);
+ g_hash_table_destroy(options);
+
+ if (channel == NULL)
+ return NULL;
+
+ data->device = channel;
+ syntax = g_at_syntax_new_gsm_permissive();
+ chat = g_at_chat_new(channel, syntax);
+ g_at_syntax_unref(syntax);
+
+ g_io_channel_unref(channel);
+
+ if (chat == NULL)
+ return NULL;
+
+ if (getenv("OFONO_AT_DEBUG"))
+ g_at_chat_set_debug(chat, ublox_debug, debug);
+
+ return chat;
+}
+
+#if 0
Here's a big block of commented out code. This isn't from the ublox
driver...
+static GAtChat *create_chat(GIOChannel *channel, struct ofono_modem
*modem,
+ char *debug)
+{
+ GAtSyntax *syntax;
+ GAtChat *chat;
+
+ if (channel == NULL)
+ return NULL;
+
+ syntax = g_at_syntax_new_gsmv1();
+ chat = g_at_chat_new(channel, syntax);
+ g_at_syntax_unref(syntax);
+ g_io_channel_unref(channel);
+
+ if (chat == NULL)
+ return NULL;
+
+ if (getenv("OFONO_AT_DEBUG"))
+ g_at_chat_set_debug(chat, ublox_debug, debug);
+
+ return chat;
+}
+
+static void shutdown_device(struct ublox_data *data)
+{
+ DBG("");
+
+ g_at_chat_unref(data->dlc);
+ data->dlc = NULL;
+
+ g_io_channel_unref(data->device);
+ data->device = NULL;
+}
+#endif
... that ends here. Drop all of this.
+
+static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct ublox_data * data = ofono_modem_get_data(modem);
+
+ DBG("ok %d", ok);
+
+ if (!ok) {
+ g_at_chat_unref(data->modem);
+ data->modem = NULL;
+ ofono_modem_set_powered(modem, FALSE);
+ DBG("CFUN failed");
+ return;
+ }
+ ofono_modem_set_powered(modem, TRUE);
+ DBG("Powered on!");
+}
+
+static int ublox_enable(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ const char *model_str = NULL;
+
+ DBG("%p", modem);
+
+ model_str = ofono_modem_get_string(modem, "Model");
+ DBG("%p is model %s", modem, model_str);
+ if (model_str == NULL)
+ model_str = strdup("SARA_R410");
+ //return -EINVAL;
+
As you are going via add_serial_device() in udevng.c, the Model string
will not be set so you don't even need to check for this. That said,
you aren't using the model_str value for anything anyway, so just drop it.
+ data->model_id = atoi(model_str);
atoi("SARA_R410") looks interesting... does this work?
+
+ switch (data->model_id) {
Drop the switch as you have no options here.
+ default:
+ DBG("unknown ublox model id %d", data->model_id);
Unknown?
+ //return -EINVAL;
+ data->vendor_family = OFONO_VENDOR_UBLOX;
+ break;
+ }
+
+ if (data->vendor_family == OFONO_VENDOR_UBLOX) {
You've asked for this above... no need for the if() statement.
+ data->dlc = open_device(modem, "Device", "Setup:
");
+ if (data->dlc == NULL) {
+ g_at_chat_unref(data->dlc);
_unref(NULL) ... not necessary.
+ data->dlc = NULL;
You already tested for this above. This is a no-op.
+ DBG("open_device failed!");
+ return -EIO;
+ }
+
If you stuck to the name data->aux above and opened either "Device" or
"Aux" depending on existence of the string or on device model then your
diff against ublox.c is automatically 50% as big as now.
+ g_at_chat_set_slave(data->modem, data->dlc);
+
+ g_at_chat_send(data->dlc, "AT+CFUN=0", none_prefix,
+ NULL, NULL, NULL);
+
+ g_at_chat_send(data->dlc, "AT+UMNOPROF=1", NULL, NULL, NULL, NULL);
+ //enable roaming in the modem
+ g_at_chat_send(data->dlc, "AT+UDCONF=76,1,0", NULL, NULL, NULL, NULL);
+ }
+
+ /* The modem can take a while to wake up if just powered on. */
+ //g_at_chat_set_wakeup_command(data->dlcs[SETUP_DLC], "AT\r", 1000,
11000);
->dlcs does not exist... you don't enable mux'ing anywhere in the
driver. Yes, I realize this is commented out, but there's half of a
thought here that I'd like to reconcile since you've left the commented
code in place. Did you intend on using mux'ing later? Either way, I
think you pretty much just end up with MUX on channel 0, AUX on channel
1, and MODEM on channel2 and if you set up the chats accordingly then
everything becomes independent of underlying device... (or something
like that, I think).
+
+ g_at_chat_send(data->dlc, "ATE0 +CMEE=1", none_prefix,
+ NULL, NULL, NULL);
+
+ g_at_chat_send(data->dlc, "AT+CFUN=4", none_prefix,
+ cfun_enable, modem, NULL);
+
+ DBG("Return in progress");
+ return -EINPROGRESS;
+}
+
+static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct ublox_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ g_at_chat_unref(data->dlc);
+ data->dlc = NULL;
+
+ if (ok)
+ ofono_modem_set_powered(modem, FALSE);
+}
+
+static int ublox_disable(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+
+ DBG("%p", modem);
+
+ g_at_chat_cancel_all(data->dlc);
+ g_at_chat_unregister_all(data->dlc);
+
+ g_at_chat_send(data->dlc, "AT+CFUN=4", none_prefix,
+ cfun_disable, modem, NULL);
+
+ g_at_chat_unref(data->modem);
+ data->modem = NULL;
+
+ return -EINPROGRESS;
+}
+
+static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_modem_online_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ cb(&error, cbd->data);
+ DBG("online!?");
+}
+
+static void ublox_set_online(struct ofono_modem *modem, ofono_bool_t online,
+ ofono_modem_online_cb_t cb, void *user_data)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ struct cb_data *cbd = cb_data_new(cb, user_data);
+ char const *command = online ? "AT+CFUN=1" : "AT+CFUN=4";
+
+ DBG("modem %p %s", modem, online ? "online" :
"offline");
+
+ if (g_at_chat_send(data->dlc, command, none_prefix, set_online_cb,
+ cbd, g_free) > 0)
+ return;
+
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
+static void ublox_pre_sim(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ struct ofono_sim *sim;
+
+ DBG("%p", modem);
+
+ ofono_devinfo_create(modem, 0, "atmodem", data->dlc);
+ DBG("%p devinfo created", modem);
+ sim = ofono_sim_create(modem, data->vendor_family, "atmodem",
+ data->dlc);
+
+ DBG("%p sim created", modem);
+
+ if (sim)
+ {
+ DBG("%p sim notification", modem);
+ ofono_sim_inserted_notify(sim, TRUE);
+ }
+}
+
+static void ublox_post_sim(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ struct ofono_gprs *gprs;
+ struct ofono_gprs_context *gc;
+ GAtChat *chat = data->dlc;
+ const char *driver = "atmodem";
+
+ DBG("%p", modem);
+
+ gprs = ofono_gprs_create(modem, data->vendor_family, "atmodem",
+ data->dlc);
+
+ gc = ofono_gprs_context_create(modem, data->vendor_family,
+ driver, chat);
+
+ if (gprs && gc)
+ ofono_gprs_add_context(gprs, gc);
+
+ ofono_lte_create(modem, 0, "atmodem", data->dlc);
The 'atmodem' variant of the lte atom uses CGAUTH for setting up the
default bearer configuration. This command isn't available on the
SARA-R4, as far as I can see.
The current u-blox LTE driver uses CGDFLT, but that isn't available on
your modem either (only on the TOBY L2). You probably want UAUTHREQ here...
+}
+
+static void ublox_post_online(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+
+ ofono_netreg_create(modem, data->vendor_family, "atmodem", data->dlc);
+
+ ofono_netmon_create(modem, data->vendor_family, "ubloxserial",
data->modem);
+}
+
+static struct ofono_modem_driver ublox_driver = {
+ .name = "ubloxserial",
+ .probe = ublox_probe,
+ .remove = ublox_remove,
+ .enable = ublox_enable,
+ .disable = ublox_disable,
+ .set_online = ublox_set_online,
+ .pre_sim = ublox_pre_sim,
+ .post_sim = ublox_post_sim,
+ .post_online = ublox_post_online,
+};
+
+static int ublox_init(void)
+{
+ return ofono_modem_driver_register(&ublox_driver);
+}
+
+static void ublox_exit(void)
+{
+ ofono_modem_driver_unregister(&ublox_driver);
+}
+
+OFONO_PLUGIN_DEFINE(ubloxserial, "u-blox serial modem driver", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, ublox_init, ublox_exit)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index ce8cdee1..d95fc527 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1322,6 +1322,7 @@ static struct {
{ "cinterion", setup_serial_modem },
{ "nokiacdma", setup_serial_modem },
{ "sim900", setup_serial_modem },
+ { "ubloxserial",setup_serial_modem },
{ "wavecom", setup_wavecom },
{ "tc65", setup_tc65 },
{ "ehs6", setup_ehs6 },