9ceb218f80
Co-authored-by: Cursor <cursoragent@cursor.com>
261 lines
6.4 KiB
C
261 lines
6.4 KiB
C
#include "pos_vtk/pos_vtk_service.h"
|
|
#include "publicdata/public_define.h"
|
|
#include <string.h>
|
|
|
|
#if (POS_VTK_EN)
|
|
|
|
#ifndef GUN_MAX_CNT
|
|
#define GUN_MAX_CNT 2
|
|
#endif
|
|
|
|
/* 简单的会话管理:每把枪对应一个会话 */
|
|
static POS_VTK_SESSION_T s_sessions[GUN_MAX_CNT];
|
|
static VTK_FRAME_PARSER_T s_frameParser;
|
|
static U32_T s_nextOpNumber = 1U;
|
|
|
|
/* 初始化所有会话状态和 VTK 帧解析器。
|
|
* 建议在系统启动、相关任务初始化阶段调用一次。
|
|
*/
|
|
void pos_vtk_init(void)
|
|
{
|
|
(void)memset(s_sessions, 0, sizeof(s_sessions));
|
|
vtk_frame_parser_init(&s_frameParser);
|
|
s_nextOpNumber = 1U;
|
|
}
|
|
|
|
static POS_VTK_SESSION_T *pos_vtk_get_session_ptr(U8_T gunNo)
|
|
{
|
|
if (gunNo >= GUN_MAX_CNT)
|
|
return NULL;
|
|
return &s_sessions[gunNo];
|
|
}
|
|
|
|
U8_T pos_vtk_start_preauth(U8_T gunNo, U32_T amountMinor)
|
|
{
|
|
POS_VTK_SESSION_T *pSess;
|
|
U8_T frameBuf[VTK_MAX_FRAME_LEN];
|
|
U16_T frameLen;
|
|
|
|
pSess = pos_vtk_get_session_ptr(gunNo);
|
|
if (!pSess)
|
|
return 0;
|
|
|
|
/* 只有 IDLE/DONE/ERROR 状态允许重新发起预扣款 */
|
|
if (pSess->e_state != POS_VTK_STATE_IDLE &&
|
|
pSess->e_state != POS_VTK_STATE_DONE &&
|
|
pSess->e_state != POS_VTK_STATE_ERROR)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (s_nextOpNumber == 0U)
|
|
s_nextOpNumber = 1U;
|
|
|
|
pSess->opNumber = s_nextOpNumber++;
|
|
pSess->preAuthAmount = amountMinor;
|
|
pSess->finalAmount = 0U;
|
|
pSess->e_lastResult = VTK_POS_RESULT_UNKNOWN;
|
|
|
|
frameLen = vtk_build_preauth_request(pSess->opNumber, amountMinor,
|
|
frameBuf, sizeof(frameBuf));
|
|
if (frameLen == 0U)
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_ERROR;
|
|
return 0;
|
|
}
|
|
|
|
POS_VTK_UART_SEND(frameBuf, frameLen);
|
|
|
|
pSess->e_state = POS_VTK_STATE_PREAUTH_PENDING;
|
|
pSess->lastUpdateTick = pos_vtk_get_tick_ms();
|
|
|
|
return 1;
|
|
}
|
|
|
|
U8_T pos_vtk_notify_charge_end(U8_T gunNo, U32_T amountMinor)
|
|
{
|
|
POS_VTK_SESSION_T *pSess;
|
|
U8_T frameBuf[VTK_MAX_FRAME_LEN];
|
|
U16_T frameLen;
|
|
|
|
pSess = pos_vtk_get_session_ptr(gunNo);
|
|
if (!pSess)
|
|
return 0;
|
|
|
|
/* 必须至少完成预扣款(无论是否 Approved),才发结算请求 */
|
|
if (pSess->e_state != POS_VTK_STATE_PREAUTH_OK &&
|
|
pSess->e_state != POS_VTK_STATE_CHARGING)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pSess->finalAmount = amountMinor;
|
|
|
|
frameLen = vtk_build_settle_request(pSess->opNumber, amountMinor,
|
|
frameBuf, sizeof(frameBuf));
|
|
if (frameLen == 0U)
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_ERROR;
|
|
return 0;
|
|
}
|
|
|
|
POS_VTK_UART_SEND(frameBuf, frameLen);
|
|
|
|
pSess->e_state = POS_VTK_STATE_SETTLE_PENDING;
|
|
pSess->lastUpdateTick = pos_vtk_get_tick_ms();
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* 根据 Operation number 找到对应会话(可能来自任一枪) */
|
|
static POS_VTK_SESSION_T *pos_vtk_find_session_by_op(U32_T opNumber)
|
|
{
|
|
U8_T i;
|
|
for (i = 0U; i < GUN_MAX_CNT; i++)
|
|
{
|
|
if (s_sessions[i].opNumber == opNumber &&
|
|
s_sessions[i].opNumber != 0U)
|
|
{
|
|
return &s_sessions[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void pos_vtk_on_rx_byte(U8_T byte)
|
|
{
|
|
const U8_T *pFrame;
|
|
U16_T frameLen;
|
|
|
|
if (!vtk_frame_parser_input(&s_frameParser, byte, &pFrame, &frameLen))
|
|
return;
|
|
|
|
/* 收到完整 VTK 帧,解析为支付响应 */
|
|
{
|
|
VTK_POS_PAY_RESP_T resp;
|
|
POS_VTK_SESSION_T *pSess;
|
|
|
|
if (!vtk_parse_payment_response(pFrame, frameLen, &resp))
|
|
return;
|
|
|
|
pSess = pos_vtk_find_session_by_op(resp.operationNumber);
|
|
if (!pSess)
|
|
return;
|
|
|
|
pSess->e_lastResult = resp.eResult;
|
|
pSess->lastUpdateTick = pos_vtk_get_tick_ms();
|
|
|
|
/* 根据消息名更新状态机 */
|
|
if (strcmp(resp.messageName, "CDP") == 0)
|
|
{
|
|
if (resp.eResult == VTK_POS_RESULT_APPROVED)
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_PREAUTH_OK;
|
|
}
|
|
else
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_ERROR;
|
|
}
|
|
}
|
|
else if (strcmp(resp.messageName, "CRD") == 0)
|
|
{
|
|
if (resp.eResult == VTK_POS_RESULT_APPROVED)
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_DONE;
|
|
}
|
|
else
|
|
{
|
|
pSess->e_state = POS_VTK_STATE_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void pos_vtk_get_session(U8_T gunNo, POS_VTK_SESSION_T *pOut)
|
|
{
|
|
POS_VTK_SESSION_T *pSess;
|
|
|
|
if (!pOut)
|
|
return;
|
|
|
|
(void)memset(pOut, 0, sizeof(*pOut));
|
|
|
|
pSess = pos_vtk_get_session_ptr(gunNo);
|
|
if (!pSess)
|
|
return;
|
|
|
|
(void)memcpy(pOut, pSess, sizeof(*pSess));
|
|
}
|
|
|
|
/*
|
|
* 外部整体使用示例(伪代码):
|
|
*
|
|
* 1)初始化
|
|
* void System_Init(void)
|
|
* {
|
|
* ...
|
|
* pos_vtk_init();
|
|
* ...
|
|
* }
|
|
*
|
|
* 2)串口接收处理
|
|
* void UART_POS_Rx_IRQHandler(void)
|
|
* {
|
|
* U8_T byte;
|
|
* if (UART_POS_ReadByte(&byte))
|
|
* {
|
|
* pos_vtk_on_rx_byte(byte);
|
|
* }
|
|
* }
|
|
*
|
|
* 3)启动充电前预扣款
|
|
* void StartChargeByUser(U8_T gunNo)
|
|
* {
|
|
* U32_T preAuthAmountMinor = 5000U; // 预扣 50 元
|
|
*
|
|
* if (!pos_vtk_start_preauth(gunNo, preAuthAmountMinor))
|
|
* {
|
|
* // 预扣请求发送失败,直接报错
|
|
* return;
|
|
* }
|
|
*
|
|
* // 后台轮询会话状态,等待预扣结果
|
|
* POS_VTK_SESSION_T sess;
|
|
* pos_vtk_get_session(gunNo, &sess);
|
|
* if (sess.e_state == POS_VTK_STATE_PREAUTH_OK &&
|
|
* sess.e_lastResult == VTK_POS_RESULT_APPROVED)
|
|
* {
|
|
* // 预扣成功,允许进入充电流程
|
|
* }
|
|
* else if (sess.e_state == POS_VTK_STATE_ERROR)
|
|
* {
|
|
* // 预扣失败,提示用户
|
|
* }
|
|
* }
|
|
*
|
|
* 4)充电结束后结算
|
|
* void StopChargeAndSettle(U8_T gunNo, U32_T finalAmountMinor)
|
|
* {
|
|
* if (!pos_vtk_notify_charge_end(gunNo, finalAmountMinor))
|
|
* {
|
|
* // 结算请求未发出,记录异常
|
|
* return;
|
|
* }
|
|
*
|
|
* POS_VTK_SESSION_T sess;
|
|
* pos_vtk_get_session(gunNo, &sess);
|
|
* if (sess.e_state == POS_VTK_STATE_DONE &&
|
|
* sess.e_lastResult == VTK_POS_RESULT_APPROVED)
|
|
* {
|
|
* // 结算成功,写订单、上报平台
|
|
* }
|
|
* else if (sess.e_state == POS_VTK_STATE_ERROR)
|
|
* {
|
|
* // 结算失败,记录异常订单
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
#endif /* POS_VTK_EN */
|
|
|