Archive
ModemManager is fun
These last weeks I’ve been out of my usual Tracker work, and have been hacking on NetworkManager/ModemManager so that they can work properly with Sierra Wireless Airlink Fastrack Xtend modems.
Ended up writing a new wavecom plugin for this purpose (Wavecom was bought by Sierra Wireless in 2009), which Dan already merged in the master branch of ModemManager.
The changes in the new wavecom plugin with respect to the generic GSM plugin are:
- AT+CPIN? replies are not ended with OK. A custom regex match was added to support CPIN? replies without OK (also had to hack the generic MM code to handle plugin-provided regular expressions).
- Disabled default power-up comand, AT+CFUN=1. This command does a full software reset in the device, including the USB stack, so the connection is closed. No additional command seems to be needed, as the modem wakes up by default in CFUN=1 (full functionality) mode. Anyway, an additional check was added during initialization so that this mode is ensured.
- Enabled RTS/CTS instead of XOFF/XON flow control.
- Implemented access technology retrieval using AT+WGPRS=9,2 to query network capabilities
- Ensure the modem uses the highest possible mobile class. These modems can be configured to use different mobile classes. For each kind of modem, the best mobile class is the highest one available, in the following order:
- Class A (3G only mode)
- Class B (PS or CS, GPRS/EDGE or GSM)
- Class CG (PS only, GPRS/EDGE)
- Class CC (CS only, GSM)
- Implemented setting and getting allowed mode, for both 2G and 3G based modems (using AT+WWSM command in the 3G case).
- Implemented setting and getting frequency bands for 2G modems (with AT+WMBS) and 3G modems (with AT+WUBS).
Still, the plugin could be improved even more. For example, there is no secondary port handling in the current plugin implementation, which means that signal strength value will not be updated while the modem is in connected state. This kind of modems support setting up virtual ports by multiplexing the serial channel (CMUX), but ModemManager doesn’t handle this yet.
If anyone has one of this Wavecom/SierraWireless modems at home, please test it with latest ModemManager and report any errors found.
Gaztea Irratia & Rhythmbox
First thing when I go back to the Basque Country to visit my family is to tune Gaztea Irratia in my car’s radio.
Now, I can listen to it from anywhere using Gnome’s Rhythmbox and the Shoutcast live stream. Just add a new radio station in Rhythmbox with this URL:
http://yp.shoutcast.com/sbin/tunein-station.pls?id=77647
And enjoy!
Avoid G_TYPE_INSTANCE_GET_PRIVATE() in GObjects
When developing GObjects in Glib/GObject framework, it is usual to have a structure defined in the source file with all the private members of the object. Doing this, the internals of the object are not published in its API, so that no other module outside can modify them without using the defined GObject methods.
There are several ways to achieve this, and one of them is the recommended one in GObject’s tutorial [1], which uses the G_TYPE_INSTANCE_GET_PRIVATE [2] macro to get the glib-instantiated private structure. This private structure, allocated for each instance of the object, is specified in the Class initialization function with g_type_class_add_private(), and allocated every time a new GObject instance is created.
Usually, you will have a macro for your specific GObject which will call G_TYPE_INSTANCE_GET_PRIVATE:
#define MY_GOBJECT_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE((o), MY_GOBJECT_TYPE, MyGObjectPrivate))
This seems a good way of doing it, and quite simple to use. Glib will take care of allocating and deallocating that private structure for us… so why avoid it?
Well… if you ever tried to run Valgrind’s callgrind tool to measure how much time your program spends in a given function, you will see the reason. Other people already did that and published results on the web, so go and check them [3] or just try it with your application:
$> valgrind --tool=callgrind /usr/local/bin/your_program</span
Now, an easy way of getting the same result, with a little bit more of work but achieving the best performance, is just using an opaque pointer in the GObject’s public structure and define, allocate and deallocate it yourself in the source file (so also can be treated as private, as the users of the API don’t know the internals of the structure).
These are the basic changes you need to do to avoid calling G_TYPE_INSTANCE_GET_PRIVATE():
**** In the HEADER of the GObject, when the struct defining the Object is specified, add a “gpointer priv” variable.
struct _MyGObject
{
/** Parent object */
GObject parent;
/** Private data pointer */
gpointer priv;
}
**** Then, in the SOURCE of the GObject, modify the GET_PRIVATE macro so that instead of doing the standard GObject lookup for the correct type, we just get the opaque “priv” pointer defined in the header, and we cast it to the correct type.
#define MY_GOBJECT_GET_PRIVATE(o) \
((MyGObjectPrivate *)((MY_GOBJECT(o))->priv))
**** As we won’t use the automatic allocation of the Private data structure, we need to allocate it ourselves in the _init() function.
static void
my_gobject_init(MyGObject *self)
{
/* Allocate Private data structure */
(MY_GOBJECT(self))->priv = \
(MyGObjectPrivate *) g_malloc0(sizeof(MyGObjectPrivate));
/* If correctly allocated, initialize parameters */
if((MY_GOBJECT(self))->priv != NULL)
{
MyGObjectPrivate *priv = MY_GOBJECT_GET_PRIVATE(self);
/* Initialize private data, if any */
}
}
**** And finally, the last change is just de-allocating the structure when no more needed in the _dispose() function.
static void
my_gobject_dispose(GObject *object)
{
MyGObject *self = (MyGObject *)object;
MyGObjectPrivate *priv = MY_GOBJECT_GET_PRIVATE(self);
/* Check if not NULL! To avoid calling dispose multiple times */
if(priv != NULL)
{
/* Deallocate contents of the private data, if any */
/* Deallocate private data structure */
g_free(priv);
/* And finally set the opaque pointer back to NULL, so that
* we don't deallocate it twice. */
(MY_GOBJECT(self))->priv = NULL;
}
}
References: