pinpadxzf31.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. #include "pinpadxzf31.h"
  2. #include "log4vendor.h"
  3. PinPadXZF31::PinPadXZF31()
  4. {
  5. m_pMutex = new SMutex();
  6. }
  7. PinPadXZF31::~PinPadXZF31()
  8. {
  9. closeDevice();
  10. delete m_pMutex;
  11. }
  12. unsigned char PinPadXZF31::bccCalculator(const unsigned char* data, int len)
  13. {
  14. unsigned char result = 0;
  15. for(int i = 0; i < len; i++)
  16. result ^= data[i];
  17. return result;
  18. }
  19. // command format
  20. // 命令格式:02h+<Ln>+<CMD>+<DATA>+<BCC>
  21. void PinPadXZF31::packMessage(unsigned char* cmdSend, unsigned int& cmdSendLen)
  22. {
  23. cmdSendLen = 0;
  24. // step1 header
  25. cmdSend[cmdSendLen++] = 0x1b;
  26. // step2 command
  27. cmdSend[cmdSendLen++] = m_SendCmd.cmdCode1;
  28. cmdSend[cmdSendLen++] = m_SendCmd.cmdCode2;
  29. // step3 length
  30. // Ln = [DATA](? bytes) + <XOR>(1 byte)
  31. unsigned int len = 1 + m_SendCmd.dataLen;
  32. cmdSend[cmdSendLen++] = len >> 8;
  33. cmdSend[cmdSendLen++] = len & 0xFF;
  34. // step4 data
  35. if (0 < m_SendCmd.dataLen) {
  36. memcpy(cmdSend + cmdSendLen, m_SendCmd.data, m_SendCmd.dataLen);
  37. cmdSendLen += m_SendCmd.dataLen;
  38. }
  39. // step5 Block Check Code
  40. cmdSend[cmdSendLen] = bccCalculator(cmdSend, cmdSendLen);
  41. cmdSendLen++;
  42. // step6 end char
  43. cmdSend[cmdSendLen++] = 0x0d;
  44. cmdSend[cmdSendLen++] = 0x0a;
  45. }
  46. bool PinPadXZF31::sendRecv(const SUNSON_F31_CMD* cmd, unsigned long timeout)
  47. {
  48. if (!m_cSerial.IsOpen()) return false;
  49. m_cSerial.Flush();
  50. memcpy(&m_SendCmd, cmd, sizeof(SUNSON_F31_CMD));
  51. unsigned char cmdSend[SUNSON_MAX_CMD_LEN];
  52. memset(cmdSend, 0, SUNSON_MAX_CMD_LEN);
  53. unsigned cmdSendLen = SUNSON_MAX_CMD_LEN;
  54. packMessage(cmdSend, cmdSendLen);
  55. if (m_cSerial.Send((const char*)cmdSend, cmdSendLen) < cmdSendLen)
  56. {
  57. LOG4VTM(ERROR, "serial port date send failed");
  58. return false;
  59. }
  60. if (timeout < 500) timeout = 500;
  61. INT64 iNow = GetSystemTime();
  62. INT64 iEnd = iNow + timeout;
  63. int iHeadLen = 4;
  64. for (int ia=0; ia<100 && iNow < iEnd; ia++)
  65. {
  66. if (m_cSerial.Receive((char*)cmdSend, 1, timeout) < 0)
  67. {
  68. LOG4VTM(ERROR, "serial port date read failed");
  69. return false;
  70. }
  71. if (cmdSend[0] == 0x02) break;
  72. else
  73. {
  74. LOG4VTM(ERROR, "serial port read data err");
  75. }
  76. iNow = GetSystemTime();
  77. }
  78. if (cmdSend[0] != 0x02)
  79. {
  80. LOG4VTM(ERROR, "serial port date format error");
  81. return false;
  82. }
  83. int iLen = m_cSerial.Receive((char*)cmdSend + 1, iHeadLen - 1, 100);
  84. if (iLen + 1 < iHeadLen)
  85. {
  86. LOG4VTM(ERROR, "serial port date read failed");
  87. return false;
  88. }
  89. int iBodyLen = (cmdSend[2] << 8) + cmdSend[3];
  90. iLen = m_cSerial.Receive((char*)m_CmdRecv.data, iBodyLen, 500);
  91. if (iLen < iBodyLen)
  92. {
  93. LOG4VTM(ERROR, "serial port date read body failed");
  94. return false;
  95. }
  96. m_CmdRecv.dataLen = iBodyLen; // Ln - CmdLen(1) = DataLen
  97. if (cmdSend[1] == 'S')
  98. m_CmdRecv.st = 0;
  99. else
  100. m_CmdRecv.st = m_CmdRecv.data[0];
  101. m_CmdRecv.data[iBodyLen] = 0;
  102. return true;
  103. }
  104. //0:ok -1:fail 其它:返回键盘错误码
  105. int PinPadXZF31::executeCmd(SUNSON_F31_CMD *cmd, SUNSON_RSP* rsp, unsigned long timeout)
  106. {
  107. if (!m_cSerial.IsOpen()) return -1;
  108. SAutoLock lock(m_pMutex);
  109. if (sendRecv(cmd, timeout))
  110. {
  111. memcpy(rsp, &m_CmdRecv, sizeof(SUNSON_RSP));
  112. if (m_CmdRecv.st == 0x04) return 0;
  113. else return m_CmdRecv.st;
  114. }
  115. return -2;
  116. }
  117. ////////////////////////////////////////////////////////////////////////////////////////////////////
  118. bool PinPadXZF31::Open(const char* sPort, int iBaud)
  119. {
  120. if (m_cSerial.IsOpen())
  121. m_cSerial.Close();
  122. return m_cSerial.Open(sPort, iBaud);
  123. }
  124. void PinPadXZF31::closeDevice()
  125. {
  126. m_cSerial.Close();
  127. }
  128. // 系统复位
  129. // 命令:0X1B+'S'(53h)+'F'(46h)+<Ln>+[XOR] +0X0D+0X0A
  130. // 描述:执行此命令后键盘进行复位,对系统时钟初始化,串口初始化,产生 4ms
  131. // 时间中断,复位次数加 1, 复位完成后蜂鸣器叫 100ms。 Ln:0001h,两个字节表示。
  132. // 成功返回:02h+'S'(53h)+ 00h+ 00h+ 02h+'O'(6F)+ 'K'(6B)
  133. // 失败返回:02h+'E'(45h)+ 00h+ 01h+03h (格式错)
  134. int PinPadXZF31::resetEpp()
  135. {
  136. SUNSON_F31_CMD cmd;
  137. memset(&cmd, 0, sizeof(cmd));
  138. cmd.cmdCode1 = 0x53;
  139. cmd.cmdCode2 = 0x46;
  140. SUNSON_RSP rsp;
  141. memset(&rsp, 0, sizeof(rsp));
  142. int iRt = executeCmd(&cmd, &rsp, 3000);
  143. return iRt;
  144. }
  145. //get sankey
  146. int PinPadXZF31::scankeyPress(unsigned char& ucKeyValue)
  147. {
  148. if (!m_cSerial.IsOpen()) return -1;
  149. SAutoLock lock(m_pMutex);
  150. char sRead[32];
  151. int iLen = m_cSerial.Receive(sRead, 1, 500);
  152. if (iLen < 1) return 0;
  153. ucKeyValue = sRead[0];
  154. return 1;
  155. }
  156. // 取产品版本号
  157. //命令:02h+01h+30h+<BCC>
  158. //描述:密码键盘将所设置在 E2ROM 芯片的有关参数发送返回。
  159. //返回:02h+Ln+<ST>+<DATA>+<BCC>。ST 可能是 04h、15h、E0h、F0h。
  160. //当 ST=F0h 表示没有安装 E2ROM 芯片。
  161. int PinPadXZF31::getEppVersion(unsigned char *version)
  162. {
  163. SUNSON_F31_CMD cmd;
  164. memset(&cmd, 0, sizeof(cmd));
  165. cmd.cmdCode1 = 0x52;
  166. cmd.cmdCode2 = 0x45;
  167. SUNSON_RSP rsp;
  168. memset(&rsp, 0, sizeof(rsp));
  169. int iRt = executeCmd(&cmd, &rsp);
  170. if (0 < rsp.dataLen)
  171. {
  172. memcpy(version, rsp.data, rsp.dataLen);
  173. version[rsp.dataLen] = 0;
  174. }
  175. return iRt;
  176. }
  177. // 取产品序列号
  178. int PinPadXZF31::getSerialNo(unsigned char *version)
  179. {
  180. SUNSON_F31_CMD cmd;
  181. memset(&cmd, 0, sizeof(cmd));
  182. cmd.cmdCode1 = 0x52;
  183. cmd.cmdCode2 = 0x53;
  184. SUNSON_RSP rsp;
  185. memset(&rsp, 0, sizeof(rsp));
  186. int iRt = executeCmd(&cmd, &rsp);
  187. if (0 < rsp.dataLen)
  188. {
  189. memcpy(version, rsp.data, rsp.dataLen);
  190. version[rsp.dataLen] = 0;
  191. }
  192. return iRt;
  193. }
  194. // 命令:0X1B +'L'(4Ch)+'K'(4Bh)+<Ln>+<DATA>+[XOR] +0X0D+0X0A
  195. // 描述:按照约定的方式下载主密钥和工作密钥。可以是明文也可是密文。
  196. // DATA: <Header>+<EK>
  197. // Header : <KEYID0> + <KEYID1> + <KEY_ATT>
  198. // KEYID0:要下载的钥号最大值(0—31)。
  199. // KEYID1:解密的密钥号(0—31),等于 0xFFFF 密钥用明文下载。等于 0XFFFE
  200. // 时用初始密钥加密下载。 KEY_ATT:密钥属性。 EK:用 KEYID1 加密 KEYID0
  201. // 而得到的密文值。 成功返回:02h+'S'(53h)+ 00h+ 02h+'O'(6F)+ 'K'(6B)
  202. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  203. // ST 值:03h:指令格式错误
  204. // 0fh:密钥已存在
  205. // 10h:密钥属性错。标示密文下载时,解密密钥不存在或密钥属性错
  206. // 14h:密钥值相同。表明所装载的主密钥的值在 EPP 内已经存在。
  207. // 17h:密钥号超出。KEYID0>31 或在密文下载密钥时,密钥号超出范围,即 KEYID1>31。
  208. // KEY_ATT:属性参数可以是:
  209. // 1、密钥不叠加版本:
  210. // 01:主密钥
  211. // 02:PIN 密钥
  212. // 03:数据运算密钥
  213. // 04:MAC 密钥
  214. // 2、密钥叠加版本:
  215. // 20:主密钥
  216. // 02:PIN 密钥
  217. // 01:数据运算密钥
  218. // 04:MAC 密钥
  219. // example: load key directly
  220. // 1B 4C 4B 00 16 00 01 FF FF 27 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
  221. // 2C 0D 0A
  222. int PinPadXZF31::LoadUserKey(int ucKeyId, int ucDecryptKeyId,
  223. unsigned char KeyAttribute, unsigned char ucKeyLen,
  224. unsigned char* KeyValue, unsigned char* ReturnInfo)
  225. {
  226. int iRt = -1;
  227. SUNSON_F31_CMD cmd;
  228. memset(&cmd, 0, sizeof(cmd));
  229. cmd.cmdCode1 = 0x4c;
  230. cmd.cmdCode2 = 0x4b;
  231. unsigned short tmp = 0xffff & ucKeyId; // 只取2字节
  232. cmd.data[cmd.dataLen++] = tmp >> 8;
  233. cmd.data[cmd.dataLen++] = 0xff & tmp;
  234. tmp = 0xffff & ucDecryptKeyId; // 只取2字节
  235. cmd.data[cmd.dataLen++] = tmp >> 8;
  236. cmd.data[cmd.dataLen++] = 0xff & tmp;
  237. cmd.data[cmd.dataLen++] = KeyAttribute;
  238. memcpy(cmd.data + cmd.dataLen, KeyValue, ucKeyLen);
  239. cmd.dataLen += ucKeyLen;
  240. SUNSON_RSP rsp;
  241. memset(&rsp, 0, sizeof(rsp));
  242. iRt = executeCmd(&cmd, &rsp);
  243. if (0 < rsp.dataLen)
  244. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  245. return iRt;
  246. }
  247. // 命令:0X1B+'S'(53h)+'Z'(5Ah)+<Ln>+<En>+[XOR] +0X0D+0X0A
  248. // 描述:按键按下时是否产生蜂鸣。
  249. // Ln:0002h,两个字节
  250. // EN:0x30 时,蜂鸣器使能开;
  251. // 0x31 时,蜂鸣器使能关。
  252. // 成功返回:02h+'S'(53h)+ 00h+ 02h+'O'(6F)+ 'K'(6B)
  253. // 失败返回 02h+'E'(45h)+ 00h+ 01h+03h (格式错)
  254. int PinPadXZF31::SetBuzzerEnabled(unsigned char ucBuzzerStatus, unsigned char* ReturnInfo)
  255. {
  256. int iRt = -1;
  257. SUNSON_F31_CMD cmd;
  258. memset(&cmd, 0, sizeof(cmd));
  259. cmd.cmdCode1 = 0x53;
  260. cmd.cmdCode2 = 0x5a;
  261. cmd.data[cmd.dataLen++] = ucBuzzerStatus;
  262. SUNSON_RSP rsp;
  263. memset(&rsp, 0, sizeof(rsp));
  264. iRt = executeCmd(&cmd, &rsp);
  265. if (0 < rsp.dataLen)
  266. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  267. return iRt;
  268. }
  269. // 命令:0X1B + 'D'(44H) + 'D'(56H) + <LN> + <DV> + [XOR] + 0X0D + 0X0A
  270. // 描述:设定 CBC 数据时的 8 字节初始向量。
  271. // LN:0009h,
  272. // DV:8 字节的初始向量,默认值是 8 个 0X00.
  273. // 成功返回:02h+'S'(53h)+ 00h+ 02h+“ok‖
  274. // 失败返回:02h+'E'(45h)+ 00h+ 01h+03
  275. int PinPadXZF31::SetStartValue(unsigned char* StartValue, unsigned char* ReturnInfo)
  276. {
  277. int iRt = -1;
  278. SUNSON_F31_CMD cmd;
  279. memset(&cmd, 0, sizeof(cmd));
  280. cmd.cmdCode1 = 0x44;
  281. cmd.cmdCode2 = 0x56;
  282. memcpy(cmd.data + cmd.dataLen, StartValue, 8);
  283. cmd.dataLen += 8;
  284. SUNSON_RSP rsp;
  285. memset(&rsp, 0, sizeof(rsp));
  286. iRt = executeCmd(&cmd, &rsp);
  287. if (0 < rsp.dataLen)
  288. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  289. return iRt;
  290. }
  291. // 命令:0X1B+'D'(44h)+'O'(4Fh)+<Ln>+<KEYID>+<JM-CMD>+<SF-CMD>+[PADDING] +
  292. // <DL>+<DATA> + [XOR] + 0X0D+0X0A
  293. // 描述:使用 KEYID 号密钥对当前数据 DATA 进行加密或解密操作。
  294. // Ln:是 KEYID,JM-CMD,SF-CMD,PADDING,DL,DATA 数据长度总和,2 个字节表示。
  295. // KEYID : 加解密密钥号。(0—31)
  296. // JM-CMD:加密解密参数:
  297. // 0x30:数据解密, 0x31:数据加密
  298. // SF-CMD:算法设置:
  299. // 0x30:ECB 模式的 3DES 运算;
  300. // 0x31:CBC 模式的 3DES 运算。
  301. // 0x32: ECB des
  302. // 0x33: CBC des
  303. // PADDING:DL 的长度如果不是 8 的倍数,则要扩充成 8
  304. // 的倍数。扩充的字节用[PADDING]填充。 DL :
  305. // 要进行加解密操作的数据长度(最大长度 1024 个字节)
  306. // DATA:要进行加解密操作的数据。
  307. // 成功返回:02h+'S'(53h)+ DATA 长度(2 个字节)+<DATA>
  308. // DATA:加密状态下为密文数据,解密状态下为明文数据。
  309. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  310. // ST 值:03h:指令格式错误
  311. // 0eh:密钥不存在.
  312. // 10h:密钥属性错。工作密钥不是数据加解密密钥
  313. // 20h:内存耗尽
  314. // 17h:密钥超出(0—31)
  315. // 31h:数据超度超过 1024 字节。
  316. // example:
  317. // 数据:0x31
  318. // 密钥号: 3
  319. // 加密,ECB
  320. // padding: 0xff
  321. // 1B 44 4F 00 09 00 03 31 30 FF 00 01 31 D4 0D 0A
  322. int PinPadXZF31::DataCompute(int KeyId, unsigned char JM_mode,
  323. unsigned char SF_mode, unsigned char padchar,
  324. int datalen, unsigned char* data,
  325. unsigned char* ReturnInfo, int& iOutLen)
  326. {
  327. int iRt = -1;
  328. SUNSON_F31_CMD cmd;
  329. memset(&cmd, 0, sizeof(cmd));
  330. cmd.cmdCode1 = 0x44;
  331. cmd.cmdCode2 = 0x4f;
  332. unsigned short tmp = 0xffff & KeyId; // 密钥号的长度取2字节
  333. cmd.data[cmd.dataLen++] = tmp >> 8;
  334. cmd.data[cmd.dataLen++] = 0xff & tmp;
  335. cmd.data[cmd.dataLen++] = JM_mode;
  336. cmd.data[cmd.dataLen++] = SF_mode;
  337. cmd.data[cmd.dataLen++] = padchar;
  338. tmp = 0xffff & datalen; // 只取2字节
  339. cmd.data[cmd.dataLen++] = tmp >> 8;
  340. cmd.data[cmd.dataLen++] = 0xff & tmp;
  341. memcpy(cmd.data + cmd.dataLen, data, datalen);
  342. cmd.dataLen += datalen;
  343. SUNSON_RSP rsp;
  344. memset(&rsp, 0, sizeof(rsp));
  345. iRt = executeCmd(&cmd, &rsp);
  346. if (0 < rsp.dataLen)
  347. {
  348. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  349. iOutLen = rsp.dataLen;
  350. }
  351. return iRt;
  352. }
  353. // 命令:0X1B+'R'(52h)+'P'(50h)+<Ln>+<PL_MIN>+<PL_MAX>+ <MODE> + <ECHO> +[XOR]
  354. // +0X0D+0X0A 描述:执行取 PIN 操作,如果可以执行取 PIN 操作 EPP
  355. // 先返回:02h+'S'(53h)+ 00h+ 02h+“ok‖,如果不 可以执行取 PIN
  356. // 操作返回:失败返回:02h+'E'(45h)+ 00h+ 01h+<ST> ST 值:03h:指令格式错误。
  357. // 10h:密钥属性错。工作密钥的属性不是 PIN 属性。
  358. // 取 PIN 操作时,有效的 PIN 键按下('0'—'9')时 EPP 输出
  359. // ECHO('*')。在按下功能键 (cancle,correct,enter)时,EPP
  360. // 输出的是功能键的原码。但在按下终止键时先返回该键的键值(数字键
  361. // 除外)然后返回结束标志 0XAA,如果按下终止键后,输入 PIN
  362. // 的长度小于设定的最效长度,EPP 输 出 PIN 长度错代码
  363. // 0X1C,数字键不能作为终止键。无论什么时发送关闭键盘命令,都关闭取 PIN 操作。
  364. // Ln:02h 两个字节表示。 PL:PIN 数据长度(04~0Ch,最大长度 12 个字节)
  365. // MODE:当输入 PIN 的长度达到设定的最大长度时,是否自动添加结束标志,自动结束。
  366. // 00H:不自动结束,必须按下终止按键才能结束。
  367. // 01H:发送结束标志自动结束。
  368. // ECHO:当按下有效的 PIN
  369. // 时要求回送的字符。这个参数可以是任意值,旭子所有的密钥键盘固定为'*'
  370. int PinPadXZF31::GetPin(unsigned char ucPinMinLen, unsigned char ucPinMaxLen,
  371. unsigned char AutoReturnFlag, unsigned char* ReturnInfo)
  372. {
  373. int iRt = -1;
  374. SUNSON_F31_CMD cmd;
  375. memset(&cmd, 0, sizeof(cmd));
  376. cmd.cmdCode1 = 0x52;
  377. cmd.cmdCode2 = 0x50;
  378. cmd.data[cmd.dataLen++] = ucPinMinLen;
  379. cmd.data[cmd.dataLen++] = ucPinMaxLen;
  380. cmd.data[cmd.dataLen++] = AutoReturnFlag;
  381. cmd.data[cmd.dataLen++] = '*';
  382. SUNSON_RSP rsp;
  383. memset(&rsp, 0, sizeof(rsp));
  384. iRt = executeCmd(&cmd, &rsp);
  385. if (0 < rsp.dataLen)
  386. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  387. return iRt;
  388. }
  389. // 命令:0X1B+'P'(50h)+'B'(42h)+<Ln>+<KEYID>+<JM-MODE>+[PADDING]+
  390. // <CardLen>+<CardNo>++[XOR] +0X0D+0X0A 描述:使用 KEYID 密钥进行 PINBLOCK
  391. // 操作。完成该命令后 EPP 内 PIN 的缓冲区用随机数填充。
  392. // Ln:KEYID,JM-MODE,CardLen,CardNo,PADDING,XOR,数据长度总和 2
  393. // 个字节表示。 KEYID:密钥号(0—31)。
  394. // JM-MODE:加密模式:
  395. // 0x30:ISO9564 格式 0
  396. // 0x31:ISO9564 格式1
  397. // 0x32:UBC 格式(新增)
  398. // 0x33:ISO9564 格式 3
  399. // 0x34:IBM3624 格式
  400. // 0X35:X9.8 格式
  401. // 0x36:ASCII 格式。(新增)。
  402. // CardLen: 卡号长度:
  403. // X9.8 时值为 12;
  404. // ISO9564 格式 0 和 ISO9564 格式 3 值为(0-12)之间的任一值;
  405. // ISO9564 格式 1 的值是 10(实际是终端号的长度)。
  406. // CardNo : 卡号数据。
  407. // PADDING:填充数据,可以是 0---F 之间的任一值,填充的多少只与实际输入的 PIN
  408. // 的个数有关。 成功返回:02h+'S'(53h)+ 00h+ 08h+<DATA> DATA:将 PIN
  409. // 和卡号按指定加密模式做加密后的密文数据。 失败返回:02h +'E'(45h) + 00h + 01h
  410. // + <ST> ST 值:03h:指令格式错误 0Eh:密钥不存在.。 10h:密钥属性错不是 PIN
  411. // 属性。 17h:密钥超出(0—31) 19h:没有 PIN,没有执行取 PIN 操作。
  412. // 1Dh:卡号长度错。
  413. // 30h:填充或卡号数据错。在做 ISO95640,ISO95641,X9.8
  414. // 时组成卡号的数据不在'0'—'9'范围。 在做 ISO95641 时组成填充的数据不在
  415. // 0x30—0x3F 之间。 34h:需要移出认证(有移出检测的键盘才有)。
  416. int PinPadXZF31::GetPinBlock(int UserKeyId, int JM_mode,
  417. unsigned char padchar, unsigned char ucCardLen,
  418. unsigned char* ucCardNumber, unsigned char* ReturnInfo, int& iOutLen)
  419. {
  420. int iRt = -1;
  421. SUNSON_F31_CMD cmd;
  422. memset(&cmd, 0, sizeof(cmd));
  423. cmd.cmdCode1 = 0x50;
  424. cmd.cmdCode2 = 0x42;
  425. unsigned short tmp = 0xffff & UserKeyId; // 只取2字节
  426. cmd.data[cmd.dataLen++] = tmp >> 8;
  427. cmd.data[cmd.dataLen++] = 0xff & tmp;
  428. cmd.data[cmd.dataLen++] = JM_mode;
  429. cmd.data[cmd.dataLen++] = padchar;
  430. cmd.data[cmd.dataLen++] = ucCardLen;
  431. memcpy(cmd.data + cmd.dataLen, ucCardNumber, ucCardLen);
  432. cmd.dataLen += ucCardLen;
  433. SUNSON_RSP rsp;
  434. memset(&rsp, 0, sizeof(rsp));
  435. iRt = executeCmd(&cmd, &rsp);
  436. if (0 < rsp.dataLen)
  437. {
  438. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  439. iOutLen = rsp.dataLen;
  440. }
  441. return iRt;
  442. }
  443. // 命 令 : 0X1B+'M'(4Dh) + 'C'(43h)+<Ln>+<KEYID>+
  444. // <MACMODE>+<MACLen>+<MACData>+[XOR] +0X0D+0X0A 描述:执行 MAC 数据的操作。MAC
  445. // 的最大长度是 2048 字节。 Ln:是 KEYID,MACMODE,MACLen,MACData,XOR
  446. // 数据长度之和 2 个字节表示。 KEYID:密钥号。 MACMODE:加密模式: 0x30:X9.9,
  447. // 0x32: UBC,
  448. // 0x33:X919,
  449. // 0x35:X9.9T((MAA 算法,每一步都 TDES 加密)
  450. // MACLen:2 个字节表示,高字节在前。低字节在后。(0—2048)
  451. // MACData:MAC 数据
  452. // 成功返回:02h+'S'(53h)+ 00h+ 08h+<DATA>
  453. // DATA:MAC 运算后的数据。
  454. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  455. // ST 值:03h:指令错误,指令不满足限制条件。
  456. // 0Eh:密钥不存在。
  457. // 10h:密钥属性错
  458. int PinPadXZF31::MakeMac(int UserKeyId, int Mac_mode, int nMacDataLen,
  459. unsigned char* ucMacData, unsigned char* ReturnInfo, int& iOutLen)
  460. {
  461. int iRt = -1;
  462. SUNSON_F31_CMD cmd;
  463. memset(&cmd, 0, sizeof(cmd));
  464. cmd.cmdCode1 = 0x4d;
  465. cmd.cmdCode2 = 0x43;
  466. unsigned short tmp = 0xffff & UserKeyId; // 只取2字节
  467. cmd.data[cmd.dataLen++] = tmp >> 8;
  468. cmd.data[cmd.dataLen++] = 0xff & tmp;
  469. cmd.data[cmd.dataLen++] = 0xff & Mac_mode;
  470. tmp = 0xffff & nMacDataLen; // 只取2字节
  471. cmd.data[cmd.dataLen++] = tmp >> 8;
  472. cmd.data[cmd.dataLen++] = 0xff & tmp;
  473. memcpy(cmd.data + cmd.dataLen, ucMacData, nMacDataLen);
  474. cmd.dataLen += nMacDataLen;
  475. SUNSON_RSP rsp;
  476. memset(&rsp, 0, sizeof(rsp));
  477. iRt = executeCmd(&cmd, &rsp);
  478. if (0 < rsp.dataLen)
  479. {
  480. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  481. iOutLen = rsp.dataLen;
  482. }
  483. return iRt;
  484. }
  485. // 测试指令:1b 4f 4b 00 03 16 01 0b 0d 0a
  486. // 命令: 0X1B+'O'(4Fh)+'K'(4Bh)+ <Ln>+ <KEY_LEN> + <END_MODE> + [XOR] +0X0D+
  487. // 0X0A 描述:命令发送成功返回 02h+'S'(53h)+ 00h+
  488. // 02h+“ok‖。然后才打开键盘允许输入。命令发送失败返回: 02h+'E'(45h)+ 00h+
  489. // 01h+03。每次按下键盘时先发送该键盘的明文,如果按下终止键且输入按键的
  490. // 个数<KEY_LEN,先发送该键的明文值,然后发送
  491. // 0xAA。如果输入按键的长度达到设定的长度时,如果 允许自动结束则返回 0XAA
  492. // 后关闭键盘,如果不允许自动结束则只有按下终止键且返回 0xAA 后关闭 键盘。
  493. // Ln:0X0002,是 KEY_LEN,XOR 数据长度之和 2 个字节表示。
  494. // KEY_LEN : 打开键盘后允许输入的按键的最大长度。
  495. // END_MODE:输入明文长度达到最大长度是是否自动结束。
  496. // 0x00:不自动结束。必须按终止键结束。结束时键盘发送 0X0D,
  497. // 0x01:自动结束。
  498. int PinPadXZF31::UseEppPlainTextMode(unsigned char PlaintextLength, unsigned char AutoEnd, unsigned char* ReturnInfo)
  499. {
  500. int iRt = -1;
  501. SUNSON_F31_CMD cmd;
  502. memset(&cmd, 0, sizeof(cmd));
  503. cmd.cmdCode1 = 0x4f;
  504. cmd.cmdCode2 = 0x4b;
  505. cmd.data[cmd.dataLen++] = PlaintextLength;
  506. cmd.data[cmd.dataLen++] = AutoEnd;
  507. SUNSON_RSP rsp;
  508. memset(&rsp, 0, sizeof(rsp));
  509. iRt = executeCmd(&cmd, &rsp);
  510. if (0 < rsp.dataLen)
  511. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  512. return iRt;
  513. }
  514. // 命令:0X1B+'C'(43h)+'K'(4Bh)+ <Ln>+ [XOR] +0X0D+ 0X0A
  515. // 描述:任何时候只要发送该命令就关闭键盘,禁止输入。
  516. // Ln:0x0001
  517. // 成功返回:02h+'S'(53h)+ 00h+ 02h+“ok‖
  518. // 失败返回:02h+'E'(45h)+ 00h+ 01h+03
  519. int PinPadXZF31::CloseEppPlainTextMode(unsigned char* ReturnInfo)
  520. {
  521. int iRt = -1;
  522. SUNSON_F31_CMD cmd;
  523. memset(&cmd, 0, sizeof(cmd));
  524. cmd.cmdCode1 = 0x43;
  525. cmd.cmdCode2 = 0x4b;
  526. SUNSON_RSP rsp;
  527. memset(&rsp, 0, sizeof(rsp));
  528. iRt = executeCmd(&cmd, &rsp);
  529. if (0 < rsp.dataLen)
  530. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  531. return iRt;
  532. }
  533. // 命令格式:0X1B + ‗G' (47h) + ‗W' (57h)+ <Ln> + 0X91 + [XOR] +0X0D +0X0A
  534. // 描述:获取当前键盘算法。
  535. // 成功返回:02h+'S'(53h)+ DATA 长度(2Byte)+<Mode>
  536. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  537. int PinPadXZF31::GetEPPSMMode(unsigned char* ReturnInfo)
  538. {
  539. int iRt = -1;
  540. SUNSON_F31_CMD cmd;
  541. memset(&cmd, 0, sizeof(cmd));
  542. cmd.cmdCode1 = 0x47;
  543. cmd.cmdCode2 = 0x57;
  544. cmd.data[cmd.dataLen++] = 0x91;
  545. SUNSON_RSP rsp;
  546. memset(&rsp, 0, sizeof(rsp));
  547. iRt = executeCmd(&cmd, &rsp);
  548. if (0 < rsp.dataLen)
  549. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  550. return iRt;
  551. }
  552. // 命令:0X1B +'S'(53h) + 'W'(57h) + <Ln> +<Mode> +[XOR] + 0X0D+0X0A
  553. // 描述:在做数据运算、MAC 校验、PINBLOCK 运算时选择用 DES 算法还是 SM 算法。
  554. // Ln:= 0x0002 ,2Byte
  555. // Mode:国密算法标志,1Byte
  556. // 0x00 DES 算法
  557. // 0x01 SM 算法
  558. // 成功返回:02h+'S'(53h)+ DATA 长度(2Byte)+“ok‖
  559. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  560. // ST 值可能是:见附录 C
  561. int PinPadXZF31::SetEPPSMMode(unsigned char ucSMMode)
  562. {
  563. int iRt = -1;
  564. SUNSON_F31_CMD cmd;
  565. memset(&cmd, 0, sizeof(cmd));
  566. cmd.cmdCode1 = 0x53;
  567. cmd.cmdCode2 = 0x57;
  568. cmd.data[cmd.dataLen++] = ucSMMode;
  569. SUNSON_RSP rsp;
  570. memset(&rsp, 0, sizeof(rsp));
  571. iRt = executeCmd(&cmd, &rsp);
  572. return iRt;
  573. }
  574. int PinPadXZF31::CheckEPPSMMode(bool bSM)
  575. {
  576. unsigned char sMode[32];
  577. int iRt = GetEPPSMMode(sMode);
  578. if (iRt != 0) return iRt;
  579. unsigned char chMode = bSM ? 1 : 0;
  580. if (chMode != sMode[0])
  581. {
  582. return SetEPPSMMode(chMode);
  583. }
  584. return 0;
  585. }
  586. // 命 令 : 0X1B+'M'(4Dh) + 'C'(43h)+<Ln>+<KEYID>+
  587. // <MACMODE>+<MACLen>+<MACData>+[XOR] +0X0D+0X0A 描述:执行 MAC 数据的操作。
  588. // Ln:是 KEYID,MACMODE,MACLen,MACData,XOR 数据长度之和 2 个字节表示。
  589. // KEYID:密钥号。
  590. // MACMODE:加密模式, 0x30:X9.9 (国密 SM4 只支持 X9.9)
  591. // MACLen:2 个字节表示,高字节在前。低字节在后。
  592. // MACData:MAC 数据。
  593. // 成功返回:02h+'S'(53h)+ 00h+ 08h+<DATA>
  594. // DATA:MAC 运算后的数据。
  595. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  596. // ST 值:03h:指令错误,指令不满足限制条件。
  597. // 0Eh:密钥不存在。
  598. // 10h:密钥属性错
  599. int PinPadXZF31::SM4MakeMac(int UserKeyId, int Mac_mode, int nMacDataLen,
  600. unsigned char* ucMacData, unsigned char* ReturnInfo)
  601. {
  602. int iRt = -1;
  603. SUNSON_F31_CMD cmd;
  604. memset(&cmd, 0, sizeof(cmd));
  605. cmd.cmdCode1 = 0x4d;
  606. cmd.cmdCode2 = 0x43;
  607. unsigned short tmp = 0xffff & UserKeyId; // 只取2字节
  608. cmd.data[cmd.dataLen++] = tmp >> 8;
  609. cmd.data[cmd.dataLen++] = 0xff & tmp;
  610. cmd.data[cmd.dataLen++] = Mac_mode;
  611. tmp = 0xffff & nMacDataLen;
  612. cmd.data[cmd.dataLen++] = tmp >> 8;
  613. cmd.data[cmd.dataLen++] = 0xff & tmp;
  614. memcpy(cmd.data + cmd.dataLen, ucMacData, nMacDataLen);
  615. cmd.dataLen += nMacDataLen;
  616. SUNSON_RSP rsp;
  617. memset(&rsp, 0, sizeof(rsp));
  618. iRt = executeCmd(&cmd, &rsp);
  619. if (0 < rsp.dataLen)
  620. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  621. return iRt;
  622. }
  623. // 命令:0X1B+'D'(44h)+'O'(4Fh)+<Ln>+<KEYID>+<JM-CMD>+<SF-CMD>+[PADDING] +
  624. // <DL>+<DATA>
  625. // +[XOR] + 0X0D+0X0A
  626. // 描述:使用 KEYID 号密钥对当前数据 DATA 进行加密或解密操作。
  627. // Ln:是 KEYID,JM-CMD,SF-CMD,PADDING,DL,DATA 数据长度总和,2 个字节表示。
  628. // KEYID : 加解密密钥号。(0—31)
  629. // JM-CMD:加密解密参数:
  630. // 0x30:数据解密,
  631. // 0x31:数据加密
  632. // SF-CMD:算法设置:
  633. // 0x30:ECB 模式的 3DES 运算;
  634. // 0x31:CBC 模式的 3DES 运算。
  635. // 0x32: ECB des
  636. // 0x33: CBC des
  637. // PADDING:DL 的长度如果不是 8 的倍数,则要扩充成 8
  638. // 的倍数。扩充的字节用[PADDING]填充。 DL : 要进行加解密操作的数据长度
  639. // DATA:要进行加解密操作的数据。
  640. // 成功返回:02h+'S'(53h)+ DATA 长度(2 个字节)+<DATA>
  641. // DATA:加密状态下为密文数据,解密状态下为明文数据。
  642. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  643. // ST 值:03h:指令格式错误
  644. // 0eh:密钥不存在.
  645. // 10h:密钥属性错。工作密钥不是数据加解密密钥
  646. // 20h:内存耗尽
  647. // 17h:密钥超出(0—31)
  648. // 31h:数据长度超出范围。
  649. int PinPadXZF31::SM4DataCompute(int KeyId, unsigned char JM_mode,
  650. int SF_mode, unsigned char padchar,
  651. int datalen, unsigned char* data,
  652. unsigned char* ReturnInfo)
  653. {
  654. int iRt = -1;
  655. SUNSON_F31_CMD cmd;
  656. memset(&cmd, 0, sizeof(cmd));
  657. cmd.cmdCode1 = 0x44;
  658. cmd.cmdCode2 = 0x4f;
  659. unsigned short tmp = 0xffff & KeyId; // 只取2字节
  660. cmd.data[cmd.dataLen++] = tmp >> 8;
  661. cmd.data[cmd.dataLen++] = 0xff & tmp;
  662. cmd.data[cmd.dataLen++] = JM_mode;
  663. cmd.data[cmd.dataLen++] = SF_mode;
  664. cmd.data[cmd.dataLen++] = padchar;
  665. tmp = 0xffff & datalen; // 只取2字节
  666. cmd.data[cmd.dataLen++] = tmp >> 8;
  667. cmd.data[cmd.dataLen++] = 0xff & tmp;
  668. memcpy(cmd.data + cmd.dataLen, data, datalen);
  669. cmd.dataLen += datalen;
  670. SUNSON_RSP rsp;
  671. memset(&rsp, 0, sizeof(rsp));
  672. iRt = executeCmd(&cmd, &rsp);
  673. if (0 < rsp.dataLen)
  674. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  675. return iRt;
  676. }
  677. // 命令:0X1B+'P'(50h)+'B'(42h)+<Ln>+<KEYID>+<JM-MODE>+[PADDING]+
  678. // <CardLen>+<CardNo>++[XOR] +0X0D+0X0A 描述:使用 KEYID 密钥进行 PINBLOCK
  679. // 操作。完成该命令后 EPP 内 PIN 的缓冲区用随机数填充。
  680. // Ln:KEYID,JM-MODE,CardLen,CardNo,PADDING,XOR,数据长度总和 2
  681. // 个字节表示。 KEYID:密钥号(0—31)。 JM-MODE:加密模式: 0x30:ISO9564 格式 0
  682. // 0x31:ISO9564 格式 1 0x33:ISO9564 格式 3 0x34:IBM3624 格式 0X35:X9.8 格式
  683. // 0x36:ASCII 格式。(新增)。 CardLen: 卡号长度: X9.8 时值为 12; ISO9564
  684. // 格式 0 和 ISO9564 格式 3 值为(0-12)之间的任一值; ISO9564 格式 1 的值是
  685. // 10(实际是终端号的长度)。 CardNo : 卡号数据。 PADDING:填充数据,可以是
  686. // 0---F 之间的任一值,填充的多少只与实际输入的 PIN 的个数有关。
  687. // 成功返回:02h+'S'(53h)+ 00h+ 08h+<DATA> DATA:将 PIN
  688. // 和卡号按指定加密模式做加密后的密文数据。 失败返回:02h +'E'(45h) + 00h + 01h
  689. // + <ST> ST 值:03h:指令格式错误 0Eh:密钥不存在.。 10h:密钥属性错不是 PIN
  690. // 属性。 17h:密钥超出(0—31) 19h:没有 PIN,没有执行取 PIN 操作。
  691. // 1Dh:卡号长度错。
  692. // 30h:填充或卡号数据错。在做 ISO95640,ISO95641,X9.8
  693. // 时组成卡号的数据不在'0'—'9'范围。 在做 ISO95641 时组成填充的数据不在
  694. // 0x30—0x3F 之间。
  695. int PinPadXZF31::SM4GetPinBlock(int UserKeyId, int JM_mode,
  696. unsigned char padchar, unsigned char ucCardLen,
  697. unsigned char* ucCardNumber, unsigned char* ReturnInfo)
  698. {
  699. int iRt = -1;
  700. SUNSON_F31_CMD cmd;
  701. memset(&cmd, 0, sizeof(cmd));
  702. cmd.cmdCode1 = 0x50;
  703. cmd.cmdCode2 = 0x42;
  704. unsigned short tmp = 0xffff & UserKeyId; // 只取2字节
  705. cmd.data[cmd.dataLen++] = tmp >> 8;
  706. cmd.data[cmd.dataLen++] = 0xff & tmp;
  707. cmd.data[cmd.dataLen++] = JM_mode;
  708. cmd.data[cmd.dataLen++] = padchar;
  709. cmd.data[cmd.dataLen++] = ucCardLen;
  710. memcpy(cmd.data + cmd.dataLen, ucCardNumber, ucCardLen);
  711. cmd.dataLen += ucCardLen;
  712. SUNSON_RSP rsp;
  713. memset(&rsp, 0, sizeof(rsp));
  714. iRt = executeCmd(&cmd, &rsp);
  715. if (0 < rsp.dataLen)
  716. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  717. return iRt;
  718. }
  719. // 命令:0X1B +'K'(4Bh) + 'R'(52h) + <Ln> +<Mode> +[XOR] + 0X0D+0X0A
  720. // 描述:相同密钥槽是否允许相同密钥重复下载。
  721. // Ln:= 0x0002 ,2Byte
  722. // Mode:1Byte
  723. // 0x00 允许重复密钥下载
  724. // 0x01 不允许重复密钥下载
  725. // 成功返回:02h+'S'(53h)+ DATA 长度(2Byte)+“ok‖
  726. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  727. // ST 值可能是:见附录 C
  728. int PinPadXZF31::EnableLoadSameKey(unsigned char Mode, unsigned char* ReturnInfo)
  729. {
  730. int iRt = -1;
  731. SUNSON_F31_CMD cmd;
  732. memset(&cmd, 0, sizeof(cmd));
  733. cmd.cmdCode1 = 0x4b;
  734. cmd.cmdCode2 = 0x52;
  735. cmd.data[cmd.dataLen++] = Mode;
  736. SUNSON_RSP rsp;
  737. memset(&rsp, 0, sizeof(rsp));
  738. iRt = executeCmd(&cmd, &rsp);
  739. if (0 < rsp.dataLen)
  740. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  741. return iRt;
  742. }
  743. // 命令:0X1B +'T'(54h) + '1'(31h) + <Ln> +<Mode> +[XOR] + 0x0D+0x0A
  744. // 描述:加密键盘安全机制。
  745. // Ln:= 0x0002 ,2Byte
  746. // Mode:2Byte
  747. // 0~3bit :0000 无
  748. // 0001 与自身加密
  749. // 0010 与 0 加密
  750. // 4~15bit:KeyID (0~31)
  751. // 成功返回:02h+'S'(53h)+ DATA 长度(2Byte)+“ok‖
  752. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  753. // ST 值可能是:见附录 C
  754. int PinPadXZF31::GetKCV(int keyId, unsigned char ucCheckMode, unsigned char* ReturnInfo)
  755. {
  756. int iRt = -1;
  757. SUNSON_F31_CMD cmd;
  758. memset(&cmd, 0, sizeof(cmd));
  759. cmd.cmdCode1 = 0x54;
  760. cmd.cmdCode2 = 0x31;
  761. unsigned short tmp = 0xffff & keyId; // 只取2字节
  762. unsigned short wTmp = tmp << 4;
  763. wTmp += 0x0f & ucCheckMode;
  764. cmd.data[cmd.dataLen++] = wTmp >> 8;
  765. cmd.data[cmd.dataLen++] = 0xff & wTmp;
  766. SUNSON_RSP rsp;
  767. memset(&rsp, 0, sizeof(rsp));
  768. iRt = executeCmd(&cmd, &rsp);
  769. if (0 < rsp.dataLen)
  770. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  771. return iRt;
  772. }
  773. //允许/禁止系统键盘模式
  774. int PinPadXZF31::SysKeyEnable(bool b)
  775. {
  776. int iRt = -1;
  777. SUNSON_F31_CMD cmd;
  778. memset(&cmd, 0, sizeof(cmd));
  779. cmd.cmdCode1 = 0x54;
  780. cmd.cmdCode2 = 0x4D;
  781. cmd.data[cmd.dataLen++] = b+1;
  782. SUNSON_RSP rsp;
  783. memset(&rsp, 0, sizeof(rsp));
  784. iRt = executeCmd(&cmd, &rsp);
  785. return iRt;
  786. }
  787. // 命令:0X1B +'E'(45h) + 'S'(53h) + <Ln> +<KeyID> +[XOR] + 0x0D+0x0A
  788. // 描述:加密键盘安全机制。
  789. // Ln:= 0x0002 ,2Byte
  790. // KeyID:2Byte (0~31)
  791. // 成功返回:02h+'S'(53h)+ DATA 长度(2Byte)+DAT
  792. // DAT:KeyLen(1Byte)+KeyAttribute(4Byte)
  793. // 失败返回:02h+'E'(45h)+ 00h+ 01h+<ST>
  794. // ST 值可能是:见附录 C
  795. int PinPadXZF31::GetKeyAttInfo(int UserKeyId, unsigned char* ReturnInfo)
  796. {
  797. int iRt = -1;
  798. SUNSON_F31_CMD cmd;
  799. memset(&cmd, 0, sizeof(cmd));
  800. cmd.cmdCode1 = 0x45;
  801. cmd.cmdCode2 = 0x53;
  802. unsigned short tmp = 0xffff & UserKeyId; // 只取2字节
  803. cmd.data[cmd.dataLen++] = tmp >> 8;
  804. cmd.data[cmd.dataLen++] = 0xff & tmp;
  805. SUNSON_RSP rsp;
  806. memset(&rsp, 0, sizeof(rsp));
  807. iRt = executeCmd(&cmd, &rsp);
  808. if (0 < rsp.dataLen)
  809. memcpy(ReturnInfo, rsp.data, rsp.dataLen);
  810. return iRt;
  811. }