Radar (Decoder Only): Accessing data through "_decodePacket"

Please provide the following info (check/uncheck the boxes after creating this topic):
Software Version
DRIVE OS Linux 5.2.6
DRIVE OS Linux 5.2.0
DRIVE OS Linux 5.2.0 and DriveWorks 3.5
NVIDIA DRIVE™ Software 10.0 (Linux)
NVIDIA DRIVE™ Software 9.0 (Linux)
other DRIVE OS version
other

Target Operating System
Linux
QNX
other

Hardware Platform
NVIDIA DRIVE™ AGX Xavier DevKit (E3550)
NVIDIA DRIVE™ AGX Pegasus DevKit (E3550)
other

SDK Manager Version
1.6.1.8175
1.6.0.8170
other

Host Machine Version
native Ubuntu 18.04
other

This is a continuation of the following topic:

I’ve set up all I need and the first header send by CarMaker was received by DriveWorks with a content noting, that CarMaker is connected as a data transmitter. However, the length variable is greater zero (=64 bytes) only in the functions _dwRadarDecoder_validatePacket and _dwRadarDecoder_synchronize, in _dwRadarDecoder_decodePacket length is always zero.

I would like to confirm the received data and process it in _dwRadarDecoder_decodePacket, but I don’t know how it’s developed in the background to forward the buffer and length values from _dwRadarDecoder_validatePacket or _dwRadarDecoder_synchronize to _dwRadarDecoder_decodePacket?

Following code is currently implemented (see comments for details - especially for _dwRadarDecoder_decodePacket):

#include <dw/sensors/plugins/radar/RadarDecoder.h>
#include <dw/sensors/plugins/radar/RadarPlugin.h>
#include <iostream>

dwStatus _dwRadarDecoder_initialize () {

	// Indicator, which function gets executed:
	std::cout << "1" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_release() {
	
	// Indicator, which function gets executed:
	std::cout << "2" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_decodePacket 	( 	
	dwRadarScan *  	 output,
	const uint8_t *  buffer,
	const size_t  	 length,
	const dwRadarScanType  	scanType )
{
	(void) output;
	(void) scanType;

	// For unknown reasons "buffer" is always empty declared by "length" equal to zero for every loop?
	std::cout << "Buffer: " << *buffer << " - Length: " << length << std::endl;

	// Indicator, which function gets executed:
	std::cout << "3" << std::endl;

	// When length is greater than zero, output the buffer content to screen
	// and abort the application before filling out the shell with new lines.
	// In this way I want to see if it ever happens that length is greater than
	// zero, which indicates that data is existing to be decoded.
	if (length > 0)
	{
		for (size_t i = 0; i < length; i++)
		{
			std::cout << buffer[i];
		}

		std::cout << std::endl;
		abort();
	}

	return DW_SUCCESS;
}


// Setting up all constants and properties of the sensor.
// Only detections will be received, hence no other data is required to be set up.

dwStatus _dwRadarDecoder_getConstants(_dwRadarDecoder_constants * constants)
{
	constants->properties.supportedScanTypes[DW_RADAR_RETURN_TYPE_DETECTION][DW_RADAR_RANGE_LONG] = 1;
	constants->properties.maxReturnsPerScan[DW_RADAR_RETURN_TYPE_DETECTION][DW_RADAR_RANGE_LONG]  = 2000;

	constants->properties.scansPerSecond=1;
	constants->properties.isDecodingOn=1;
	constants->properties.numScanTypes=1;
	constants->properties.packetsPerScan = 1;
	constants->properties.inputPacketsPerSecond = 0;

	constants->headerSize = 64;
	constants->maxPayloadSize = 2048;
	constants->vehicleStateSize = 0;
	constants->mountSize = 0;

	// Indicator, which function gets executed:
	std::cout << "4" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_synchronize ( 	
	const uint8_t * buffer,
	const size_t  	length,
	size_t *  	remaining)
{
	(void) buffer; // Currently not used

	// Set remaining data to zero, when first message of 64 bytes is received.
	// Is this required to provide the data to the "_dwRadarDecoder_decodePacket(...)" function?
	// This will be correctly set when the first message is received from CarMaker
	if (length == 64) {
		*remaining = 0;
	}

	// Indicator, which function gets executed:
	std::cout << "5" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_validatePacket ( 
	const uint8_t*   buffer,
	const size_t  	 length,
	dwRadarScanType* scanType) 
{
	(void) buffer; // Currently not used
	(void) length; // Currently not used

	// Required, otherwise segmentation fault.
	scanType->range = DW_RADAR_RANGE_LONG;
	scanType->returnType = DW_RADAR_RETURN_TYPE_DETECTION;

	// Indicator, which function gets executed:
	std::cout << "6" << std::endl;

	return DW_SUCCESS;
}


bool _dwRadarDecoder_isScanComplete ( 	
	dwRadarScanType  scanType,
	const uint8_t ** buffer,
	size_t *  	 length,
	size_t  	 numPackets 
	) 
{
	(void) scanType; // Currently not used
	(void) buffer;	 // Currently not used
	(void) length;	 // Currently not used

	// Tried to set up the numPackets in the hope that
	// _dwRadarDecoder_decodePacket(...) will be provided with data.
	// Had no effect.
	numPackets = 1;

	// Indicator, which function gets executed:
	std::cout << "7" << std::endl;

	return true;
}


dwStatus _dwRadarDecoder_encodeVehicleState ( 	
	uint8_t *  	buffer,
	const size_t  	maxOutputSize,
	const dwRadarVehicleState * packet 
	) 
{
	(void) buffer;			// Currently not used
	(void) maxOutputSize;	// Currently not used
	(void) packet;			// Currently not used

	// Indicator, which function gets executed:
	std::cout << "8" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_encodeMountPosition ( 	
	uint8_t *  	buffer,
	const size_t  	maxOutputSize,
	const dwRadarMountPosition * packet 
	)
{
	(void) buffer;			// Currently not used
	(void) maxOutputSize;	// Currently not used
	(void) packet;			// Currently not used

	// Indicator, which function gets executed:
	std::cout << "9" << std::endl;

	return DW_SUCCESS;
}

When exactly will the data located in buffer with the buffer length indicator “length” be forwarded to the _dwRadarDecoder_decodePacket function? What are the requirements?

I’m trying to understand the concept and structure of the decoder step by step, since the documentation doesn’t explain this in detail.

Hi @k.bodi2,

Did you mean length of _dwRadarDecoder_validatePacket() isn’t zero but length of _dwRadarDecoder_decodePacket() is zero?

Correct.

Could you ignore length and bypass 12 bytes header as below?

const uint8_t *bufferPtr = buffer + sizeof(uint32_t) + sizeof(dwTime_t);

I found our internal radar decoders don’t use length so I think it may be some problems.

Hey @VickNV,

thanks for replying. Made an update to my code (also for better readability):

#include <dw/sensors/plugins/radar/RadarDecoder.h>
#include <dw/sensors/plugins/radar/RadarPlugin.h>
#include <iostream>

dwStatus _dwRadarDecoder_initialize () {

	// Indicator, which function gets executed:
	std::cout << "---> Function: initialize" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_release() {
	
	// Indicator, which function gets executed:
	std::cout << "---> Function: release" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_decodePacket 	( 	
	dwRadarScan *  	 output,
	const uint8_t *  buffer,
	const size_t  	 length,
	const dwRadarScanType  	scanType )
{
	(void) output; 	 // Currently not used
	(void) scanType; // Currently not used

	// Indicator, which function gets executed:
	std::cout << std::endl << "---> Function: decodePacket" << std::endl;

	// For unknown reasons "buffer" is always empty declared by "length" equal to zero for every loop?
	std::cout << "Buffer: " << (void*)buffer << " - Length: " << length << std::endl;


	//------------------------------------------------------------------------------------------------------
	// How should I use this? Should *bufferPtr be defined globally in order to use it in decodePacket?
	const uint8_t *bufferPtr = buffer + sizeof(uint32_t) + sizeof(dwTime_t);

	(void) bufferPtr; // Currently not used
	//------------------------------------------------------------------------------------------------------


	// Read out all available data as if buffer were filled with 64 bytes of header and 64 bytes of payload:
	for (size_t i = 0; i < 128; i++)
	{
		if (buffer[i] == '\0')
		{
			std::cout << ".";
			continue;
		}
		std::cout << buffer[i];
	}

	std::cout << std::endl << std::endl;

	abort();

	return DW_SUCCESS;
}


// Setting up all constants and properties of the sensor.
// Only detections will be received, hence no other data is required to be set up.

dwStatus _dwRadarDecoder_getConstants(_dwRadarDecoder_constants * constants)
{
	// Indicator, which function gets executed:
	std::cout << "---> Function: getConstants" << std::endl;

	constants->properties.supportedScanTypes[DW_RADAR_RETURN_TYPE_DETECTION][DW_RADAR_RANGE_LONG] = 1;
	constants->properties.maxReturnsPerScan[DW_RADAR_RETURN_TYPE_DETECTION][DW_RADAR_RANGE_LONG]  = 2000;

	constants->properties.scansPerSecond=1;
	constants->properties.isDecodingOn=1;
	constants->properties.numScanTypes=1;
	constants->properties.packetsPerScan = 1;
	constants->properties.inputPacketsPerSecond = 0;

	constants->headerSize = 64;
	constants->maxPayloadSize = 64;
	constants->vehicleStateSize = 0;
	constants->mountSize = 0;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_synchronize ( 	
	const uint8_t * buffer,
	const size_t  	length,
	size_t *  	remaining)
{
	// Indicator, which function gets executed:
	std::cout << std::endl << "---> Function: synchronize" << std::endl;

	// Set remaining data to zero, when first message of 64 bytes is received.
	// Is this required to provide the data to the "_dwRadarDecoder_decodePacket(...)" function?
	// This will be correctly set when the first message is received from CarMaker
	if (length == 64) {
		*remaining = 0;
	}

	std::cout << "Buffer: " << (void*)buffer << " - Length: " << length << std::endl;

	// Read out all buffer data till buffer[length]:
	for (size_t i = 0; i < length; i++)
	{
		if (buffer[i] == '\0' || isspace(buffer[i])
		{
			std::cout << ".";
			continue;
		}
		std::cout << buffer[i];
	}

	std::cout << std::endl << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_validatePacket ( 
	const uint8_t*   buffer,
	const size_t  	 length,
	dwRadarScanType* scanType) 
{
	(void) buffer; // Currently not used
	(void) length; // Currently not used

	// Indicator, which function gets executed:
	std::cout << "---> Function: validate" << std::endl;

	// Required, otherwise segmentation fault.
	scanType->range = DW_RADAR_RANGE_LONG;
	scanType->returnType = DW_RADAR_RETURN_TYPE_DETECTION;

	return DW_SUCCESS;
}


bool _dwRadarDecoder_isScanComplete ( 	
	dwRadarScanType  scanType,
	const uint8_t ** buffer,
	size_t *  	 length,
	size_t  	 numPackets 
	) 
{
	(void) scanType; // Currently not used
	(void) buffer;	 // Currently not used
	(void) length;	 // Currently not used

	// Indicator, which function gets executed:
	std::cout << "---> Function: isScanComplete" << std::endl;

	// Tried to set up the numPackets in the hope that
	// _dwRadarDecoder_decodePacket(...) will be provided with data.
	// Had no effect.
	numPackets = 1;

	return true;
}


dwStatus _dwRadarDecoder_encodeVehicleState ( 	
	uint8_t *  	buffer,
	const size_t  	maxOutputSize,
	const dwRadarVehicleState * packet 
	) 
{
	(void) buffer;			// Currently not used
	(void) maxOutputSize;	// Currently not used
	(void) packet;			// Currently not used

	// Indicator, which function gets executed:
	std::cout << "---> Function: encodeVehicleState" << std::endl;

	return DW_SUCCESS;
}


dwStatus _dwRadarDecoder_encodeMountPosition ( 	
	uint8_t *  	buffer,
	const size_t  	maxOutputSize,
	const dwRadarMountPosition * packet 
	)
{
	(void) buffer;			// Currently not used
	(void) maxOutputSize;	// Currently not used
	(void) packet;			// Currently not used

	// Indicator, which function gets executed:
	std::cout << "---> Function: encodeMountPosition" << std::endl;

	return DW_SUCCESS;
}

I did as you say, but frankly speaking, I don’t know what you expect me to do…
What you were proposing is from my understanding taking the address of the first element of the array buffer and adding 12 steps to it in order to switch the address 12 memory cells forward. From my understanding, this is like checking buffer[12], am I right? What exactly are you trying to achieve with this, when implemented in _dwRadarDecoder_decodePacket?

However, I extended the code in such a way, that _dwRadarDecoder_decodePacket would print out 128 bytes of buffer (even if headerSize = 64 and maxPayloadsize = 64), since I don’t know how big the buffer array is (length is zero as you know).

I also made sure, that the address of the first element of buffer is printed out. It makes sense, that the address of buffer[0] is different between the functions, but again: Why?

Here is the output log till _dwRadarDecoder_decodePacket is first time called and the application aborted in the end:

[22-09-2021 15:38:16] Platform: Detected Generic x86 Platform
[22-09-2021 15:38:16] TimeSource: monotonic epoch time offset is 1632308228173013
[22-09-2021 15:38:16] Platform: number of GPU devices detected 1
[22-09-2021 15:38:16] Platform: currently selected GPU device discrete ID 0
[22-09-2021 15:38:16] SDK: Resources mounted from /home/<User>/driveworks/samples/../data/
[22-09-2021 15:38:16] TimeSource: monotonic epoch time offset is 1632308228173013
[22-09-2021 15:38:16] Initialize DriveWorks SDK v2.2.3136
[22-09-2021 15:38:16] Release build with GNU 7.4.0 from heads/buildbrain-branch-0-gca7b4b26e65
[22-09-2021 15:38:16] SensorFactory::createSensor() -> radar.socket, ip=X.X.X.X:XXXX,port=XXXX,device=CUSTOM,protocol=tcp,decoder=/home/<User>/driveworks/build/src/sensors/plugins/radar/libsample_radar_decoder.so
---> Function: initialize
---> Function: getConstants
[22-09-2021 15:38:16] RadarSocket::RadarSocket, connected to X.X.X.X:XXXX
[22-09-2021 15:38:16] Initialize DriveWorks VisualizationSDK v2.2.3136
[22-09-2021 15:38:16] Initialize DriveWorksGL SDK v2.2.3136
[22-09-2021 15:38:16] GL-SDK: initialize OpenGL

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................
                          
-------- [Repeatedly printed many many times] --------

---> Function: validate

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: synchronize
Buffer: 0x56275343c5ec - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: decodePacket
Buffer: 0x56275343c580 - Length: 0
....FVg���.....veworks/build/src/sensors/plugins/radar/libsample_radar_decoder.so......a...........FVg���.*IPGMovie 10.0.1 202

./radar_socket.sh: line 1: 15969 Aborted                 (core dumped) ./sample_radar_replay --protocol=radar.socket --params=ip=X.X.X.X,port=XXXX,device=CUSTOM,protocol=tcp,decoder=/home/<User>/driveworks/build/src/sensors/plugins/radar/libsample_radar_decoder.so

As an addition: “*IPGMovie 10.0.1 2021-5-18” is the message from CarMaker, that the client has successfully connected to it.

_dwRadarDecoder_decodePacket() manipulate dwRadarScan ** data. Then applications can get them by call dwSensorRadar_readScan().

buffer of _dwRadarDecoder_decodePacket() should have extra 12 bytes in the front comparing to _dwRadarDecoder_validatePacket().

They are from a raw packet pool allocated according to scansPerSecond and packetsPerScan set up in _dwRadarDecoder_getConstants().

…and what exactly is triggering that new TCP messages should be received when a scan is successfully decoded and accessible through dwSensorRadar_readScan()?

Good to know. Nevertheless, check the above log posted by me. You will see, that buffer has the message noting “*IPGMovie…” etc. but it’s located at the end of all 128 bytes. Shifting 12 bytes forward allows me to see the full message "*IPGMovie 10.0.1 2021-5-18 " in buffer as part of _dwRadarDecoder_decodePacket, but is this deterministically defined somehow?

Code snippet:

dwStatus _dwRadarDecoder_decodePacket 	( 	
	dwRadarScan *  	 output,
	const uint8_t *  buffer,
	const size_t  	 length,
	const dwRadarScanType  	scanType )
{
	(void) output; 	 // Currently not used
	(void) scanType; // Currently not used

	// Indicator, which function gets executed:
	std::cout << std::endl << "---> Function: decodePacket" << std::endl;

	// For unknown reasons "buffer" is always empty declared by "length" equal to zero for every loop?
	std::cout << "Buffer: " << (void*)buffer << " - Length: " << length << std::endl;


	//------------------------------------------------------------------------------------------------------
	// How should I use this? Should *bufferPtr be defined globally in order to use it in decodePacket?
	const uint8_t *bufferPtr = buffer + sizeof(uint32_t) + sizeof(dwTime_t);

	//(void) bufferPtr; // Currently not used
	//------------------------------------------------------------------------------------------------------


	// Read out all available data as if buffer were filled with 64 bytes of header and 64 bytes of payload:
	for (size_t i = 0; i < 128; i++)
	{
		if (buffer[i] == '\0')
		{
			std::cout << ".";
			continue;
		}
		std::cout << buffer[i];
	}
	std::cout << std::endl << std::endl;

	// Check bufferPtr content for the next 128 bytes:
	for (size_t i = 0; i < 128; i++)
	{
		if (bufferPtr[i] == '\0')
		{
			std::cout << ".";
			continue;
		}
		std::cout << bufferPtr[i];
	}
	std::cout << std::endl << std::endl;

	abort();

	return DW_SUCCESS;
}

Log Output:

[...]

---> Function: synchronize
Buffer: 0x5596f12209ac - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: synchronize
Buffer: 0x5596f12209ac - Length: 64
*IPGMovie.10.0.1.2021-5-18......................................

---> Function: validate

---> Function: decodePacket
Buffer: 0x5596f1220940 - Length: 0
....Df���.....veworks/build/src/sensors/plugins/radar/libsample_radar_decoder.so......a...........Df���.*IPGMovie 10.0.1 202

....veworks/build/src/sensors/plugins/radar/libsample_radar_decoder.so......a...........Df���.*IPGMovie 10.0.1 2021-5-18  

To be honest, I still don’t know what exactly I have to do to solve this issue for me.

Is there any available sample/example for the decoder plugin? I don’t care for sensor specific data processing - I’m only interested in establishing a functional interface through the Decoder plugin.

It will keep calling recvfrom() once connected (see the below message).

[22-09-2021 15:38:16] RadarSocket::RadarSocket, connected to X.X.X.X:XXXX

Could you rephrase what’s the current issue you want to solve?
I think after the 12-bytes shift, you should see the raw data sent by the radar. Isn’t it?