libqmi-glib
Aleksander Morgado
aleksander at lanedo.com
Mon Apr 23 04:24:33 PDT 2012
Hey Thomas, Dan & everyone else,
I've recently been playing quite some time with QMI devices, and
analyzing Chromium's libqmi. I also started libqmi-glib, what I thought
would be just a small layer on top of Chromium's libqmi's generic
implementation, providing a GLib/GIO like interface. This small layer
ended up being quite a rewrite of Chromium's libqmi, fixing some things
and taking some other approaches sometimes.
Will try to detail some of the similarities and differences:
* chromium-libqmi provides a 'qmidev' object for each /dev/cdc-wdm
port. libqmi-glib provides a QmiDevice GObject instead for the same
purpose. They both control every read and write on the port.
* chromium-libqmi will epoll() the FD retrieved when opening the port.
Once epoll says there is data ready to be read, the library will try to
perform a blocking read() to get the header of the message (to get the
whole length needed), plus another blocking read() to get the full
message. libqmi-glib instead will base its polling on a non-blocking
GIOChannel attached to the main loop, so that we process data available
events and we only really read the whole message when we already have it
in our buffers (similar to ModemManager's serial port handling).
* Both implementations have an implicit client for the control service
with cid = 0. In libqmi-glib, this client can be retrieved directly from
the QmiDevice, with qmi_device_{peek|get}_client_ctl().
* In libqmi-glib, whenever a QmiDevice is opened, we'll launch a
version-info request in the port. This allows us to get the list of
services the device supports, but also serves as probing purposes to
know whether a port is really QMI-capable or not. I'm assuming here that
every QMI-capable device is able to reply to the version info request;
if not, we could make this setup optional.
* Both implementations allow to create clients for services. In
chromium-libqmi, qmidev_get_client() allows creating new clients for a
specific qmidev, taking care of CID allocation. In libqmi-glib, the
generic CID allocation/releasing is done in the async-initable abstract
QmiClient class, so every service-specific subclass (e.g. QmiClientDms)
needs to be async-initable. If the CID allocation fails, the creation of
the QmiClient object fails (except for the implicit CTL client, which
doesn't need CID allocation).
* In chromium-libqmi, clients configure different 'listen criteria' so
that whenever a message is received from the device, it is matched
against the different listen criterias of the configured listeners, and
passed through to the ones which pass the criteria. This seems to be a
good way to handle both message transactions (a message and its reply),
as well as unsolicited messages. In libqmi-glib, a HT of transactions is
kept in the QmiDevice, and whenever a reply message is received from the
device it is matched against the specific transaction. Unsolicited
messages are not yet handled in the library, but they will possibly be
based on custom registrations to specific event/service types, similar
to the listeners logic in chromium-libqmi.
* Both chromium-libqmi and libqmi-glib provide async ways of
performing service-specific operations. In libqmi-glib, sending a
message and receiving a reply are done in a single GIO-like async call.
The request is sent with qmi_device_command(), and the reply or error
received with qmi_device_command_finish(). Clients will use this async
call to provide request-specific methods, e.g:
qmi_client_ctl_get_version_info() and
qmi_client_ctl_get_version_info_finish(), and the whole logic is already
chained up in the GLib main loop. In chromium-libqmi, the user can of
course choose how to make the implementation asynchronous, either with
the GLib main loop itself, or some other event loop (e.g. libevent), or
even busy waiting with the blocking read()s on the FD.
* In chromium-libqmi, messages are written/read directly as a
message-object operation (the qmidev kind of requests the message to
write/read itself in the port). In libqmi-glib, the QmiMessage object
doesn't do any read/write, it just builds/parses raw binary streams and
the real read/write is done by the QmiDevice. The final result is really
the same at the end, the logic is just a bit different.
* Most (all?) the message building/parsing logic is taken as-is from
chromium-libqmi (plus some bits from Dan's 'qmitest').
* chromium-libqmi provides a 'mock' device for testing purposes. I
didn't include this just yet in libqmi-glib.
* libqmi-glib provides a 'qmicli' tester tool, similar to
ModemManager's 'mmcli'. chromium-libqmi also provides additional
independent tester tools for different operations.
I'm not sure what others' needs are w.r.t to libqmi; in my case I would
like to have the GLib/GIO-like API of libqmi-glib in order to integrate
it nicely in ModemManager, as well as the state machine logic already
chained up in the GLib main loop. Regarding the upstream implementation
of libqmi, I'm assuming it could be as generic as chromium-libqmi is,
ideally providing separate libraries for 1) message building/parsing +
common enums/types and 2) the state machine, so that libqmi-glib can use
the message building/parsing one as is and replace the state machine. If
everyone is happy with the GLib main loop anyway (which is the only big
difference between both implementations), we could also take libqmi-glib
as the upstream codebase.
libqmi-glib currently lives on gitorious.org, and no need to say it's WIP:
git clone git://gitorious.org/lanedo/libqmi-glib.git
Compiling with `-DMESSAGE_ENABLE_TRACE' enables tracing in stdout all
sent & received messages, and `cli/qmi-cli --help-all' shows the
currently available operations included in the command line interface tool.
Comments, thoughts?
--
Aleksander
More information about the libqmi-devel
mailing list