You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为蜂窝调制解调器建立GIOStream与GDBusConnection连接

问题:使用libmm-glib建立与蜂窝调制解调器的GDBusConnection

我在Ubuntu 20.04系统上,尝试用libmm-glib编写程序收集Telit LE910C4-NF调制解调器的信息,但卡在了建立GIOStream并创建GDBusConnection这一步。命令行查看设备时发现/dev/ttyUSB0、/dev/ttyUSB4被标记为"ignored",尝试用/dev/cdc-wdm0初始化GFile也失败了。

我的预期操作步骤:

  • 获取与调制解调器关联的GFile(不确定该用哪个设备路径)
  • 用GFile构建GIOStream
  • 用GIOStream构建GDBusConnection
  • 用GDBusConnection构建MMManager
  • 通过MMManager查询调制解调器信息

编译命令

gcc main.c -I/usr/include/libmm-glib -I/usr/include/ModemManager -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -lglib-2.0 -lz -lgio-2.0 -lpthread -lmm-glib

原代码

#include <libmm-glib.h>
#include <gio/gio.h>
//#include <gtk/gtk.h>
#include <stdio.h>
int main (void)
{
    printf("begin 1\n");

    GCancellable                     *cancellable;
    GError                           **ppError;
    MMManager                        *pManager;
    GDBusAuthObserver                *observer;
    GDBusObjectManagerClientFlags    flags = G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE;
    const gchar                      *guid  = NULL; 
    //g_type_init(); 
    //GFile * save = g_file_new_for_path("/org/freedesktop/ModemManager1/Modem/3");
    //GFile * save = g_file_new_for_path("/sys/devices/platform/soc@0/32c00000.bus/32e50000.usb/ci_hdrc.1/usb1/1-1/1-1.3");
    GFile * save = g_file_new_for_path("/dev/ttyUSB0");


    if(save == NULL)
    {
        printf("null GFile\n");
    }    
    else
    {
        printf("GFile OK\n");

    }
    GFileIOStream *pStream = g_file_open_readwrite(save, NULL, NULL);

    if(pStream == NULL)
    {
        printf("null pStream\n");
    }    
    else
    {
        printf("pStream OK\n");
    }
    
    GDBusConnection *pConnection= g_dbus_connection_new_sync(pStream,
                                                      guid, // for authent. as a server
                                                      flags,
                                                      NULL, // observer,
                                                      NULL, // cancellable,
                                                      ppError);

    if(pConnection == NULL)
    {
        printf("null GDBusConnection\n");
    }

    pManager = mm_manager_new_sync(pConnection,
                                   flags,
                                   cancellable,
                                   ppError);

    if(pManager == NULL)
    {
        printf("null pManager\n");
    }

    mm_manager_scan_devices_sync(pManager,
                 cancellable,
                 ppError);

    MMObject modem;

    printf("d\n");

    //const gchar* pChar = mm_object_get_path(&modem);

    //free resources here
    
    printf("end\n");
    return(0);
}

设备信息

-----------------------------
  General  |              path: /org/freedesktop/ModemManager1/Modem/3
           |         device id: 
  -----------------------------
  Hardware |      manufacturer: Telit
           |             model: LE910C4-NF
           | firmware revision: 25.21.660  1  [Mar 04 2021 12:00:00]
           |    carrier config: default
           |      h/w revision: 1.30
           |         supported: gsm-umts, lte
           |           current: gsm-umts, lte
           |      equipment id: 
  -----------------------------
  System   |            device: /sys/devices/platform/soc@0/32c00000.bus/32e50000.usb/ci_hdrc.1/usb1/1-1/1-1.3
           |           drivers: qmi_wwan, option
           |            plugin: telit
           |      primary port: cdc-wdm0
           |             ports: cdc-wdm0 (qmi), ttyUSB0 (ignored), ttyUSB1 (gps),
           |                    ttyUSB4 (ignored), wwan0 (net)
  -----------------------------
  Status   |             state: failed
           |     failed reason: sim-missing
           |       power state: on
           |    signal quality: 0% (cached)
  -----------------------------
  Modes    |         supported: allowed: 3g; preferred: none
           |                    allowed: 4g; preferred: none
           |                    allowed: 3g, 4g; preferred: 4g
           |                    allowed: 3g, 4g; preferred: 3g
           |           current: allowed: any; preferred: none
  -----------------------------
  Bands    |         supported: utran-4, utran-5, utran-2, eutran-2, eutran-4, eutran-5,
           |                    eutran-12, eutran-13, eutran-14, eutran-66, eutran-71
  -----------------------------
  IP       |         supported: ipv4, ipv6, ipv4v6
  -----------------------------
  SIM      |    sim slot paths: slot 1: none (active)
           |                    slot 2: none

解决方案

核心问题分析

你走了弯路:libmm-glib的正常用法是通过系统D-Bus总线连接到ModemManager服务,而不是直接打开设备文件构建GDBusConnection。直接操作tty或cdc-wdm设备是底层方式,libmm-glib已经封装了这些细节,不需要手动处理。

正确实现步骤

  1. 连接到系统D-Bus(ModemManager服务运行在系统总线上)
  2. 通过D-Bus连接获取MMManager实例
  3. 从MMManager中枚举调制解调器对象
  4. 查询指定调制解调器的信息

修正后的代码

#include <libmm-glib.h>
#include <gio/gio.h>
#include <stdio.h>

int main(void)
{
    printf("begin\n");

    GError *error = NULL;
    MMManager *manager;
    GList *modems, *l;

    // 初始化GLib类型系统(GLib 2.36+可省略,但显式调用更安全)
    g_type_init();

    // 连接到系统D-Bus并获取MMManager实例
    manager = mm_manager_new_sync(NULL, NULL, &error);
    if (!manager) {
        g_printerr("Failed to create MMManager: %s\n", error->message);
        g_error_free(error);
        return 1;
    }

    // 扫描并获取所有调制解调器
    modems = mm_manager_get_modems(manager);
    if (!modems) {
        printf("No modems found\n");
        g_object_unref(manager);
        return 0;
    }

    // 遍历调制解调器并打印信息
    for (l = modems; l != NULL; l = l->next) {
        MMObject *obj = MM_OBJECT(l->data);
        MMModem *modem = mm_object_get_modem(obj);
        const gchar *path = g_dbus_object_get_path(G_DBUS_OBJECT(obj));
        const gchar *model = mm_modem_get_model(modem);
        const gchar *manufacturer = mm_modem_get_manufacturer(modem);
        MMModemState state = mm_modem_get_state(modem);

        printf("Modem Path: %s\n", path);
        printf("Manufacturer: %s\n", manufacturer);
        printf("Model: %s\n", model);
        printf("State: %s\n", mm_modem_state_get_string(state));
        printf("-------------------------\n");

        g_object_unref(modem);
    }

    // 释放资源
    g_list_free_full(modems, g_object_unref);
    g_object_unref(manager);

    printf("end\n");
    return 0;
}

关键说明

  • 为什么不需要直接操作设备文件:ModemManager服务已经负责与硬件设备的通信,libmm-glib作为客户端只需要通过D-Bus与ModemManager交互即可。
  • 关于"ignored"端口:这些端口是ModemManager识别后不需要用于控制的端口(比如某些调试端口),正常控制用的是primary port(这里是cdc-wdm0),但同样不需要你直接操作。
  • 权限问题:运行程序需要足够权限,要么用sudo,要么将用户添加到dialout或plugdev组:
    sudo usermod -aG dialout $USER
    sudo usermod -aG plugdev $USER
    

编译命令保持不变

gcc main.c -I/usr/include/libmm-glib -I/usr/include/ModemManager -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -lglib-2.0 -lz -lgio-2.0 -lpthread -lmm-glib

内容的提问来源于stack exchange,提问作者sasukenebe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 21:50:37