에러 커맨드 추가
- rxx: (Unknown command) - 수신 TAG가 명령 테이블에 없는 경우 - rxd: (Disabled command) - 수신 TAG가 테이블에 있지만 enabled=false로 비활성화된 경우 - rxn: (NULL handler) - 엔트리는 매칭됐지만 함수 포인터가 NULL인 경우(펌웨어 버그 방어) - rxc: (CRC fail) - CRC16 검증 실패 - rxs: (Too short) - 패킷이 너무 짧은 경우(CRC 활성 시 7바이트 미만, 비활성 시 4바이트 미만)
This commit is contained in:
@@ -278,6 +278,20 @@ static bool dr_crc16_check_packet(const uint8_t *packet, uint32_t packet_len)
|
|||||||
return dr_crc16_check(packet, data_len, expected_crc);
|
return dr_crc16_check(packet, data_len, expected_crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 에러 응답 헬퍼 ----
|
||||||
|
* 패킷: [err_tag 4B] [cmd_tag 에코 4B] = 8바이트 = 4워드
|
||||||
|
* CRC16은 tx_bin 레이어에서 자동 부가
|
||||||
|
*/
|
||||||
|
static void dr_send_error(const char *err_tag, const char *cmd_tag)
|
||||||
|
{
|
||||||
|
if (g_plat.tx_bin) {
|
||||||
|
uint8_t err_buf[8];
|
||||||
|
memcpy(&err_buf[0], err_tag, 4);
|
||||||
|
memcpy(&err_buf[4], cmd_tag, 4);
|
||||||
|
g_plat.tx_bin(err_buf, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- 수신 버퍼 → ParsedCmd 구조체 변환 ---- */
|
/* ---- 수신 버퍼 → ParsedCmd 구조체 변환 ---- */
|
||||||
|
|
||||||
/* 수신된 원시 바이트 버퍼를 파싱하여 TAG와 데이터를 분리
|
/* 수신된 원시 바이트 버퍼를 파싱하여 TAG와 데이터를 분리
|
||||||
@@ -289,43 +303,57 @@ static bool dr_crc16_check_packet(const uint8_t *packet, uint32_t packet_len)
|
|||||||
*/
|
*/
|
||||||
static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
|
static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t data_len;
|
||||||
|
|
||||||
|
/* TAG 4바이트조차 수신되지 않음 → rxs: + "????" (TAG 특정 불가) */
|
||||||
if (length < 4) {
|
if (length < 4) {
|
||||||
return false; /* TAG 4바이트조차 수신되지 않음 */
|
dr_send_error("rxs:", "????");
|
||||||
|
if (g_plat.log && g_log_enable) {
|
||||||
|
g_plat.log("[parser] too short (%u bytes) -> rxs:\r\n", length);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TAG 먼저 추출 (에러 응답 에코에 사용) */
|
||||||
|
dr_copy_tag(buffer, out->tag);
|
||||||
|
|
||||||
/* CRC 검증이 활성화된 경우 패킷 무결성 확인 */
|
/* CRC 검증이 활성화된 경우 패킷 무결성 확인 */
|
||||||
if (g_plat.crc_check)
|
if (g_plat.crc_check)
|
||||||
{
|
{
|
||||||
if (!dr_crc16_check_packet(buffer, length))
|
if (length < 7) {
|
||||||
{
|
dr_send_error("rxs:", out->tag);
|
||||||
if (g_plat.log && g_log_enable) {
|
if (g_plat.log && g_log_enable) {
|
||||||
g_plat.log("CRC check FAILED!\n");
|
g_plat.log("[parser] CRC enabled but too short (%u) -> rxs:\r\n", length);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CRC 검증 성공 → CRC 2바이트를 제외한 실제 데이터 길이로 조정 */
|
if (!dr_crc16_check_packet(buffer, length))
|
||||||
length = (uint8_t)(length - 2);
|
{
|
||||||
|
dr_send_error("rxc:", out->tag);
|
||||||
|
if (g_plat.log && g_log_enable) {
|
||||||
|
g_plat.log("[parser] CRC mismatch '%s' -> rxc:\r\n", out->tag);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_len = (uint8_t)(length - 4 - 2); /* TAG(4) + CRC(2) 제외 */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* TAG 4바이트 복사 */
|
|
||||||
dr_copy_tag(buffer, out->tag);
|
|
||||||
|
|
||||||
/* TAG 이후 데이터 길이 계산 (최대 DR_MAX_DATA까지) */
|
|
||||||
out->data_len = (length > 4) ? (uint8_t)(length - 4) : 0;
|
|
||||||
if (out->data_len > DR_MAX_DATA)
|
|
||||||
{
|
{
|
||||||
out->data_len = DR_MAX_DATA;
|
data_len = (uint8_t)(length - 4); /* TAG(4) 제외 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TAG 뒤의 데이터 바이트를 ParsedCmd.data[]에 복사 */
|
/* 최대 길이 클램프 */
|
||||||
for (i = 0; i < out->data_len; i++)
|
if (data_len > DR_MAX_DATA) {
|
||||||
{
|
data_len = DR_MAX_DATA;
|
||||||
out->data[i] = buffer[4 + i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data_len > 0) {
|
||||||
|
memcpy(out->data, buffer + 4, data_len);
|
||||||
|
}
|
||||||
|
out->data_len = data_len;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,10 +516,20 @@ static int dr_cmd_dispatch(const ParsedCmd *cmd)
|
|||||||
for (i = 0; i < g_cmd_count; i++) {
|
for (i = 0; i < g_cmd_count; i++) {
|
||||||
if (dr_tag_eq(tag_lower, g_cmd_table[i].tag)) {
|
if (dr_tag_eq(tag_lower, g_cmd_table[i].tag)) {
|
||||||
|
|
||||||
/* 비활성화된 명령이면 실행하지 않음 */
|
/* 비활성화된 명령 → rxd: 응답 */
|
||||||
if (!g_cmd_table[i].enabled) {
|
if (!g_cmd_table[i].enabled) {
|
||||||
|
dr_send_error("rxd:", cmd->tag);
|
||||||
if (g_plat.log && g_log_enable) {
|
if (g_plat.log && g_log_enable) {
|
||||||
g_plat.log("Command '%s' disabled\n", cmd->tag);
|
g_plat.log("Command '%s' disabled -> rxd:\n", cmd->tag);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL 핸들러 가드 → rxn: 응답 */
|
||||||
|
if (g_cmd_table[i].handler == NULL) {
|
||||||
|
dr_send_error("rxn:", cmd->tag);
|
||||||
|
if (g_plat.log) {
|
||||||
|
g_plat.log("[parser] NULL handler for '%s' -> rxn:\n", cmd->tag);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -501,9 +539,10 @@ static int dr_cmd_dispatch(const ParsedCmd *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 테이블에 없는 TAG 수신 시 */
|
/* 테이블에 없는 TAG → rxx: 응답 */
|
||||||
|
dr_send_error("rxx:", cmd->tag);
|
||||||
if (g_plat.log && g_log_enable) {
|
if (g_plat.log && g_log_enable) {
|
||||||
g_plat.log("Unknown TAG '%s'\n", cmd->tag);
|
g_plat.log("Unknown TAG '%s' -> rxx:\n", cmd->tag);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -523,16 +562,10 @@ int dr_cmd_parser(const uint8_t *buf, uint8_t len)
|
|||||||
{
|
{
|
||||||
ParsedCmd cmd;
|
ParsedCmd cmd;
|
||||||
|
|
||||||
/* 패킷 파싱 (CRC 검증 포함) */
|
/* 패킷 파싱 (CRC 검증 포함) - 에러 응답은 dr_parse_cmd 내부에서 전송 */
|
||||||
if (!dr_parse_cmd(buf, len, &cmd)) {
|
if (!dr_parse_cmd(buf, len, &cmd)) {
|
||||||
if (g_plat.log) g_plat.log("[PARSER] PARSE FAIL\r\n");
|
if (g_plat.log) g_plat.log("[PARSER] PARSE FAIL\r\n");
|
||||||
|
return -1;
|
||||||
/* CRC 실패 시 "crc!" 에러 응답을 BLE로 전송 (65530 = 에러 코드) */
|
|
||||||
if (g_plat.crc_check && g_plat.tx_bin) {
|
|
||||||
single_format_data(ble_bin_buffer, "crc!", 65530);
|
|
||||||
dr_binary_tx_safe(ble_bin_buffer, 3);
|
|
||||||
}
|
|
||||||
return -1; /* CRC/파싱 실패 → 음수 반환으로 레거시 파서에 위임 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 수신 명령어 종류 확인용 로그 */
|
/* 수신 명령어 종류 확인용 로그 */
|
||||||
|
|||||||
Reference in New Issue
Block a user