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