Initial commit: CCU621_M firmware project with BLE debug link support.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 17:28:36 +08:00
commit 9ceb218f80
1597 changed files with 724159 additions and 0 deletions
+191
View File
@@ -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 */