[RFC] HFP support into oFono and BlueZ
by Gustavo F. Padovan
Hi,
These patches implement the new API for the Audio Gateway in BlueZ. It
follows the last version of the HandsfreeGateway and HandsfreeAgent
Intefaces API.
The first two patches is for BlueZ and the other for oFono. You can
test it with using enable-modem and test-voicecall scripts into the
test dir of oFono.
Feel free to test it and send me your comments. We have some bugs yet.
The audio part is not working yet. We are going to work on pulseaudio
this week to get this done soon.
Regards,
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
9 years, 10 months
[PATCH 1/3] hfp: create modem for new devices paired on runtime
by Gustavo F. Padovan
It listens the Paired property to create a modem to the recently paired
devices. It also renames added_watch to adapter_watch, a more proper
name.
---
plugins/hfp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/plugins/hfp.c b/plugins/hfp.c
index 981b05b..3e41342 100644
--- a/plugins/hfp.c
+++ b/plugins/hfp.c
@@ -66,6 +66,7 @@ static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *chld_prefix[] = { "+CHLD:", NULL };
static DBusConnection *connection;
+static GHashTable *uuid_hash = NULL;
static void hfp_debug(const char *str, void *user_data)
{
@@ -427,6 +428,7 @@ static int hfp_create_modem(const char *device)
{
struct ofono_modem *modem;
struct hfp_data *data;
+ const char *path;
ofono_info("Using device: %s", device);
@@ -451,6 +453,9 @@ static int hfp_create_modem(const char *device)
ofono_modem_set_data(modem, data);
ofono_modem_register(modem);
+ path = ofono_modem_get_path(modem);
+ g_hash_table_insert(uuid_hash, g_strdup(device), g_strdup(path));
+
return 0;
free:
@@ -465,6 +470,9 @@ static void parse_uuids(DBusMessageIter *i, const char *device)
DBusMessageIter variant, ai;
const char *value;
+ if (g_hash_table_lookup(uuid_hash, device))
+ return;
+
dbus_message_iter_recurse(i, &variant);
dbus_message_iter_recurse(&variant, &ai);
@@ -624,6 +632,33 @@ static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
return TRUE;
}
+static gboolean uuid_emitted(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
+{
+ const char *device, *property;
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+ if (g_str_equal(property, "UUIDs") == FALSE)
+ return TRUE;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ device = dbus_message_get_path(message);
+ parse_uuids(&iter, device);
+
+ return TRUE;
+}
+
static void list_adapters_cb(DBusPendingCall *call, gpointer user_data)
{
DBusError err;
@@ -725,6 +760,8 @@ static void hfp_remove(struct ofono_modem *modem)
hfp_unregister_ofono_handsfree(modem);
+ g_hash_table_remove(uuid_hash, data->handsfree_path);
+
g_free(data->handsfree_path);
g_free(data);
@@ -798,7 +835,8 @@ static struct ofono_modem_driver hfp_driver = {
.post_sim = hfp_post_sim,
};
-static guint added_watch;
+static guint adapter_watch;
+static guint uuid_watch;
static int hfp_init(void)
{
@@ -809,12 +847,21 @@ static int hfp_init(void)
connection = ofono_dbus_get_connection();
- added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
BLUEZ_MANAGER_INTERFACE,
"AdapterAdded",
adapter_added, NULL, NULL);
- if (added_watch == 0) {
+ uuid_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ BLUEZ_DEVICE_INTERFACE,
+ "PropertyChanged",
+ uuid_emitted, NULL, NULL);
+
+
+ uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ if (adapter_watch == 0 || uuid_watch == 0) {
err = -EIO;
goto remove;
}
@@ -828,7 +875,9 @@ static int hfp_init(void)
return 0;
remove:
- g_dbus_remove_watch(connection, added_watch);
+ g_dbus_remove_watch(connection, adapter_watch);
+ g_dbus_remove_watch(connection, uuid_watch);
+ g_hash_table_destroy(uuid_hash);
dbus_connection_unref(connection);
@@ -837,9 +886,12 @@ remove:
static void hfp_exit(void)
{
- g_dbus_remove_watch(connection, added_watch);
+ g_dbus_remove_watch(connection, adapter_watch);
+ g_dbus_remove_watch(connection, uuid_watch);
ofono_modem_driver_unregister(&hfp_driver);
+
+ g_hash_table_destroy(uuid_hash);
}
OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION,
--
1.6.4.4
11 years, 11 months
Modem emulator and DUN server side for oFono and BlueZ
by Zhang, Zhenhua
Hi,
I am now working on modem emulator and one usage is for DUN server role. Since Padovan is working on client role, it's good to share my rough thinking for server side implementation. Here are the simple steps I have:
1. Create an oFono emulator atom in oFono. It's the emulator manager that could create DUN, HFP AG or SPP type emulators. It exposes dbus methods like CreateEmulator, DestroyEmulator, GetProperty, etc.
2. DUN agent server in BlueZ watch oFono and call CreateEmulator and pass the file descriptor to oFono. This server could further implement HFP AG and SPP connection.
3. Once an emulator is created, other atom like voicecall, grps, sms register their interested AT command handlers to it. The goal is that we could handle all mandatory AT commands defined in DUN profile spec.
4. Once a DUN emulator received ATD*99#, DUN client performs ppp connection so we forward ppp command to ppp stack. It is done by ppp server side extension. It should be the simple command forwarding.
5. Once the PPP link over DUN is established, DUN client performs ConnMan integration and setup IP address, DNS server, etc.
6. Once the Bluetooth link is disconnected, we destroy the PPP and DUN emulator. If emulator atom itself is destroyed, we destroy the PPP and the Bluetooth connection. If the PPP link is disconnected but Bluetooth link is alive, we destroy the PPP and stay emulator alive.
Comments are welcome. :)
Regards,
Zhenhua
11 years, 11 months
Testing asset for oFono
by Aki Niemi
Hi,
There are currently a bunch of helper scripts under /test for the D-Bus
API in addition to unit tests, and I'm wondering if there are any plans
to automate especially the former into a suite that could be run
semi-regularly, or even at 'make distcheck'?
I think it would be useful to have something like the current scripts,
but modified to be actual test cases as well as more easily
parametrized.
The tests could then be driven with a set of parameters (which cases to
run, what numbers to call, etc.) and a default test profile to work
with, for example, the default phonesim configuration.
Other profiles could then be made for other test environments, such as a
live modem and a test network or network simulator.
Any thoughts on this?
Cheers,
Aki
12 years, 1 month
[RFC] Proposal for flight mode
by Pekka Pessi
Hello all,
Here is the first step in adding proper flight mode to ofono. The patch
adds a boolean property "Online" to modem; if that is false, modem is in
flight mode and it has killed its cellular radio.
If the modem driver does not implement online method, the value of the
property is initially true. This feature is intended as temporary. It just
makes the new property as non-intrusive as possible.
There is also a watch list for online/offline state.
The second patch adds the online method to isimodem. The online property of
the isimodem follows the online/offline state of Nokia modems (however, this
has only been tested with N95).
In the next phase, I'll add separate atom lists for flight and online modes.
The old-fashioned post_sim will become post_online. The new method
post_sim_flight will request modem driver to add flight-mode atoms.
--Pekka
BTW, if you have applied the patch I sent earlier today, "usbpnmodem:
configure usbpn interfaces automatically", you can actually try Nokia phones
via USB. They should just work provided you have kernel 2.6.31 or newer
without any manual configuration. Select the "PC suite mode" from the phone
when you connect the USB cable.
12 years, 1 month
[PATCH] usbpnmodem: configure usbpn interfaces automatically
by Pekka Pessi
---
drivers/isimodem/isimodem.c | 2 +-
gisi/netlink.c | 246 +++++++++++++++++++++++++++++++++++++++---
gisi/netlink.h | 11 ++-
plugins/usbpnmodem.c | 10 ++-
4 files changed, 246 insertions(+), 23 deletions(-)
diff --git a/drivers/isimodem/isimodem.c b/drivers/isimodem/isimodem.c
index e6e0bc1..b6ae82b 100644
--- a/drivers/isimodem/isimodem.c
+++ b/drivers/isimodem/isimodem.c
@@ -256,7 +256,7 @@ static int isi_modem_probe(struct ofono_modem *modem)
return -errno;
}
- link = g_pn_netlink_by_name(ifname);
+ link = g_pn_netlink_by_modem(idx);
if (link) {
DBG("%s: %s", ifname, strerror(EBUSY));
return -EBUSY;
diff --git a/gisi/netlink.c b/gisi/netlink.c
index 1a18b45..36bf273 100644
--- a/gisi/netlink.c
+++ b/gisi/netlink.c
@@ -68,6 +68,7 @@
#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr*)(void*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define SIZE_NLMSG (16384)
struct _GPhonetNetlink {
GPhonetNetlinkFunc callback;
@@ -98,18 +99,6 @@ GPhonetNetlink *g_pn_netlink_by_modem(GIsiModem *idx)
return NULL;
}
-GPhonetNetlink *g_pn_netlink_by_name(const char *ifname)
-{
- if (ifname == NULL) {
- return g_pn_netlink_by_modem(make_modem(0));
- } else {
- GIsiModem *idx = g_isi_modem_by_name(ifname);
- if (!idx)
- return NULL;
- return g_pn_netlink_by_modem(idx);
- }
-}
-
static void bring_up(unsigned ifindex)
{
struct ifreq req = { .ifr_ifindex = ifindex, };
@@ -124,6 +113,25 @@ error:
close(fd);
}
+static int netlink_socket(void)
+{
+ int fd;
+ int bufsize = SIZE_NLMSG;
+
+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd == -1)
+ return -1;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, (sizeof bufsize))) {
+ int error = errno;
+ g_warning("sockopt(SO_RCVBUF): %s", strerror(error));
+ close(fd), fd = -1;
+ errno = error;
+ }
+
+ return fd;
+}
+
static void g_pn_nl_addr(GPhonetNetlink *self, struct nlmsghdr *nlh)
{
int len;
@@ -196,7 +204,7 @@ static gboolean g_pn_nl_process(GIOChannel *channel, GIOCondition cond,
{
struct {
struct nlmsghdr nlh;
- char buf[16384];
+ char buf[SIZE_NLMSG];
} resp;
struct iovec iov = { &resp, (sizeof resp), };
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
@@ -225,10 +233,11 @@ static gboolean g_pn_nl_process(GIOChannel *channel, GIOCondition cond,
switch (nlh->nlmsg_type) {
case NLMSG_ERROR: {
- const struct nlmsgerr *err;
- err = (struct nlmsgerr *)NLMSG_DATA(nlh);
- g_critical("Netlink error: %s", strerror(-err->error));
- return FALSE;
+ const struct nlmsgerr *err = NLMSG_DATA(nlh);
+ if (err->error)
+ g_critical("Netlink error: %s",
+ strerror(-err->error));
+ return TRUE;
}
case RTM_NEWADDR:
case RTM_DELADDR:
@@ -271,6 +280,7 @@ static int g_pn_netlink_getlink(int fd)
(struct sockaddr *)&addr, sizeof(addr));
}
+
GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
GPhonetNetlinkFunc callback,
void *data)
@@ -281,7 +291,7 @@ GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
unsigned group = RTNLGRP_LINK;
unsigned interface = g_isi_modem_index(idx);
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ fd = netlink_socket();
if (fd == -1)
return NULL;
@@ -332,3 +342,203 @@ void g_pn_netlink_stop(GPhonetNetlink *self)
free(self);
}
}
+
+static int netlink_getack(int fd)
+{
+ struct {
+ struct nlmsghdr nlh;
+ char buf[SIZE_NLMSG];
+ } resp;
+ struct iovec iov = { &resp, (sizeof resp), };
+ struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, };
+ ssize_t ret;
+ struct nlmsghdr *nlh = &resp.nlh;
+
+ ret = recvmsg(fd, &msg, 0);
+ if (ret == -1)
+ return -errno;
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ g_critical("Netlink message of %zu bytes truncated at %zu",
+ ret, (sizeof resp));
+ return -EIO;
+ }
+
+ for (; NLMSG_OK(nlh, (size_t)ret); nlh = NLMSG_NEXT(nlh, ret)) {
+
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ return 0;
+
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
+ return err->error;
+ }
+ }
+
+ return -EIO;
+}
+
+/* Set local address */
+static int netlink_setaddr(int fd, uint32_t ifa_index, uint8_t ifa_local)
+{
+ struct ifaddrmsg *ifa;
+ struct rtattr *rta;
+ uint32_t reqlen = NLMSG_LENGTH(NLMSG_ALIGN(sizeof *ifa) + RTA_SPACE(1));
+ struct req {
+ struct nlmsghdr nlh;
+ char buf[512];
+ } req = {
+ .nlh = {
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ .nlmsg_type = RTM_NEWADDR,
+ .nlmsg_pid = getpid(),
+ .nlmsg_len = reqlen,
+ },
+ };
+
+ struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
+
+ ifa = NLMSG_DATA(&req.nlh);
+ ifa->ifa_family = AF_PHONET;
+ ifa->ifa_prefixlen = 0;
+ ifa->ifa_index = ifa_index;
+
+ rta = IFA_RTA(ifa);
+ rta->rta_type = IFA_LOCAL;
+ rta->rta_len = RTA_LENGTH(1);
+ *(uint8_t *)RTA_DATA(rta) = ifa_local;
+
+ if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof addr) == -1)
+ return -errno;
+
+ return 0;
+}
+
+int g_pn_netlink_set_address(GIsiModem *idx, uint8_t local)
+{
+ int fd = -1;
+ uint32_t ifindex;
+ int error = 0;
+
+ if (idx == NULL)
+ return -ENODEV;
+
+ if (local != PN_DEV_PC && local != PN_DEV_SOS)
+ return -EINVAL;
+
+ ifindex = g_isi_modem_index(idx);
+
+ fd = netlink_socket();
+ if (fd == -1)
+ goto error;
+
+ error = netlink_setaddr(fd, ifindex, local);
+ if (error)
+ goto error;
+
+ error = netlink_getack(fd);
+ if (error)
+ goto error;
+
+ close(fd);
+ return 0;
+
+error:
+ if (!error)
+ error = -(errno ? errno : -EIO);
+ if (fd != -1)
+ close(fd);
+ return error;
+}
+
+/* Add remote address */
+static int netlink_addroute(int fd, uint32_t ifa_index, uint8_t remote)
+{
+ struct rtmsg *rtm;
+ struct rtattr *rta;
+ uint32_t reqlen = NLMSG_LENGTH(
+ NLMSG_ALIGN(sizeof *rtm) +
+ RTA_SPACE(1) +
+ RTA_SPACE(sizeof ifa_index));
+ struct req {
+ struct nlmsghdr nlh;
+ char buf[512];
+ } req = {
+ .nlh = {
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK
+ | NLM_F_CREATE | NLM_F_APPEND,
+ .nlmsg_type = RTM_NEWROUTE,
+ .nlmsg_pid = getpid(),
+ .nlmsg_len = reqlen,
+ },
+ };
+ size_t buflen = (sizeof req.buf) - (sizeof *rtm);
+
+ struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
+
+ rtm = NLMSG_DATA(&req.nlh);
+ rtm->rtm_family = AF_PHONET;
+ rtm->rtm_dst_len = 6;
+ rtm->rtm_src_len = 0;
+ rtm->rtm_tos = 0;
+
+ rtm->rtm_table = RT_TABLE_MAIN;
+ rtm->rtm_protocol = RTPROT_STATIC;
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_type = RTN_UNICAST;
+ rtm->rtm_flags = 0;
+
+ rta = IFA_RTA(rtm);
+ rta->rta_type = RTA_DST;
+ rta->rta_len = RTA_LENGTH(1);
+ *(uint8_t *)RTA_DATA(rta) = remote;
+
+ rta = RTA_NEXT(rta, buflen);
+ rta->rta_type = RTA_OIF;
+ rta->rta_len = RTA_LENGTH(sizeof ifa_index);
+ *(uint32_t *)(void *)RTA_DATA(rta) = ifa_index;
+
+ if (sendto(fd, &req, reqlen, 0, (void *)&addr, sizeof addr) == -1)
+ return -errno;
+
+ return 0;
+}
+
+int g_pn_netlink_add_route(GIsiModem *idx, uint8_t remote)
+{
+ int fd = -1;
+ uint32_t ifindex;
+ int error = 0;
+
+ if (idx == NULL)
+ return -ENODEV;
+
+ if (remote != PN_DEV_SOS && remote != PN_DEV_HOST)
+ return -EINVAL;
+
+ ifindex = g_isi_modem_index(idx);
+
+ fd = netlink_socket();
+ if (fd == -1)
+ goto error;
+
+ error = netlink_addroute(fd, ifindex, remote);
+ if (error)
+ goto error;
+
+ error = netlink_getack(fd);
+ if (error)
+ goto error;
+
+ close(fd);
+ return 0;
+
+error:
+ if (!error)
+ error = -errno;
+ if (!error)
+ error = -EIO;
+ if (fd != -1)
+ close(fd);
+ return error;
+}
diff --git a/gisi/netlink.h b/gisi/netlink.h
index dfade5b..5b58fa4 100644
--- a/gisi/netlink.h
+++ b/gisi/netlink.h
@@ -41,13 +41,17 @@ typedef enum {
PN_LINK_UP
} GPhonetLinkState;
+enum {
+ PN_DEV_PC = 0x10, /* PC Suite */
+ PN_DEV_HOST = 0x00, /* Modem */
+ PN_DEV_SOS = 0x6C, /* Symbian or Linux */
+};
+
typedef void (*GPhonetNetlinkFunc)(GIsiModem *idx,
GPhonetLinkState st,
char const *iface,
void *data);
-GPhonetNetlink *g_pn_netlink_by_name(char const *ifname);
-
GPhonetNetlink *g_pn_netlink_by_modem(GIsiModem *idx);
GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
@@ -56,6 +60,9 @@ GPhonetNetlink *g_pn_netlink_start(GIsiModem *idx,
void g_pn_netlink_stop(GPhonetNetlink *self);
+int g_pn_netlink_set_address(GIsiModem *, uint8_t local);
+int g_pn_netlink_add_route(GIsiModem *, uint8_t remote);
+
#ifdef __cplusplus
}
#endif
diff --git a/plugins/usbpnmodem.c b/plugins/usbpnmodem.c
index 5f06e9d..e1ce4fd 100644
--- a/plugins/usbpnmodem.c
+++ b/plugins/usbpnmodem.c
@@ -49,6 +49,7 @@ static void usbpn_status_cb(GIsiModem *idx,
void *data)
{
struct ofono_modem *modem;
+ int error;
DBG("Phonet link %s (%u) is %s",
ifname, g_isi_modem_index(idx),
@@ -63,12 +64,17 @@ static void usbpn_status_cb(GIsiModem *idx,
if (st == PN_LINK_REMOVED)
return;
- link = g_pn_netlink_by_name(ifname);
- if (link) {
+ if (g_pn_netlink_by_modem(idx)) {
DBG("Modem for interface %s already exists", ifname);
return;
}
+ error = g_pn_netlink_set_address(idx, PN_DEV_SOS);
+ if (error && error != -EEXIST) {
+ DBG("g_pn_netlink_set_address: %s\n", strerror(-error));
+ return;
+ }
+
modem = ofono_modem_create(NULL, "isimodem");
if (!modem)
return;
--
1.6.3.3
12 years, 1 month
[PATCH 3/4] gatchat: Emit notification when command is sent to modem.
by Andrzej Zaborowski
Function g_at_chat_send_with_callback takes an additional parameter
that is a function to call when command is sent to hardware.
---
gatchat/gatchat.c | 35 +++++++++++++++++++++++++++--------
gatchat/gatchat.h | 17 +++++++++++++++++
2 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index 4552767..000b624 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -49,6 +49,7 @@ struct at_command {
guint id;
GAtResultFunc callback;
GAtNotifyFunc listing;
+ GAtSubmitNotifyFunc submit_callback;
gpointer user_data;
GDestroyNotify notify;
};
@@ -148,6 +149,7 @@ static struct at_command *at_command_create(const char *cmd,
const char **prefix_list,
gboolean expect_pdu,
GAtNotifyFunc listing,
+ GAtSubmitNotifyFunc sent,
GAtResultFunc func,
gpointer user_data,
GDestroyNotify notify,
@@ -203,6 +205,7 @@ static struct at_command *at_command_create(const char *cmd,
c->prefixes = prefixes;
c->callback = func;
c->listing = listing;
+ c->submit_callback = sent;
c->user_data = user_data;
c->notify = notify;
@@ -700,7 +703,7 @@ static gboolean wakeup_no_response(gpointer user_data)
g_at_chat_finish_command(chat, FALSE, NULL);
cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
- NULL, wakeup_cb, chat, NULL, TRUE);
+ NULL, NULL, wakeup_cb, chat, NULL, TRUE);
if (!cmd) {
chat->timeout_source = 0;
@@ -752,7 +755,8 @@ static gboolean can_write_data(gpointer data)
if (chat->cmd_bytes_written == 0 && wakeup_first == TRUE) {
cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
- NULL, wakeup_cb, chat, NULL, TRUE);
+ NULL, NULL, wakeup_cb, chat, NULL,
+ TRUE);
if (!cmd)
return FALSE;
@@ -789,6 +793,9 @@ static gboolean can_write_data(gpointer data)
if (bytes_written < towrite)
return TRUE;
+ if (cmd->submit_callback)
+ cmd->submit_callback(cmd->id, cmd->user_data);
+
/* Full command submitted, update timer */
if (chat->wakeup_timer)
g_timer_start(chat->wakeup_timer);
@@ -967,7 +974,8 @@ gboolean g_at_chat_set_debug(GAtChat *chat,
static guint send_common(GAtChat *chat, const char *cmd,
const char **prefix_list,
gboolean expect_pdu,
- GAtNotifyFunc listing, GAtResultFunc func,
+ GAtNotifyFunc listing, GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
gpointer user_data, GDestroyNotify notify)
{
struct at_command *c;
@@ -975,8 +983,8 @@ static guint send_common(GAtChat *chat, const char *cmd,
if (chat == NULL || chat->command_queue == NULL)
return 0;
- c = at_command_create(cmd, prefix_list, expect_pdu, listing, func,
- user_data, notify, FALSE);
+ c = at_command_create(cmd, prefix_list, expect_pdu, listing,
+ sent, func, user_data, notify, FALSE);
if (!c)
return 0;
@@ -995,7 +1003,7 @@ guint g_at_chat_send(GAtChat *chat, const char *cmd,
const char **prefix_list, GAtResultFunc func,
gpointer user_data, GDestroyNotify notify)
{
- return send_common(chat, cmd, prefix_list, FALSE, NULL, func,
+ return send_common(chat, cmd, prefix_list, FALSE, NULL, NULL, func,
user_data, notify);
}
@@ -1007,7 +1015,7 @@ guint g_at_chat_send_listing(GAtChat *chat, const char *cmd,
if (listing == NULL)
return 0;
- return send_common(chat, cmd, prefix_list, FALSE, listing, func,
+ return send_common(chat, cmd, prefix_list, FALSE, listing, NULL, func,
user_data, notify);
}
@@ -1019,7 +1027,18 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
if (listing == NULL)
return 0;
- return send_common(chat, cmd, prefix_list, TRUE, listing, func,
+ return send_common(chat, cmd, prefix_list, TRUE, listing, NULL, func,
+ user_data, notify);
+}
+
+guint g_at_chat_send_with_callback(GAtChat *chat, const char *cmd,
+ const char **valid_resp,
+ GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ return send_common(chat, cmd, valid_resp, TRUE, NULL, sent, func,
user_data, notify);
}
diff --git a/gatchat/gatchat.h b/gatchat/gatchat.h
index ea6626e..80d87be 100644
--- a/gatchat/gatchat.h
+++ b/gatchat/gatchat.h
@@ -37,6 +37,7 @@ typedef struct _GAtChat GAtChat;
typedef void (*GAtResultFunc)(gboolean success, GAtResult *result,
gpointer user_data);
typedef void (*GAtNotifyFunc)(GAtResult *result, gpointer user_data);
+typedef void (*GAtSubmitNotifyFunc)(guint id, gpointer user_data);
GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax);
GAtChat *g_at_chat_new_blocking(GIOChannel *channel, GAtSyntax *syntax);
@@ -117,6 +118,22 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
GAtNotifyFunc listing, GAtResultFunc func,
gpointer user_data, GDestroyNotify notify);
+/*!
+ * Same as g_at_chat_send but with an ability to return a notification the
+ * moment the command finally leaves the queue and is submitted to lower
+ * layer.
+ *
+ * This is useful for cases where the modem's response time needs to be
+ * measured, assuming that the lower layers processing time is shorter
+ * than the minimum accuracy needed.
+ */
+guint g_at_chat_send_with_callback(GAtChat *chat, const char *cmd,
+ const char **valid_resp,
+ GAtSubmitNotifyFunc sent,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify);
+
gboolean g_at_chat_cancel(GAtChat *chat, guint id);
gboolean g_at_chat_cancel_all(GAtChat *chat);
--
1.6.1
12 years, 1 month
[PATCH 2/4][RFC] gatchat: Allow cancelling a running command.
by Andrzej Zaborowski
Users need to be extra careful using the cancel functions because
there's a potential race condition where an OK or ERROR for the command
being cancelled arrives just the same moment the next command in the
queue is being submitted, and is treated as a response to that command.
Ideally we would have some kind of "barrier" command that could be
inserted into the queue and whose response would be different than
OK or ERROR.
---
gatchat/gatchat.c | 32 +++++++++++++++-----------------
1 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index f94605f..4552767 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -1026,6 +1026,7 @@ guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
gboolean g_at_chat_cancel(GAtChat *chat, guint id)
{
GList *l;
+ gboolean head;
if (chat == NULL || chat->command_queue == NULL)
return FALSE;
@@ -1040,18 +1041,20 @@ gboolean g_at_chat_cancel(GAtChat *chat, guint id)
if (!l)
return FALSE;
- if (l == g_queue_peek_head(chat->command_queue) &&
- chat->cmd_bytes_written > 0) {
- struct at_command *c = l->data;
+ head = l->data == g_queue_peek_head(chat->command_queue);
- /* We can't actually remove it since it is most likely
- * already in progress, just null out the callback
- * so it won't be called
- */
- c->callback = NULL;
- } else {
- at_command_destroy(l->data);
- g_queue_remove(chat->command_queue, l->data);
+ at_command_destroy(l->data);
+ g_queue_remove(chat->command_queue, l->data);
+
+ if (head) {
+ chat->cmd_bytes_written = 0;
+
+ g_slist_foreach(chat->response_lines, (GFunc)g_free, NULL);
+ g_slist_free(chat->response_lines);
+ chat->response_lines = NULL;
+
+ if (g_queue_get_length(chat->command_queue) > 0)
+ chat_wakeup_writer(chat);
}
return TRUE;
@@ -1071,15 +1074,10 @@ gboolean g_at_chat_cancel_all(GAtChat *chat)
continue;
}
- if (n == 0 && chat->cmd_bytes_written > 0) {
- c->callback = NULL;
- n += 1;
- continue;
- }
-
at_command_destroy(c);
g_queue_remove(chat->command_queue, c);
}
+ chat->cmd_bytes_written = 0;
return TRUE;
}
--
1.6.1
12 years, 1 month
[PATCH] add vid/pid for Dell 5541 and 5542
by Torgny Johansson
Hi!
The following patch adds two new devices in the ofono.rules file:
Regards
Torgny Johansson
diff --git a/plugins/ofono.rules b/plugins/ofono.rules
index e6da49d..0575362 100644
--- a/plugins/ofono.rules
+++ b/plugins/ofono.rules
@@ -42,6 +42,10 @@ ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8147",
ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8183", ENV{OFONO_DRIVER}="mbm"
ATTRS{idVendor}=="413c", ATTRS{idProduct}=="8184", ENV{OFONO_DRIVER}="mbm"
+# Dell F3307
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818b", ENV{OFONO_DRIVER}="mbm"
+ATTRS{idVendor}=="413c", ATTRS{idProduct}=="818c", ENV{OFONO_DRIVER}="mbm"
+
# Toshiba
ATTRS{idVendor}=="0930", ATTRS{idProduct}=="130b", ENV{OFONO_DRIVER}="mbm"
12 years, 1 month
[PATCH v2 0/6] Huawei GPRS support
by Kalle Valo
Hello all,
here's my current patch set of adding Huawei GPRS support to ofono. I
have tested it with Huawei E1552 USB dongle and finnish Saunalahti prepaid
sim.
Because I had to somehow provide the second GAtChat to atmodem's gprs and
netreg modules, I decided to add two new structs.
There's one major bug still, ofono segfaults when I deactivate the gprs
context. I don't know the reason for this yet.
Please comment.
---
Kalle Valo (6):
huawei: add gprs context
atmodem: add signal strength support for huawei
atmodem: follow separate event chat with huawei
huawei: detect SecondaryDevice which is used for events
atmodem: create struct atmodem_network_registration
atmodem: create struct atmodem_gprs
drivers/atmodem/gprs.c | 23 ++++++++---
drivers/atmodem/gprs.h | 29 ++++++++++++++
drivers/atmodem/network-registration.c | 37 ++++++++++++++++--
drivers/atmodem/network-registration.h | 29 ++++++++++++++
plugins/atgen.c | 7 +++
plugins/calypso.c | 7 +++
plugins/em770.c | 2 +
plugins/g1.c | 8 +++-
plugins/hso.c | 15 ++++++-
plugins/huawei.c | 66 +++++++++++++++++++++++++++++++-
plugins/mbm.c | 14 ++++++-
plugins/novatel.c | 9 ++++
plugins/palmpre.c | 15 ++++++-
plugins/phonesim.c | 16 ++++++--
plugins/ste.c | 15 ++++++-
plugins/udev.c | 61 ++++++++++++++++++++++++++----
16 files changed, 319 insertions(+), 34 deletions(-)
create mode 100644 drivers/atmodem/gprs.h
create mode 100644 drivers/atmodem/network-registration.h
12 years, 1 month