ModemManager: improving port probing



Hi all,

I've been lately trying to improve the probing process in ModemManager,
so that it is faster and easier to maintain, keeping in mind the
different specific needs of the current plugins.

The current status of the work can be seen in the 'probing-refactor'
branch in the following git repo:
git://gitorious.org/aleksander/modemmanager.git It currently only
compiles some plugins (Cinterion, Nokia and Generic) which are the ones
ported to the new probing process being suggested here. The branch is
organized in logical commits so that it can be easily reviewed (hope so,
at least).

I had mixed feelings on whether I should suggest all these new things
before having it fully ready, but I think it makes sense to at least
discuss them before I spend more time on it.



1. Plugin Manager
-----------------------------------------------

The MMManager object handled too many different tasks, that it made
sense to me to have an independent MMPluginManager object which takes
care of: 
 * Finding plugins and loading them
 * Controlling the requests to find the best plugin to support a given
port.

So whenever a new port is found/detected, we can just pass it to
mm_plugin_manager_find_port_support() and wait for the async method to
return the best plugin found for it. When devices with multiple ports
are detected, the Plugin Manager also takes care of propagating the
first best plugin found to support checks of ports in the same device.

This Plugin Manager work is at the beginning of the branch; and quite
independent to the rest of the changes (in other words, directly
mergeable to master if you guys like it).



2. Port Support Checks
-----------------------------------------------

The whole probing process is now done in a new MMPortProbe object
(somewhat equivalent to the MMPluginBaseSupportsTask object, which was
removed). The object serves as a temporary storage for already probed
information (as the MMPluginBaseSupportsTask one), but also allows
specifying what needs to be probed in the port and does also the real
probing.

The MMPluginBase will control whether a probing is needed, and will also
process the results of the probing reported by the MMPortProbe object.
Specific plugins are able to set at construction time different property
values to modify the both the probing process and the pre- and
post-probing filters to run. See the ported Nokia plugin as example:
https://gitorious.org/aleksander/modemmanager/commit/d2992abdb1f386962063e6b61ae8bf26eb0f995a

The whole port support check done by every plugin can be summarized in
the following steps:
 * [MMPluginBase] Check whether we need to launch probing (pre-probing
filters).
 * [MMPortProbe] Launch port probing, get probing results.
 * [MMPluginBase] Check whether the results we got are the ones expected
(post-probing filters).
 * [MMPluginBase] Report port support check results.


2.1 Pre-probing filters

Pre-probing filters are those which control whether the probing, as
requested by the specific plugin, takes place. The best example of this
filter type is the VENDOR_IDS one: The probing request will be aborted
(and therefore report as unsupported) unless the port reports a Vendor
ID equal to one in the given array.
 
 * MM_PLUGIN_BASE_ALLOWED_VENDOR_IDS: A plugin can set this property to
a 0-terminated array of uint16s containing the udev-reported vendor IDs
it can handle, e.g.:

    static const guint16 vendor_ids[] = { 0x0421 , 0 };

    return MM_PLUGIN (
        g_object_new (MM_TYPE_PLUGIN_NOKIA,
                      ...
                      MM_PLUGIN_BASE_ALLOWED_VENDOR_IDS, vendor_ids,
                      NULL));

Other pre-probing filters considered and already implemented are
Subsystems, Drivers, Product ID and Udev Tags. See:
https://gitorious.org/aleksander/modemmanager/commit/142d0161070777a8a8cac44e8320b07b70fb437a


2.2 Probing-specific configurations

If the port passed all pre-probing filters, a probing process can be
started. The specific probing to be done directly depends on the
requested post-probing filters. Some examples:
  ** Cinterion modems do not expose QCDM ports, therefore no QCDM port
probing is needed.
  ** ZTE modems are never RS232, therefore no Vendor/Product AT-probing
is needed.

If all the requested probing information is already cached, the probing
is not launched again. This may happen when probing a port in a RS232
modem, where capabilities and Vendor-string probing may be done by an
earlier plugin.

When any AT-specific probing is requested (capabilities, vendor,
product), we first check whether the port is an AT port or not (just
sending "AT" and not expecting any error). If the port is found to be an
AT port, capabilities/vendor/product probing can continue. We will only
check if the port is to be QCDM if the plugin object was created with
MM_PLUGIN_BASE_ALLOWED_QCDM set to TRUE.

As before, plugins are allowed to specify custom initialization
commands, in this case with the MM_PLUGIN_BASE_CUSTOM_INIT property
which expects a NULL-terminated array of the new MMPortProbeAtCommand
structs. This custom initialization can also be used to check whether
the port is an AT port or not. As an example, the Nokia plugin may use:

    static gboolean
    parse_init (const gchar *response,
                const GError *error,
                GValue *result,
                GError **result_error)
    {
        if (error)
            /* Go on to next command */
            return FALSE;

        /* If we didn't get any error, it is an AT port */
        g_value_init (result, G_TYPE_BOOLEAN);
        g_value_set_boolean (result, TRUE);
        return TRUE;
    }

    static gboolean
    parse_init_last (const gchar *response,
                     const GError *error,
                     GValue *result,
                     GError **result_error)
    {
        g_value_init (result, G_TYPE_BOOLEAN);
        /* On last error, report as not being an AT port */
        g_value_set_boolean (result, error ? FALSE : TRUE);
        return TRUE;
    }

    /* ------ */

    static const MMPortProbeAtCommand custom_init[] = {
        { "ATE1 E0", parse_init },
        { "ATE1 E0", parse_init },
        { "ATE1 E0", parse_init_last },
        { NULL }
    };

    return MM_PLUGIN (
        g_object_new (MM_TYPE_PLUGIN_NOKIA,
                      ...
                      MM_PLUGIN_BASE_CUSTOM_INIT, custom_init,
                      NULL));

This is, "ATE1 E0" will be sent up to 3 times, and if we kept getting
errors in all 3 tries, the port is reported as not being an AT port.
Being able to say whether a port is AT or not from the custom init is
just about convenience, the custom init command is of course not for
that and the callback is allowed to return without setting the output
'result'. Also, if the callback sets 'result_error', the whole probing
process would get cancelled. See:
https://gitorious.org/aleksander/modemmanager/commit/40e66ea506101a0af6922bde24ad9579392f0429


2.3 Post-probing filters

Post-probing filters are those which control whether the plugin can
support the port once the desired probing results are ready. The best
example of this filter type is the CAPABILITIES one: The support request
will report unsupported unless the probed capabilities from the port
match the capabilities given in the property.

 * MM_PLUGIN_BASE_ALLOWED_CAPABILITIES: A plugin can set this property
to a guint representing a mask of flags where supported capabilities are
given, e.g.:

    static const guint32 capabilities =
MM_PORT_PROBE_CAPABILITY_GSM_OR_CDMA;

    return MM_PLUGIN (
        g_object_new (MM_TYPE_PLUGIN_NOKIA,
                      ...
                      MM_PLUGIN_BASE_ALLOWED_CAPABILITIES, capabilities,
                      NULL));

Other post-probing filters considered and implemented are Vendor Strings
and Product Strings (used only in plugins supporting RS232 devices).
See:
https://gitorious.org/aleksander/modemmanager/commit/bc1d62ddb58abbff3eea21196deac8cf9eff3473


2.4 Port support results

Given a port, there is always a single plugin that may support it. MM
currently reports 'support level' values (given as an integer in the
[0-100] range), but the truth seems to be that only one single plugin
ends up reporting a support_level > 0 (due to the udev or AT-probed
vendor/product filtering). Therefore, a new SUPPORTED state was added to
the possible replies of the port support check done by the plugins, to
be used instead of reporting a support_level > 0.

The whole supports_port() method was also changed so that it always
reports results asynchronously (so there is no longer need for
IN_PROGRESS status). This eases a lot the management of port support
requests within the Plugin Manager. See:
https://gitorious.org/aleksander/modemmanager/commit/b07189f14fe6e88a87cd8db5312d9fdf6734e680


3. TODOs
-----------------------------------------------

3.1 Port Grabbing: In the same way that the port support checking was
fully moved to the MMPluginBase, port grabbing can also possibly be
completely moved out of the plugin implementations. For example, letting
plugins specify in a new property the GType of the modem object to
create when GSM capability is found, and such.

3.2 Port remaining plugins to the new probing process. I first wanted to
discuss all these ideas in the list before going on with that.


Comments?


Cheers!

-- 
Aleksander



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]