--[[ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE AGREEMENT THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ This file is property of the SICK AG BU83 Author : Evgenii Zorin and Lukas Schwender This programm is a Wireshark dissector which adds a interpretation of the SICK data protocol "Compact" into the Wireshark enviroment and allows a interpretation of specific data fields. RESTRICTIONS: - Measurement Data restricted to Port 2115 for UDP and TCP/IP - IMU Data restricted to Port 7503 for UDP - Support of COMPACT format telegram version 4 - Support of IMU format telegram version 1 Decrease amount of streaming data for real time dissecting (use Data reduction Interval filter) for the best performance NOTE: This programm should be used as a troubleshooting tool for SICK AG employees, SSU members and customers. This programm does not follow the SICK AG coding styles or the company quality standards. SOURCE: https://mika-s.github.io/wireshark/lua/dissector/2017/11/04/creating-a-wireshark-dissector-in-lua-1.html ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ]]-- local plugin_info = { version = "V3.7", author = "Evgenii Zorin, Lukas Schwender", description = "Compact Data protocol SICK AG" } set_plugin_info(plugin_info) --[[ INTEGRATE SCRIPT TO WIRESHARK ----------------------------- 1) Open Wireshark 2) Help -> About Wireshark 3) Folders -> Global Lua Plugins 4) Double klick 5) Place the file in the folder 6) Press Ctrl + Shift + L to load the script ENABLE / DISABLE IN WIRESHARK ----------------------------- 1) Analize -> Enabled Protocols... 2) Search "compact" 3) Activate / deactivate -> OK ]]-- --[[ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SETTINGS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ]]-- -- Destination UDP Port of the protocol CompactPort = 2115 -- Measurement Data port IMUPort = 7503 -- IMU Data port -- If format structure will be changed, adjust sizes and offsets for Header, Meta Data, Measuremen Data, IMU Data, and CRC. -- Script should automatically redesign all fields. I hope :) -- ** Offsets for Header ** --[[ Header | 32 Bytes | | 0, 32 -------------------------------------------------------------- startOfFrame | 4 Bytes | UINT32 | 0, 4 commandId | 4 Bytes | UINT32 | 4, 4 telegramCounter | 8 Bytes | UINT64 | 8, 8 timeStampTransmit | 8 Bytes | UINT64 | 16, 8 telegramVersion | 4 Bytes | UINT32 | 24, 4 sizeModule0 | 8 Bytes | UINT64 | 28, 4 --]] local Header_offset = { ["Header"] = {0, 32}, ---------------------------------- ["startOfFrame"] = {0, 4}, ["commandId"] = {4, 4}, ["telegramCounter"] = {8, 8}, ["timeStampTransmit"] = {16, 8}, ["telegramVersion"] = {24, 4}, ["sizeModule0"] = {28, 4}, } -- ** Offsets for CRC ** --[[ CRC | Bytes | | 0, 4 --]] local CRC_offset = { ["CRC"] = {0, 4}, ---------------------------------- } -- ** Offsets for Meta Data ** --[[ Meta Data | 72 Bytes | | 0, 72 -------------------------------------------------------------- SegmentCounter | 8 Bytes | UINT64 | 0, 8 FrameNumber | 8 Bytes | UINT64 | 8, 8 SenderId | 4 Bytes | UINT32 | 16, 4 NumberOfLinesInModule | 4 Bytes | UINT32 | 20, 4 NumberOfBeamsPerScan | 4 Bytes | UINT32 | 24, 4 NumberOfEchosPerBeam | 4 Bytes | UINT32 | 28, 4 TimeStampStart | 8*n Bytes | [UINT64] | 32, 8 Array; n = Number of elements TimeStampStop | 8*n Bytes | [UINT64] | 40, 8 Array; n = Number of elements Phi | 4*n Bytes | [FLOAT] | 48, 4 Array; n = Number of elements ThetaStart | 4*n Bytes | [FLOAT] | 52, 4 Array; n = Number of elements ThetaStop | 4*n Bytes | [FLOAT] | 56, 4 Array; n = Number of elements DistanceScalingFactor | 4 Bytes | FLOAT | 60, 4 NextModuleSize | 4 Bytes | FLOAT | 64, 4 Reserved1 | 1 Byte | FLOAT | 68, 1 DataContentEchos | 1 Byte | UINT32 | 69, 1 DataContentBeams | 1 Byte | UINT8 | 70, 1 Reserved2 | 1 Byte | UINT8 | 71, 1 --]] local Metadata_offset = { ["Meta Data"] = {0, 72}, -------------------------------------- ["SegmentCounter"] = {0, 8}, ["FrameNumber"] = {8, 8}, ["SenderId"] = {16, 4}, ["NumberOfLinesInModule"] = {20, 4}, ["NumberOfBeamsPerScan"] = {24, 4}, ["NumberOfEchosPerBeam"] = {28, 4}, ["TimeStampStart"] = {32, 8}, ["TimeStampStop"] = {40, 8}, ["Phi"] = {48, 4}, ["ThetaStart"] = {52, 4}, ["ThetaStop"] = {56, 4}, ["DistanceScalingFactor"] = {60, 4}, ["NextModuleSize"] = {64, 4}, ["Reserved1"] = {68, 1}, ["DataContentEchos"] = {69, 1}, ["DataContentBeams"] = {70, 1}, ["Reserved2"] = {71, 1}, } -- ** Offsets for Measurement Data --[[ Measurement Data | 7 Byte | | 0, 7 ------------------------------------------------------------- Distance | 2 Byte | UINT16 | 0, 2 RSSI | 2 Byte | UINT16 | 2, 2 Beam characteristics | 1 Byte | UINT8 | 4, 1 Azimuth angle (theta) | 2 Byte | UINT16 | 5, 2 | echo 0 | echo 1 | echo 2 | ----------------------------------------------------------------------------------------------------------------- | distance_0 | rssi_0 | distance_1 | rssi_0 | distance_2 | rssi_2 | properties | theta | ----------------------------------------------------------------------------------------------------------------- | Described by DataContentEchoes | Described byData | ContentBeams --]] local MeasurementData_offset = { ["MeasurementData"] = {0, 7}, ------------------------------------- ["Distance"] = {0, 2}, ["RSSI"] = {2, 2}, ["Beam characteristics"] = {4, 1}, ["Azimuth angle (theta)"] = {5, 2}, } -- ** Offsets for IMU data --[[ IMU Data | Byte | | 0, 64 ------------------------------------------------------------- Start of Frame | 4 Bytes | UINT32 | 0, 4 Command ID | 4 Bytes | UINT32 | 4, 4 Telegram version | 4 Bytes | UINT32 | 8, 4 Acceleration x | 4 Bytes | FLOAT | 12, 4 Acceleration y | 4 Bytes | FLOAT | 16, 4 Acceleration z | 4 Bytes | FLOAT | 20, 4 Angular velocity x | 4 Bytes | FLOAT | 24, 4 Angular velocity y | 4 Bytes | FLOAT | 28, 4 Angular velocity z | 4 Bytes | FLOAT | 32, 4 Orientation quaternion w | 4 Bytes | FLOAT | 36, 4 Orientation quaternion x | 4 Bytes | FLOAT | 40, 4 Orientation quaternion y | 4 Bytes | FLOAT | 44, 4 Orientation quaternion z | 4 Bytes | FLOAT | 48, 4 IMU sensor time stamp | 8 Bytes | UINT64 | 52, 8 Check sum | 4 Bytes | UINT32 | 60, 4 --]] local IMUData_offset = { ["IMUData"] = {0, 64}, ------------------------------------------ ["Start of Frame"] = {0, 4}, ["Command ID"] = {4, 4}, ["Telegram version"] = {8, 4}, ["Acceleration x"] = {12, 4}, ["Acceleration y"] = {16, 4}, ["Acceleration z"] = {20, 4}, ["Angular velocity x"] = {24, 4}, ["Angular velocity y"] = {28, 4}, ["Angular velocity z"] = {32, 4}, ["Orientation quaternion w"] = {36, 4}, ["Orientation quaternion x"] = {40, 4}, ["Orientation quaternion y"] = {44, 4}, ["Orientation quaternion z"] = {48, 4}, ["IMU sensor time stamp"] = {52, 8}, ["Check sum"] = {60, 4}, } -- Create a single Wireshark "Prot" (Protocol) object with name (1) and decription (2) called SICK__CompactProtocol. -- Proto element contains message fields and dissector function SICK__CompactProtocol = Proto("Compact", "Compact Data Procol SICK AG") --[[ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PROTOFIELD FIELDS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ]]-- -- Define Wireshark "ProtoFields". -- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr] --[[ type: Field Type: one of: ftypes.BOOLEAN, ftypes.CHAR, ftypes.UINT8, ftypes.UINT16, ftypes.UINT24, ftypes.UINT32, ftypes.UINT64, ftypes.INT8, ftypes.INT16, ftypes.INT24, ftypes.INT32, ftypes.INT64, ftypes.FLOAT, ftypes.DOUBLE , ftypes.ABSOLUTE_TIME, ftypes.RELATIVE_TIME, ftypes.STRING, ftypes.STRINGZ, ftypes.UINT_STRING, ftypes.ETHER, ftypes.BYTES, ftypes.UINT_BYTES, ftypes.IPv4, ftypes.IPv6, ftypes.IPXNET, ftypes.FRAMENUM, ftypes.PCRE, ftypes.GUID, ftypes.OID, ftypes.PROTOCOL, ftypes.REL_OID, ftypes.SYSTEM_ID, ftypes.EUI64 or ftypes.NONE. base (optional): The representation, one of: base.NONE, base.DEC, base.HEX, base.OCT, base.DEC_HEX, base.HEX_DEC, base.UNIT_STRING or base.RANGE_STRING. mask: To show only 0 bit in the ProtoFiel, use mask 0x01 | 0000 0001 To show only 1 bit in the ProtoFiel, use mask 0x02 | 0000 0010 To show only 0 and 1 bit in the ProtoFiel, use mask 0x03 | 0000 0011 ]]-- -- ** valuestring ** local Status_bool = {[0] = "False", [1] = "True"} -- ** HEADER - GENERAL** StartOfFrame = ProtoField.new("Start Of Frame\t\t", "compact.startOfFrame", ftypes.UINT32, nill, base.HEX) CommandId = ProtoField.new("Command Id\t\t\t", "compact.commandId", ftypes.UINT32, nill, base.DEC) -- ** HEADER - DATA** TelegramCounter = ProtoField.new("Telegram Counter\t\t", "compact.telegramCounter",ftypes.UINT64, nill, base.DEC) TimeStampTransmit = ProtoField.new("Time Stamp Transmit\t\t", "compact.timeStampTransmit",ftypes.ABSOLUTE_TIME, nill, base.UTC) TelegramVersion = ProtoField.new("Telegram Version\t\t", "compact.telegramVersion",ftypes.UINT32, nill, base.DEC) SizeModule0 = ProtoField.new("Size of Module 0\t\t", "compact.sizeModule0",ftypes.UINT32, nill, base.DEC) -- ** Meta Data ** SegmentCounter = ProtoField.new("Segment Counter\t\t", "compact.segmentCounter", ftypes.UINT64, nill, base.DEC) FrameNumber = ProtoField.new("Frame Number\t\t", "compact.frameNumber", ftypes.UINT64, nill, base.DEC) SenderId = ProtoField.new("Sender Id\t\t\t", "compact.senderId", ftypes.UINT32, nill,base.DEC) NumberOfLinesInModule = ProtoField.new("Number Of Lines In Module\t", "compact.numberOfLinesInModule", ftypes.UINT32, nill, base.DEC) NumberOfBeamsPerScan = ProtoField.new("Number Of Beams Per Scan\t", "compact.numberOfBeamsPerScan", ftypes.UINT32, nill, base.DEC) NumberOfEchosPerBeam = ProtoField.new("Number Of Echos Per Scan\t", "compact.NumberOfEchosPerBeam", ftypes.UINT32, nill, base.DEC) aTimeStampStart = ProtoField.new("Time Stamp Start\t", "compact.timeStampStart", ftypes.ABSOLUTE_TIME, nill, base.UTC) aTimeStampStop = ProtoField.new("Time Stamp Stop\t", "compact.timeStampStop", ftypes.ABSOLUTE_TIME, nill, base.UTC) aPhi = ProtoField.new("Phi\t\t", "compact.phi", ftypes.FLOAT, nill, base.NONE) aThetaStart = ProtoField.new("Theta Start\t\t", "compact.thetaStart", ftypes.FLOAT, nill, base.NONE) aThetaStop = ProtoField.new("Theta Stop\t\t", "compact.thetaStop", ftypes.FLOAT, nill, base.NONE) DistanceScalingFactor = ProtoField.new("Distance Scaling Factor", "compact.DistanceScalingFactor", ftypes.FLOAT, nill, base.NONE) NextModuleSize = ProtoField.new("Next Module Size\t", "compact.nextModuleSize", ftypes.UINT32, nill, base.DEC) Reserved1 = ProtoField.new("Reserved\t\t", "compact.reserved", ftypes.UINT8, nill, base.HEX) -- RESERVED DataContentEchos = ProtoField.new("Data Content Echos\t\t\t", "compact.dataContentEchos", ftypes.UINT8, nill, base.HEX, 0x3) DataContentEchos_Bit0 = ProtoField.new("Distance data are available\t\t", "compact.dataContentEchos.Bit0", ftypes.UINT8, Status_bool, base.NONE, 0x1) DataContentEchos_Bit1 = ProtoField.new("RSSI data are available\t\t", "compact.dataContentEchos.Bit1", ftypes.UINT8, Status_bool, base.NONE, 0x2) DataContentEchos_Bit2 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit2", ftypes.UINT8, Status_bool, base.NONE, 0x4) -- RESERVED DataContentEchos_Bit3 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit3", ftypes.UINT8, Status_bool, base.NONE, 0x8) -- RESERVED DataContentEchos_Bit4 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit4", ftypes.UINT8, Status_bool, base.NONE, 0x10) -- RESERVED DataContentEchos_Bit5 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit5", ftypes.UINT8, Status_bool, base.NONE, 0x20) -- RESERVED DataContentEchos_Bit6 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit6", ftypes.UINT8, Status_bool, base.NONE, 0x40) -- RESERVED DataContentEchos_Bit7 = ProtoField.new("Reserved", "compact.dataContentEchos.Bit7", ftypes.UINT8, Status_bool, base.NONE, 0x80) -- RESERVED DataContentBeams = ProtoField.new("Data Content Beams\t\t\t", "compact.dataContentBeams", ftypes.UINT8, nill, base.HEX, 0x3) DataContentBeams_Bit0 = ProtoField.new("Further beam properties are available\t", "compact.dataContentBeams.Bit0", ftypes.UINT8, Status_bool, base.NONE, 0x1) DataContentBeams_Bit1 = ProtoField.new("Azimuth angles per beam are available\t", "compact.dataContentBeams.Bit1", ftypes.UINT8, Status_bool, base.NONE, 0x2) DataContentBeams_Bit2 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit2", ftypes.UINT8, Status_bool, base.NONE, 0x4) -- RESERVED DataContentBeams_Bit3 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit3", ftypes.UINT8, Status_bool, base.NONE, 0x8) -- RESERVED DataContentBeams_Bit4 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit4", ftypes.UINT8, Status_bool, base.NONE, 0x10) -- RESERVED DataContentBeams_Bit5 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit5", ftypes.UINT8, Status_bool, base.NONE, 0x20) -- RESERVED DataContentBeams_Bit6 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit6", ftypes.UINT8, Status_bool, base.NONE, 0x40) -- RESERVED DataContentBeams_Bit7 = ProtoField.new("Reserved", "compact.dataContentBeams.Bit7", ftypes.UINT8, Status_bool, base.NONE, 0x80) -- RESERVED Reserved2 = ProtoField.new("Reserved", "compact.reserved2", ftypes.UINT8, nill, base.HEX) -- RESERVED -- ** Measurement Data ** Distance = ProtoField.new("Distance\t", "compact.distance", ftypes.UINT16, nill, base.DEC) RSSI = ProtoField.new("RSSI\t", "compact.RSSI", ftypes.UINT16, nill, base.DEC) BeamCharacteristics = ProtoField.new("Beam Characteristics", "compact.beamCharacteristics", ftypes.UINT8, nill, base.HEX, 0x1) BeamCharacteristics_Bit0 = ProtoField.new("If a reflector was detected for any echo on this beam", "compact.beamCharacteristics.Bit0", ftypes.UINT16, Status_bool, base.NONE, 0x1) BeamCharacteristics_Bit1 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit1", ftypes.UINT8, Status_bool, base.NONE, 0x2) -- RESERVED BeamCharacteristics_Bit2 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit2", ftypes.UINT8, Status_bool, base.NONE, 0x4) -- RESERVED BeamCharacteristics_Bit3 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit3", ftypes.UINT8, Status_bool, base.NONE, 0x8) -- RESERVED BeamCharacteristics_Bit4 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit4", ftypes.UINT8, Status_bool, base.NONE, 0x10) -- RESERVED BeamCharacteristics_Bit5 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit5", ftypes.UINT8, Status_bool, base.NONE, 0x20) -- RESERVED BeamCharacteristics_Bit6 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit6", ftypes.UINT8, Status_bool, base.NONE, 0x40) -- RESERVED BeamCharacteristics_Bit7 = ProtoField.new("Reserved", "compact.beamCharacteristics.Bit7", ftypes.UINT8, Status_bool, base.NONE, 0x80) -- RESERVED AzimuthAngletheta = ProtoField.new("Azimuth angle (theta)", "compact.distance", ftypes.UINT16, nill, base.NONE) CurrentLine = ProtoField.new("Line", "compact.currentLine", ftypes.NONE, nill, base.NONE) -- ** IMU - DATA ** CommandIdIMU = ProtoField.new("CommandId\t\t\t", "imu.CommandId", ftypes.UINT32, nill, base.DEC) TelegramVersionIMU = ProtoField.new("Telegram Version\t\t", "imu.telegramVersion", ftypes.UINT32, nill, base.DEC) AccelerationX = ProtoField.new("Acceleration X\t\t", "imu.accelerationX", ftypes.FLOAT, nill, base.NONE) AccelerationY = ProtoField.new("Acceleration Y\t\t", "imu.accelerationY", ftypes.FLOAT, nill, base.NONE) AccelerationZ = ProtoField.new("Acceleration Z\t\t", "imu.accelerationZ", ftypes.FLOAT, nill, base.NONE) VelocityX = ProtoField.new("Angular Velocity X\t\t", "imu.velocityX", ftypes.FLOAT, nill, base.NONE) VelocityY = ProtoField.new("Angular Velocity Y\t\t", "imu.velocityY", ftypes.FLOAT, nill, base.NONE) VelocityZ = ProtoField.new("Angular Velocity Z\t\t", "imu.velocityZ", ftypes.FLOAT, nill, base.NONE) OrientationW = ProtoField.new("Orientation Quaternion W\t", "imu.orientationW", ftypes.FLOAT, nill, base.NONE) OrientationX = ProtoField.new("Orientation Quaternion X\t", "imu.orientationX", ftypes.FLOAT, nill, base.NONE) OrientationY = ProtoField.new("Orientation Quaternion Y\t", "imu.orientationY", ftypes.FLOAT, nill, base.NONE) OrientationZ = ProtoField.new("Orientation Quaternion Z\t", "imu.orientationZ", ftypes.FLOAT, nill, base.NONE) ImuTimestamp = ProtoField.new("IMU Sensor Timestamp\t\t", "imu.timestamp", ftypes.ABSOLUTE_TIME, nill, base.NONE) CheckSumImu = ProtoField.new("Check Sum\t\t\t", "imu.checkSum", ftypes.UINT32, nill, base.DEC) -- ** CRC ** crc = ProtoField.new("CRC", "compact.crc",ftypes.UINT32, nill, base.DEC) SICK__CompactProtocol.fields = { StartOfFrame, CommandId, TelegramCounter, TimeStampTransmit, TelegramVersion, SizeModule0, SegmentCounter, FrameNumber, SenderId, NumberOfLinesInModule, NumberOfBeamsPerScan, NumberOfEchosPerBeam, aTimeStampStart, aTimeStampStop, aPhi, aThetaStart, aThetaStop, DistanceScalingFactor, NextModuleSize, Reserved1, DataContentEchos, DataContentEchos_Bit0, DataContentEchos_Bit1, DataContentEchos_Bit2, DataContentEchos_Bit3,DataContentEchos_Bit4, DataContentEchos_Bit5, DataContentEchos_Bit6, DataContentEchos_Bit7, DataContentBeams, DataContentBeams_Bit0, DataContentBeams_Bit1, DataContentBeams_Bit2, DataContentBeams_Bit3, DataContentBeams_Bit4, DataContentBeams_Bit5, DataContentBeams_Bit6, DataContentBeams_Bit7, Reserved2, Distance, RSSI, BeamCharacteristics, BeamCharacteristics_Bit0, BeamCharacteristics_Bit1, BeamCharacteristics_Bit2, BeamCharacteristics_Bit3, BeamCharacteristics_Bit4, BeamCharacteristics_Bit5, BeamCharacteristics_Bit6, BeamCharacteristics_Bit7, AzimuthAngletheta, CurrentLine, CommandIdIMU, TelegramVersionIMU, AccelerationX, AccelerationY, AccelerationZ, VelocityX, VelocityY, VelocityZ, OrientationW, OrientationX, OrientationY, OrientationZ, ImuTimestamp, CheckSumImu, crc, } --[[ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MAIN PROGRAMM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ]]-- -- Function to comver usecs to NSTime object -- To show Data and Time in Tree function getTime(buffer) local usecs = buffer():le_uint64() local secs = (usecs / 1000000):tonumber() local nsecs = (usecs % 1000000):tonumber() * 1000 local nstime = NSTime.new(secs, nsecs) return nstime end -- Function to generate and show Modules, Meta Data and Measurement Data in Tree function CreateSubtreeModule_N(Buffer, Subtree, Module, Module_number, MetaDataModule) -- ** Meta Data ** -- Add Module subtree + module number local ModuleSubtree = Subtree:add(SICK__CompactProtocol, Module(), "Module " .. Module_number) -- Add Meta data to Module subtree local MetaDataModuleSubtree = ModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(0, MetaDataModule:len()), "Meta Data Module " .. Module_number) -- Segment counter / Frame number / Sender ID -- SegmentCounter MetaDataModuleSubtree:add_le(SegmentCounter, MetaDataModule(Metadata_offset["SegmentCounter"][1], Metadata_offset["SegmentCounter"][2])) -- FrameNumber MetaDataModuleSubtree:add_le(FrameNumber, MetaDataModule(Metadata_offset["FrameNumber"][1], Metadata_offset["FrameNumber"][2])) -- SenderId MetaDataModuleSubtree:add_le(SenderId, MetaDataModule(Metadata_offset["SenderId"][1], Metadata_offset["SenderId"][2])) -- Lines / Beams / Echos in module -- numberOfLinesInModule local LinesInModule = MetaDataModule(Metadata_offset["NumberOfLinesInModule"][1], Metadata_offset["NumberOfLinesInModule"][2]):le_uint() MetaDataModuleSubtree:add_le(NumberOfLinesInModule, MetaDataModule(Metadata_offset["NumberOfLinesInModule"][1], Metadata_offset["NumberOfLinesInModule"][2])) -- NumberOfBeamsPerScan local beamsPerScan = MetaDataModule(Metadata_offset["NumberOfBeamsPerScan"][1], Metadata_offset["NumberOfBeamsPerScan"][2]):le_uint() MetaDataModuleSubtree:add_le(NumberOfBeamsPerScan, MetaDataModule(Metadata_offset["NumberOfBeamsPerScan"][1], Metadata_offset["NumberOfBeamsPerScan"][2])) -- NumberOfEchosPerBeam local echosPerScan = MetaDataModule(Metadata_offset["NumberOfEchosPerBeam"][1], Metadata_offset["NumberOfEchosPerBeam"][2]):le_uint() MetaDataModuleSubtree:add_le(NumberOfEchosPerBeam, MetaDataModule(Metadata_offset["NumberOfEchosPerBeam"][1], Metadata_offset["NumberOfEchosPerBeam"][2])) -- ** Time Stamps ** -- ** START ** -- Time START Stamp subtree -- TimeStampStart 32, n*8 local offset = Metadata_offset["TimeStampStart"][1] local timeStart_len = Metadata_offset["TimeStampStart"][2] local aTimeStampStartsubtree = MetaDataModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(offset, LinesInModule * timeStart_len), "Time Stamp Start Status") -- Time START Array local timeStart = {} for i=1, LinesInModule do local offset_i = offset + (i - 1 ) * timeStart_len aTimeStampStartsubtree:add(aTimeStampStart, MetaDataModule(offset_i, timeStart_len), getTime(MetaDataModule(offset_i, timeStart_len))):append_text("\t(Line" .. i .. ")") timeStart[i - 1] = MetaDataModule(offset_i, timeStart_len):le_uint64() end -- ** STOP ** -- Time STOP Stamp subtree -- TimeStampStop 32+n*8, n*8 local timeStop_len = Metadata_offset["TimeStampStop"][2] local offset = Metadata_offset["TimeStampStart"][1] + LinesInModule * timeStart_len local aTimeStampStopsubtree = MetaDataModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(offset, LinesInModule * timeStop_len), "Time Stamp Stop Status") -- Time STOP Array local timeStop = {} for i=1, LinesInModule do local offset_i = offset + (i - 1 ) * timeStop_len aTimeStampStopsubtree:add_le(aTimeStampStop, MetaDataModule(offset_i, timeStop_len), getTime(MetaDataModule(offset_i, timeStop_len))):append_text("\t(Line" .. i .. ")") timeStop[i - 1] = MetaDataModule(offset_i, timeStop_len):le_uint64() end -- ** PHI ** -- Phi subtree -- Phi 32+n*16, n*4 local offset = Metadata_offset["TimeStampStart"][1] + LinesInModule * (timeStart_len + timeStop_len) local phi_len = Metadata_offset["Phi"][2] local aPhisubtree = MetaDataModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(offset, LinesInModule * phi_len), "Phi") -- Phi local phi = {} for i=1, LinesInModule do local offset_i = offset + (i - 1 ) * phi_len local phi_deg = MetaDataModule(offset_i, phi_len):le_float() * 180 / math.pi aPhisubtree:add_le(aPhi, MetaDataModule(offset_i, phi_len)):append_text(" rad,\t".. phi_deg .. " deg\t" .. "(Line" .. i .. ")") end -- ** THETA ** -- ** START ** -- Theta START subtree -- Theta start 32+n*20, n*4 local offset = Metadata_offset["TimeStampStart"][1] + LinesInModule * (timeStart_len + timeStop_len + phi_len) local thetaStart_len = Metadata_offset["ThetaStart"][2] local aThetaStartsubtree = MetaDataModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(offset, LinesInModule * thetaStart_len), "Theta Start") -- Theta Start Array local thetaStart = {} for i=1, LinesInModule do local offset_i = offset + (i - 1 ) * thetaStart_len local thetaStart_deg = MetaDataModule(offset_i, thetaStart_len):le_float() * 180 / math.pi aThetaStartsubtree:add_le(aThetaStart, MetaDataModule(offset_i, thetaStart_len)):append_text( " rad,\t" .. thetaStart_deg .. " deg\t" .. "(Line" .. i.. ")") thetaStart[i - 1] = MetaDataModule(offset_i, thetaStart_len):le_float() end -- ** STOP ** -- Theta STOP subtree -- Theta stop 32+n*24, n*4 local offset = Metadata_offset["TimeStampStart"][1] + LinesInModule * (timeStart_len + timeStop_len + phi_len + thetaStart_len) local thetaStop_len = Metadata_offset["ThetaStop"][2] local aThetaStopsubtree = MetaDataModuleSubtree:add(SICK__CompactProtocol, MetaDataModule(offset, LinesInModule * thetaStop_len), "Theta Stop") -- Theta STOP Array local thetaStop = {} for i=1, LinesInModule do local offset_i = offset + (i - 1 ) * thetaStop_len local thetaStop_deg = MetaDataModule(offset_i, thetaStop_len):le_float() * 180 / math.pi aThetaStopsubtree:add_le(aThetaStop, MetaDataModule(offset_i, thetaStop_len)):append_text( " rad,\t" .. thetaStop_deg .. " deg\t" .. "(Line" .. i.. ")") thetaStop[i -1] = MetaDataModule(offset_i, thetaStop_len):le_float() end local offset = (LinesInModule - 1) * (timeStart_len + timeStop_len + phi_len + thetaStart_len + thetaStop_len) -- Scaling Factor -- Scaling factor 60+n*28, 4 local scalingfactorOffset = Metadata_offset["DistanceScalingFactor"][1] + offset --local offset = (LinesInModule - 1) * (timeStart_len + timeStop_len + phi_len + thetaStart_len + thetaStop_len) local scalingFactor_len = Metadata_offset["DistanceScalingFactor"][2] local scalingFactor = MetaDataModule(scalingfactorOffset, scalingFactor_len):le_float() MetaDataModuleSubtree:add_le(DistanceScalingFactor, MetaDataModule(scalingfactorOffset, scalingFactor_len)) -- Next Module size -- Next Module size 64+n*28, 4 local nextModuleOffset = Metadata_offset["NextModuleSize"][1] + offset local nextModule_len = Metadata_offset["NextModuleSize"][2] local nextModuleSize = MetaDataModule(nextModuleOffset , nextModule_len):le_uint() MetaDataModuleSubtree:add_le(NextModuleSize, MetaDataModule(nextModuleOffset, nextModule_len)):append_text(" Bytes") -- RESERVED -- RESERVED 68+n*28, 1 MetaDataModuleSubtree:add_le(Reserved1, MetaDataModule(Metadata_offset["Reserved1"][1] + offset, Metadata_offset["Reserved1"][2])) -- Dta Content Echo subtree -- Dta Content Echo 69+n*28, 1 local dataContentEchoOffset = Metadata_offset["DataContentEchos"][1] + offset local dataContentEcho_len = Metadata_offset["DataContentEchos"][2] local DataContentEchosSubtree = MetaDataModuleSubtree:add_le(DataContentEchos, MetaDataModule(dataContentEchoOffset, dataContentEcho_len)) DataContentEchosSubtree:add(DataContentEchos_Bit0, MetaDataModule(dataContentEchoOffset, dataContentEcho_len)) DataContentEchosSubtree:add(DataContentEchos_Bit1, MetaDataModule(dataContentEchoOffset, dataContentEcho_len)) -- Dta content Beams subtree -- Dta content Beams 70+n*28, 1 local dataComtentBeamsOffset = Metadata_offset["DataContentBeams"][1] + offset local datacontentBeams_len = Metadata_offset["DataContentBeams"][2] local DataContentBeamsSubtree = MetaDataModuleSubtree:add(DataContentBeams, MetaDataModule(dataComtentBeamsOffset, datacontentBeams_len)) DataContentBeamsSubtree:add(DataContentBeams_Bit0, MetaDataModule(dataComtentBeamsOffset, datacontentBeams_len)) DataContentBeamsSubtree:add(DataContentBeams_Bit1, MetaDataModule(dataComtentBeamsOffset, datacontentBeams_len)) -- RESERVED -- RESERVED 71+n*28, 1 MetaDataModuleSubtree:add_le(Reserved2, MetaDataModule(Metadata_offset["Reserved2"][1] + offset, Metadata_offset["Reserved2"][2])) -- ** MODULE 0 ** -- define MeasurementData Module 0 local MeasurementDataModule = {} local dist_len = MeasurementData_offset["Distance"][2] local rssi_len = MeasurementData_offset["RSSI"][2] local beamCharacteristic_len = MeasurementData_offset["Beam characteristics"][2] local theta_len = MeasurementData_offset["Azimuth angle (theta)"][2] local dist_rssi_len = dist_len + rssi_len local beam_theta_len = beamCharacteristic_len + theta_len -- ** MODULE > 0 ** for i = 1, beamsPerScan do local sizeOfMeasurementData = LinesInModule * echosPerScan * dist_rssi_len + LinesInModule * beam_theta_len MeasurementDataModule[i] = Buffer(MetaDataModule:offset() + MetaDataModule:len() + sizeOfMeasurementData * (i -1), sizeOfMeasurementData) MeasurementDataModuleSubtree = ModuleSubtree:add(SICK__CompactProtocol, MeasurementDataModule[i], "Measurement Data Module " .. Module_number .. " (Beams set " .. i .. ")") local CurrentLineBuffer = {} for j = 1, LinesInModule do CurrentLineBuffer[j] = Buffer(MetaDataModule:offset() + MetaDataModule:len() + sizeOfMeasurementData * (i -1), sizeOfMeasurementData) local individual_len = dist_rssi_len * echosPerScan + beam_theta_len local CurrentLineSubtree = MeasurementDataModuleSubtree:add_le(CurrentLine, CurrentLineBuffer[j]((j - 1) * individual_len, individual_len)):append_text(" " .. j) for k = 1, echosPerScan do local offsetDist = (j - 1) * individual_len + (k - 1) * dist_rssi_len local offsetRSSI = offsetDist + dist_len local dist = MeasurementDataModule[i](offsetDist,dist_len):le_uint() * scalingFactor CurrentLineSubtree:add_le(Distance, MeasurementDataModule[i](offsetDist,dist_len)):append_text(" mm * Scaling Factor("..scalingFactor..") = "..dist.." mm (ECHO" .. k .. ")") CurrentLineSubtree:add_le(RSSI, MeasurementDataModule[i](offsetRSSI, rssi_len)):append_text(" (RSSI" .. k .. ")") end local offsetBeamCharacteristic = (j - 1) * individual_len + echosPerScan * dist_rssi_len local BeamCharacteristicsSubtree = CurrentLineSubtree:add_le(BeamCharacteristics, CurrentLineBuffer[j](offsetBeamCharacteristic, beamCharacteristic_len)) BeamCharacteristicsSubtree:add(BeamCharacteristics_Bit0, CurrentLineBuffer[j](offsetBeamCharacteristic, beamCharacteristic_len)) local offsetAzimuthAngletheta= offsetBeamCharacteristic + beamCharacteristic_len -- Azimuth Angle theta --[[ uint16 Integers, where the following conversion applies: •a_uint: Angle value as integer •a_rad: Angle value in radians. •a_rad = (a_uint – 16384)/ 5215 This conversion ensures that the maximum allowed value range of [-pi, 3*pi] is fully utilized. ]]-- local AzimuthAngletheta_rad = (CurrentLineBuffer[j](offsetAzimuthAngletheta, theta_len):le_uint() - 16384) / 5215 local AzimuthAngletheta_deg = AzimuthAngletheta_rad * 180 / math.pi CurrentLineSubtree:add_le(AzimuthAngletheta, MeasurementDataModule[i](offsetAzimuthAngletheta, theta_len)):append_text(",\t".. AzimuthAngletheta_rad.." rad,\t" .. AzimuthAngletheta_deg.. " deg\n") -- CurrentLineSubtree:append_text(" " .. AzimuthAngletheta_rad.." rad, " .. AzimuthAngletheta_deg.. " deg") -- Show RAD and DEG CurrentLineSubtree:append_text(" (Theta " .. AzimuthAngletheta_deg.. " deg)") -- Show only DEG end end -- Return Next Module size for loop return nextModuleSize end function SICK__CompactProtocol.dissector(Buffer, PInfo, Tree) -- Dessegment more segments in case of TCP/IP (LRS4000) local Header_t = Buffer(Header_offset["Header"][1], Header_offset["Header"][2]) local sizeofm0 = Header_t(Header_offset["sizeModule0"][1], Header_offset["sizeModule0"][2]):le_uint() -- 36 = Header size (32) + CRC size (4) if sizeofm0 + 36 ~= Buffer:len() then PInfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT end -- Each packet calls dissector twice -- Applaing filter calls dissector twice again -- Skipping first call increase speed twice -- Skip first call if not PInfo.visited then return -- Use second call for dissectoring elseif PInfo.visited then goto continue end ::continue:: -- Get message buffer length and check for empty frames Length = Buffer:len() if Length == 0 then return end -- Set protocol name to UI PInfo.cols.protocol = SICK__CompactProtocol.name -- Type of message (commandId) local TypeOfMessage = Buffer(Header_offset["commandId"][1],Header_offset["commandId"][2]):le_uint() -- CRC Buffer local crc_len = CRC_offset["CRC"][2] local Crc = Buffer(Length - crc_len, crc_len) -- Add subtree for main protocol fields and all sub fields and set subtree name to UI local Subtree = Tree:add(SICK__CompactProtocol, Buffer(0, Length), "Compact Protocol") -- Chech type of message -- 1 - Measurement data if 1 == TypeOfMessage then PInfo.cols.info = "Measurement Data" -- define Header local Header = Buffer(Header_offset["Header"][1], Header_offset["Header"][2]) local HeaderSubtree = Subtree:add(SICK__CompactProtocol, Header(Header_offset["Header"][1], Header_offset["Header"][2]), "Header") -- Start Of Frame HeaderSubtree:add(StartOfFrame, Header(Header_offset["startOfFrame"][1],Header_offset["startOfFrame"][2])) -- Command ID HeaderSubtree:add_le(CommandId, Header(Header_offset["commandId"][1], Header_offset["commandId"][2])) -- Telegram Counter HeaderSubtree:add_le(TelegramCounter, Header(Header_offset["telegramCounter"][1], Header_offset["telegramCounter"][2])) -- Time Stamp Transmit HeaderSubtree:add(TimeStampTransmit, Header(Header_offset["timeStampTransmit"][1], Header_offset["timeStampTransmit"][2]), getTime(Header(Header_offset["timeStampTransmit"][1], Header_offset["timeStampTransmit"][2]))) -- Telegram Version HeaderSubtree:add_le(TelegramVersion, Header(Header_offset["telegramVersion"][1], Header_offset["telegramVersion"][2])) -- Size Module 0 HeaderSubtree:add_le(SizeModule0, Header(Header_offset["sizeModule0"][1], Header_offset["sizeModule0"][2])):append_text(" Bytes") local telegramVersion = Header(Header_offset["telegramVersion"][1], Header_offset["telegramVersion"][2]):le_uint() -- Define Modules local Module = {} -- Define Module 0 Module[0] = Buffer(Header:len(), Header(Header_offset["sizeModule0"][1], Header_offset["sizeModule0"][2]):le_uint()) if 4 == telegramVersion then -- Define MetaData Module 0 local linesInModule = Buffer(Header:offset() + Header:len() + Metadata_offset["NumberOfLinesInModule"][1], Metadata_offset["NumberOfLinesInModule"][2]):le_uint() local measurementData_len = Metadata_offset["TimeStampStart"][2] + Metadata_offset["TimeStampStop"][2] + Metadata_offset["Phi"][2] + Metadata_offset["ThetaStart"][2] + Metadata_offset["ThetaStop"][2] local MetaDataModule_len = Metadata_offset["Meta Data"][2] + (linesInModule - 1) * measurementData_len -- Define Meta Datas local MetaDataModule = {} -- Define Meta Data 0 MetaDataModule[0] = Buffer(Header:offset() + Header:len(), MetaDataModule_len) local Module_number = 0 local nextModuleSize = CreateSubtreeModule_N(Buffer, Subtree, Module[0] , Module_number, MetaDataModule[0], linesInModule) for i = 1, 4 do if nextModuleSize ~= 0 then local Module_number = i linesInModule = Buffer(Module[i-1]:offset() + Module[i-1]:len() + Metadata_offset["NumberOfLinesInModule"][1], Metadata_offset["NumberOfLinesInModule"][2]):le_uint() local MetaDataModule_len = Metadata_offset["Meta Data"][2] + (linesInModule - 1) * measurementData_len -- Define Module N Module[i] = Buffer(Module[i-1]:offset() + Module[i-1]:len(), nextModuleSize) -- define Meta Data N MetaDataModule[i] = Buffer(Module[i-1]:offset() + Module[i-1]:len(), MetaDataModule_len) nextModuleSize = 0 nextModuleSize = CreateSubtreeModule_N(Buffer, Subtree, Module[i], Module_number, MetaDataModule[i]) end end else -- Add Module subtree + module number local ModuleSubtree = Subtree:add(SICK__CompactProtocol, Module[0], "Module 0" .. " !!!NO SUPPORT FOR COMPACT Telegram version " .. telegramVersion .. " !!!") end -- CRC subree local CrcSubtree = Subtree:add(SICK__CompactProtocol, Crc(), "CRC") CrcSubtree:add_le(crc, Crc()) -- 2 - IMU Data elseif 2 == TypeOfMessage then PInfo.cols.info = "IMU Data" local telegramVersion = Buffer(IMUData_offset["Telegram version"][1], IMUData_offset["Telegram version"][2]):le_uint() if telegramVersion == 1 then -- IMU Subtree local IMUSubtree = Subtree:add(SICK__CompactProtocol, Buffer(IMUData_offset["IMUData"][1], IMUData_offset["IMUData"][2]), "IMU Data") -- start of frame IMUSubtree:add_le(StartOfFrame, Buffer(IMUData_offset["Start of Frame"][1], IMUData_offset["Start of Frame"][2])) -- Command Id IMUSubtree:add_le(CommandIdIMU, Buffer(IMUData_offset["Command ID"][1], IMUData_offset["Command ID"][2])) -- Telegram Version IMUSubtree:add_le(TelegramVersionIMU, Buffer(IMUData_offset["Telegram version"][1], IMUData_offset["Telegram version"][2])) -- Acceleration X IMUSubtree:add_le(AccelerationX, Buffer(IMUData_offset["Acceleration x"][1], IMUData_offset["Acceleration x"][2])):append_text(" m/s²") -- Acceleration Y IMUSubtree:add_le(AccelerationY, Buffer(IMUData_offset["Acceleration y"][1], IMUData_offset["Acceleration y"][2])):append_text(" m/s²") -- Acceleration Z IMUSubtree:add_le(AccelerationZ, Buffer(IMUData_offset["Acceleration z"][1], IMUData_offset["Acceleration z"][2])):append_text(" m/s²") -- Velocity X IMUSubtree:add_le(VelocityX, Buffer(IMUData_offset["Angular velocity x"][1], IMUData_offset["Angular velocity x"][2])):append_text(" rad/s") -- Velocity Y IMUSubtree:add_le(VelocityY, Buffer(IMUData_offset["Angular velocity y"][1], IMUData_offset["Angular velocity y"][2])):append_text(" rad/s") -- Velocity Z IMUSubtree:add_le(VelocityZ, Buffer(IMUData_offset["Angular velocity z"][1], IMUData_offset["Angular velocity z"][2])):append_text(" rad/s") -- Orientation W IMUSubtree:add_le(OrientationW, Buffer(IMUData_offset["Orientation quaternion w"][1], IMUData_offset["Orientation quaternion w"][2])) -- Orientation X IMUSubtree:add_le(OrientationX, Buffer(IMUData_offset["Orientation quaternion x"][1], IMUData_offset["Orientation quaternion x"][2])) -- Orientation Y IMUSubtree:add_le(OrientationY, Buffer(IMUData_offset["Orientation quaternion y"][1], IMUData_offset["Orientation quaternion y"][2])) -- Orientation Z IMUSubtree:add_le(OrientationZ, Buffer(IMUData_offset["Orientation quaternion z"][1], IMUData_offset["Orientation quaternion z"][2])) -- Imu Sensor Time stamp IMUSubtree:add(ImuTimestamp, Buffer(IMUData_offset["IMU sensor time stamp"][1], IMUData_offset["IMU sensor time stamp"][2]), getTime(Buffer(IMUData_offset["IMU sensor time stamp"][1], IMUData_offset["IMU sensor time stamp"][2]))) -- Check Sum IMUSubtree:add_le(CheckSumImu, Buffer(IMUData_offset["Check sum"][1], IMUData_offset["Check sum"][2])) else -- IMU Subtree local IMUSubtree = Subtree:add(SICK__CompactProtocol, Buffer(IMUData_offset["IMUData"][1], IMUData_offset["IMUData"][2]), "IMU Data" .. " !!!NO SUPPORT FOR IMU Telegram version " .. telegramVersion .. " !!!") -- Telegram Version IMUSubtree:add_le(TelegramVersionIMU, Buffer(IMUData_offset["Telegram version"][1], IMUData_offset["Telegram version"][2])) end end end --Add new protocol object for the desired udp port to the Wireshark DissectorTable local UdpPort = DissectorTable.get("udp.port") local TcpPort = DissectorTable.get("tcp.port") UdpPort:add(CompactPort, SICK__CompactProtocol) UdpPort:add(IMUPort, SICK__CompactProtocol) TcpPort:add(CompactPort, SICK__CompactProtocol)