sidescanpy.io.jsf.messages#

jsf messages - define message types for jsf files

JSF files are from EdgeTech Side Scan Sonars. They are binary formatted and contain a series of messages. Each message starts with a header that contains basic information about the message.

2025 rshomberg@uri.edu

Contents

class sidescanpy.io.jsf.messages.JSFMessageHeader(marker: int, protocol_version: int, session_ID: int, message_type: int, command_type: int, subsystem_num: int, channel: int, sequence_number: int, _reserved: int, message_size: int)#

Bases: object

to_bytes()#

Packs the dataclass fields into a 16-byte binary buffer.

class sidescanpy.io.jsf.messages.JSFMessage(*, _header)#

Bases: ABC

Abstract class representing a full JSF Message

to_full_packet()#

Combines the header and body into a single byte stream.

class sidescanpy.io.jsf.messages.SonarDataMessage(_raw_timestamp_sec: int, _starting_depth: int, ping_number: int, _reserved01: int, _reserved02: int, _most_significant_bits: int, _least_significant_bits: int, _least_significant_bits2: int, _reserved03: int, _reserved04: int, _reserved05: int, _id_code: int, _validity_flags: int, _reserved06: int, _data_format: int, _raw_y_distance_antenna_to_tow_point: int, _raw_x_distance_antenna_to_tow_point: int, _reserved07: int, _reserved08: int, _raw_pipe_dist_km: float, _reserved09: int, _reserved10: int, _reserved11: int, _reserved12: int, _reserved13: int, _reserved14: int, _reserved15: int, _reserved16: int, _reserved17: int, _reserved18: int, _reserved19: int, _reserved20: int, _reserved21: int, _reserved22: int, _reserved23: int, _reserved24: int, _raw_longitude: int, _raw_latitude: int, _coord_units_code: int, _annotation_str01: bytes, _annotation_str02: bytes, _annotation_str03: bytes, _annotation_str04: bytes, _annotation_str05: bytes, _annotation_str06: bytes, _annotation_str07: bytes, _annotation_str08: bytes, _annotation_str09: bytes, _annotation_str10: bytes, _annotation_str11: bytes, _annotation_str12: bytes, _annotation_str13: bytes, _annotation_str14: bytes, _annotation_str15: bytes, _annotation_str16: bytes, _annotation_str17: bytes, _annotation_str18: bytes, _annotation_str19: bytes, _annotation_str20: bytes, _annotation_str21: bytes, _annotation_str22: bytes, _annotation_str23: bytes, _annotation_str24: bytes, _raw_num_samples_lsb: int, _raw_sampling_interval_ns_msb: int, _gain_factor: int, _user_transmit_level: int, _reserved25: int, _raw_transmit_freq_start_lsb: int, _raw_transmit_freq_end_lsb: int, _raw_sweep_length_ms: int, _raw_pressure: int, _raw_depth: int, _raw_sample_freq: int, _pulse_id: int, _raw_altitude: int, sound_speed_ms: float | None, mixer_freq: float, _cpu_time_year: int, _cpu_time_day: int, _cpu_time_hour: int, _cpu_time_min: int, _cpu_time_sec: int, _cpu_time_basis: int, _weighting_factor: int, _number_of_pulses: int, _raw_compass_heading: int, _raw_pitch: int, _raw_roll: int, _reserved26: int, _reserved27: int, _trigger_source_code: int, _mark_number_code: int, _position_fix_hr: int, _position_fix_min: int, _position_fix_sec: int, _raw_course_msb: int, _raw_speed_msb: int, _position_fix_day: int, _position_fix_yr: int, _timestamp_day_offset_ms: int, _max_abs_adc_val: int, _reserved28: int, _reserved29: int, _sonar_software_version1: int, _sonar_software_version2: int, _sonar_software_version3: int, _sonar_software_version4: int, _sonar_software_version5: int, _sonar_software_version6: int, _init_spherical_correction_factor: int, _packet_number: int, _raw_adc_decimation: int, _reserved30: int, _raw_water_temp: int, _layback_distance: float, _reserved31: int, _raw_cable_out: int, _reserved32: int, _raw_trace_data: numpy.ndarray, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

property timestamp#

Returns the nanosecond timestamp as a NumPy datetime64 object.

class sidescanpy.io.jsf.messages.LegacySideScanDataMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.NavigationOffsetsMessage(x_offset: float, y_offset: float, latitude_offset: float, longitude_offset: float, aft_offset: float, starboard_offset: float, depth_offset: float, altitude_offset: float, heading_offset: float, pitch_offset: float, roll_offset: float, yaw_offset: float, tow_point_elevation_offset: float, reserved_1: float, reserved_2: float, reserved_3: float, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.SystemInformationMessage(system_type: int, low_rate_io_enabled_option: int, sonar_software_version: int, num_subsystems: int, num_serial_devices: int, tow_vehicle_serial: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.FileTimeStampMessage(_raw_time_seconds: int, _raw_offset_ms: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.FilePaddingMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.NMEAStringMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

to_bytes()#

Serializes fixed fields and appends the variable length NMEA string.

class sidescanpy.io.jsf.messages.NMEAGenericMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEADBTMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEAVTGMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEAGGAMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEARMCMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEAGLLMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEADPTMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.NMEAZDAMessage(_raw_time_seconds: int, _raw_offset_ms: int, source: int, _reserved01: int, _reserved02: int, _reserved03: int, _raw_message: str, *, _header: 'JSFMessageHeader')#

Bases: NMEAStringMessage

class sidescanpy.io.jsf.messages.PitchRollDataMessage(_raw_time_seconds, _raw_offset_ms, _reserved01, _reserved02, _reserved03, _reserved04, _raw_accel_x, _raw_accel_y, _raw_accel_z, _raw_rate_x, _raw_rate_y, _raw_rate_z, _raw_pitch, _raw_roll, _raw_temperature, _raw_diagnostics, _raw_heave, _raw_heading, _data_flags, _raw_yaw, _reserved05, *, _header)#

Bases: JSFMessage

Attitude sensor reading (JSF message type 2020).

Body layout per the EdgeTech JSF spec (44 bytes, little endian): int32 seconds since 1970, int32 milliseconds in the current second, 4 reserved bytes, int16 acceleration x/y/z (x 20*1.5/32768 G), int16 rate gyro x/y/z (x 500*1.5/32768 deg/s), int16 pitch and roll (x 180/32768 deg; bow up and port up positive), int16 temperature (0.1 degC), uint16 device-specific info, int16 heave (mm, positive down), uint16 heading (0.01 deg), int32 validity flags, int16 yaw (0.01 deg), int16 reserved.

A derived field is set only when its validity bit is set (bit 0-2 acceleration x/y/z, 3-5 rate x/y/z, 6 pitch, 7 roll, 8 heave, 9 heading, 10 temperature, 11 device info, 12 yaw); otherwise it stays None. Devices are known to clear bits for sensors they lack (for example heave and yaw) while setting pitch, roll and heading.

class sidescanpy.io.jsf.messages.PressureSensorReadingMessage(_raw_time_seconds: int, _raw_offset_ms: int, _reserved01: int, _reserved02: int, _reserved03: int, _reserved04: int, _raw_pressure: int, _raw_temperature: int, _raw_salinity: int, _data_flags: int, _raw_conductivity: int, _raw_sound_vel: int, _raw_depth: int, _reserved05: int, _reserved06: int, _reserved07: int, _reserved08: int, _reserved09: int, _reserved10: int, _reserved11: int, _reserved12: int, _reserved13: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

sidescanpy.io.jsf.messages.calculate_dvl_altitude_plane_fit(beam_distances, beam_angle=20.0)#

Calculate altitude, pitch, and roll from DVL 4-beam distances using plane fitting.

This method fits a plane to the 4 beam endpoints and extracts: - Altitude (vertical distance to the fitted plane) - Pitch (rotation about cross-track axis) - Roll (rotation about along-track axis)

DVL beams are typically arranged in a Janus configuration: - Beam 1: Forward-starboard (+x, +y) - Beam 2: Aft-starboard (-x, +y) - Beam 3: Aft-port (-x, -y) - Beam 4: Forward-port (+x, -y)

class sidescanpy.io.jsf.messages.DopplerVelocityLogDataMessage(_raw_time_seconds: int, _raw_offset_ms: int, _reserved01: int, _reserved02: int, _reserved03: int, _reserved04: int, _data_validity_flags: int, _raw_bottom_dist1: int, _raw_bottom_dist2: int, _raw_bottom_dist3: int, _raw_bottom_dist4: int, _raw_bottom_vel_x: int, _raw_bottom_vel_y: int, _raw_bottom_vel_z: int, _raw_water_vel_x: int, _raw_water_vel_y: int, _raw_water_vel_z: int, _raw_depth_from_depth_sensor: int, _raw_pitch: int, _raw_roll: int, _raw_heading: int, _raw_salinity: int, _raw_temperature: int, _raw_sound_vel: int, _reserved05: int, _reserved06: int, _reserved07: int, _reserved09: int, _reserved10: int, _reserved11: int, _reserved12: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.SituationMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.SituationComprehensiveMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.CableCounterDataMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.KilometerOfPipeDataMessage(*, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.ContainerTimeStampMessage(_raw_time_seconds: int, _raw_offset_ms: int, _reserved01: int, _reserved02: int, _reserved03: int, _reserved04: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.UnknownMessage2040(raw_0: int, raw_1: int, raw_2: int, raw_3: int, raw_4: int, raw_5: int, raw_6: int, raw_7: int, raw_8: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage

class sidescanpy.io.jsf.messages.SonarMessageStatusMessage(overflow_count: int, error_count: int, last_error_0: int, last_error_1: int, last_error_2: int, last_error_3: int, last_error_4: int, last_error_5: int, last_error_6: int, last_error_7: int, last_error_8: int, last_error_9: int, free_disk_space: int, data_acquisition_indicator: int, service_needed: int, reserved_37: int, reserved_38: int, storage_flags: int, temperature_status: int, time_status: int, reserved_42_43: int, bottle_temperature: int, ambient_temperature: int, power_48_volts: int, reserved_56_59: int, low_rate_io_0: int, low_rate_io_1: int, low_rate_io_2: int, low_rate_io_3: int, serial_port_state_0: int, serial_port_state_1: int, serial_port_state_2: int, serial_port_state_3: int, serial_port_state_4: int, serial_port_state_5: int, serial_port_state_6: int, serial_port_state_7: int, runtime_alerts: int, reserved_80: int, reserved_84: int, reserved_88: int, reserved_92: int, *, _header: 'JSFMessageHeader')#

Bases: JSFMessage