#include "pos_vtk/pos_vtk_service.h" #include "publicdata/public_define.h" #include #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 */