/* MQTT解析器测试函数 */
void mqtt_parser_test(void)
{
uint8_t packet_buffer[256];
uint32_t result;
uint8_t i;
uint8_t passed = 1;
CircularQueue q;
/* 测试数据数组 */ uint8_t test_data1[] = { 0x30, 0x0A, /* PUBLISH QoS0 + 剩余长度 */ 0x00, 0x03, 'a', 'b', 'c', /* 主题 */ 0x00, 0x00, /* 报文标识符 (QoS0时忽略) */ 'h', 'e', 'l', 'l', 'o' /* 负载 */ }; uint8_t test_data2[] = {0x38, 0x00}; /* 无效的PUBLISH */ uint8_t test_data3[] = { 0x30, /* PUBLISH QoS0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0x80 /* 非法的剩余长度格式 */ }; uint8_t test_data4[] = { 0x30, 0x05, /* PUBLISH QoS0 + 剩余长度 */ 0x00, 0x03, 'a', 'b' /* 缺少一个字节 */ }; uint8_t test_data5[] = {0x30, 0x80}; /* 不完整的剩余长度 */ uint8_t test_data6[] = { /* 报文1: CONNECT */ 0x10, 0x10, /* 固定报头 */ 0x00, 0x04, 'M', 'Q', 'T', 'T', /* 协议名 */ 0x04, /* 协议级别 */ 0x02, /* 连接标志 */ 0x00, 0x0A, /* 保持活动 */ 0x00, 0x03, 'c', 'i', 'd', /* 客户端ID */ /* 报文2: PUBLISH QoS1 */ 0x32, 0x0A, /* PUBLISH QoS1 */ 0x00, 0x03, 't', 'o', 'p', /* 主题 */ 0x00, 0x01, /* 报文标识符 */ 'm', 's', 'g' /* 负载 */ }; uint8_t test_data7[] = { 0x10, 0x13, /* CONNECT + 剩余长度 */ 0x00, 0x04, 'M', 'Q', 'T', 'T', /* 协议名 */ 0x04, /* 协议级别 */ 0x02, /* 连接标志 */ 0x00, 0x0A, /* 保持活动 */ 0x00, 0x05, 'c', 'l', 'i', 'e', 'n', /* 客户端ID */ 0x00, 0x04, 'u', 's', 'e', 'r', /* 用户名 */ 0x00, 0x04, 'p', 'a', 's', 's' /* 密码 */ }; /* 初始化队列 */ Queue_Init(&q); /* 通过串口输出测试信息 */ printf("\r\n===== MQTT解析器测试开始 =====\r\n"); /* 测试用例1: 有效PUBLISH报文 (QoS0) */ printf("\r\n测试用例1: 有效PUBLISH报文 (QoS0)\r\n"); Queue_Writes(&q, test_data1, sizeof(test_data1)); result = mqtt_parser(&q, packet_buffer); if (result == sizeof(test_data1)) { printf(" - 测试通过: 成功解析报文,长度=%lu\r\n", result); } else { printf(" - 测试失败: 预期长度=%lu, 实际长度=%lu\r\n", (uint32_t)sizeof(test_data1), result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例2: 无效报文类型 */ printf("\r\n测试用例2: 无效报文类型\r\n"); Queue_Writes(&q, test_data2, sizeof(test_data2)); result = mqtt_parser(&q, packet_buffer); if (result == 0) { printf(" - 测试通过: 正确拒绝无效报文\r\n"); } else { printf(" - 测试失败: 预期0, 实际%lu\r\n", result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例3: 剩余长度格式错误 */ printf("\r\n测试用例3: 剩余长度格式错误\r\n"); Queue_Writes(&q, test_data3, sizeof(test_data3)); result = mqtt_parser(&q, packet_buffer); if (result == 0) { printf(" - 测试通过: 正确检测剩余长度错误\r\n"); } else { printf(" - 测试失败: 预期0, 实际%lu\r\n", result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例4: 报文不完整 */ printf("\r\n测试用例4: 报文不完整\r\n"); Queue_Writes(&q, test_data4, sizeof(test_data4)); result = mqtt_parser(&q, packet_buffer); if (result == 0) { printf(" - 测试通过: 正确处理不完整报文\r\n"); } else { printf(" - 测试失败: 预期0, 实际%lu\r\n", result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例5: 超时处理 */ printf("\r\n测试用例5: 超时处理\r\n"); Queue_Writes(&q, test_data5, sizeof(test_data5)); /* 模拟多次调用以触发超时 */ for (i = 0; i <= MQTT_PARSE_TIMEOUT; i++) { result = mqtt_parser(&q, packet_buffer); } if (result == 0 && Queue_Length(&q) == 0) { printf(" - 测试通过: 正确处理超时并丢弃数据\r\n"); } else { printf(" - 测试失败: 队列长度=%u, 结果=%lu\r\n", Queue_Length(&q), result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例6: 多个报文连续解析 */ printf("\r\n测试用例6: 多个报文连续解析\r\n"); Queue_Writes(&q, test_data6, sizeof(test_data6)); /* 解析第一个报文 */ result = mqtt_parser(&q, packet_buffer); if (result == 16) { printf(" - 报文1解析成功: 长度=%lu\r\n", result); /* 解析第二个报文 */ result = mqtt_parser(&q, packet_buffer); if (result == 12) { printf(" - 报文2解析成功: 长度=%lu\r\n", result); printf(" - 测试通过: 成功解析多个报文\r\n"); } else { printf(" - 测试失败: 报文2预期12, 实际%lu\r\n", result); passed = 0; } } else { printf(" - 测试失败: 报文1预期16, 实际%lu\r\n", result); passed = 0; } /* 清空队列 */ Queue_Init(&q); /* 测试用例7: 有效CONNECT报文 */ printf("\r\n测试用例7: 有效CONNECT报文\r\n"); Queue_Writes(&q, test_data7, sizeof(test_data7)); result = mqtt_parser(&q, packet_buffer); if (result == sizeof(test_data7)) { printf(" - 测试通过: 成功解析CONNECT报文\r\n"); } else { printf(" - 测试失败: 预期长度=%lu, 实际长度=%lu\r\n", (uint32_t)sizeof(test_data7), result); passed = 0; } /* 最终测试结果 */ printf("\r\n===== 测试结果 =====\r\n"); if (passed) { printf("所有测试用例通过!\r\n"); } else { printf("部分测试用例失败!\r\n"); } printf("====================\r\n");
}
uint32_t mqtt_parser(CircularQueue *q, uint8_t *packet_buff)
{
static uint8_t state = 0; // 解析状态
static uint32_t total_length = 0; // 报文总长度
static uint8_t rlen_bytes = 0; // 剩余长度字节数
static uint8_t timeout_cnt = 0; // 超时计数器
uint32_t i; uint8_t packet_type; // 报文类型 // 剩余长度解析 uint8_t byte, multiplier = 1; uint32_t rlen = 0; rlen_bytes = 0; while (!Queue_Empty(q)) { // 超时处理机制 if (timeout_cnt >= MQTT_PARSE_TIMEOUT) { Queue_MoveReadIndex(q, 1); // 丢弃首字节 state = 0; timeout_cnt = 0; printf("\n[超时] 丢弃无效数据\n"); continue; } switch (state) { case 0: // 固定报头解析状态 { if (Queue_Length(q) < 2) { timeout_cnt++; return 0; // 数据不足,等待下次调用 } Queue_PeekAt(q, 0, &packet_type); // 获取报文类型 // 严格验证报文类型 if (!validate_mqtt_header(packet_type)) { Queue_MoveReadIndex(q, 1); // 仅丢弃错误字节 printf("\n[错误] 无效报文类型: 0x%02X\n", packet_type); timeout_cnt = 0; continue; } do { if (Queue_Length(q) < (2 + rlen_bytes)) { timeout_cnt++; return 0; // 数据不足 } Queue_PeekAt(q, 1 + rlen_bytes, &byte); rlen += (byte & 0x7F) * multiplier; // MQTT协议合规性检查 if (rlen_bytes >= 4 && (byte & 0x80)) { Queue_MoveReadIndex(q, 1 + rlen_bytes); printf("\n[错误] 剩余长度格式错误\n"); timeout_cnt = 0; continue; } multiplier *= 128; rlen_bytes++; } while (byte & 0x80); total_length = 1 + rlen_bytes + rlen; state = 1; timeout_cnt = 0; break; } case 1: // 报文数据读取状态 { if (Queue_Length(q) < total_length) { timeout_cnt++; return 0; // 数据不足 } // 批量读取报文数据 for (i = 0; i < total_length; i++) { Queue_PeekAt(q, i, &packet_buff[i]); printf("%02X ", packet_buff[i]); } Queue_MoveReadIndex(q, total_length); // 移除已处理数据 printf("\n[成功] 报文类型:0x%02X 长度:%u\n", packet_buff[0], total_length); state = 0; timeout_cnt = 0; return total_length; // 返回成功解析的长度 } } } return 0; // 队列为空时返回0
}
// 返回实际写入字节数,便于调用方处理
uint8_t Queue_Writes(CircularQueue *q, uint8_t *data, uint8_t length)
{
uint8_t used;
uint8_t free;
uint8_t actual_length;
uint8_t cont_free;
ENTER_CRITICAL(); // 进入临界区 // 计算剩余空间 used = (q->write - q->read) & (QUEUE_SIZE - 1); free = QUEUE_SIZE - 1 - used; // 保留一个位置区分满/空状态 // 计算实际可写入长度 actual_length = (length > free) ? free : length; if (actual_length == 0) { EXIT_CRITICAL(); return 0; } // 计算连续写入空间(从 write 指针到缓冲区末尾) cont_free = QUEUE_SIZE - q->write; if (actual_length <= cont_free) { // 空间连续:直接复制 memcpy(&q->buffer[q->write], data, actual_length); q->write += actual_length; } else { // 空间分两段:先复制尾部,再复制头部剩余部分 memcpy(&q->buffer[q->write], data, cont_free); memcpy(q->buffer, data + cont_free, actual_length - cont_free); q->write = actual_length - cont_free; // 回绕到头部 } // 确保 write 指针在 [0, QUEUE_SIZE-1] 范围内 q->write &= (QUEUE_SIZE - 1); // 等价于取模运算 EXIT_CRITICAL(); // 退出临界区 return actual_length;
}
/* MQTT解析器测试函数 */
void mqtt_parser_test(void)这个函数执行不符合预期,结果入下===== MQTT解析器测试开始 =====
测试用例1: 有效PUBLISH报文 (QoS0)
30 0A 00 03 61 62 63 00 00 68 65 6C
[成功] 报文类型:0x30 长度:12
- 测试失败: 预期长度=14, 实际长度=12
测试用例2: 无效报文类型
[错误] 无效报文类型: 0x38
- 测试通过: 正确拒绝无效报文
测试用例3: 剩余长度格式错误
[错误] 剩余长度格式错误
- 测试通过: 正确检测剩余长度错误
测试用例4: 报文不完整
- 测试通过: 正确处理不完整报文
测试用例5: 超时处理
[超时] 丢弃无效数据
- 测试失败: 队列长度=1, 结果=0
测试用例6: 多个报文连续解析
10 10 00 04 4D 51 54 54 04 02 00 0A 00 03 63 69 64 32
[成功] 报文类型:0x10 长度:18
- 测试失败: 报文1预期16, 实际18
测试用例7: 有效CONNECT报文
10 13 00 04 4D 51 54 54 04 02 00 0A 00 05 63 6C 69 65 6E 00 04
[成功] 报文类型:0x10 长度:21
- 测试失败: 预期长度=31, 实际长度=21
===== 测试结果 =====
部分测试用例失败!
====================
最新发布