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.
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] );
- .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();
.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