Queues

Queues are IQ Complex data blocks fifo, allocated system-wide. They have the following properties:

  • They have a unique name: two queues created with the same name refer to the same SDRVM object,
  • They are designed to be shared between tasks, one task may write to a queue and the other read from the same queue,
  • They work as FIFOs of blocks
  • The queues have a limited and fixed size of 25 blocks, currently this value cannot be changed by the user at runtime. When the queue is full, the writer process is blocked until the oldest block has been removed from the queue.

ddc

Queues.create

Call this function create a new queue. It takes two parameters :

  • Queue name, string : the name to be used as the unique identifier for the internal Queue object,
  • a Boolean to indicate if the queue has to be created if it does not exist yet.

This function returns a JSIQQueue object.

var queue = Queues.create( string name , bool create);

Queues.delete

Call this function to delete an existing queue. It returns :

  • true if the queue was existing,
  • false otherwise.
bool deleted = Queues.delete(string name);

Queues.exists

Test if a Queue is present in the system. It returns :

  • true if the queue exists,
  • false otherwise.
bool exists = Queues.exists(string name);

Using JSIQQueue

The JSIQQueue Object is defined as follows :

object JSIQQueue {
    constructor JSIQQueue( name ) ; 
    string getName();

    bool ReadFromRx( JSRadio object, [Object options] ); // runs until rx is stopped
    bool isFromRx();

    bool ReadFromFile( filename, [Object options]  ) ; // loads .WAV / .CS16 / .CF32 files based on file extension
    bool isFromFile();

    IQData dequeue( bool blocking = false by default );
    bool enqueue( IQData object ); // samples pushed are cleared in caller and transfered in the queue !

    bool writeToFile( string wavefilename , [option:channel]); // stops when an empty block is processed
    bool isSendingToFile();

    bool isFull();
    int getSize();

    bool flush();

    bool stop(); // stops now
}; 

A task can refer to an existing queue by calling the constructor with the existing name.

  • Example

in Task 1 :

var queue = Queues.create('rx');
queue.enqueue( ... );

in Task 2 :

var queue = new JSIQQueue('rx');
var IQ = queue.dequeue(true); // wait for data

Which is equivalent to :

var queue = Queues.create('rx', false);
var IQ = queue.dequeue(true); // wait for data

.getName

Returns the unique name (string) of an existing queue.

var name = Queues.delete(string name);

.ReadFromRx

var ok = queue.ReadFromRx( JSReceiver object,  [Object options] );

Automatically connects the input of a queue to a JSReceiver object. While user code can extract IQ data from a receiver and enqueue to a given queue, this direct connection is more efficient and requires less CPU cycles.

The option object must be has follows :

var options = {
    'frequency' : number, /* rx center frequency. The receiver is tuned to this frequency before being turned on */
    'sample_rate': number, /* sample rate to be used by the receiver */
    'all_channels' : boolean /* on receivers with multiple channels, set to true to have all channels active*/
};

Example :

var IQBlock = new IQData('iq');
var fifo_from_rx = Queues.create( 'input');
// open RX 
var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });
rx.setRxCenterFreq( 435 );
// engage streaming
if( !fifo_from_rx.ReadFromRx( rx ) ) {
    print('Cannot stream from rx');
    exit();
}
// now loop : read IQ block from radio, do something
while( fifo_from_rx.isFromRx() ) {
    if( IQBlock.readFromQueue( fifo_from_rx ) ) {    // load samples from input queue into IQBlock object
        mycodeusingsample( IQBlock );
    }
}

.isFromRx

Returns true if the Queue is currently automatically receiving data from a JSReceiver object.

.dequeue

var iq = queue.dequeue( bool wait_if_empty );

Returns the oldest block in the queue.

  • If the wait_if_empty value is true : the caller is blocked until a value has been added in the queue,
  • If the wait_if_empty value is false : An empty (size = 0) IQData block is returned in the queue is empty.

Example :

var fifo_to_task = Queues.create( 'outut');
var IQBlock = new IQData('iq');
var samples = 0 ;

while(true) {
   IQBlock = fifo_to_task.dequeue(true);
   samples = samples + IQBlock.getLength();
   print('Received : ' + samples + ' samples.');
}

.enqueue

 queue.enqueue( IQData block );

Adds a new block in the queue. If the Queue is full, the writer task is suspended.

Example :

var q = Queues.create( 'queue');
var IQ = DSP.tone( 440, 1000, 1000 );

var x = { 'attribute_1' : 4, 'center' : 440 } ;
IQ.setAttribute( x );

// send the block to the queue
q.enqueue( IQ ); 

.ReadFromFile

Note: When the Queue is reading IQ Samples from a file, the read is sequential, block by block and cannot be suspended or restarted. See also IQFile for a manually controlled reader.

var ok = queue.ReadFromFile( string filename,  [Object options] );
Automatically connects the input of a queue to a file. The extension is used to recognize the file type. The following extensions are valid :

  • .CF32 or .FC32 or .IQ32 : Complex float single precision (8 bytes by sample, 4 for I, 4 for Q)
  • .CS16 : Complex signed integer : 16 bits
  • .CS8 : Complex signed integer: 8 bits
  • .WAV : wave files, two channels (float or integer)

The option object must be has follows :

var options = {
    'block_size'  : number,
    'sample_rate' : number, /*  if not provided , for CS16 & CF32 for example*/
    'center_freq' : numer 
};

Option parameters :

  • block_size : specifies how samples are read from the underlying file to make a IQData blocks,
  • sample_rate : forces the sample rate of the IQData blocks,
  • center_freq : specifies the center frequency, in Hz.

.isFromFile

var bool_value = queue.isFromFile();
Returns true if the Queue is currently automatically receiving data from a file. When the file has been completely read, this function returns false.

.writeToFile

var ok = queue.writeToFile( string filename , [option:channel]);

Automatically connects the output of a queue to a flat file writer.

Warning !! : if the queue is directly from a receiver, the file grows quickly and may fill the entire filesystem...

The extension is used to recognize the file type. The following extensions are valid :

  • .CF32 or .FC32 or .IQ32 : Complex float single precision (8 bytes by sample, 4 for I, 4 for Q)
  • .CS16 : Complex signed integer : 16 bits
  • .CS8 : Complex signed integer: 8 bits
  • .WAV : wave files, two channels (float or integer)

.isSendingToFile

Returns true if the Queue is currently automatically sending data to a file.

.isFull

Returns true if the Queue is currently full. Adding more data to a full Queue will block the writing task until another task as consumed at least one block

.flush

Deletes all pending IQ blocks from the queue when called.

.getSize

Returns the number of IQ Blocks currently in the Queue.

.stop

Stops the background tasks handling streaming.

Last update: August 24, 2023