Skip to content

Frame Reference

Each frame emitted by the unit is decoded into a struct carried by a variant of OscpFrame.

OscpFrame variant Header value Struct Length constant Length
OscpFrame::Raw 0x00 OscpRaw OSCP_RAW_LEN 61 B
OscpFrame::Euler 0x01 OscpEuler OSCP_EULER_LEN 25 B
OscpFrame::Quat 0x02 OscpQuat OSCP_QUAT_LEN 29 B
OscpFrame::RotMat 0x03 OscpRotMat OSCP_ROT_MAT_LEN 49 B
OscpFrame::Gnss 0x04 OscpGnss OSCP_GNSS_LEN 64 B
OscpFrame::Debug1 0x05 OscpDebug1 OSCP_DEBUG_1_LEN 58 B
OscpFrame::Debug2 0x06 OscpDebug2 OSCP_DEBUG_2_LEN 58 B
OscpFrame::Startup 0x07 OscpStartup OSCP_STARTUP_LEN 40 B

Command responses

Command responses are reported as OscpFrame::CmdResponse(OscpFrameCmd) with one of OscpFrameCmd::Success (0xA0), ::Failed (0xA1), ::Unknown (0xA2) or ::NotImpl (0xA3). These values are defined by the library, not by the IMU protocol. Only the RS422 parser produces this variant; see Command classes.


The header byte

The first byte of every operating frame is stored in header_byte as an OscpHeader. Its fields are read with the following methods:

let t  = e.header_byte.frame_type();         /* bits [2:0] -> Result<OscpFrameType, u8> */
let om = e.header_byte.operating_mode();     /* bits [5:3] -> Result<OscpOperatingMode, u8> */
let mc = e.header_byte.misalignment_corr();  /* bits [7:6] -> Result<OscpMisalignmentCorr, u8> */
Field Bits Values
Frame type [2:0] See table above (OscpFrameType::Raw … ::Startup)
Operating mode [5:3] OscpOperatingMode::Idle / ::Low / ::Medium
Misalignment correction [7:6] OscpMisalignmentCorr::Disabled / ::Enabled

A method returns Err(value) if the bits do not map to a variant. The raw byte is returned by header_byte.to_byte().


The status byte

Every frame contains a status byte. 0x00 indicates no fault. Other values are a combination of the following masks:

Mask Value Meaning
OSCP_STATUS_OK 0x00 No fault
OSCP_STATUS_OVERRUN 0x01 IMU real-time controller overrun
OSCP_STATUS_MEMS_ERR 0x02 MEMS sensor error
OSCP_STATUS_INCL_ERR 0x04 Inclinometer error
OSCP_STATUS_MAG_ERR 0x08 Magnetometer error
OSCP_STATUS_TEMP_ERR 0x10 Temperature sensor error
OSCP_STATUS_GNSS_ERR 0x20 GNSS error (G variants only)
OSCP_STATUS_OG_ERR 0x40 Optical gyroscope error (optical-based models only)
if e.status & OSCP_STATUS_MEMS_ERR != 0 { /* handle MEMS fault */ }

Raw frame - OscpRaw

Raw sensor output.

Fields
Field Type Unit
header_byte OscpHeader -
counter u8 -
timestamp_ms u64 ms
gyro_x/y/z f32 dps
accel_x/y/z f32 g
incl_x/y f32 mg
mag_x/y/z f32 µT
temp f32 °C
status u8 -
crc u16 -

Euler frame - OscpEuler

AHRS attitude as Euler angles.

Fields
Field Type Unit
header_byte OscpHeader -
counter u8 -
timestamp_ms u64 ms
roll f32 deg
pitch f32 deg
yaw f32 deg
status u8 -
crc u16 -

Quaternion frame - OscpQuat

AHRS attitude as a unit quaternion (w, x, y, z).

Fields
Field Type Unit
header_byte OscpHeader -
counter u8 -
timestamp_ms u64 ms
w, x, y, z f32 - (normalized)
status u8 -
crc u16 -

Rotation matrix frame - OscpRotMat

AHRS attitude as a 3×3 direction-cosine matrix.

Fields
Field Type Notes
header_byte OscpHeader -
counter u8 -
timestamp_ms u64 ms
rm [[f32; 3]; 3] Row-major direction-cosine matrix
status u8 -
crc u16 -

GNSS frame - OscpGnss

Position, velocity and fix quality.

Fields
Field Type Unit
header_byte OscpHeader -
counter u8 -
timestamp_ms u64 ms
gnss_fix_type u8 -
num_satellites u8 count
longitude f32 deg
latitude f32 deg
height i32 mm
horizontal_accuracy u32 mm
vertical_accuracy u32 mm
velocity_north/east/down i32 mm/s
speed_accuracy u32 mm/s
heading_of_motion f32 deg
heading_accuracy f32 deg
pdop f32 -
gnss_flags GnssFlags See below
status u8 -
crc u16 -

GnssFlags methods:

Method Bits Returns
gnss_fix_ok() [0] bool, fix valid
invalid_llh() [1] bool, latitude/longitude/height invalid
last_correction_age() [7:4] u8

Debug frames - OscpDebug1 / OscpDebug2

Diagnostic frames. Debug 1 contains the per-axis sensor bias user registers and the user filter settings. Debug 2 contains the user magnetometer calibration matrix and the AHRS fusion parameters. Register values are raw u32; refer to the datasheet for their interpretation. Both frames are sent in response to OFD (oscp_cmd_of(..., OscpFrameSel::Debug, ...)) in CONFIG state.

Packed configuration bytes
Field Type Methods
gyro_filter_cfg / accel_filter_cfg (Debug 1) FilterCfg filters() [1:0], lpf() [4:2], hpf() [7:5]
fusion_cfg (Debug 2) FusionCfg fusion_convention() [3:0], fusion_heading_source() [7:4]

Debug frames contain counter but not timestamp_ms.


Startup frame - OscpStartup

Sent once at boot, and in response to SUF (oscp_cmd_suf(...)) in CONFIG state. Contains the unit identification and saved configuration.

Fields
Field Type Notes
header_byte OscpHeader -
mark_number [u8; 10] Byte array; see note below
unit_number u16 Unit number
sw_major_ver / sw_minor_ver / sw_patch_ver u8 Firmware version
enabled_frames u8 Bitmask, see below
dyn_range_cfg DynRangeCfg gyro_dr() [3:0], accel_dr() [7:4]
gyro_filter_cfg / accel_filter_cfg FilterCfg filters(), lpf(), hpf()
incl_ahrs_cfg InclAhrsCfg incl_dr() [3:0], ahrs_convention() [5:4], ahrs_heading_src() [7:6]
ahrs_gain / ahrs_accel_rej / ahrs_mag_rej f32 AHRS configuration
ahrs_rec_trig_per u32 AHRS recovery trigger period (s)
status u8 -
crc u16 -

enabled_frames masks:

Mask Value
OSCP_ENABLE_RAW 0x01
OSCP_ENABLE_EULER 0x02
OSCP_ENABLE_QUAT 0x04
OSCP_ENABLE_ROT_MAT 0x08
OSCP_ENABLE_GNSS 0x10

Reading back dynamic ranges

gyro_dr(), accel_dr() and incl_dr() return the 4-bit code reported by the unit. This code is not the value written by DRG, DRA or DRI and is not sequential. Convert it with from_dyn_range_code:

use oscp_imu::{OscpGyroDr, OscpAccelDr, OscpInclDr};

let gyro  = OscpGyroDr::from_dyn_range_code(s.dyn_range_cfg.gyro_dr());   /* e.g. Ok(OscpGyroDr::Dps250) */
let accel = OscpAccelDr::from_dyn_range_code(s.dyn_range_cfg.accel_dr());
let incl  = OscpInclDr::from_dyn_range_code(s.incl_ahrs_cfg.incl_dr());
Readback code mapping
Code Gyroscope Accelerometer Inclinometer
0b0000 ±250 °/s ±2 g ±0.5 g
0b0001 ±4000 °/s ±16 g ±3.0 g
0b0010 ±125 °/s ±4 g ±1.0 g
0b0011 - ±8 g ±2.0 g
0b0100 ±500 °/s - -
0b1000 ±1000 °/s - -
0b1100 ±2000 °/s - -

Unlisted codes return Err(code).

mark_number is a byte array

mark_number is 10 bytes with no terminator. UTF-8 validity is not guaranteed. Convert before printing and remove trailing padding:

let mark = core::str::from_utf8(&s.mark_number)
    .unwrap_or("<invalid>")
    .trim_end_matches('\0');

Struct layout

Frame structs are not packed. Each field is decoded with from_le_bytes into a naturally aligned struct, so field access has no alignment restrictions. All frame types implement Copy.


Next: Command reference →