using System.Runtime.InteropServices; using System.Text; namespace Olei.LidarSensor; /// /// Frame header structure for Olei LiDAR sensor (40 bytes) /// All data is in little-endian format /// [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct LidarHeader { /// /// Frame ID, always 0xFEF0010F /// public const uint FRAME_ID = 0xFEF0010F; /// /// Protocol version, current is 0x0200 /// public const ushort PROTOCOL_VERSION = 0x0200; public uint Id; public ushort ProtocolVersion; public byte DistanceScale; // Brand name code (3 bytes) public byte BrandName1; public byte BrandName2; public byte BrandName3; // Commercial type code (12 bytes) public ulong CommercialType1; public uint CommercialType2; public ushort InternalTypeCode; public ushort HardwareVersion; public ushort SoftwareVersion; public uint TimeStamp; public ushort RotationRateAndDirection; public byte SafeZoneStatus; public byte ErrorStatus; public uint NtpTimestampInteger; /// /// Check if the frame ID is valid /// public readonly bool IsValidFrame => Id == FRAME_ID; /// /// Get rotation rate (Bit[14:0]) /// public readonly ushort RotationRate => (ushort)(RotationRateAndDirection & 0x7FFF); /// /// Get rotation direction (Bit[15]): false = clockwise, true = counter clockwise /// public readonly bool IsCounterClockwise => (RotationRateAndDirection & 0x8000) != 0; /// /// Check if motor fault occurred (BIT0 of ErrorStatus) /// public readonly bool HasMotorFault => (ErrorStatus & 0x01) != 0; /// /// Check if abnormal voltage occurred (BIT1 of ErrorStatus) /// public readonly bool HasAbnormalVoltage => (ErrorStatus & 0x02) != 0; /// /// Check if temperature fault occurred (BIT2 of ErrorStatus) /// public readonly bool HasTemperatureFault => (ErrorStatus & 0x04) != 0; /// /// Check if any error occurred /// public readonly bool HasError => ErrorStatus != 0; /// /// Get brand name as string /// public readonly string GetBrandName() { Span bytes = stackalloc byte[3]; bytes[0] = BrandName1; bytes[1] = BrandName2; bytes[2] = BrandName3; return Encoding.ASCII.GetString(bytes).TrimEnd('\0'); } /// /// Get OUTPUT bits (BIT[3:0] of SafeZoneStatus) /// public readonly byte GetOutputBits => (byte)(SafeZoneStatus & 0x0F); /// /// Get INPUT bits (BIT[7:4] of SafeZoneStatus) /// public readonly byte GetInputBits => (byte)((SafeZoneStatus >> 4) & 0x0F); }