Files
CCU621M/app/pos_vtk/vtk_pos_protocol.c
T

192 lines
5.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "pos_vtk/vtk_pos_protocol.h"
#include "pos_vtk/vtk_tlv.h"
#include "publicdata/public_define.h"
#include <string.h>
#if (POS_VTK_EN)
/******************************************************************************
* 模块说明:VTK 支付消息构造与解析
*
* 负责将业务参数映射为 VTK TLV 参数,并打包/解析串口帧:
* - vtk_build_preauth_request() :构造预扣款(CDP)请求。
* - vtk_build_settle_request() :构造结算(CRD)请求。
* - vtk_parse_payment_response(): 解析 POS 返回的 CDP/CRD 响应结果。
*
* 内部约定:
* - Tag 0x01: Message name ASCII,例如 "CDP"/"CRD"
* - Tag 0x03: Operation no. ASCII 十进制)
* - Tag 0x04: Amount ASCII 十进制,单位:分)
* - Tag 0x0D: Simple data block 的首字节为结果码:
* 0 = Approved, 1 = Declined, 2 = Timeout, 其它 = Unknown
******************************************************************************/
/* 内部约定:结果码放在 Simple data block(Tag=0x0D) 的首字节
* 0 = Approved, 1 = Declined, 2 = Timeout, 其它 = Unknown
*/
#define VTK_TAG_MESSAGE_NAME ((U8_T)0x01)
#define VTK_TAG_OPERATION_NO ((U8_T)0x03)
#define VTK_TAG_AMOUNT ((U8_T)0x04)
#define VTK_TAG_RESULT ((U8_T)0x0D)
static VTK_POS_RESULT_E vtk_result_from_code(U8_T code)
{
switch (code)
{
case 0: return VTK_POS_RESULT_APPROVED;
case 1: return VTK_POS_RESULT_DECLINED;
case 2: return VTK_POS_RESULT_TIMEOUT;
default: return VTK_POS_RESULT_UNKNOWN;
}
}
static U32_T vtk_ascii_to_u32(const U8_T *p, U16_T len)
{
U32_T v = 0;
U16_T i;
if (!p || len == 0)
return 0;
for (i = 0; i < len; i++)
{
if (p[i] < '0' || p[i] > '9')
break;
v = v * 10U + (U32_T)(p[i] - '0');
}
return v;
}
static U16_T vtk_build_common(const char *msgName,
U32_T opNumber,
U32_T amountMinor,
U8_T *pOutFrame,
U16_T outMax)
{
U8_T tlvBuf[VTK_MAX_APP_LEN];
U16_T tlvLen = 0U;
if (!msgName || !pOutFrame)
return 0;
/* 消息名,例如 "CDP" / "CRD" */
if (!vtk_tlv_append_ascii(VTK_TAG_MESSAGE_NAME, msgName,
tlvBuf, sizeof(tlvBuf), &tlvLen))
return 0;
/* 操作号:十进制 ASCII */
if (!vtk_tlv_append_ascii_uint(VTK_TAG_OPERATION_NO, opNumber, 1U,
tlvBuf, sizeof(tlvBuf), &tlvLen))
return 0;
/* 金额(分):十进制 ASCII */
if (!vtk_tlv_append_ascii_uint(VTK_TAG_AMOUNT, amountMinor, 1U,
tlvBuf, sizeof(tlvBuf), &tlvLen))
return 0;
/* 组装 VTK 串口帧(VMC→POS */
return vtk_build_frame(tlvBuf, tlvLen, VTK_PD_VMC_TO_POS,
pOutFrame, outMax);
}
U16_T vtk_build_preauth_request(U32_T opNumber, U32_T amountMinor,
U8_T *pOutFrame, U16_T outMax)
{
return vtk_build_common("CDP", opNumber, amountMinor,
pOutFrame, outMax);
}
U16_T vtk_build_settle_request(U32_T opNumber, U32_T amountMinor,
U8_T *pOutFrame, U16_T outMax)
{
return vtk_build_common("CRD", opNumber, amountMinor,
pOutFrame, outMax);
}
U8_T vtk_parse_payment_response(const U8_T *pFrame, U16_T frameLen,
VTK_POS_PAY_RESP_T *pResp)
{
VTK_FRAME_INFO_T info;
const U8_T *pVal;
U16_T valLen;
if (!pFrame || !pResp)
return 0;
if (!vtk_parse_frame(pFrame, frameLen, &info))
return 0;
/* 只接受来自 POS 的响应(0x97FB */
if (info.protoDisc != VTK_PD_POS_TO_VMC)
return 0;
(void)memset(pResp, 0, sizeof(*pResp));
pResp->eResult = VTK_POS_RESULT_UNKNOWN;
/* 消息名 */
if (vtk_tlv_find_first(info.pApp, info.appLen,
VTK_TAG_MESSAGE_NAME, &pVal, &valLen))
{
if (valLen > 3U) valLen = 3U;
(void)memcpy(pResp->messageName, pVal, valLen);
pResp->messageName[valLen] = '\0';
}
/* 操作号 */
if (vtk_tlv_find_first(info.pApp, info.appLen,
VTK_TAG_OPERATION_NO, &pVal, &valLen))
{
pResp->operationNumber = vtk_ascii_to_u32(pVal, valLen);
}
/* 金额 */
if (vtk_tlv_find_first(info.pApp, info.appLen,
VTK_TAG_AMOUNT, &pVal, &valLen))
{
pResp->amountMinor = vtk_ascii_to_u32(pVal, valLen);
}
/* 结果码(Simple data block 首字节) */
if (vtk_tlv_find_first(info.pApp, info.appLen,
VTK_TAG_RESULT, &pVal, &valLen))
{
if (valLen > 0U)
{
pResp->eResult = vtk_result_from_code(pVal[0]);
}
}
return 1;
}
/*
* 外部使用示例:
*
* 1)构造并发送预扣款请求(CDP)
*
* U8_T frameBuf[VTK_MAX_FRAME_LEN];
* U16_T frameLen;
*
* // 操作号 12345,预扣 50 元(5000 分)
* frameLen = vtk_build_preauth_request(12345U, 5000U,
* frameBuf, sizeof(frameBuf));
* if (frameLen > 0U)
* {
* POS_VTK_UART_SEND(frameBuf, frameLen);
* }
*
* 2)解析 POS 返回的响应(在串口接收处理里获得完整 VTK 帧后调用)
*
* VTK_POS_PAY_RESP_T resp;
* if (vtk_parse_payment_response(frameBuf, frameLen, &resp))
* {
* // resp.messageName 例如 "CDP"/"CRD"
* // resp.operationNumber 例如 12345
* // resp.amountMinor 例如 5000
* // resp.eResult = VTK_POS_RESULT_APPROVED / DECLINED / TIMEOUT / UNKNOWN
* }
*/
#endif /* POS_VTK_EN */