《T/CGAS 003-2017 民用智能燃气表通用技术要求》中定义了表号编制组成为:
表号由 16 位 BCD 码组成,由表厂代码(3 位)+生产年月(4 位)+流水号(6 位)+嵌入式软件代号(2 位)+校验位(1 位)构成。
校验位算法 应采用 ISO7064,MOD11,10 校验系统校验码计算方法生成。
ISO7064 MOD11,10 校验码系统属于混合系统,它在运算中采用两个模数,其中一种模数等于被保护的字符集中的字符数,另一个模数比它大 1,形成的校验码位于被保护的字符串组成的字符集内。
一个包含按标准混合公式产生的校验码的字符串须满足下式的验证:
$$
(...((((M+a_n)||M\times2)|(M+1)+a_{(n-1)}||M\times2)|(M+1)+...+a_1)||M=1
$$
式中:
n:包含校验码的字符串的字符数目, 24 位条码中 n=24;
i:从右侧计算的字符所在位置的序号,如最右端字符 i=1;
$a_i$ :i 位置上的字符值;
M 和 (M+1):两个模数,M 的数值等于该字符集中的字符数目(此数总是偶数),在全数 字字符的条码中,M=10 ;
||M:除以 M 后的余数,如果值为零,则用 M 代替;
|(M+1):除以 (M+1) 后的余数,在经过上述处理后余数不会为 0。
条码中字符串的字符从左到右逐个处理。用 j=1,...,n 来表示。n 为包括校验码在内的字符串中字符的数目(如 24 位条码,n=24)。当 j=1 时,定义 $P_j=M$。公式如下:
$$
S_j=P_j|(M+1)+a_{(n-j+1)}\\
P_{(j+1)}=S_j||M\times2
$$
式中:
||M:除以 M 后的整余数,如果为 0,则用 M 代替,(ISO7064,MOD11,10 校验码 系统中 M=10);
|(M+1):除以 (M+1) 后的整余数,在经过上述处理后余数不会为 0;
$a_{(n-j+1)}$:字符值。
验证:如果 $S_n\equiv1(mod M)$,则字符串正确。确定校验码 $a_1$ 时,应使之满足 $P_n + a_1\equiv1(mod M)$。
分享一下 C 语言的实现,仅供参考 :
/**
* 计算 ISO7064 MOD11,10 校验码
* sn 不包含校验码的序列号字符串的指针
* return 校验码字符
*/
char CalcCheckCode(char *sn) {
int n = strlen(sn);
int p = 10;
for (int i = 0, s; i < n; i++) {
s = p + (int)(*sn++ - 0x30);
s %= 10;
if (s == 0) {
s = 10;
}
p = (s * 2) % 11;
}
return (10 - (p - 1)) + 0x30;
}
例如:
SN:119 1505 500001 91 6,其中 6 为校验码。