USSD 概述

非结构化补充服务数据 (USSD) 是全球 (移动通信系统 (GSM) 设备的通信协议,通常称为“MO”) 。

若要了解 USSD,最好将其与最紧密相关的同级进行比较:短消息服务 (短信) 。 USSD 和 SMS 都是 GSM 标准,这意味着它们作为第二代移动设备中的功能引入。 但是,与 SMS 相反,USSD 是基于会话的连接。 虽然短信用于短会话消息传送,但 USSD 通常用于移动设备的命令和控制。 由于有必要维护会话,因此 USSD 不支持像短信一样提供存储和转发功能。 USSD 和短信都发送了符合 7 位 GSM 的字符,但 USSD 最大发送为 184 个字符,而短信的字符为 160。

USSD 消息可以通过打开拨号程序并键入代码从移动电话发送。 并非所有代码都受每个电话或 MO 的支持。 在某些情况下,手机软件或操作系统可能会阻止手动发送代码。 必须实现的一个必需代码是 *#06#。 此代码返回国际移动设备标识符 (调制解调器的 IMEI) ,但某些电话会阻止你直接拨打。 如果遵循通过手机设置查找调制解调器的 IMEI 的传统方法,则使用此代码检索了该号码。

如果电话硬件可以直接处理代码的命令(如 IMEI 示例中所示),则不会启动任何网络会话。 需要网络通信的其他代码将打开会话,然后发送由命令和任何必要参数组成的消息(如果适用)。 其中一个示例是使用 MO 检查当前余额和计划状态的代码。

Windows中的 USSD 作为 WinRT API 图面实现。 此接口的实现类充当 USSD 会话的状态机,但最终依赖于 WWAN 服务来执行繁重的工作。 这些 API 是使用工厂模式实现的。

实现 USSD

需要记住的一个关键事项是,面向公众的 API 由 IDL 定义。 实现可能会造成混淆,尤其是不熟悉 WinRT 时。 混乱的一部分来自看似模糊的“工厂”一词的使用。 工厂可以引用静态接口的类实现或提供运行时类类的可激活接口的真实工厂。

本主题回顾 WinRT 概念,然后基于这些概念描述实现。 可能始终引用 IDL 进行进一步澄清。

接口

接口定义应用程序二进制接口 (ABI) 。 它们描述了可调用任何实现接口的类的函数。

运行时类

这些是实际类。 它们按名称表示最终作为类名向 ABI 公开的内容。 每个运行时类可能具有零个或多个接口 (,但如果每个运行时类具有一个或多个接口) 、零个或多个静态接口,并且如有必要,必须声明至少一个默认接口。 每个接口在不同的文件中实现为不同的“Impl”类,但它们似乎是 ABI 的单个统一类。

典型接口在现有对象上显示为实例方法。

静态接口在运行时类本身上显示为静态方法。

可激活标记定义将生成运行时类实例的工厂接口。 这完全模糊化给客户端,显示为该运行时类的构造函数。

USSD 实现

Diagram showing USSD implementation.

Flow:打开、发送、接收、关闭。

打开、发送

Flow diagram for USSD request with reply.

  1. 客户端使用一个静态函数 UssdSession.CreateFromNetworkAccountId 或 UssdSession.CreateFromNetworkInterfaceId 创建 UssdSession 对象。

  2. 无论调用的 API 如何,都需要网络接口 ID 来初始化 UssdSession。 对于 *NetworkAccountID,需要执行步骤从帐户 ID 中检索网络接口 ID。 调用 CreateInternal () ,在新建的实例上创建 UssdSession 实例并调用 Initialize () 。 在初始化步骤中,将启动工作线程,并创建用于触发线程事件的事件句柄。 步骤 3 和步骤 4 也会在实例的 Initialize () 期间进行。

  3. 在 WwanWrapper 成员对象上调用 Initialize () 。 此函数接受静态回调函数和上下文,以允许静态函数将回调映射到对象上下文。

  4. WwanWrapper 通过提供静态回调函数指针和“this”作为上下文来打开 WwanService、枚举接口和订阅 USSD 通知的句柄。

  5. UssdSession 对象将返回到客户端。

  6. 客户端通过使用消息字符串调用构造函数来构造新的 UssdMessage。 WinRT 模糊处理此过程中的 UssdMessageFactory。

  7. 客户端在会话对象上调用 SendMessageAndGetReplyAsync,并传递 UssdMessage 实例。

  8. 此时 SendMessageAndGetReplyAsync 会创建一个名为 UssdSendMessageAndGetReplyOperation 的特殊操作对象。 从其名称来看,该对象将封装在堆栈中发送的单个消息的逻辑 (并等待回复) ,但情况并非如此。 WinRT 需要异步操作的特殊输出参数,我们可以在此函数的定义中看到第二个参数。

    HRESULT SendMessageAndGetReplyAsync(
                [in] UssdMessage* message,
                [out, retval] Windows.Foundation.IAsyncOperation<UssdReply>** asyncInfo);
    

    它是 IUssdSendMessageAndGetReplyOperation,它是通过 typedef 命名接口,通过承诺此操作将不可避免地返回 UssdReply 来满足此参数。 此接口未在 IDL 中定义,但由 UssdSendMessageAndGetReplyOperationImpl 类实现。 请注意,此类的标头具有特殊的扩展:

    class UssdSendMessageAndGetReplyOperationImpl :
        public Microsoft::WRL::RuntimeClass<
            Windows::Networking::NetworkOperators::IUssdSendMessageAndGetReplyOperation,
            Windows::Internal::AsyncBaseFTM<IUssdSendMessageAndGetReplyCompletedHandler, Microsoft::WRL::SingleResult>>
    

    UssdSendMessageAndGetReplyOperation 对象允许 WinRT 模糊处理此异步操作的复杂性以及随之而来的所有隔离和内存代理。 有关详细信息,请参阅 SendMessageAndGetReplyAsync

    现在,了解上述异步操作只是调用 UssdSession 对象,其中实际包含此操作的逻辑。 为了简单起见,我们可以直观显示 UssdSession 本身封装此处的工作。 我们现在可以断言,尽管异步性质,但一次只能发送一个 UssdMessage。

    SendMessageAndGetReplyAsync 函数实际上的作用:

    • UssdSession 对象更改为忙碌状态,存储 UssdMessage 的内容,并触发异步操作。
    • OnOperationStart () 是异步逻辑的入口点。 对于此方案,假定没有活动会话。 此函数使用 RequestType=WwanUssdRequestInitiate 创建WWAN_USSD_REQUEST对象。
    • 步骤 9 和 10 是此函数执行的操作。
  9. 调用 m_wwanWrapper.SendRequest 来处理将消息传递给 WwanService 的工作。

  10. WwanWrapper 使用 WwanService 句柄调用 WwanService API 来执行该操作。

接收

Flow diagram for USSD receive.

步骤 10 后,我们处于向 WwanService 发送请求以初始化新 USSD 会话并在该会话下发送 USSD 消息的状态。 一段时间后,回复将可用。

  1. WwanService 将使用附加的上下文调用步骤 4 中提供的静态回调函数。
  2. 上下文将用于检索 WwanWrapper 实例并调用 NotificationCallback () 。
  3. WwanWrapper 将遵循与步骤 11 相同的模式,调用 UssdSession 的静态回调,并提供存储在步骤 3 中的上下文。
  4. 与步骤 12 类似,上下文用于调用 UssdSession 实例上的回调。
  5. UssdSession 将WWAN_USSD_EVENT (存储在锁) 下,并通知工作线程处理事件。
  6. HandleOperationReply () 采用现有的 UssdSendMessageAndGetReplyOperationImpl 对象,并将事件数据传递给其内部处理程序。
  7. 该操作将构造 UssdReply 并调用 FireCompletion () ,将异步操作标记为已完成。
  8. WinRT 将异步操作的完成模糊处理到客户端。 (等待操作或具有回调逻辑。)

可以在同一会话下发送更多消息。 如果会话保持,则未来的 RequestType 将为 WwanUssdRequestContinue。

关闭

Flow diagram for USSD close. 步骤 18 后,客户端已收到对其 UssdMessage 的答复。 他们可能或可能没有继续使用活动的 UssdSession 发送其他消息。 我们将假设将来某个时候,客户端将在 UssdSession 上手动调用 Close () 。 如果客户端未显式调用 Close () ,则会在 UssdSession 析构函数期间调用它。

  1. 客户端在 UssdSession 实例上调用 Close () 。
  2. 使用 RequestType=WwanUssdRequestCancel 创建WWAN_USSD_REQUEST。
  3. 请求将发送到步骤 9 中的m_wwanWrapper。
  4. 请求将发送到 WwanService,如步骤 10 中所述。

此请求的结果并不重要。 对于所有意向和目的,会话将关闭。 即使在从不传递消息的极端边缘情况下,新的 USSD 会话也会始终替代现有会话。

硬件实验室工具包 (HLK) 测试

请参阅 安装 HLK 的步骤

在 HLK Studio 中连接到设备手机网络调制解调器驱动程序并运行测试: Win6_4.MB。GSM。Data.TestUssd

MB USSD 故障排除指南

  • 使用 MB 收集日志中的说明收集和解码日志。

  • 用于筛选的关键字

    1. OID_WWAN_USSD
    2. NDIS_STATUS_WWAN_USSD
    3. WWAN_USSD_REQUEST
    4. WWAN_USSD_EVENT

另请参阅

MB USSD 操作