Files

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 */