#include "pos_vtk/vtk_tlv.h" #include "publicdata/public_define.h" #include #if (POS_VTK_EN) /****************************************************************************** * 模块说明:VTK TLV 编解码工具 * * - 仅支持简单的 TLV 格式:1 字节 Tag + 1 字节 Length + Value。 * - 用于构造 VTK 应用层 TLV 消息(例如 Message name、Operation number、Amount)。 * * 对外接口: * - vtk_tlv_append() :追加任意二进制 TLV。 * - vtk_tlv_append_ascii() :追加 ASCII 字符串 TLV。 * - vtk_tlv_append_ascii_uint(): 以十进制 ASCII 形式追加整数 TLV。 * - vtk_tlv_find_first() :在 TLV 缓冲中查找首个指定 Tag。 ******************************************************************************/ U8_T vtk_tlv_append(U8_T tag, const U8_T *pVal, U16_T len, U8_T *pBuf, U16_T bufMax, U16_T *pOffset) { U16_T offset; if (!pBuf || !pOffset) return 0; offset = *pOffset; /* 仅支持短格式长度(1 字节,len < 128) */ if (len > 127U) return 0; if ((U16_T)(offset + 2U + len) > bufMax) return 0; pBuf[offset++] = tag; pBuf[offset++] = (U8_T)len; if (len > 0U && pVal) { (void)memcpy(&pBuf[offset], pVal, len); offset = (U16_T)(offset + len); } *pOffset = offset; return 1; } U8_T vtk_tlv_append_ascii(U8_T tag, const char *str, U8_T *pBuf, U16_T bufMax, U16_T *pOffset) { U16_T len; if (!str) return 0; len = (U16_T)strlen(str); return vtk_tlv_append(tag, (const U8_T *)str, len, pBuf, bufMax, pOffset); } /* 把无符号整数转换为十进制 ASCII(不带 '\0'),右对齐或自然长度 */ static U8_T vtk_utoa_dec(U32_T value, char *out, U8_T minWidth) { char buf[16]; U8_T i = 0U; U8_T len; if (!out) return 0; /* 生成反向字符串 */ do { buf[i++] = (char)('0' + (value % 10U)); value /= 10U; } while (value != 0U && i < sizeof(buf)); /* 实际长度至少为 minWidth */ while (i < minWidth && i < sizeof(buf)) { buf[i++] = '0'; } len = i; /* 反转到输出缓冲 */ while (i > 0U) { *out++ = buf[--i]; } return len; } U8_T vtk_tlv_append_ascii_uint(U8_T tag, U32_T value, U8_T minWidth, U8_T *pBuf, U16_T bufMax, U16_T *pOffset) { char tmp[16]; U8_T len; len = vtk_utoa_dec(value, tmp, minWidth); if (len == 0U) return 0; return vtk_tlv_append(tag, (const U8_T *)tmp, len, pBuf, bufMax, pOffset); } U8_T vtk_tlv_find_first(const U8_T *pBuf, U16_T bufLen, U8_T tag, const U8_T **ppVal, U16_T *pValLen) { U16_T offset = 0U; if (!pBuf || !ppVal || !pValLen) return 0; while (offset + 2U <= bufLen) { U8_T t = pBuf[offset]; U8_T l = pBuf[offset + 1U]; U16_T next; next = (U16_T)(offset + 2U + l); if (next > bufLen) return 0; /* TLV 结构损坏 */ if (t == tag) { *ppVal = &pBuf[offset + 2U]; *pValLen = l; return 1; } offset = next; } return 0; } /* * 外部使用示例: * * // 构造 TLV 缓冲用于预扣款请求(CDP) * U8_T tlvBuf[VTK_MAX_APP_LEN]; * U16_T tlvLen = 0; * * // Tag 0x01: Message name = "CDP" * vtk_tlv_append_ascii(0x01, "CDP", tlvBuf, sizeof(tlvBuf), &tlvLen); * * // Tag 0x03: Operation number = "12345" * vtk_tlv_append_ascii_uint(0x03, 12345U, 1U, tlvBuf, sizeof(tlvBuf), &tlvLen); * * // Tag 0x04: Amount = "5000" (单位:分) * vtk_tlv_append_ascii_uint(0x04, 5000U, 1U, tlvBuf, sizeof(tlvBuf), &tlvLen); * * // 解析响应时查找结果码(假设结果码放在 Tag 0x0D 的 Simple data block 首字节) * const U8_T *pVal; * U16_T valLen; * if (vtk_tlv_find_first(tlvBuf, tlvLen, 0x0D, &pVal, &valLen) && valLen > 0U) * { * U8_T resultCode = pVal[0]; * // 0=Approved, 1=Declined, 2=Timeout... * } */ #endif /* POS_VTK_EN */