好的,我们继续接续上一篇文章,对 3GPP TS 31.102 规范进行深度拆解。


深度解析 3GPP TS 31.102:4.2.7 EFACMmax & 4.2.9 EFACM (计费建议)

本文技术原理深度参考了3GPP TS 31.102 V18.8.0 (2025-03) Release 18规范中,关于“4.2.7 EFACMmax (ACM maximum value)”和“4.2.9 EFACM (Accumulated Call Meter)”的核心章节。同时,我们也将关联解读“4.2.13 EFPUCT (Price per Unit and Currency Table)”,旨在为读者完整呈现USIM卡中经典的“计费建议(AoC)”功能是如何通过这组文件协同工作的。

在之前的探索中,我们了解了USIM如何保障身份安全和指导网络选择。现在,让我们把目光转向一个与用户钱包息息相关的话题——通话费用。虽然在当今许多套餐“任性打”的时代,精确计算每分钟通话费的需求有所减弱,但在特定场景下,如国际漫游、使用预付费卡或需要精细成本控制的企业用户,实时了解通话开销依然是一个强需求。

3GPP标准为此定义了一项名为“计费建议 (Advice of Charge, AoC)”的功能。它允许网络在通话过程中,向手机发送“计费脉冲”,手机则根据这些脉冲和预设的费率,估算出一个通话费用并显示给用户。这套机制的核心数据就存储在USIM卡的一组文件中。

我们的主角“李想”,这次作为一名志愿者去一个偏远地区进行短期项目。为了方便,他购买了一张当地的预付费SIM卡,里面有100个“通话单位”。他非常关心自己的通话余额,不希望在关键时刻因为欠费而中断联系。AoC功能和与之相关的USIM文件,正是为了解决李想的这种“话费焦虑”而设计的。

今天,我们将一同解剖EFACMmaxEFACMEFPUCT这“计费三剑客”,看看它们是如何协同作战,为李想提供一个清晰透明的“话费账本”的。


1. 话费的“信用额度”:4.2.7 EFACMmax (ACM最大值)

EFACMmax是计费三剑客中的“总指挥官”,它设定了通话计费的上限,即李想这张卡总共拥有的“信用额度”。

If service n° 13 is “available”, this file shall be present.

This EF contains the maximum value of the accumulated call meter.

这段原文明确了两点:

  1. 服务关联: 它的存在与否,取决于USIM服务表(EF_UST)中第13号服务(AoC)是否被激活。

  2. 核心功能: 存储了累计通话计量器(Accumulated Call Meter, ACM)所能达到的最大值

1.1 文件结构与编码剖析

表 4.2.7-1: EFACMmax 文件结构

| 属性 | 值 |

| :--- | :--- |

| Identifier | ‘6F37’ |

| Structure | Transparent |

| File size | 3 bytes |

| Update activity | Low |

| Access Conditions | READ: PIN, UPDATE: PIN/PIN2, … |

字节内容

| 字节 | 描述 | M/O | 长度 |

| :--- | :--- | :--- | :--- |

| 1 to 3 | Maximum value (最大值) | M | 3 bytes |

逐项解读:

  • File size: 固定的3个字节(24位)。这意味着它可以表示一个从0到 2^24 - 1 (16,777,215) 的巨大数值,足以应对绝大多数计费单位的需求。

  • Access Conditions:

    • READ权限为PIN,用户需要解锁USIM才能查看话费上限。

    • UPDATE权限为PIN/PIN2,这意味着运营商或用户自己(如果知道PIN2)可以修改这个“信用额度”。对于预付费卡,这个值通常由运营商在个人化时设定(ADM权限),用户充值时,运营商通过OTA命令更新这个值。

编码的精髓:二进制整数

Coding: First byte … Second byte … Third byte …

All ACM data is stored in the USIM and transmitted over the USIM/ME interface as binary.

与之前看到的BCD码不同,EFACMmax中的3个字节直接被解释为一个24位的无符号二进制整数

  • 第一个字节代表数值的最高位部分(2^23 到 2^16)。

  • 第二个字节代表中间位部分(2^15 到 2^8)。

  • 第三个字节代表最低位部分(2^7 到 2^0)。

场景化举例:

运营商为李想的预付费卡设定了10000个通话单位的上限。这个十进制数10000转换为十六进制是'2710'。为了存入3个字节,它会被表示为'002710'

  • EFACMmax文件的内容将是:00 27 10 (十六进制)。

当李想在手机上查询话费总额度时,手机读取这3个字节,将其作为一个24位二进制数重新组合,得到10000这个值。


2. 动态的“消费记录”:4.2.9 EFACM (累计通话计量器)

如果说EFACMmax是静态的“总额度”,那么EFACM就是动态的“已消费额度”,它实时记录着李想已经用掉了多少通话单位。

If service n° 13 is “available”, this file shall be present.

This EF contains the total number of units for both the current call and the preceding calls.

深度解析:

EFACM文件是AoC功能的核心。它的工作模式是一个累加器。网络在通话过程中会不断发送计费脉冲信号。每收到一个脉冲,手机就会向USIM发起一个INCREASE命令,让EFACM中的数值增加。

2.1 文件结构与特殊命令

表 4.2.9-1: EFACM 文件结构

| 属性 | 值 |

| :--- | :--- |

| Identifier | ‘6F39’ |

| Structure | Cyclic (循环文件) |

| Record length | 3 bytes |

| Update activity | High |

| Access Conditions | …, INCREASE: PIN, … |

字节内容

| 字节 | 描述 | M/O | 长度 |

| :--- | :--- | :--- | :--- |

| 1 to 3 | Accumulated count of units (累计单位数) | M | 3 bytes |

关键特性解读:

  • Structure: Cyclic!这是一个非常重要的设计。虽然通常这个文件只有一个记录,但循环文件的特性使得对它的更新操作非常高效和安全,特别适合频繁写入的场景。

  • Update activity: High!在通话过程中,这个文件会被频繁地更新,可能每分钟甚至每几秒钟一次。

  • Access Conditions: 这里出现了一个特殊的访问权限——INCREASE。标准的UPDATE命令是“覆盖写入”,而INCREASE命令是“增量更新”。手机不需要先读取旧值,在本地加一,再写入新值,这样不仅效率低,而且在断电等异常情况下可能导致数据不一致。手机可以直接发送一个INCREASE命令,告诉USIM“把当前值加上N”,USIM内部会自动完成这个原子操作,既高效又安全。

编码方式:

EFACM中存储的3字节数值,其编码方式与EFACMmax完全相同,都是一个24位的无符号二进制整数。

2.2 AoC工作流程

让我们通过李想打一次电话的完整过程,来看看EFACM是如何工作的。

  1. 通话前: 李想查询余额。手机读取EFACMmax得到总额度10000,读取EFACM得到已用额度(假设为'0009C4',即十进制2500)。手机计算出余额为 10000 - 2500 = 7500 个单位,并显示给他。

  2. 通话开始: 李想拨通了一个电话。

  3. 通话中:

    • 通话进行到第1分钟,网络向手机发送了一个计费脉冲(Charging Pulse)。

    • 手机收到脉冲后,立即向USIM发送一个INCREASE命令,指令EFACM的值增加1。

    • USIM内部将EFACM的值从2500更新为2501。

    • 手机屏幕上可能会实时更新显示“已用2501单位”或“余额7499单位”。

    • 通话继续,网络每隔一段时间(如1分钟)就发送一个脉冲,EFACM的值就不断累加。

  4. 达到上限: 当EFACM的值累加到与EFACMmax相等时(即10000),手机会收到USIM的警告。此时,手机可以根据运营商的策略,采取行动:

    • 强行挂断电话:这是预付费卡最常见的行为。

    • 发出提示音: 提醒用户余额已用尽。

    • 允许通话继续,但开始产生欠费:适用于后付费用户。

  5. 通话结束: EFACM中的最终值(例如2510)被永久保存在USIM中,作为下次通话计费的起点。

这个流程清晰地展示了EFACM作为动态计数器,是如何在通话过程中实时反映消费情况的。


3. 从“单位”到“货币”的桥梁:4.2.13 EFPUCT (每单位价格和货币表)

李想知道自己还有7500个“通话单位”,但这到底是多少钱呢?一个单位是一分钟,还是一块钱?这时,第三位剑客EFPUCT就登场了。

If service n° 13 is “available”, this file shall be present.

This EF contains the Price per Unit and Currency Table (PUCT). The PUCT is Advice of Charge related information which may be used by the ME … to compute the cost of calls in the currency chosen by the subscriber…

EFPUCT的作用就是提供一个“换算公式”,将抽象的“计费单位”转换为用户能够理解的实际货币价值。

3.1 文件结构与编码剖析

表 4.2.13-1: EFPUCT 文件结构

| 属性 | 值 |

| :--- | :--- |

| Identifier | ‘6F41’ |

| Structure | Transparent |

| File size | 5 bytes |

| Access Conditions | READ: PIN, UPDATE: PIN/PIN2, … |

字节内容

| 字节 | 描述 | M/O | 长度 |

| :--- | :--- | :--- | :--- |

| 1 to 3 | Currency code (货币代码) | M | 3 bytes |

| 4 to 5 | Price per unit (每单位价格) | M | 2 bytes |

编码详解:

  • Currency code (3 bytes): 使用3个字母的ISO 4217货币代码,如'CNY'代表人民币,'USD'代表美元。编码方式是SMS 7位编码。

  • Price per unit (2 bytes): 这是整个AoC机制中最复杂但也是最灵活的编码部分。这两个字节被用来表示一个浮点数,其计算公式为:

    price per unit = EPPU * 10^EX

    这两个字节被拆分为三个部分:

    1. EPPU (Elementary Price per Unit): 一个12位的整数部分,由字节4的全部和字节5的低4位组成。

    2. EX的绝对值 |EX|: 一个3位的整数,由字节5的b5-b7位组成。

    3. EX的符号 Sign(EX): 1位,由字节5的最高位b8表示(0为正,1为负)。

这种科学计数法式的表示方式,使得EFPUCT可以用区区2个字节,表示从极小(如0.001元/单位)到极大(如1000元/单位)的费率,具有极高的灵活性。

场景化举例:

假设李想的预付费卡,每个通话单位是0.25元。我们来看如何编码这个费率。

  • 0.25 = 25 * 10^-2

  • EPPU = 25

  • EX = -2

编码过程:

  • EPPU (25) 转换为12位二进制。

  • EX = -2,所以 Sign(EX) = 1, |EX| = 2。

  • 将这三部分按照规范组合成2个字节。

手机在计算话费时,执行相反的解码过程:

  1. 读取EFPUCT的字节4和5,解析出EPPU=25, EX=-2。

  2. 计算出 Price per unit = 25 * 10^-2 = 0.25。

  3. 再读取货币代码为'CNY'

  4. 手机读取到EFACM中已用单位为2510。

  5. 计算出总花费 = 2510 * 0.25 = 627.5 元。

  6. 最终,手机可以在屏幕上清晰地向李想显示:“本次通话消费10单位,花费2.5元。总已用2510单位,总花费627.5元。”


总结:“计费三剑客”的协同作战

EFACMmax, EFACM, EFPUCT这三个文件共同构成了一套完整、闭环的终端侧计费建议(AoC)解决方案。

  • EFACMmax 设立了计费的“天花板”,是预付费业务控制的基石。

  • EFACM 充当了动态的“计数器”,通过高效安全的INCREASE命令,实时追踪通话消耗。

  • EFPUCT 则扮演了“翻译官”的角色,通过其灵活的浮点数编码,将抽象的计费单位与真实世界的货币价值挂钩。

这套机制虽然在今天看来有些“复古”,但它所体现的设计思想——将复杂逻辑(如累加、浮点数表示)封装在USIM或手机内部,通过标准化文件进行参数配置——至今仍在3GPP规范中随处可见。它完美地展示了如何在资源极其有限的智能卡上,实现一个可靠、灵活且用户友好的功能。对于李想来说,这套机制让他对手中的预付费卡消费情况了如指掌,彻底告别了“话费焦虑”。


FAQ环节

Q1:EFACM为何要设计成循环文件(Cyclic),而不是更简单的线性固定文件?

A1:主要出于性能和寿命的考虑。EFACM在通话中会被高频次地更新。智能卡的存储介质(EEPROM/Flash)有写入寿命限制。循环文件在设计上对频繁更新有优化,其更新操作通常比线性文件更快,并且可以更好地管理擦写周期,从而延长卡片寿命。使用INCREASE命令配合循环文件,是实现一个高性能、高可靠性计数器的标准做法。

Q2:如果EFACM的值已经等于EFACMmax,此时再执行INCREASE命令会发生什么?

A2:USIM会拒绝执行该命令,并向手机返回一个特定的状态错误码。手机接收到这个错误码后,就知道已经达到了计费上限,从而可以触发相应的动作,如强制挂断电话。这是AoC实现预付费控制的核心逻辑。

Q3:EFPUCT中的价格是含税价吗?汇率如何处理?

A3:EFPUCT中定义的价格通常是运营商设定的一个基础费率,是否含税取决于运营商的策略和当地法规。这个机制本身不处理汇率问题。它显示的是基于EFPUCT中设定的货币(如'EUR')。如果李想的手机设置为显示人民币,那么手机应用层面需要自行实现一个汇率转换的功能,但这已超出了USIM规范的范畴。USIM只提供基础的“单位本地货币”的换算。

Q4:在VoLTE/VoNR通话中,AoC机制还适用吗?

A4:传统的基于CS域计费脉冲的AoC机制在纯VoLTE/VoNR环境中通常不直接适用,因为PS域的计费更为复杂,可能基于时长、流量、QoS等多种因素。然而,AoC的设计思想被继承了下来。IMS(IP多媒体子系统)中有自己的一套计费信息传递机制,可以通过SIP消息向终端传递费用信息。终端收到这些信息后,依然可以调用USIM中的计费文件(如果运营商策略如此设计的话)或者在本地进行费用估算和显示,为用户提供类似的“计费建议”体验。

Q5:如果我的套餐是无限通话,EFACMmaxEFACM这些文件还有用吗?

A5:对于纯粹的后付费无限通话套餐用户,这两个文件的实际计费作用确实大大减弱。在这种情况下,运营商可能会将EFACMmax设置为一个非常大甚至是无效的值(如'000000',规范定义其为无效),或者干脆不在USIM中激活服务n°13(AoC)。但这些文件作为标准的一部分依然存在,以备在某些特殊场景下使用(如用户切换到按时长计费的国际漫游套餐)。