在新的国家电网智能终端相关标准中,规定了通过专门的加密芯片来保证设备数据安全性的方法,而设备主控单元与加密芯片采用了广泛应用的ISO7816通讯协议。工控主板EM9160为了适应这一新的技术需求,对其内核进行了升级,使其多个串口都可支持ISO7816协议,为客户进行智能终端整机设计时,提供了灵活的选择。
对EM9160工控主板,可在其异步串口的基础上,通过简单的设置,就可把串口转为符合ISO7816协议的接口,实现与各种智能卡的通讯。EM9160共有6个异步串口,在Windows CE环境中为“COM2:”- “COM7:”,其中支持ISO7816的串口如下表所示:
串口 |
管脚配置 |
备注 |
COM3 |
TXD:半双工数据线 | |
RXD:复位输出控制 | 低电平有效 | |
GPIO14:作为SCK | 输出频率与波特率等参数有关 | |
COM5 |
TXD:半双工数据线 | |
RXD:复位输出控制 | 低电平有效 | |
GPIO15:作为SCK | 输出频率与波特率等参数有关 | |
COM6 |
TXD:半双工数据线 | |
RXD:复位输出控制 | 低电平有效 | |
GPIO15:作为SCK | 输出频率与波特率等参数有关 | |
COM7 |
TXD:半双工数据线 | |
RXD:复位输出控制 | 低电平有效 | |
GPIO15:作为SCK | 输出频率与波特率等参数有关 |
EM9160的“COM5:”- “COM7:”串口信号均为TTL电平,建议客户首选其中之一作为与ISO7816智能芯片的通讯接口。如果这些串口已分配给设备的其他功能,也可以考虑使用COM3口,需要注意的是COM3口的缺省配置是RS232电平,客户需要在购买时特别通知我们把COM3设置为TTL电平才能与安全模块相连。当然GPIO15或GPIO14一旦作为了ISO7816的工作时钟输出,就不能再用作其他的用途了。
作为应用程序,在操作ISO7816模式的串口(以COM5为例)时,一般的流程如下:
1、按标准方法打开串口“COM5:”;
2、通过DeviceIoControl(…)函数使能ISO7816通讯模式;
3、设置包括波特率、奇偶校验在内的相关串口参数;
4、根据需要可通过DeviceIoControl(…)函数对对端芯片进行一次复位操作;
5、进行正常数据通讯;
6、通过DeviceIoControl(…)函数禁止ISO7816通讯模式;
7、按标准方法关闭串口“COM5:”。
在上述流程中,需要注意的是一定要先使能ISO7816模式,再设置波特率,才能保证得到正确的通讯参数。
为了实现从通常的异步串口到ISO7816的转换,EM9161的串口驱动增加了3个IOCTL功能如下:
#include
#define IOCTL_SERIAL_ENABLE_ISO7816 \
CTL_CODE(FILE_DEVICE_SERIAL_PORT,40,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_SERIAL_DISABLE_ISO7816 \
CTL_CODE(FILE_DEVICE_SERIAL_PORT,41,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define IOCTL_SERIAL_RESET_ISO7816 \
CTL_CODE(FILE_DEVICE_SERIAL_PORT,42,METHOD_BUFFERED,FILE_ANY_ACCESS)
使能ISO7816的DeviceIoControl调用,需要同时设置相应的参数。这些参数包括ISO7816的协议类型,帧数据的应答规范等,定义相应的参数如下:
#define AT91C_US_USMODE_ISO7816_0 0x4 // ISO7816 protocol: T = 0
#define AT91C_US_USMODE_ISO7816_1 0x6 // ISO7816 protocol: T = 1
#define AT91C_US_INACK (0x1 << 20) // Inhibit Non Acknowledge
#define AT91C_US_DSNACK (0x1 << 21) // Disable Successive NACK
此外ISO的波特率按如下公式计算:
BR = SCK /(FI / DI)
上式中的SCK = 串口波特率×(FI / DI),例如串口波特率为9600,则SCK时钟频率为3.5712MHz。在EM9161中,对DI和FI的设置,是通过设置(FI/DI)这个比值来实现的,其中有效的值如下表所示:
DI = 1 |
DI = 2 |
DI = 4 |
DI = 8 |
DI = 16 |
DI = 32 |
DI = 12 |
DI = 20 |
|
FI = 372 |
372 |
186 |
93 |
47 |
23 |
12 |
31 |
19 |
FI = 558 |
558 |
279 |
140 |
70 |
35 |
17 |
47 |
28 |
FI = 774 |
774 |
372 |
186 |
93 |
47 |
23 |
62 |
37 |
FI = 1116 |
1116 |
558 |
279 |
140 |
70 |
35 |
93 |
56 |
FI = 1488 |
1488 |
744 |
372 |
186 |
93 |
47 |
124 |
74 |
FI = 1806 |
1806 |
930 |
465 |
233 |
116 |
58 |
155 |
93 |
FI = 512 |
512 |
256 |
128 |
64 |
32 |
16 |
43 |
26 |
FI = 768 |
768 |
384 |
192 |
96 |
48 |
24 |
64 |
38 |
FI = 1024 |
1024 |
512 |
256 |
128 |
64 |
32 |
85 |
51 |
FI = 1536 |
1536 |
768 |
384 |
192 |
96 |
48 |
128 |
77 |
FI = 2048 |
2048 |
1024 |
512 |
256 |
128 |
64 |
171 |
102 |
选择蓝色区域的值,可得到对应的黄色区域的FI和绿色区域的DI,由此可计算相应的波特率。
在具体的调用中,参数的传递是通过两个DWORD实现的,代码如下:
DWORD dwMode, dwFI_DI_Ratio;
DWORD pBuf[2];
dwMode = AT91C_US_USMODE_ISO7816_0;
dwFI_DI_Ratio = 372;
pBuf[0] = dwMode;
pBuf[1] = dwFI_DI_Ratio;
if (!DeviceIoControl ( m_hSer, // 串口handle
IOCTL_SERIAL_ENABLE_ISO7816, // 命令码
pBuf, sizeof(pBuf), // input parameters
NULL, 0, // output parameters
NULL, NULL ))
{
printf('IOCTL_SERIAL_ENABLE_ISO7816 failed!\r\n');
}
关闭ISO7816通讯模式比较简单,没有任何参数:
if (!DeviceIoControl ( m_hSer, // 串口handle
IOCTL_SERIAL_DISABLE_ISO7816, // 命令码
NULL, 0,
NULL, 0,
NULL, NULL ))
{
printf('IOCTL_SERIAL_DISABLE_ISO7816 failed!\r\n');
}
对ISO7816对端芯片的复位,需要设置复位时间,以ms为单位:
DWORD dwMilliseconds = 1; // 可以设为0,实际复位时间为几十微秒
if (!DeviceIoControl ( m_hSer,
IOCTL_SERIAL_RESET_ISO7816,
&dwMilliseconds, sizeof(DWORD), // input parameters
NULL, 0, // output parameters
NULL, NULL ))
{
printf('IOCTL_SERIA, L_RESET_ISO7816 , failed!\r\n');
}
&am, p;nb, sp; 设置了ISO模式后, ,应用程序仍然可以像操作普通串口那样,进行数据的读写,只是需要注意, 的, 是I, SO7816的半双工模式的,所以数据通讯的过程更像是RS485的过程。用户可参考英创网站的《RS485接口通讯的WinCE编程要点》一文,来规划自己的应用程序通讯流程。