Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
#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 */
|
||||
|
||||
Reference in New Issue
Block a user