LivoxProto1: Print when Lidar isn't ready for work

This commit is contained in:
2025-10-24 00:51:28 -04:00
parent 83c937ae8f
commit bede123691
3 changed files with 126 additions and 2 deletions
+69 -2
View File
@@ -981,9 +981,76 @@ static void discardHeartbeatAck(
const struct sockaddr_in& senderAddr const struct sockaddr_in& senderAddr
) )
{ {
(void)data;
(void)bytesReceived;
(void)senderAddr; (void)senderAddr;
// Check if we have enough data for a HeartbeatACK message
if (bytesReceived
< static_cast<ssize_t>(sizeof(livoxProto1::comms::HeartbeatACK)))
{
std::cout << __func__ << ": Received heartbeat ACK with insufficient "
"data (" << bytesReceived << " bytes, expected "
<< sizeof(livoxProto1::comms::HeartbeatACK) << ")" << std::endl;
return;
}
// Directly use a non-const reference to HeartbeatACK structure
livoxProto1::comms::HeartbeatACK& ack =
*reinterpret_cast<livoxProto1::comms::HeartbeatACK*>(
const_cast<uint8_t*>(data));
ack.swapContentsToHostEndianness();
if (!ack.validateCrc32())
{
std::cerr << __func__ << ": Discarded heartbeat ACK - CRC32 validation "
"failed" << std::endl;
return;
}
if (!ack.header.validateCrc16())
{
std::cerr << __func__ << ": Discarded heartbeat ACK - CRC16 validation "
"failed" << std::endl;
return;
}
if (!ack.sanityCheck())
{
std::cerr << __func__ << ": Discarded heartbeat ACK - sanity check "
"failed" << std::endl;
return;
}
if (ack.work_state == 0x01) { return; }
// Print work_state with human-readable description
std::string workStateStr;
switch (ack.work_state)
{
case 0x00:
workStateStr = "Initializing";
break;
case 0x01:
workStateStr = "Normal";
break;
case 0x02:
workStateStr = "Power-Saving";
break;
case 0x03:
workStateStr = "Standby";
break;
case 0x04:
workStateStr = "Error";
break;
default:
workStateStr = "Unknown";
break;
}
std::cerr << __func__ << ": Lidar not ready for operation: work_state: 0x"
<< std::hex << static_cast<int>(ack.work_state) << std::dec
<< " (" << workStateStr << "), ack_msg: 0x"
<< std::hex << ack.ack_msg << std::dec << std::endl;
} }
void Device::startHeartbeat() void Device::startHeartbeat()
+38
View File
@@ -800,5 +800,43 @@ bool SamplingResponse::validateCrc32() const
return isValid; return isValid;
} }
// HeartbeatACK methods
void HeartbeatACK::swapContentsToHostEndianness()
{
if (endian::isLittleEndian()) { return; }
// Only swap content fields, not CRC fields
header.swapToHostEndianness();
command.swapToHostEndianness();
ack_msg = __builtin_bswap32(ack_msg);
// Note: footer.swapToHostEndianness() swaps CRC, so we skip it here
}
bool HeartbeatACK::sanityCheck() const
{
return header.sanityCheck() &&
command.sanityCheck() &&
(command.cmd_set == 0x00) && (command.cmd_id == 0x03) &&
footer.sanityCheck();
}
bool HeartbeatACK::validateCrc32() const
{
// Calculate CRC32 for the entire message excluding the footer.crc_32 field
const uint8_t* messageData = reinterpret_cast<const uint8_t*>(this);
size_t messageSize = sizeof(HeartbeatACK) - sizeof(footer.crc_32);
uint32_t calculatedCrc = comms::calculateCrc32(messageData, messageSize);
// Compare with the CRC in the footer
bool isValid = (calculatedCrc == footer.crc_32);
// Debug output only if validation fails
if (!isValid) {
std::cout << "HeartbeatACK CRC32 Debug: calculated=0x" << std::hex << calculatedCrc
<< ", received=0x" << footer.crc_32 << std::dec << std::endl;
}
return isValid;
}
} // namespace comms } // namespace comms
} // namespace livoxProto1 } // namespace livoxProto1
+19
View File
@@ -280,6 +280,25 @@ struct SamplingResponse
bool validateCrc32() const; bool validateCrc32() const;
} __attribute__((packed)); } __attribute__((packed));
/** EXPLANATION:
* Complete heartbeat ACK response frame from Livox devices.
* This is the complete wire format including header, command fields, data, and footer.
*/
struct HeartbeatACK
{
Header header; // 0-8: Protocol frame header
Command command; // 9-10: Command identification
uint8_t ret_code; // 11: Return Code (0x00 = Success, 0x01 = Fail)
uint8_t work_state; // 12: LiDAR/Hub State (0x00: Initializing, 0x01: Normal, 0x02: Power-Saving, 0x03: Standby, 0x04: Error)
uint8_t feature_msg; // 13: LiDAR Feature Message (Bit0: Rain/Fog Suppression Switch)
uint32_t ack_msg; // 14-17: ACK Message (Initialization Progress or Status Code)
Footer footer; // 18-21: Protocol frame footer
void swapContentsToHostEndianness();
bool sanityCheck() const;
bool validateCrc32() const;
} __attribute__((packed));
} // namespace comms } // namespace comms
} // namespace livoxProto1 } // namespace livoxProto1