writeStream not responding

187 views
Skip to first unread message

SUDHAKAR B

unread,
Jul 30, 2021, 12:17:23 PM7/30/21
to Pothos Users
Hi Community,

I am working to develop a driver for RFSoC using SoapySDR. All APIs are responding from the host PC except writeStream. I am unable to figure out what is missing. Please  advise.

On the host PC, following is the part of the code where I am setting up and activating the stream and calling the writeStream function subsequently:

SoapySDR::Stream *tx_stream = sdr->setupStream( SOAPY_SDR_TX, SOAPY_SDR_CS16, channels); //complex int16 (4 bytes per element)
if( tx_stream == NULL)
{
fprintf( stderr, "Failed\n");
SoapySDR::Device::unmake( sdr );
return EXIT_FAILURE;
}
int TxCheck = sdr->activateStream( tx_stream, 0, 0, 0);
printf("\n Tx stream activation check value: %d \n", TxCheck);

// 5. create a re-usable buffer for tx samples
//std::complex<float> buff[1024];

const void *buffs[1];
buffs[0] = {&sine_wave};

printf("buffs0 values: %d \n", *((int*) buffs[0]+1));

// 6. send some samples
for( int i = 0; i < 10; ++i)
{
int flags;
long long time_ns;
std::cout << buffs << std::endl;
int ret = sdr->writeStream( tx_stream, (void **)sine_wave, 1024, flags, time_ns, 100000);
printf("ret = %d, flags = %d, time_ns = %lld\n", ret, flags, time_ns);
}

// 7. shutdown the stream
sdr->deactivateStream( tx_stream, 0, 0); //stop streaming
sdr->closeStream( tx_stream );

On the RFSoC board driver, I am trying to print a message to confirm that I reached the specific area. Once I am sure that my control reached the right place, I want to map the memory buffers so that the Tx data can be transferred to DAC. 

Following is the (petalinux) code portion on the board side:
SoapySDR::Stream *setupStream(
const int direction,
const std::string &format,
const std::vector<size_t> &channels,
const SoapySDR::Kwargs &args)
{
std::ignore = direction;
std::ignore = format;
std::ignore = channels;
std::ignore = args;

printf("I am in stream setup printf\n");

return (SoapySDR::Stream *) this;
}

int activateStream(
SoapySDR::Stream *stream,
const int flags = 0,
const long long timeNs = 0,
const size_t numElems = 0){
printf("I am in stream activation\n");

return 10;
}

int readStream(
SoapySDR::Stream *stream,
void * const *buffs,
const size_t numElems,
int &flags,
long long &timeNs,
const long timeoutUs)
{
std::ignore = stream;
//std::ignore = buffs;
//std::ignore = numElems;
std::ignore = flags;
std::ignore = timeNs;
std::ignore = timeoutUs;

//this is the user's buffer for channel 0
void *buff0 = buffs[0];
int32_t *bufx = (int32_t *) buff0;

//well, this is a ZCU111 Device !
printf("I am in ReadStream printf\n");

for(size_t i=0; i<numElems; i++)
bufx[i] = (int32_t) 0;

return 0;
}

int writeStream(
SoapySDR::Stream *stream,
const void * const *buffs,
const size_t numElems,
int &flags,
const long long timeNs,
const long timeoutUs) {
// std::ignore = stream;
// std::ignore = buffs;
// std::ignore = numElems;
// std::ignore = flags;
// std::ignore = timeNs;
// std::ignore = timeoutUs;

//this is the user's buffer for channel 0
// void *buff0 = buffs[0];
// int32_t *bufx = (int32_t *) buff0;

printf("I am in Writestream printf\n");
std::cout <<"I am in Writestream Cout" <<std::endl;

return 0;
}

Following is the log I see on the board side log:
-----------setGain API--------------
 My received direction: 0
My received channel: 1
My gain value: 1.120000
You reached the gain API area. new gain value: 1.120000
QMC update successful
Gain change sucessful
    GainCorrectionFactor:   1.120000
    PhaseCorrectionFactor:  0.000000
    EnablePhase:            0
    EnableGain:             1
    OffsetCorrectionFactor: 0
    EventSource:            2

-----------setFreq. API--------------
 My received direction: 0
My received channel: 0
My Center frequency value: 3502080000.000000

 ------- setSampleRate. API --------
 My received direction: 0
My received channel: 0
Recd Sampling Rate: 245000000.000000


 ------- setSampleRate. API --------
 My received direction: 0
My received channel: 1
Recd Sampling Rate: 245000000.000000

I am in stream setup printf
I am in stream activation
SoapyServerListener::close()
SoapyServerListener::close()
-----------------------------------------------------------------------------------


I see the 3rd and 4th lines from bottom of the log are printed from setup and activation functions but not sure if the stream is activated. To start with, I want to test the writeStream and hence going ahead only with SOAPY_SDR_TX.

I am able to change a few parameters on the radio system through the APIs. Thanks to SoapySDR framework. Looking for good examples of driver side code that goes on the remote device.

Please let me know if any additional details are needed. Please help me.

Thanks and Regards,
Sudhakar

Message has been deleted

righthal...@gmail.com

unread,
Jul 31, 2021, 11:38:16 AM7/31/21
to Pothos Users
It is hard to tell what you are try to do and what your set up is, but the "SoapySDR::Device::unmake( sdr );" indicates that you are trying to interface with the C++ soapySDR libraries. If that is the case you are calling the default version of "writeStream" because you have not correctly defined the "writeStream". it should be declared -

int SoapySDR::Device::writeStream(Stream *, const void * const *, const size_t, int &, const long long, const long)

SUDHAKAR B

unread,
Aug 1, 2021, 11:36:13 PM8/1/21
to righthal...@gmail.com, Pothos Users
Hi,

Thank you for your email. Following is my code flow:

On the host PC:
--------------------
1) I have a sine_wave data array: const int sine_wave[1024]
2) In main() function, I am creating SoapySDR::kwargs with remote device details and calling make
3) With the device pointer obtained in #2, I am calling different functions from the driver side code.
  For example,
 const double gain_val = 1.12;
sdr->setGain(SOAPY_SDR_TX, 1, gain_val); 

4) Received successful response from setupStream and activation functions (Able to see the print messages included on the driver side code on the remote device log)
SoapySDR::Stream *tx_stream = sdr->setupStream( SOAPY_SDR_TX, SOAPY_SDR_CS16, channels);

5) I received a success response for (tried all parameters and the following line is with minimum most options)
int TxCheck = sdr->activateStream( tx_stream);//, 0, 0, NUM_SAMPS);
printf("\n Tx stream activation check value: %d \n", TxCheck);

6) readStream is successful - able to see the print messages on remote device log and also receive a success response on the host PC.

7) 'writeStream' alone is not responding. I am going clueless on the reason for failure. 
int Write_ret = sdr->writeStream( tx_stream, (const void **)sine_wave, 1024, flags, timeNs);
printf("Write_ret = %d, flags = %d, timeNs = %lld\n", Write_ret, flags, timeNs);

I want to know all the list of conditions that I need to meet before calling writeStream. 


On the remote device (RFSoC board):
---------------------------------------------------
1) I am defining a device class, extended from SoapySDR::Device
2) Using writeStream function as a public member.

readStream is as follows:
int readStream(SoapySDR::Stream *stream, void * const *buffs, const size_t numElems,
int &flags, long long &timeNs,const long timeoutUs)
{
std::ignore = stream;
//std::ignore = buffs;
//std::ignore = numElems;
std::ignore = flags;
std::ignore = timeNs;
std::ignore = timeoutUs;

//this is the user's buffer for channel 0
void *buff0 = buffs[0];
int32_t *bufx = (int32_t *) buff0;

//well, this is a ZCU111 Device !
printf("I am in ReadStream printf\n");

// for(size_t i=0; i<numElems; i++)
// bufx[i] = (int32_t) 0;

return 0;
}

writeStream is as follows:
int writeStream(SoapySDR::Stream *stream, const void * const *buffs,
const size_t numElems, int &flags, const long long timeNs)
{
std::ignore = stream;
//std::ignore = buffs;
std::ignore = flags;
std::ignore = timeNs;
//std::ignore = timeoutUs;

printf("Received numElements in WriteStream: %d \n",numElems);
printf("Driver key from writeStream function: %s \n", this->getDriverKey());
printf("buffs0 values: %d \n", *((int*) buffs[0]+1));

printf("I am in Writestream printf\n");
return 0;
}

First of all, I want to establish the communication to all API functions between the hostPC and the remote device. Then I want to implement the integration between SoapySDR calls and the radio hardware functionality.

Please let me know if there are specific conditions I need to meet before initiating a writeStream operation.

Thanks and Regards,
Sudhakar



--
You received this message because you are subscribed to the Google Groups "Pothos Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pothos-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pothos-users/e48923ac-117d-4ba4-819c-186290ae06ean%40googlegroups.com.

righthal...@gmail.com

unread,
Aug 2, 2021, 6:57:20 PM8/2/21
to Pothos Users
It looks like you are missing the "const long timeoutUs" as the last argument in the writeStream argument list.

SUDHAKAR B

unread,
Aug 3, 2021, 2:07:33 AM8/3/21
to righthal...@gmail.com, Pothos Users
Hi,

I do not see a change in behavior even after adding the timeUs parameter. Can you please give me links for some examples that I can study on the remote device side implementation? Also kindly let me know if there are some prerequisites that I need to meet in case of writeStream.

Thanks and regards,
Sudhakar

righthal...@gmail.com

unread,
Aug 3, 2021, 7:05:14 PM8/3/21
to Pothos Users
To Start Transmission in SdrGlut I -

1). check for full duplex operation - If half duplex, deactivate receive stream.
2). Set Sample rate
3). Set Center Frequency
4). Set Transmission gain
5).setup Stream.
6). activate Stream
7). Set filters based on type of transmission. AM,FM,NBFM, USB or USB.
8). Start the auto.
9). Capture the Audio and modulate according to type.
10). Up sample to required bandwidth.
11). writeStream.

If you down load the source - it is all in Transmit.cpp


If you want the board side - SoapyHackRF is a good reference.
Message has been deleted

SUDHAKAR B

unread,
Aug 5, 2021, 10:46:21 PM8/5/21
to righthal...@gmail.com, Pothos Users
Hi,

Following is my complete class definition:

class zcu111Device : public SoapySDR::Device
{
public:
XRFdc_Config myDevice_Config;
zcu111Device(void)
{
rfdc_inst_init(RFDC_DEVICE_ID);
return;
}

std::string getDriverKey(void) const
{
return "zcu111";
}

std::string getHardwareKey(void) const
{
return "XCZU28DR";
}
std::string getVendorInfo(void) const
{
return "IISc 5G Lab";
}
SoapySDR::Kwargs getHardwareInfo(void) const
{
//key/value pairs for any useful information
//this also gets printed in --probe
SoapySDR::Kwargs args;
args["Developer"] = "IISc 5G Lab";
args["Device ID"] = (std::to_string)(myDevice_Config.DeviceId); //"ZCU111 RFSoC";
args["RFDC Version"] = (std::to_string)(XRFdc_GetDriverVersion());
args["RFSoC Driver Ver"] = (std::to_string)(rfsocDriver_show_version());
return args;
}
/*******************************************************************
* Antenna API
******************************************************************/
std::vector<std::string> listAntennas(const int direction, const size_t channel) const
{
std::vector<std::string> antennas;
//std::ignore = direction;
//std::ignore = channel;

if (direction == SOAPY_SDR_RX) {
antennas.push_back("RX");
//return antennas;
}
if (direction == SOAPY_SDR_TX) {
antennas.push_back("TX");
//return antennas;
}
return antennas;
}

void setAntenna(const int direction, const size_t channel, const std::string &name)
{
std::ignore = direction;
std::ignore = channel;
std::ignore = name;

if (direction != (SOAPY_SDR_RX || SOAPY_SDR_TX))
{
throw std::runtime_error("ZCU111 Device - setAntena failed: Only RX and TX are supported");
}

}

std::string getAntenna(const int direction, const size_t channel) const
{
//std::ignore = direction;
std::ignore = channel;

if(direction == SOAPY_SDR_RX)
return "RX";
if(direction == SOAPY_SDR_TX)
return "TX";
}

/*******************************************************************
* Gain API
******************************************************************/
std::vector<std::string> listGains(const int direction, const size_t channel) const
{
//list available gain elements,
//the functions below have a "name" parameter
std::vector<std::string> results;
std::ignore = direction;
std::ignore = channel;

results.push_back("zcu111GainList");

return results;
}

bool hasGainMode(const int direction, const size_t channel) const
{
//This part of the API is meant for AGC and the AGC is not supported in current FPGA design - Sudhakar
std::ignore = direction;
std::ignore = channel;

return false; //default is false
}

void setGain(const int direction, const size_t channel, const double value){
//Part of QMC settings.
u32 Type;
printf("\n-----------setGain API--------------\n My received direction: %d \n", direction);
printf("My received channel: %d \n", channel);
printf("My gain value: %f \n", value);
(direction == SOAPY_SDR_TX) ? (Type = 1) : (Type = 0); //0 = ADC, 1=DAC
changeGain(value, Type, 1, 1); //int changeGain(double new_gain_value, u32 Type, u32 Tile_Id, u32 Block_Id)
}

/*!
* Get the overall value of the gain elements in a chain.
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
* \return the value of the gain in dB
*/
double getGain(const int direction, const size_t channel) const{
std::ignore = direction;
std::ignore = channel;
return 0.0;
}

/*!
* Get the overall range of possible gain values.
* \param direction the channel direction RX or TX
* \param channel an available channel on the device
* \return a list of gain ranges in dB
*/
SoapySDR::Range getGainRange(const int direction, const size_t channel) const{
//Part of QMC Settings.
std::ignore = direction;
std::ignore = channel;

SoapySDR::Range gainRange;
return gainRange;
}
/*******************************************************************
* Frequency API
******************************************************************/
double getFrequency(const int direction, const size_t channel) const
{
std::ignore = direction;
std::ignore = channel;
return 433e6;
}

void setFrequency(const int direction, const size_t channel, const double frequency, const SoapySDR::Kwargs &args = SoapySDR::Kwargs())
{
printf("\n-----------setFreq. API--------------\n My received direction: %d \n", direction);
printf("My received channel: %d \n", channel);
printf("My Center frequency value: %f \n", frequency);
//SetMixerSettings(frequency, 1, 1, 1);
}

std::vector<std::string> listFrequencies(const int direction, const size_t channel) const
{
std::vector<std::string> names;
std::ignore = direction;
std::ignore = channel;

names.push_back("zcu111FreqList");
return names;
}

SoapySDR::RangeList getFrequencyRange(const int direction, const size_t channel, const std::string &name) const
{
std::ignore = direction;
std::ignore = channel;
std::ignore = name;

SoapySDR::RangeList results;
results.push_back(SoapySDR::Range(0, 4e09));

return results;
}


/*******************************************************************
* Sample Rate API
******************************************************************/
double getSampleRate(const int direction, const size_t channel) const
{
std::ignore = direction;
std::ignore = channel;

return 433e6;
}

std::vector<double> listSampleRates(const int direction, const size_t channel) const
{
std::vector<double> results;
std::ignore = direction;
std::ignore = channel;

results.push_back(0.0);
return results;
}

void setSampleRate(const int direction, const size_t channel, const double rate)
{
printf("\n ------- setSampleRate. API -------- \n My received direction: %d \n", direction);
printf("My received channel: %u \n", channel);
printf("Recd Sampling Rate: %f \n\n", rate);
}
/************************************************************
* Sensor API
* **********************************************************/
size_t getNumChannels(const int direction) const
{
//ZCU111_Device only supports RX.
return (direction == SOAPY_SDR_RX) ? 1 : 0;
}

std::vector<std::string> listSensors(void) const
{
std::vector<std::string> listsensor;

listsensor.push_back("zcu111Device_Sensor");
return listsensor;
}

SoapySDR::ArgInfo getSensorInfo(const std::string &key) const
{
std::ignore = key;
SoapySDR::ArgInfo bufflenArg;
bufflenArg.key = "zcu111";
bufflenArg.value = std::to_string(0);
bufflenArg.name = "zcu111";
return bufflenArg;
}

std::string readSensor(const std::string &key) const
{
std::ignore = key;
return std::to_string(0);
}


/*******************************************************************
* Stream API
******************************************************************/
std::vector<std::string> getStreamFormats(const int direction, const size_t channel) const
{
std::vector<std::string> formats;
std::ignore = direction;
std::ignore = channel;

formats.push_back(SOAPY_SDR_CF32); //complex float32 (8 bytes per element)
formats.push_back(SOAPY_SDR_CS12); // complex int12 (3 bytes per element)
formats.push_back(SOAPY_SDR_CS16); //complex int16 (4 bytes per element)
return formats;
}

std::string getNativeStreamFormat(const int direction, const size_t channel, double &fullScale) const
{
//std::ignore = direction;
//std::ignore = channel;

fullScale = 128;
return "SOAPY_SDR_CS16";
}

SoapySDR::ArgInfoList getStreamArgsInfo(const int direction, const size_t channel) const
{
std::ignore = channel;

if (direction != SOAPY_SDR_RX) {
throw std::runtime_error("ZCU111 Device is RX only");
}

SoapySDR::ArgInfoList streamArgs;
SoapySDR::ArgInfo bufflenArg;
bufflenArg.key = "bufflen";
bufflenArg.value = std::to_string(1);
bufflenArg.name = "Buffer Size";
bufflenArg.units = "bytes";
bufflenArg.type = SoapySDR::ArgInfo::INT;

streamArgs.push_back(bufflenArg);
return streamArgs;

}

SoapySDR::Stream *setupStream(
const int direction,
const std::string &format,
const std::vector<size_t> &channels,
const SoapySDR::Kwargs &args)
{
// std::ignore = direction;
//std::ignore = format;
std::ignore = channels;
std::ignore = args;

std::string recd_format;
recd_format = format;
SoapySDR::Stream * my_stream_ptr, *tx_stream, *rx_stream;

printf("I am in stream setup\n");
printf("Received format in setupStream: %s \n", recd_format);
(direction == SOAPY_SDR_TX) ? my_stream_ptr = tx_stream : rx_stream;

return my_stream_ptr;
// for(size_t i=0; i<numElems; i++)
// bufx[i] = (int32_t) 0;

return 0;
}
int writeStream(
SoapySDR::Stream *stream,
const void * const *buffs,
const size_t numElems,
int &flags,
const long long timeNs, long timeUs)
{
std::ignore = stream;
//std::ignore = buffs;
//std::ignore = flags;
std::ignore = timeNs;
//std::ignore = timeoutUs;

printf("Received numElements in WriteStream: %d \n",numElems);
printf("Driver key from writeStream function: %s \n", this->getDriverKey());
printf("buffs0 values: %d \n", *((int*) buffs[0]+1));


printf("I am in Writestream printf\n");
return 0;
}
};

On Wed, Aug 4, 2021 at 5:14 PM righthal...@gmail.com <righthal...@gmail.com> wrote:
I just realized that you are now showing something different for "writeStream" - this form is only correct if it is done in the class definition, but the indention shown implies that you are no longer in the definition. I really need to see your whole device class to tell if it is is correct.

righthal...@gmail.com

unread,
Aug 6, 2021, 1:05:45 AM8/6/21
to Pothos Users
Your "this->getDriverKey()" will not even compile on my machine it has to be "getDriverKey().c_str()".
May be your crashing on that, but capturing the error and continuing.

I replaced the writeStream in SoapyHackRF with yours. It just required replacing the "int writeStream" with "int SoapyHackRF::writeStream". I got the expected output -

Received numElements in WriteStream: 18528 
Driver key from writeStream function: HackRF 
buffs0 values: 0 
I am in Writestream printf
Received numElements in WriteStream: 18528 
Driver key from writeStream function: HackRF 
buffs0 values: 0 
...

That says that your problem is else where in your driver.

By the way how are you doing the include of your code ? You have found a nice way of doing it.




example.txt
Reply all
Reply to author
Forward
0 new messages