using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Linq; using System.Text; namespace EdgeTech.SonarComms.Demo { public class SonarMessage { const string _versionInfo = "$Header: SonarMessage.cs Revision:1.13 Mon Apr 23 15:45:28 2012 mps $"; private string versionInfo; public const UInt16 HEADER_MARKER = 0x1601; public const byte CURRENT_PROTOCOL_VERSION = 0x0A; public const int SONAR_PING_DISABLE = 0; public const int SONAR_PING_ENABLE = 1; public SonarMessage() { } public struct Header { public UInt16 StartOfHeader; // 0x1601 always public byte VersionNumber; // 0x0A (currently) public byte SessionID; public UInt16 MessageType; public byte CommandType; // Get, Set, or Reply public byte SubSystemNumber; // 0=Sub-Bottom, 20=Single or low freq SideScan, 21=High freq SS public byte ChannelNumber; // 0=Port, 1=Starboard public byte SequenceNumber; public UInt16 reserved; public UInt32 ByteCount; } //public Header sonarMessageHeader; public struct Packet { public Header msgHdr; public long msg; } //public Packet sonarPacket; /* ---------------------------------------------------------------------- */ /* Coupling Parameters data structure. */ /* ---------------------------------------------------------------------- */ public struct TriggerParametersType { /* Subsystem number to trigger this subsystem on */ public Int32 subSystem; /* Trigger mode - Specifies how system is triggered */ public UInt32 triggerMode; /* Trigger on every Nth event (minimum value of 1). */ public UInt32 triggerDivisor; /* Trigger delay in micro-seconds for external or coupled modes. */ /* Trigger inhibit time for gated mode. (minimum value of 0) */ public UInt32 triggerDelay; } /* ---------------------------------------------------------------------- */ /* Command Types */ /* ---------------------------------------------------------------------- */ /* Command type(sonarCommand in header). A topside will send SET */ /* commands, which return no values, GET commands, which return the */ /* current parameter set. The bottom unit only sends REPLY messages in */ /* response to a GET or unsolicited data. */ /* ---------------------------------------------------------------------- */ public enum SonarCommandType { /* Send a value or execute a command */ SONAR_COMMAND_SET = 0, /* Request current value / last value of item. All GETs can be sent */ /* with a byte count of 0. Some GET messages will accept parameters. */ /* See the individual message descriptions for details. */ SONAR_COMMAND_GET, /* Reply to a COMMAND_GET or unsolicited error msgs */ SONAR_COMMAND_REPLY, /* Error replay to a command. The command was not executed. */ /* In this case, the return value is the error (SonarMessageLongType) */ /* as defined by SonarMessageErrorType. */ SONAR_COMMAND_ERROR, /* Similar to a REPLY for the data socket, but is playback data. This */ /* will only occur when storage playback is enabled. */ SONAR_COMMAND_PLAYBACK, /* Similar to a REPLY for the data socket, but is QC data. This will */ /* only occur when QC data is enabled. */ SONAR_COMMAND_QUALITY, } /* ---------------------------------------------------------------------- */ /* Error codes that can be returned as SONAR_COMMAND_ERROR */ /* ---------------------------------------------------------------------- */ enum SonarMessageErrorType { /* 0: No error */ SONAR_MESSAGE_ERROR_NONE, /* 1: General command failure indicator */ SONAR_MESSAGE_ERROR_FAILED, /* 2: Message size does not match expected size */ SONAR_MESSAGE_ERROR_DATA_SIZE, /* 3: Subsystem number is not present in this system */ SONAR_MESSAGE_ERROR_SUBSYSTEM, /* 4: Channel number is not present in this system */ SONAR_MESSAGE_ERROR_CHANNEL, /* 5: sonarMessage field contains an unknown command */ SONAR_MESSAGE_ERROR_UNKNOWN, /* 6: Pulse file error. Pulse not loaded */ SONAR_MESSAGE_ERROR_PULSE_FILE, /* 7: Session ID error. Command rejected */ SONAR_MESSAGE_ERROR_SESSION_ID, /* 8: Override required: Command rejected */ SONAR_MESSAGE_ERROR_OVERRIDE_REQUIRED, } /* ---------------------------------------------------------------------- */ /* Message Types */ /* ---------------------------------------------------------------------- */ /* sonarMessage field indicates the type of data to follow. */ /* ---------------------------------------------------------------------- */ public enum SonarMessageType { /* -------------------------------------------------------------------- */ /* Overall commands. */ /* For the following messages, the channel and subSystem should be 0. */ /* -------------------------------------------------------------------- */ /* Null message - can be used to test communications */ SONAR_MESSAGE_NONE = MESSAGE_OFFSET_STANDARD, /* Reset to default values (No Data) on set */ /* Note: The subsystem should be 255 to reset the entire system or */ /* the specific subsystem number. The channel must be 0. */ SONAR_MESSAGE_SYSTEM_RESET, /* Get or set the time (TimestampType) */ /* Note that because of the nagle algorithm on sockets, the actual */ /* message can be delayed. To set the time with greater accuracy, say, */ /* within 10 ms, the nagle algorithm should be disabled by the sender. */ /* Or a subsequent message bigger than the maximum network packet size */ /* should be sent following this message (usually about 1600 bytes). */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ /* NOTE: The SONAR_MESSAGE_NONE message can be any size desired. */ SONAR_MESSAGE_SYSTEM_TIME, /* Change the time by the delta in milliseconds (SonarMessageLongType) */ /* NOTE that in order to get accurate time sync, a delta must be set via*/ /* this message, and it must be based on the GetTickCount() function. */ /* The normal GetSystemTime() is only accurate to about 50 ms. */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ /* The value is the difference in time between the sonar's time and the */ /* topsides time. Therefore this value should be subtracted from the */ /* sonar's local time base. */ SONAR_MESSAGE_TIME_DELTA, /* Get the software version string (SonarMessageStringType) */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. The version string consists of an alphabetic string */ /* followed by a version number of the form N.M where N and M are both */ /* integers. */ SONAR_MESSAGE_SYSTEM_VERSION, /* Shutdown System */ /* Accepts a (SonarMessageLongType), which can have any of the */ /* following values: 0: Exit sonar program only, 1: Shutdown, 2: Reboot */ SONAR_MESSAGE_SYSTEM_SHUTDOWN, /* User defined message */ /* Accepts a (UserDefinedMessageHeaderType) followed by user data. */ SONAR_MESSAGE_USER_DEFINED, /* Status request / returned (SonarMessageStatusType) */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ SONAR_MESSAGE_SYSTEM_STATUS = MESSAGE_OFFSET_STATUS, /* Alive messages are echoed back on the same connection. This allows */ /* for the detection of lost connection links. Accepts a long parameter*/ /* (SonarMessageLongType) which is echoed back to the caller and is */ /* typically a sequence number. */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ SONAR_MESSAGE_ALIVE, /* Override data lockout caused by suspected system failure in the */ /* sonar system. Once an overrride message is sent, the sonar system */ /* will not stop the data flow because of potential data quality */ /* problems. */ SONAR_MESSAGE_OVERRIDE, /* Run all of the power on self test diagnostics. This will normally */ /* cause an audible chirp on the subbottom (if present) and side scan */ /* low (if present) and other internal diagnostics. This can either */ /* cause OR CLEAR a POST error code. If a post error code is detected */ /* sonar data WILL NOT be returned to the topside unless an override */ /* message is sent. The subsystem and channel should be set to 0 for */ /* this message. The sonarCommand field in the header should be set to */ /* SONAR_COMMAND_GET as this command returns the post status bit field */ /* as the lsb 8 bits of its return value (SonarMessageLongType). See */ /* the SonarMessageStatusType and the serviceNeeded field for a list */ /* of the possible return values. */ SONAR_MESSAGE_RUN_POST_DIAGNOSTICS, /* Get the type of system (SonarMessageLongType). Where: */ /* 0 - No Acquisition */ /* 1 - single frequency multi-pulse sidescan */ /* 2 - single frequency sidescan - 560A - 272 towfish */ /* 3 - simultaneous dual frequency sidescan - 560D - DF1000 towfish */ /* 4 - simultaneous dual frequency sidescan */ /* 5 - sub-bottom sonar */ /* 6 - combined sub-bottom and dual frequency sidescan */ /* 7 - single frequency synthetic aperature sidescan */ /* 8 - single frequency sidescan */ /* 9 - simultaneous dual frequency multi-pulse sidescan */ /* 10 - 4125 ultra portable sidescan - two disparate configurations */ /* 11 - one frequency focused sidescan, one frequency standard */ /* 12 - single frequency multipulse Bathymetric system */ /* 13 - single frequency monopulse Bathymetric system */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ SONAR_MESSAGE_SYSTEM_TYPE, /* Get the operational status of the system (SonarMessageLongType). */ /* Where: 0 - Operational, 1 - Not operational. */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ SONAR_MESSAGE_SYSTEM_OPERATIONAL, /* Time sync status request / returned (SonarMessageTimesyncStatusType) */ /* Note: This is a system command, the subsystem and channel numbers */ /* must be 0. */ SONAR_MESSAGE_TIMESYNC_STATUS, /* -------------------------------------------------------------------- */ /* Sonar Return Data */ /* -------------------------------------------------------------------- */ /* Subbottom data returned to topside (JSFDataType) */ /* This is returned from the sonar and is not a command message. */ SONAR_MESSAGE_DATA = MESSAGE_OFFSET_DATA, /* Window for data transmission (SonarMessageWindowType) */ /* Subsystem and channel must be valid. */ SONAR_MESSAGE_DATA_NETWORK_WINDOW, /* Sidescan data returned to topside (SidescanHeaderType) */ /* This is returned from the sonar and is not a command message. */ SONAR_MESSAGE_DATA_SIDESCAN, /* Activate / Deactivate return data type. The data for the subsystem */ /* / channel specified in the header is activated / deactivated */ /* (0 - deactivate : 1 - activate) (SonarMessageLongType) */ /* Subsystem and channel must be valid. */ SONAR_MESSAGE_DATA_ACTIVE, /* -------------------------------------------------------------------- */ /* Compressed header data messages */ /* -------------------------------------------------------------------- */ /* Subbottom data returned to topside (CompactSonarHeaderType) */ /* This is returned from the sonar and is not a command message. */ /* The compression library will unpack this and replace with */ /* a SONAR_MESSAGE_DATA message. */ SONAR_MESSAGE_DATA_COMPACTHEADER, /* Sidescan data returned to topside (CompactSonarHeaderType) */ /* This is returned from the sonar and is not a command message. */ /* The compression library will unpack this and replace with */ /* a SONAR_MESSAGE_DATA_SIDESCAN message */ SONAR_MESSAGE_DATA_SIDESCAN_COMPACTHEADER, /* -------------------------------------------------------------------- */ /* SAS data messages */ /* -------------------------------------------------------------------- */ /* SAS data output for processing (SASDataType) */ /* this is returned from the SAS processor and is not a command message.*/ SONAR_MESSAGE_DATA_SAS, /* -------------------------------------------------------------------- */ /* Quality data messages */ /* -------------------------------------------------------------------- */ /* QC data parameters (SonarMessageQCParametersType) */ /* Subsystem must be valid. */ SONAR_MESSAGE_QC_PARAMETERS, /* -------------------------------------------------------------------- */ /* Processing of data */ /* -------------------------------------------------------------------- */ /* Window for processing optimization (SonarMessageWindowType) */ /* Subsystem and channel must be valid. */ SONAR_MESSAGE_PROCESSING_ENHANCE_WINDOW = MESSAGE_OFFSET_PROCESS, /* Samples to ignore due to direct path on AGC, normalization */ /* algorithms (SonarMessageLongType) */ /* Subsystem and channel must be valid. */ /* If this value is positive the units are output samples. If 0 or -1 */ /* agc processing starts at time 0 (and does not exclude the transmit */ /* pulse length. If less than -1, the units are considered to be micro */ /* seconds after the transmit pulse, so for example to exclude a return */ /* at the 3 ms point in the acoustic record use the value -3000. */ SONAR_MESSAGE_PROCESSING_DIRECT_PATH, /* -------------------------------------------------------------------- */ /* Management of pulses */ /* -------------------------------------------------------------------- */ /* Enable/disable ping: 0 => disable, 1=>enable (SonarMessageLongType) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING = MESSAGE_OFFSET_PULSES, /* 1000.0 * DAC gain to scale outgoing pulse by (SonarMessageLongType) */ /* Subsystem and channel must be valid. */ /* A value of 1000 will apply full power (the maximum amount aka 100%) */ SONAR_MESSAGE_PING_GAIN, /* A set message takes no parameters. A set message resets the list of */ /* pulse records so that the next get message will return the first */ /* record in the list. */ /* A get message with a (SonarMessageLongType) parameter, returns up to */ /* the specified number of pulse records as an array of */ /* (SonarMessagePingType) values, up to a maximum of 30. */ /* Note that the maximum pulses supported is 30, so requesting 30 will */ /* provide all possible pulses in one message. */ /* A get message can also be sent with no parameters, in this case it */ /* returns a single (SonarMessagePingType) structure. */ /* The pulse record following the last valid pulse record will have a */ /* NULL pulse name field. */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_LIST, /* Select an outgoing set of pulses, and matched filters. */ /* (SonarMessageStringType) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_SELECT, /* Number of pings pers second required * 1000 */ /* (SonarMessageLongType) */ /* Actual ping rate may be slightly lower (2048 sample granuality) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_RATE, /* Set trigger for internal(0), external(1), coupled(2), or gated(3) */ /* (SonarMessageLongType). Coupled mode causes a system to be triggered*/ /* by another one (eg Sidescan triggered by Subbottom) */ /* See SONAR_MESSAGE_PING_COUPLING_PARAMETERS message. In gated mode */ /* the external trigger is used as a trigger inhibit, and the inhibit */ /* time is based on the coupling parameter delay. */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_TRIGGER, /* Set delay for external trigger in ms (SonarMessageLongType). This */ /* message applies only to the soft trigger. A soft trigger uses the */ /* ethernet to transmit trigger requests to an underwater electronics */ /* bottle and is not present in an FS-SB standard system. See the */ /* SONAR_MESSAGE_PING_COUPLING_PARAMETERS message for a hardwired */ /* trigger delay. */ /* Note: This is a subsystem command, the channel number must be 0. */ /* */ /* WARNING: THIS MESSAGE IS NO LONGER SUPPORTED */ SONAR_MESSAGE_PING_DELAY, /* A get message takes a parameter that is 1000 * the ping rate in Hz. */ /* (SonarMessageLongType) and returns a (SonarMessageLongType) with the */ /* maximum number of samples that can be received for that ping rate. */ /* A get message can also be sent with no parameters, in this case it */ /* returns the maximum number of samples for the current ping rate. */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_MAX_SAMPLES, /* Set the ping rate for sidescan systems. Sets the ping rate based */ /* on the range in millimeters. (SonarMessageLongType) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_RANGE, /* Set the coupling parameters for this system when in trigger mode */ /* coupled, and the hardware trigger delay in external trigger modes. */ /* (TriggerParametersType) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_COUPLING_PARAMETERS, /* Get the list of human readable strings and fish IDs. Only a */ /* SONAR_COMMAND_GET message is meaningful. Returns an array of */ /* (SonarMessageFishType) records. The number of records can be */ /* determined by the size of the return message. */ /* This message should be used to get the available EdgeTech fish to */ /* present to the end user. The user should first select the fish */ /* which is attached to the sonar processing system, and should then */ /* select a pulse only from the subset of the selected fish. */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_FISH_LIST, /* Sets the (multi-ping) operating mode (SonarMessageLongType) */ /* Value 0 => Standard operating mode, 1 => Multiple ping mode */ /* This is a subsystem command and the channel should be set to 0. */ /* */ /* This message has a different effect on sub-bottom and sidescan */ /* systems. */ /* */ /* For sidescan systems: This message is handled by the Discover */ /* external topside interface, and switches the mode of the specified */ /* subsystem. Only one subsystem at a time may currently be in multiple*/ /* ping mode. If a subsystem is in multiple ping mode it is the only */ /* subsystem that may have pinging enabled. These restrictions may be */ /* altered in the future. */ /* */ /* For Sub-bottom systems: A value of 0, multiple pings are disabled, */ /* and data is referenced to the ping time. If the data window requires*/ /* more data than can be provided for the specified ping rate, then the */ /* ping rate will be reduced. */ /* A value of 1, multiple pings are enabled, and the data window will */ /* NOT effect the ping rate. In this case, the initialSkip parameter */ /* of the data window determines which ping time in the history buffer */ /* to reference when delivering data. A data window is not permitted to*/ /* cross ping boundaries, and if the initial skip plus the number of */ /* samples desired (suitably decimated) cases the window to either cross*/ /* ping boundaries or deliver "invalid" data at the end of a ping */ /* (equivelent to the pulse length) then the amount of data delivered */ /* will be reduced. On some systems, or in external trigger mode this */ /* can cause the amount of data delivered to vary from ping to ping. */ /* When multiple pings are enabled, a history buffer of prior pings is */ /* maintained. Since this history is 8 entrys deep, the maximum number */ /* of pings in the water is 8. This value may change in the future. */ SONAR_MESSAGE_PING_MODE, /* A set message takes no parameters. A set message resets the list of */ /* pulse records so that the next get message will return the first */ /* record in the list. */ /* A get message with a (SonarMessageLongType) parameter, returns up to */ /* the specified number of pulse records as an array of */ /* (SonarMessagePingEnhancedType) values, up to a maximum of 30. */ /* Note that the maximum pulses supported is 30, so requesting 30 will */ /* provide all possible pulses in one message. */ /* A get message can also be sent with no parameters, in this case it */ /* returns a single (SonarMessagePingEnhancedType) structure. */ /* The pulse record following the last valid pulse record will have a */ /* NULL pulse name field. */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_PING_LIST_ENHANCED, /* Set the pulse auto select mode. When non-zero, auto pulse selection */ /* is enabled. When enabled, pulses cannot be selected via PING_SELECT */ /* messages, but are determined by the operating ping rate or range. */ /* The parameter passed (SonarMessageLongType) is the maximum number of */ /* pulses in the water for a Multiping sidescan type system. Set this */ /* to 1 to disable multiping but enable auto mode. The presently */ /* supported values are 0 through 4. This is a subsystem level command */ /* and the channel number should be set to 0. */ SONAR_MESSAGE_PING_AUTOSELECTMODE, /* -------------------------------------------------------------------- */ /* ADC Control */ /* -------------------------------------------------------------------- */ /* Set gain factor for ADC when AGC disabled (SonarMessageLongType) */ /* Value is * 1000.0 (only 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, */ /* and 2048 supported) */ /* Subsystem and channel must be valid. Ignored on sidescan systems. */ SONAR_MESSAGE_ADC_GAIN = MESSAGE_OFFSET_ADC, /* 0=> disable, 1=> enable (Automatic Gain Control) */ /* (SonarMessageLongType) */ /* Subsystem and channel must be valid. Ignored on sidescan systems. */ SONAR_MESSAGE_ADC_AGC, /* ADC rate in Hz * 1000. This is a read only value and changes with */ /* the pulse selected (SonarMessageLongType) */ /* Note: This is a subsystem command, the channel number must be 0. */ SONAR_MESSAGE_ADC_RATE, } // End SonarMessageType /* ---------------------------------------------------------------------- */ /* Message offsets for each message type. */ /* ---------------------------------------------------------------------- */ /* Starting message offset for standard messages */ const int MESSAGE_OFFSET_STANDARD = 20; /* Starting message offset for standard status messages */ const int MESSAGE_OFFSET_STATUS = 40; /* Starting message offset for standard data messages */ const int MESSAGE_OFFSET_DATA = 80; /* Starting message offset for standard processing messages */ const int MESSAGE_OFFSET_PROCESS = 100; /* Starting message offset for standard pulse messages */ const int MESSAGE_OFFSET_PULSES = 120; /* Starting message offset for standard ADC messages */ const int MESSAGE_OFFSET_ADC = 140; /* Starting message offset for playback messages */ const int MESSAGE_OFFSET_PLAYBACK = 160; /* Startng message offset for system level messages */ const int MESSAGE_OFFSET_SYSTEM = 180; /* ---------------------------------------------------------------------- */ /* Message offsets for storage messages */ /* ---------------------------------------------------------------------- */ /* Starting message offset for storage file messages */ const int MESSAGE_OFFSET_STORAGE_FILE = 420; /* Starting message offset for storage return messages */ const int MESSAGE_OFFSET_STORAGE_RETURN = 440; /* Index file messages = FileIndexMessages.h; */ const int MESSAGE_OFFSET_FILEINDEX = 460; /* ---------------------------------------------------------------------- */ /* Message offsets for dynamic focus sidescan */ /* ---------------------------------------------------------------------- */ /* Starting message offset for Dynamic focus messages */ const int MESSAGE_OFFSET_DF = 1320; /* ---------------------------------------------------------------------- */ /* Message offsets for device messages */ /* ---------------------------------------------------------------------- */ /* Starting message offset for device messages */ const int MESSAGE_OFFSET_DEV = 2000; /* Starting message offset for device messages */ const int MESSAGE_OFFSET_DEV_GENERIC = 2008; /* Starting message offset for Pitch / Roll device messages */ const int MESSAGE_OFFSET_DEV_PITCHROLL = 2020; /* Starting message offset for analog inputs */ const int MESSAGE_OFFSET_DEV_ANALOGIO = 2040; /* Starting message offset for Pressure sensor device messages. */ const int MESSAGE_OFFSET_DEV_PRESSURE = 2060; /* Starting message offset for Pressure sensor device messages. */ const int MESSAGE_OFFSET_DEV_ALTITUDE = 2070; /* Starting message offset for DVL sensor device messages. */ const int MESSAGE_OFFSET_DEV_DVL = 2080; /* Starting message offset for comprehensive situation messages. */ const int MESSAGE_OFFSET_DEV_SITUATION = 2090; /* Starting message offset for cable handling devices */ const int MESSAGE_OFFSET_DEV_MISC = 2100; /* Starting message offset for container messages */ const int MESSAGE_OFFSET_CONTAINER = 2110; /* starting offset for bathymetric data messages */ const int MESSAGE_OFFSET_BATHYMETRIC_DATA = 3000; /* starting offset for bathymetric control messages */ const int MESSAGE_OFFSET_BATHYMETRIC_CONTROL = 3030; /* ---------------------------------------------------------------------- */ /* Message offsets for Discover interface messages */ /* ---------------------------------------------------------------------- */ public const int MESSAGE_OFFSET_DISCOVER = 8000; public const int MESSAGE_OFFSET_DISCOVER_272 = 8020; public const int MESSAGE_OFFSET_DISCOVER_4125 = 8025; public const int MESSAGE_OFFSET_DISCOVER_LOGGING = 8030; public const int MESSAGE_OFFSET_DISCOVER_DATA = 8060; public const int MESSAGE_OFFSET_DISCOVER_SB = 8100; /* ---------------------------------------------------------------------- */ /* Other miscellaneous constants */ /* ---------------------------------------------------------------------- */ public const int FILE_NAME_SIZE = 80; public const int SONAR_MESSAGE_STRING_LENGTH = 256; public const int MAX_PULSES_PER_PULSEFILE = 8; public const int MAX_NUM_ENTRIES_IN_PULSE_LIST = 30; // Use [StructLayout...] attribute to accomodate old C-style fixed-length // string used in fileName [StructLayout(LayoutKind.Sequential)] public class SonarMessagePingType { // Emulate C-style: char fileName[FILE_NAME_SIZE]; // in C# by using [MarshalAs...] attribute and string type: /* Name used to identify this pulse for selection. */ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = FILE_NAME_SIZE)] public string fileName; // Size = FILE_NAME_SIZE /* Type of pulse. */ /* If non-zero, bits 4 and up should encode the MPX number which is 1 */ /* for non-multiping pulses and 2 for mpx 2 pulses. */ public UInt16 pulseType; /* approximate maximum ping rate in Hz. */ public byte maxPingRate; /* approximate data sample rate in kHz. */ public byte dataRate; /* Minimum frequency in Hz. */ public UInt32 fMin; /* Maximum frequency in Hz. */ public UInt32 fMax; /* Pulse duration in milliSeconds */ public UInt32 time; /* Unique pulse identifier */ public UInt16 pulseID; /* Unused field - round to long boundary. */ public UInt16 reserved; /* Pulse description - null terminated ASCII string */ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SONAR_MESSAGE_STRING_LENGTH)] public string description; // Size = SONAR_MESSAGE_STRING_LENGTH /* Type of sonar pulse was designed for. */ public UInt32 systemType; } // public struct SonarMessagePingType [StructLayout(LayoutKind.Sequential)] public class SonarMessagePingEnhancedType { /* Name used to identify this pulse for selection. */ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = FILE_NAME_SIZE)] public string fileName; // Size = FILE_NAME_SIZE /* Type of pulse. */ UInt16 pulseType; /* Number of pulses for multiping */ UInt16 numberOfPulses; /* approximate maximum ping rate in Hz. */ float maxPingRate; /* approximate data sample rate in kHz. */ /* For processed data */ float dataRate; /* Minimum frequency in Hz. */ /* Index 0 : Port or single channel */ /* Index 1 : Stbd if present */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * MAX_PULSES_PER_PULSEFILE)] float[,] fMin = new float[2, MAX_PULSES_PER_PULSEFILE]; /* Maximum frequency in Hz. */ /* Index 0 : Port or single channel */ /* Index 1 : Stbd if present */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * MAX_PULSES_PER_PULSEFILE)] float[,] fMax = new float[2, MAX_PULSES_PER_PULSEFILE]; /* Pulse duration in milliSeconds */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2 * MAX_PULSES_PER_PULSEFILE)] float[,] time = new float[2, MAX_PULSES_PER_PULSEFILE]; /* Unique pulse identifier */ UInt16 pulseID; /* Unused field - round to long boundary. */ UInt16 reserved; /* Pulse description - null terminated ASCII string */ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SONAR_MESSAGE_STRING_LENGTH)] public string description; // Size = SONAR_MESSAGE_STRING_LENGTH /* Type of sonar pulse was designed for. */ UInt32 systemType; /* Option bits */ /* Bit 0: When set data is basebanded. When clear data is decimated */ /* This option effects where the data is in the frequency space. */ int flags; /* Reserved for future use */ int[] reserved2; // num elements = 16 } // Use [StructLayout...] attribute to accomodate fields that contain arrays [StructLayout(LayoutKind.Sequential)] public class SonarDataMessageHeaderType { /* 0 - 3 : Time in seconds since 1/1/1970 (standard time() value) */ /* Use with (millisecondsToday mod 1000) to get a full time stamp */ int timeSince1970; /* 4 - 7 : Starting depth (window offset) in samples. */ UInt32 startDepth; /* 8 - 11 : Ping number (increments with ping) */ public UInt32 pingNum; /* 12 - 15 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] Int16[] reserved0 = new Int16[2]; /* 16 - 17 : Most Significant Bits */ /* high order bits for fields requiring greater range */ /* Bits 0 - 3 startFreq - Start Frequency */ /* Bits 4 - 7 endFreq - End Frequency */ /* Bits 8 - 11 samples - Samples in this packet */ /* Bits 12 - 15 Reserved */ /* This field was added in protocol version 0xA, and was previously 0 */ UInt16 MSB1; /* 18 - 27 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] Int16[] reserved1 = new Int16[5]; /* 28 - 29 : ID Code (always 1 = seismic data) */ Int16 traceIDCode; /* 30 - 31 : Validity flags bitmap */ /* Bit 0 : Lat Lon or XY valid */ /* Bit 1 : Course valid */ /* Bit 2 : Speed valid */ /* Bit 3 : Heading valid */ /* Bit 4 : Pressure valid */ /* Bit 5 : Pitch roll valid */ /* Bit 6 : Altitude valid */ /* Bit 7 : Reserved */ /* Bit 8 : Water temperature valid */ /* Bit 9 : Depth valid */ /* Bit 10 : Annotaiton valid */ /* Bit 11 : Cable counter valid */ /* Bit 12 : KP valid */ /* Bit 13 : Position interpolated */ UInt16 validityFlags; /* 32 - 33 : Reserved - do not use */ UInt16 reserved2; /* 34 - 35 : DataFormatType */ /* 0 = 1 short per sample - envelope data */ /* the total number of bytes of data to follow is 2 * samples. */ /* 1 = 2 shorts per sample - stored as real(1), imag(1), */ /* the total number of bytes of data to follow is 4 * samples. */ /* 2 = 1 short per sample - before matched filter (raw) */ /* the total number of bytes of data to follow is 2 * samples. */ /* 3 = 1 short per sample - real part analytic signal */ /* the total number of bytes of data to follow is 2 * samples. */ /* 4 = 1 short per sample - pixel data / ceros data */ /* the total number of bytes of data to follow is 2 * samples. */ /* 5 = 1 byte per sample - pixel data */ /* the total number of bytes of data to follow is 1 * samples. */ /* 6 = 1 Int32 per sample - raw data */ /* the total number of bytes of data to follow is 4 * samples. */ /* 7 = 2 floats per sample - stored as real(1), imag(1), */ /* the total number of bytes of data to follow is 8 * samples. */ /* 8 = 1 float per sample - envelope data */ /* the total number of bytes of data to follow is 4 * samples. */ /* 9 = 2 shorts per sample - stored as real(1), imag(1), */ /* the total number of bytes of data to follow is 4 * samples. */ /* This is the code for unmatchfiltered analytic data whereas value 1 */ /* is intended for match filtered analytic data. */ /* ----- */ /* NOTE: Values greater than 255 indicate that the data to follow is */ /* compressed and must be decompressed prior to use via the */ /* decompression dll or other means. */ Int16 dataFormat; /* 36 - 37 : Aft distance from antennae to tow point in cm */ Int16 NMEAantennaeR; /* 38 - 39 : Starboard distance from antennae to tow point in cm */ Int16 NMEAantennaeO; /* 40 - 43 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] Int16[] reserved3 = new Int16[2]; /* 44 - 47 : KP kilometer of pipe (kilometers) */ /* validity flag bit 12 */ float kp; /* 48 - 79 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] Int16[] reserved4 = new Int16[16]; /* -------------------------------------------------------------------- */ /* Navigation data : */ /* If the coorUnits are seconds(2), the x values represent longitude */ /* and the y values represent latitude. A positive value designates */ /* the number of seconds east of Greenwich Meridian or north of the */ /* equator. */ /* -------------------------------------------------------------------- */ /* 80 - 83 : Longitude in 10000 * (Minutes of Arc) or X in mm */ /* validity flag bit 0 */ Int32 groupCoordX; /* 84 - 87 : Latitude in 10000 * (Minutes of Arc) or Y in mm */ /* validity flag bit 0 */ Int32 groupCoordY; /* 88 - 89 : Units of coordinates - 1->length mm(x/y), 2->10000 * */ /* (Minutes of Arc), 3->length in dm. */ Int16 coordUnits; /* 90 - 113 : Annotation string */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] sbyte[] annotation = new sbyte[24]; /* 114 - 115 : Samples in this packet */ /* Note: Use the message header byte count in conjunction with the */ /* dataformat field to determine if the actual number of samples */ /* can exceed 65535. if the true number of samples exceeds 65535,*/ /* then this is the 16-lsbs of the number of samples. */ /* */ /* Note: For protocol versions 0xA and above, the MSB1 field should */ /* include the MSBS needed to determine the number of samples. */ /* See field MSB1 for MSBs for large sample sizes. */ UInt16 samples; /* 116 - 119 : Sample interval in ns of stored data */ UInt32 sampleInterval; /* 120 - 121 : Gain factor of ADC */ UInt16 ADCGain; /* 122 - 123 : user pulse power setting (0 - 100) percent */ Int16 pulsePower; /* 124 - 125 : Reserved - do not use */ Int16 reserved5; /* 126 - 127 : Starting frequency in daHz (10 Hz) */ /* See field MSB1 for MSBS for large frequency values ( > 655350). */ UInt16 startFreq; /* 128 - 129 : Ending frequency in daHz (10 Hz) */ /* See field MSB1 for MSBS for large frequency values ( > 655350). */ UInt16 endFreq; /* 130 - 131 : Sweep length in ms */ UInt16 sweepLength; /* 132 - 135 : Pressure in milliPSI - (1/1000 PSI) */ /* validity flag bit 4 */ Int32 pressure; /* 136 - 139 : Depth estimate in mm */ /* validity flag bit 9 */ Int32 depth; /* 140 - 141 : Sample rate in Hz mod 65536 */ /* Note: For Raw data it is 1/2 the sampling rate mod 65536. */ UInt16 sampleRate; /* 142 - 143 : Unique pulse identifier */ UInt16 pulseID; /* 144 - 147 : Altitude in mm */ /* validity flag bit 6 */ Int32 altitude; /* 148 - 155 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] Int32[] reserved6 = new Int32[2]; /* 156 - 157 : Year data recorded (CPU time) */ Int16 year; /* 158 - 159 : day */ Int16 day; /* 160 - 161 : hour */ Int16 hour; /* 162 - 163 : minute */ Int16 minute; /* 164 - 165 : second */ Int16 second; /* 166 - 167 : Always 3 */ Int16 timeBasis; /* 168 - 169 : weighting factor for block floating point expansion */ /* -- defined as 2 -N volts for lsb */ /* IMPORTANT: All data MUST be scaled by pow(2, -weightingFactor) */ /* DO NOT IGNORE THIS VALUE. */ Int16 weightingFactor; /* 170 - 171 : Number of pulses in the water */ Int16 numPulses; /* -------------------------------------------------------------------- */ /* From pitch/roll/temp/heading sensor(s) */ /* -------------------------------------------------------------------- */ /* 172 - 173 : Compass heading 0.00 to 360.00 degrees in 1/100 degree */ /* validity flag bit 3 */ UInt16 heading; /* 174 - 175 : Pitch ((degrees / 180.0) * 32768.0) maximum resolution */ /* -- positive values indicate bow up. */ /* validity flag bit 5 */ Int16 pitch; /* 176 - 177 : Roll ((degrees / 180.0) * 32768.0) maximum resolution */ /* -- positive values indicate port up. */ /* validity flag bit 5 */ Int16 roll; /* 178 - 179 : Temperature (10 * degrees C) of towfish electronics. */ Int16 temperature; /* -------------------------------------------------------------------- */ /* User defined area from 180-239 */ /* -------------------------------------------------------------------- */ /* 180 - 181 : Reserved - do not use */ Int16 reserved7; /* 182 - 183 : TriggerSource (0 = internal, 1 = external, 2 - coupled) */ Int16 trigSource; /* 184 - 185 : Mark Number (0 = no mark) */ UInt16 markNumber; /* Note that the NMEA time fields are the time of the GPS fix and come */ /* from the same sentence which reported the fix. */ /* 186 - 187 : Hour */ Int16 NMEAHour; /* 188 - 189 : Minutes */ Int16 NMEAMinutes; /* 190 - 191 : Seconds */ Int16 NMEASeconds; /* 192 - 193 : Course in degrees */ /* validity flag bit 1 */ Int16 NMEACourse; /* 194 - 195 : Speed in tenths of a knot */ /* validity flag bit 2 */ Int16 NMEASpeed; /* 196 - 197 : Day */ /* Note: Will be 0 if NMEA sentence does not have this field */ Int16 NMEADay; /* 198 - 199 : Year */ /* Note: Will be 0 if NMEA sentence does not have this field */ Int16 NMEAYear; /* 200 - 203 : Millieconds today */ /* Use with seconds since 1970 to get time to the ms */ UInt32 millisecondsToday; /* 204 - 205 : Maximum absolute value of ADC samples for this packet */ UInt16 ADCMax; /* 206 - 209 : Reserved - do not use */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] Int16[] reserved8 = new Int16[2]; /* 210 - 215 : Sonar Software version number */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] sbyte[] softwareVersion = new sbyte[6]; /* 216 - 219 : Initial spherical correction factor in samples. */ /* A value of -1 indicates that the spherical spreading is disabled. */ Int32 sphericalCorrection; /* 220 - 221 : Packet number - Each ping starts with packet 1 */ UInt16 packetNum; /* 222 - 223 : A/D decimation * 100 before FFT */ Int16 ADCDecimation; /* 224 - 225 : Decimation factor after FFT */ Int16 decimation; /* 226 - 227 : Water Temperature in 1/10 degree C */ /* validity flag bit 8 */ Int16 waterTemperature; /* 228 - 231 : Distance to the fish in meters */ float layback; /* 232 - 235 : Reserved - do not use */ Int32 reserved9; /* 236 - 237 : cable out in decimeters */ /* validity flag bit 11 */ UInt16 cableOut; /* 238 - 239 : Reserved - do not use */ UInt16 reserved10; /* -------------------------------------------------------------------- */ /* Data area begins here */ /* -------------------------------------------------------------------- */ /* Data begins at byte 240, has this.samples data points in it */ /* Normally : Int16 data[] (see dataFormat field); */ /* -------------------------------------------------------------------- */ } // public struct SonarDataMessageHeaderType public string getVersionInfo() { versionInfo = _versionInfo.Remove(0, 9); string endStr = " mps $"; char[] end = endStr.ToCharArray(); versionInfo = versionInfo.TrimEnd(end); return versionInfo; } } // public class SonarMessage }