Skip to content

Warning

For more simplicity and readability, the creation of an RX object or TX has been simplified as follows on the examples in this document:

var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });

Ideally, checks are to be made before launching a capture or acquisition: is an SDR device present and ready?

var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });
if( typeof rx != 'object' ) {
    print('no radio ?');
    exit();
}

if( !rx.isValid()) {
    print('no radio ?');
    exit();
}

if( rx.isAvailable() ) {
   // set sample rate
   if( rx.setRxSampleRate( 1e6 )) {
      print('Sample rate changed');
   }
} else {
   print('device is already used, we do not change Sampling Rate');
}

System

System.cwd

Change working directory

System.cwd('/home/user/test');

System.exec

Execute system command, sending optional parameters as array

**WARNING : there is no size limit for outputs 'stdout' and 'stderr' **

System.exec('/path_to_file/<command>',[ parameters array]);

Function will return JSON object :

{
  'exec' : '/path/to/the/command/',
  'stdout': standard output as text
  'stderr': error output as text
}

Example :

var c = {
    'command' : '/bin/bash', 
    'args' : ['-c','ls']
} ;

var res = System.exec( c );
print( JSON.stringify( res ));

System.isMounted

Check if specified path is a mounted filesystem or not.

System.isMounted('chemin_complet');

Example :

if( System.isMounted('/media/disk/04DA-6F70') ) {
    print('search boot');
    createTask('/media/disk/04DA-6F70/boot.js');
}

System.ps

Get a list of JS tasks which are actually running on the SDR Javascript Virtual Machine

var running_tasks = System.ps();
  • Example, list tasks :
var tasks = System.ps();
print( JSON.stringify( tasks ));

System.kill

Tells a specific running task to stop.

System.kill(task_id);

System.mkFifo

Create a Linux FIFO file.
Function will return a TRUE boolean value if FIFO was yet existing or created just now.

var ok = System.mkFifo('/tmp/data.fifo');

Note : if the FIFO will be used to transfer IQ data to a third-party application through file ( E.G.: IQData.appendToFile(...)), you have to use correct extension type ( .CF16 .CF32). More informations on 'IQdata Class' section.

  • Example
var ok = System.mkFifo('/tmp/data.fifo.CS16');

JSTask

exit

  • Exit from actual task
exit();

load

  • Include a Javascript file to the actual one (similar to function load).
  • URL may be used instead of local path
load('/home/scripts/example/plotlib.js');
load('http://mywebsite:8081/scripts/plotlib.js');

print

  • Send a text to the actual standard output.
  print( param1, param2, ... , paramN );

example :

print('Hello world');

getTID

  • Returns actuel task number (TaskID) running in ths VM
getTID();
  • Example
var tid=getTID();
print(JSON.stringify(tid));

argc()

  • Returns the number of arguments received by the task
var count=argc();

argv(x)

  • Get parameters receiver from task
variable = argv(x);
  • Example : get first parameter:
var my_first_parameter=argv(0);
print(my_first_parameter);

sleep

  • Pause task (in milliseconds)
sleep(millis);

getRunningTime

  • Returns running time in milliseconds from the starting on the task.
getRunningTime();

createTask

  • Create a task from a script file, using optional parameters
createTask(filename, [optional : paramètre1, paramètre2, ....] );
  • Example
// Create task
createTask('/home/use/sdr4space/examples/record_signal.js');
  • New created task will appear as follows on log/output :
(task:1)> Sample rate changed
(task:1)> 1
(task:1)> 1764.001000
(task:1)> 1 detected changes

waitTask

Wait for task end. Actual running task is suspended until the ID task (parameter) will terminate.

     waitTask( ID );

MQTT and Mailbox

MBoxCreate

Create mailbox to communicate between tasks.
Mailbox name is unique : if another mailbox yet exists using this same name, command will not work.

bool result = MBoxCreate(mailbox_name) ;

Mbox can be connected to MQTT topic by using a second JSON-type argument as follows :

var config = {
   'host': 'localhost',
   'login': 'mqtt',
   'pass' : 'mqtt',
   'topic': 'demo' 
} ;

bool result = MBoxCreate(mailbox_name, config) ;
  • Display MQTT sent messages:
 mosquitto_sub -t 'demo/#' -u mqtt -P mqtt -h localhost
  • Send MQTT message do sdr4space.lite app :
mosquitto_pub -h localhost -u mqtt -P mqtt -t 'demo' -m "message test" 

Messages will be sent to the specified MQTT broker.
If a message is received on the topic passed as parameter, then it is added to the pending messages list.

if( !MBoxCreate('pong')) {
    print('could not create the mailbox');  
    exit(0);
}

MBoxPost

Post a message to the 'mailbox_name' mailbox

MBoxPost(mailbox_name, message)
  • Example, sending 10 messages:
if( !MBoxCreate('ping')) {
    print('could not create the mailbox');  
    exit(0);
}
for( var i=0 ; i < 10 ; i++ ) {
    // send a message to task pong
    MBoxPost('test', 'message test nr ' + i);
        }

MBoxCheck

Check (True/false) for pending messages in the mailbox.

MBoxCheck(mailbox_name);
print("Messages en attente: ",MBoxCheck('test'));

MBoxExists

Check if mailbox exists.

MBoxExists(mailbox_name);
  • Example :
if (MBoxExists('test')) { print('Mailbox : test exists !'};

MBoxPop

Get a pending message on the mailbox (oldest one first if several)

:!: MBoxPop returns following values : {"msg_valid":true,"msg_from":0,"msg_payload":"message 1"}

MBoxPop(mailbox_name);
print('MBox test message task starting');

if( !MBoxCreate('test')) {
    print('could not create the mailbox');  
    exit(0);
}

// Envoie 10 messages sur la boite 'test'
for( var i=0 ; i < 10 ; i++ ) {
    // send a message to task pong
    MBoxPost('test', 'message ' + i);
    sleep(200);
}
print("Messages en attente: ",MBoxCheck('test'));
for (  ; ; ) {
if (MBoxCheck('test') && MBoxExists('test')) { 
            print(JSON.stringify(MBoxPop('ping')));
            } else {break;}
}
print('Task testmsg ends');
MBoxCreate('box');
MBoxPost('box', 1 );
MBoxPost('box', 'test string' );
MBoxPost('box', {'x': 3} );

var x = MBoxPopWait( 'box', 10000 );
print( JSON.stringify( x ));
x = MBoxPopWait( 'box', 10000 );
print( JSON.stringify( x ));
x = MBoxPopWait( 'box', 10000 );
print( JSON.stringify( x ));

{"msg_valid":true,"msg_from":0,"msg_payload":"1.000000"}
{"msg_valid":true,"msg_from":0,"msg_payload":"test string"}
{"msg_valid":true,"msg_from":0,"msg_payload":"{\"x\":3}"

MBoxPopWait

Wait for incoming message on the 'boxname' mailbox for a 'timeout' duration (milliseconds)

MBoxPopWait( boxname, timeout);
  • Example:
var msg = MBoxPopWait('ping', 10000);
print('Pong:: received message : ' + msg.msg_from + ' content :' + msg.msg_payload );

Messages processing

.msg_valid

Check for pending message

.msg_payload

Extract message contents

Example

var S = MBoxPopWait( 'stream', 50) ;
if (JSON.parse(S.msg_valid) == 1) {
    var stream_status = (JSON.parse(S.msg_payload).toFixed(0));
    print ("MQTT stream : ", stream_status);
}

MBox example : ping and pong

A 'ping.js' task will create a new 'ping' mailbox and send messages to this mailbox at regular intervals.
The 'pong.js' task is receiving messages, and reports information to the first 'ping' task using a 'pong' mailbox ...

  • ping.js
rename('ping');
createTask('pong.js');
print('Ping task starting');
// Create the message box for detections
if( !MBoxCreate('ping')) {
    print('could not create the mailbox');  
    exit(0);
}
for( var i=0 ; i < 100 ; i++ ) {
    // send a message to task pong
    MBoxPost('ping', 'message ' + i);
    // wait for a message from task pong
    var msg = MBoxPopWait('pong', 10000);
    print('Ping :: received message :' + msg.msg_from + ', content:' + msg.msg_payload );
    sleep(1000);
}

print('Task ping ends');
  • pong.js
//remane('pong');
if( !MBoxCreate('pong')) {
    print('could not create the mailbox');  
    exit(0);
}
print('Pong task starting');
for( var i=0 ; i < 50 ; i++ ) {
    var msg = MBoxPopWait('ping', 10000);
    print('Pong:: received message : ' + msg.msg_from + ' content :' + msg.msg_payload );
    MBoxPost('pong','ok');
}
print('Task pong ends');
 Loading boot task from file : [./ping.js]

(ping:0)> Ping task starting
(ping:0)> Ping :: received message :-1, content:undefined
(task:1)> Pong task starting
(task:1)> Pong:: received message : 0 content :message 0
(ping:0)> Ping :: received message :1, content:ok
(task:1)> Pong:: received message : 0 content :message 1
(ping:0)> Ping :: received message :1, content:ok
(task:1)> Pong:: received message : 0 content :message 2
(ping:0)> Ping :: received message :1, content:ok
(task:1)> Pong:: received message : 0 content :message 3
.....

SharedMap

Persistent data sharing between tasks.
Creates a copy of past data and stores it independently of job creation / deletion.
Stored data is not erased when the task that created it ends.
The SharedMap object supports concurrent access between tasks.

.store

Store 'data' datas in a SharedMap object 'dictionnary_1)

var x = new SharedMap('dictionnary_1');
x.store( 'key1', data );

'data' is a JSON object type.

.load

Get data contents from a SharedMap engine

.contains

Check if key is present in a SharedMap objest

.clear

Remove the key from SharedMap object

.keys

Display keys from SharedMap engine

  • Example :

First task :

    var x = new SharedMap('dictionnary_1');
    var data = { 'param1' : 3, 'param2' : 0 };
    x.store( 'key1', data );

Second task :

    var x = new SharedMap('dictionnary_1');
    if( x.contains('key1') ) {
        var y = x.load('key1');
        print( y.param1 );
    }

Retrieve all stored keys :

var x = new SharedMap('dictionnary_1');
var data = { 'param1' : 3, 'param2' : 0 };
x.store( 'key1', data );
x.store( 'key2', data );
var keys = x.keys();
// keys = ["key1","key2"]

Webserver




Commands

  • Declare webserver :
var w = new WebServer('monitor');

sendResponse

sendHeader

addHandler

removeHandler

addUser

delUser

Soapy module

Soapy.makeDevice

Define a new SoapySDR device (source).

  • RTLSDR
var radio = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;

  • PlutoSDR
var radio = Soapy.makeDevice({'query' : 'driver=plutosdr' }) ;

  • BladeRF
var rx = Soapy.makeDevice( {'query' : 'driver=bladerf' });

BladeRF module






BladeRF.makeDevice

  var radio = BladeRF.makeDevice( { 'serial': '41b1e86b40c64bcabe43696f8f1ea962', 'device_name' : 'board0'} );

BladeRF.list

Example:

  var list = BladeRF.list();
  print('we have ' + list.length + ' boards.');
  var x = list[0] ;
  var radio = BladeRF.makeDevice( x );

UI module (GUI)




UI.inspect

Autocorrelation

//File AC



var samples = new IQData('');
samples.loadFromFile('/tmp/test.cf32');
print(samples.getLength() + ' samples');

samples.setCenterFrequency( <change_me> );
samples.setSampleRate(500e3);
samples.dump(); 

// compute AC
var ac = samples.getAC(8192);
UI.inspect( ac );

Spectrum

// File --> spectrum 

    var samples = new IQData('');
    samples.loadFromFile('/tmp/test.cf32');
    print(samples.getLength() + ' échantillons');

    samples.setCenterFrequency( 923.4 );
    samples.setSampleRate(2.4e6)
    samples.dump(); 

    print(samples.getLength() + ' échantillons');
    var spectrum = samples.getPowerSpectrum( 1024 ) ;
    UI.inspect( spectrum );

UI.viewSat

UI.addPOI


var POI_params = {
'name' : 'myPOI',
'description' : 'description',
'longitude' : 0.25,
'latitude' : 45.2
};
UI.addPOI(POI_params);

UI.centerMap

IO module

This Javascript module is managing I/O functions

IO.fwrite

Write a buffer to file

IO.fwrite(filename, buffer)

IO.fwritestr

Write a string to file

IO.fwritestr(filename, string)

IO.fappend

Append buffer content to file

IO.fappend(filename, buffer)
  • Example : download and save a TLE file
var myTLE = IO.HTTPGet("http://www.celestrak.com/NORAD/elements/weather.txt",true);
IO.fappend('/tmp/weather.txt',myTLE);

IO.fappendstr

Append a string to an existing file

IO.fappendstr(filename, string)

IO.fread

Load (read) a file.

IO.fread(filename)

IO.frename

Rename file

IO.frename(old_name,new_name)
  • Example :
var rename = IO.frename(old_name,new_name);
print(rename); // returns 1 if OK

IO.fdelete

Delete file

IO.fdelete(filename)

IO.getfsize

Get file size

IO.getfsize(filename)
  • Example : display size of a local file
var size = IO.getfsize('/tmp/weather.txt');
print('Size : ',size.toFixed(0), ' bytes');

IO.getVolumeUse

Display occupied disk space (percent).

Note : 'filename' parameter is an existing file located on the volume.

IO.getVolumeUse(filename)
  • Example :
var x = IO.getVolumeUse('/etc/passwd');
print('Disk use : ' + x + ' %' );

IO.FTPSend

Send a file to a remote host using FTP protocol

IO.FTPSend(params, filename)
  • Set '' params'' as follows :
var params = {
     host: '192.168.1.10',
     user: 'myusername',
     password: 'mypassword',
     passive: true,
     destination_folder: '/usr/remote/'
};

  • Example:
var rc = IO.ftpSend( params, 'localfile.txt');

IO.HTTPGet

Download a remote file using HTTP protocol (similar to WGET/CURL)

IO.HTTPGet(URL, [true])

True --> binary file

  • Example : download and save as /tmp/weather.txt :
var myTLE = IO.HTTPGet("http://www.celestrak.com/NORAD/elements/weather.txt",true);
IO.fappend('/tmp/weather.txt',myTLE);

IO.SFTPSend

  • Send file using SFTP/SSH protocol
:!: Initial exchange of SSH ID-keys between local host and remote server is mandatory  
    (perform a manual SSH connection first).
IO.SFTPSend({host: 'remote_ip', tcp_port: 22, destination_folder: '/home/sdrvm/pub/', user: 'my_name', password: 'my_password'}, filename)
  • Example: send file via SCP
// Send the last plot file 'plot.png' using SSH
var lastplot = IO.SFTPSend({host: 'remote_ip', tcp_port: 22, destination_folder: '/home/sdrvm/pub/', user: 'my_name', password: 'my_password'}, 'plot.png');
sleep(1000);

SAT module

Satobserver

  • Objet : Observer('my_place')
var home = new Observer('Rambouillet Office');

setPosition

Define observer location (longitude, latitude, altitude : format JSON),

setPosition({ 'longitude' : number, 'latitude' : number, 'asl' : number });
  • Example:
var home = new Observer('My_Office');
home.setPosition( { 'longitude' : 2.829, 'latitude' : 47.243, 'asl' : 163 } );

getPosition

Retrieve actual position

print(JSON.stringify(home.getPosition()));
  • Returns JSON string: { 'longitude' : number, 'latitude' : number, 'asl' : number }

TLE modules

Loading TLE

  • Internet:
      var satlist =TLE.loadTLE('https://www.celestrak.com/NORAD/elements/amateur.txt' ) ;
  • local storage :
      var satlist = TLE.loadTLE('/tmp/amateur.txt') ;`
  • Force manual TLE :
var TLE = new Satellite('ISS');
var loaded = TLE.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');
if( !loaded ) {
    print('error loading TLE for ISS ?');
    exit();
}

TLE.loadTLE

  • Load a TLE and returns array objects for a specific satellite :
TLE.loadTLE(path)
{ 'name': string, nom du satellite,
'norad_number' : ID Norad du satellite,
'L1': string, TLE ligne 1,
'L2': string, TLE ligne 2,
'epoch': date des TLE
 },

:!: Load TLE from URL is path value is starting by 'http', use local file path instead

  • Example:
var satlist = TLE.loadTLE('https://www.celestrak.com/NORAD/elements/satnogs.txt' ) ;
print('We have loaded ' + satlist.length + ' sat definitions.');

JSatellite

  • Objet : Satellite('name')
var ISS = new Satellite('ISS');

.setTLE

Define 2-lines TLE for a given object.

setTLE(TLE1, TLE2);

* Example :

var loaded = ISS.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');

.getNorad

Get NORAD ID from object

.getNorad()

.getPosition

Returns JSON-type object describing actual position of satellite.
To get a position in future, provide optional parameter offset_seconds.

.getPosition(offset_seconds);
  • Output :
{ 'longitude' : number, 'latitude' : number, 'distance' : number }
  • Example :
var ISS = new Satellite('ISS');
var loaded = ISS.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');
var currentPosition = ISS.getPosition();
print( JSON.stringify( currentPosition ));


.getLookAngle

Returns information on the satellite observation conditions either immediately or within [offset] minutes (optional)

getLookAngle(observer_position, [offset temps en secondes]);

Input datas :

  • observer_position : observer position, object : { 'longitude' : number, 'latitude' : number, 'asl' : number }
  • optional parameter [offset] : number of seconds in future

Output :

{ 'azimuth' : number, 'elevation' : number, 'range' : number, 'in_view' : boolean }
  • Example
var home = new Observer('home');
home.setPosition( { 'longitude' : 0.029079, 'latitude' : 44.643868, 'asl' : 163 } );
var ISS = new Satellite('ISS');
var loaded = ISS.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');
var passes = ISS.predictPasses( home, 24.0 ) 
var currentPosition = ISS.getPosition();
var look = ISS.getLookAngle( home );
print( JSON.stringify( look ));

.predictPasses

Predict the passages of the Satellite object for the observer given as a parameter, up to [calculation period] hours.

  • Example
.predictPasses( { 'longitude' : 1.829079, 'latitude' : 48.643868, 'asl' : 163 }, 24);

Returns following elements (JSON string) :

        [{
            'aos' : 'dd/mm/yyyy hh:MM:ss', // date time of AOS
            'aos_secs' : number of secs,   // seconds since now to AOS
            'los' : 'dd/mm/yyyy hh:MM:ss', // date time of LOS
            'los_secs' : number of secs,   // seconds since now to LOS
            'max_elevation' : number,       // maximum elevation (degs) for observer for the pass
            'pass_duration' : number   // duration of the pass in secons
         },
         ...
        ]
  • Example:
var home = new Observer('home');
home.setPosition( { 'longitude' : 0.029079, 'latitude' : 45.643868, 'asl' : 163 } );

var ISS = new Satellite('ISS');
var loaded = ISS.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');

var passes = ISS.predictPasses( home, 24.0 ) ; // predic passes for the next 24 hours
// print the next passes
print( JSON.stringify( passes ));

.getDopplerEstimation

  • Provide a doppler estimation for a satellite, at a frequency of center_freq_hz and for a given observer location

  • Parameter seconds_offset is optional to get an estimation in the future at T + seconds_offset

  • Doppler value is computed for a given period of 5 seconds, by 500 msecs steps. 10 values are processed.
    Output will return average doppler, max and mins values for the interval

.getDopplerEstimation( observer, center_freq_hz, [seconds_offset ] );
  • Returned JSON object :
{'doppler_min' : number in Hz, 'doppler_max' : number in Hz, 'doppler_avg' : number in Hz }
  • Example:
var ISS = new Satellite('ISS');
var loaded = ISS.setTLE('1 25544U 98067A   20262.17917074  .00000067  00000-0  93590-5 0  9992','2 25544  51.6432 248.2943 0000854 102.9022 344.0032 15.48951196246432');

var home = new Observer('home');
home.setPosition( { 'longitude' : 1.829079, 'latitude' : 48.643868, 'asl' : 163 } );

    // Estimate doppler now
    var doppnow = ISS.getDopplerEstimation( home, 437.0e6 );
    print( JSON.stringify( doppnow ));
    // Doppler at T + 5seconds
    var futuredopp = ISS.getDopplerEstimation( home, 437.0e6 , 5);
    print( JSON.stringify( futuredopp ));

.getPassDetails

Provide details for a given pass

getPassDetails( observer, offset_secs, length_sec );

Returns following values, 1 second stepping.

        [{
            'when' : 'dd/mm/yyyy hh:MM:ss', // date time
            'dt' : number of secs,   // seconds after first element (relative time offset)
            'az' : number, // azimuth in degrees
            'el' : number , // elevation in degrees
            'range' : number,       // distance from observer, in meters
            'dopp1Ghz' : number   // doppler for a receiver at observer, assuming tx freq is 1 GHz
         },
         ...
        ]

  • Example: display 10 minutes of a pass occuring over the next 80 minutes (4800 seconds).
var pass = ISS.getPassDetails( home, 4800, 300 );
print(JSON.stringify(pass));

.waitInView

Wait for the satellite to be in view from observer location.
Additional waiting delay may be provided as parameter, acting as a timeout.
A Returned value is boolean : TRUE if satelite is in view, FALSE if expired delay.

bool ISS.waitInView( <observer>, [ optional time out x milliseconds ] ) ;

  • Example : check if satellite will be in view over the next 5 seconds (5000 milliseconds)
while( ISS.waitInView( home, 5000 ) == false ) {
    print('not yet...');
    currentPosition = ISS.getPosition();
    print('Distance (km) : '+currentPosition.distance/1e3);
}

ISS example

* Compute next passes for ISS :

var home = new Observer('home');
home.setPosition( { 'longitude' : 1.833807, 'latitude' : 48.650696, 'asl' : 207 } ); //Rambouillet

var TLE;
var ISS;
var satlist =TLE.loadTLE('https://www.celestrak.com/NORAD/elements/amateur.txt' ) ;
    print('We have loaded ' + satlist.length + ' sat definitions.');
for(var j=0 ; j < satlist.length ; j++ ) {
      TLE=satlist[j];
   if(TLE.name=="ISS (ZARYA)"){
      ISS = new Satellite(satlist[j].name);
      ISS.setTLE( TLE.L1, TLE.L2 );
      print (JSON.stringify(TLE));
      print(TLE.name);
break;
 }
}
    var k;

var passes = ISS.predictPasses( home, 96 ) ; // predict passes for the next 4 days
// print the next passes
for( var i=0 ; i < passes.length ; i++ ) {
     var next = passes[i] ;
     print('--------------------------------------------------------------------------------');
     print('Pass #'+i) ;
     print('  AOS : ' + next.aos + ', LOS : ' + next.los + ', duration: ' + next.pass_duration + ' secondes');
     print('  MAX Elev : ' + next.max_elevation );
}

JSRadio

construct the JSRadio object



  object JSRadio {
     constructor JSRadio(key);
     string getKey();
     bool valid() // true if hw init ok
     bool isAvailable() // true if nothing running on it (another steaming operation)
     bool setExternalClockRef( bool, clock_Hz ); // 
     dump();

     double getRxCenterFreq() ; // MHz
     bool setRxCenterFreq( freq ); // MHz
     double getMinRxFreq() ; // MHz
     double getMaxRxFreq() ; // MHz

     int getRxSampleRate();
     bool setRxSampleRate( int );

     // non blocking : returns samples from current rx if receiver already used by another task
     IQData Capture( int samples );

     // Blocking : if device already sampling for another task, the capture will wait
     // availability of the device can be checked before with isAvailable()
     IQData captureSubBand( int samples , OLshift, bw );

     int getGainStageCount();
     double getMinGain( stage );
     double getMaxGain( stage );
     double setGain( double value, stage );

     // TX support
     bool hasTX();
     bool txOn();
     bool txOff();
     bool setTxGain( value );
     number getTxGain();
     number getMinTXGain();
     number getMaxTXGain();
     bool txData( IQData samples );


}
var capture_rx = new JSRadio('capture');
if( !capture_rx.isValid() ) {
    print('capture radio not found.');
    exit();
}
print('Capture radio ok, Sample rate is :' + capture_rx.getRxSampleRate() / 1e6 + ' MSPS');
capture_rx.setRxCenterFreq( 436.95 );
var IQ = capture_rx.captureSubBand( 100e3, 50e3, 100e3 );
IQ.saveToFile('/opt/sdrnode/record/capture.cf32') ;

.getKey

    duk_push_c_function(ctx, myobject_getKey, 0 /*nargs*/);
    duk_put_prop_string(ctx, -2, "getKey");

.isValid

  • Check if given object is valid
.isValid();
  • Example:
int('Searching for SoapySDR device...');
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
if( !rx.isValid()) {
    print('no radio ?');
    exit();
}

.dump

    duk_push_c_function(ctx, myobject_dump, 0 /*nargs*/);
    duk_put_prop_string(ctx, -2, "dump");

RX (receiving)

.getRxSampleRate

  • Get the RX samplerate (Hz)
.getRxSampleRate();

.setRxSampleRate

  • Define the RX samplerate (Hz)
.setRxSampleRate(sample_rate);

.getRxCenterFreq

  • Returns the central frequency (MHz)
.getRxCenterFreq();
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
print(rx.getMaxRxFreq());
print(rx.getRxCenterFreq());

.getMinRxFreq

  • Returns the minimum allowed frequency for RX (MHz)
.getMinRxFreq();

.getMaxRxFreq

  • Returns the mmaximum allowed allowed frequency for RX (MHz)
.getMaxRxFreq();
  • Example:
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
print(rx.getMaxRxFreq());

.getGainStageCount

  • Get the amplification stages number
.getGainStageCount()

.getMinGain

  • Get the minimum allowed gain for this device
.getMinGain();

.getMaxGain

  • Get the maximum allowed gain for this device
.getMaxGain();

.setRxCenterFreq

  • Define a center frequency for this object (MHz).
.setRxCenterFreq(freq_MHz);
  • Example :
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
print("Freq : ",rx.getRxCenterFreq());
print("Listening now on 1090 MHz");
rx.setRxCenterFreq(1090);
print("Freq now : ",rx.getRxCenterFreq());
(boot:0)> Freq : 100.000000
(boot:0)> Listening now on 1090 MHz
(boot:0)> Freq now : 1090.000000

.setGain

  • Define gain for stage 'stage'
.setGain(gain,stage);
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
rx.setGain(30,0);

Example: RX status

var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
print('Fmin : ',rx.getMinRxFreq().toFixed(0));
print('Fmax : ',rx.getMaxRxFreq().toFixed(0));
print('Samplerate : ',rx.getRxSampleRate().toFixed(0));
print('RXamp stages : ',rx.getGainStageCount().toFixed(0));
print('Gain Min : ',rx.getMinGain().toFixed(1));
print('Gain Max : ',rx.getMaxGain().toFixed(1));
print('Actual freq : ',rx.getRxCenterFreq().toFixed(0), ' MHz');
exit();
Fmin : 24
Fmax : 1764
SR : 2048000
RXamp stages : 1
Gain Min : 0.0
Gain Max : 49.6
Actual freq : 100MHz
Samplerate : 2048000
exit requested from user

TX (transmitting)




.hasTX

Check if SDR device is able to transmit

.hasTX();

.txOn

Start transmit

.txOn(freq_MHz, SR_Hz);

.txOff

Stop transmit

.txOff();

.txData

.txData();

.setTxGain

Define TX gain

.setTXGain(gain);

.getTXGain

Get TX gain

.getTXGain();

.getMinTXGain

Get minimum allowed gain for this device

.getMinTXGain();

.getMaxTXGain

Get maximum allowed gain for this device

.getMaxTXGain();

Example

  • Sending tones
//var tx = Soapy.makeDevice({'query' : 'driver=plutosdr' }) ;
var tx = BladeRF.makeDevice( {'device_name' : 'blade' });
print('TX : ',tx.hasTX())
print('Gain : ', tx.getTxGain());
var maxgain=tx.getMaxTXGain();
tx.setTxGain( maxgain-10 ); 
print('New gain : ',tx.getTxGain());
tx.txOn( 144, 4e6 ); 
tx.txData( DSP.tone( 440, 10000, 12500 ));
tx.txData( DSP.tone( 880, 15000, 12500 ));
tx.txOff();
  • Console :

     Loading boot task from file : [./tx.js]

    (boot:0)> TX : TRUE
    (boot:0)> Gain : 0.000000
    (boot:0)> New gain : 50.000000
    virtual bool BladeRFAD::txOn(int64_t, int)() TX SampleRate set to 4.000 MHz
    virtual bool BladeRFAD::txOn(int64_t, int)() Effective TX Fitler set to 3200000.000000
    virtual bool BladeRFAD::txOn(int64_t, int)() Starting TX on 144.000 MHz with Sample Rate : 4.000 MHz
    tx_thread() starting streaming
    void data_upsample_thread(tx_thread_config*)() Starting
    virtual bool BladeRFAD::txOff()() Waiting for TX queue to be processed...
    void data_upsample_thread(tx_thread_config*)() ratio : 318.664137 in:25296 out:8060928
    void data_upsample_thread(tx_thread_config*)() ending
    virtual bool BladeRFAD::txOff()() Waiting for BladeRF queue to be processed...
    virtual bool BladeRFAD::txOff()() BladeRF queue processed
    void* streamtx_callback(bladerf*, bladerf_stream*, bladerf_metadata*, void*, size_t, void*)() phy stop requested.
    tx_thread() ending streaming

    No running task, ending.

IQdata (IQ samples)

  object IQData {
     constructor IQData( string name );
     number getChannelCount() : number of channels in the data , by default 1

     Samples getReal([option:channel])  ; // returns real part
     Samples getImag([option:channel])  ; // returns imag part

     number rms( [option:channel] );

     readFromQueue( IQQueue object ) ; // replaces current samples with what is in the queue - waits (locks task)

     FloatData getReal() ; // returns the real part in a FloatData object 
     FloatData getImag() ; // returns the imaginary part in a FloatData object

  }
  • Note : Default samplerate for IQ object is 1Msps. Use IQ.setSampleRate(SR_Hz) command to set samplerate for a given IQ object.

  • Example :

// Define and load IQ object
var o = new IQData('');
if( !o.loadFromFile('/tmp/dvbs.cf32') ) {
    exit(); 
}
// Set frequency and samplerate
o.setCenterFrequency( 100 );
o.setSampleRate(8e6);

print('we have '+ o.getLength() + ' samples recorded at '+ o.getCenterFrequency() + ' MHz, Bandwidth : ' + o.getSampleRate() / 1e3 + ' kHz');
print('file length:' + o.getDuration() + ' secs.');

// Extract 1024 sample from offset 10 ,as array (1024 Isamples and 1024 Qsamples)
var rawIQ = new Float32Array(1024*2);
var n = o.getSamples( 10, rawIQ );
print('extracted ' + n + ' IQ Pairs');
We have loaded ' + satlist.length + ' sat definitions.');

.dump

Display details on IQ object.

var o = new IQData('');
if( !o.loadFromFile('/tmp/dvbs.cf32') ) {
    exit(); 
}
o.dump();

.getLength

Returns IQdata object size in bytes
(format CF32 : 1 sample = 8 bytes)

.getLength();
  • Example
var o = new IQData('');
o.loadFromFile('/opt/sdrnode/test.cf32');
print(o.getLength() + ' samples');

.setLength

Define length (samples number) of an IQ object

     setLength( number of samples ) ;

.getSampleRate

Returns samplerate (Hz) of an IQ object

:!: If undefined, default samplerate is 1Msps

 .getSampleRate();

.getCenterFrequency

  • Get center frequency of IQ object
.getCenterFrequency();

.setSampleRate

Define a samplerate for an IQ object

.setSampleRate(SR_Hz);
  • Example
var o = new IQData('');
o.loadFromFile('/tmp/dvbs.cf32')
o.setSampleRate(8e6);

.setCenterFrequency

Set the senter frequency (MHz) of an IQ object

.setCenterFrequency(Freq_MHz);
var o = new IQData('/tmp/test.cf32');
o.setCenterFrequency(98);
var x = o.getCenterFrequency();
print(x);

.getDuration

Get IQ object duration

:!: You have to define samplerate '' .setSampleRate(SR_Hz)'' first.

.getDuration();
  • Example:
var o = new IQData('/tmp/test.cf32');
o.setSampleRate(8e6);
print('Size:' + o.getLength() + "  - SR: "  o.getSampleRate() + "  - duration: " o.getDuration() + ' secs.');

.getTimestamp

Get UNIX timestamp of an IQ block (milliseconds since 01/01/1970)

var x = new IQData('x');
var timestamp = x.getTimeStamp();

.rms

    duk_push_c_function(ctx, myobject_getRMS, 0 /*nargs*/);
    duk_put_prop_string(ctx, -2, "rms");

.loadFromFile

Load IQ object from file.

var o = new IQData('');
if( !o.loadFromFile('/opt/sdrnode/dvbs.cf32') ) {
    exit(); 
}

.saveToFile

Save IQ object to file.
Exisiting file is replaced. (use .appendToFile() to add samples to exisiting file )

Following formats are handled by recognizing their extension name.

  • .CF32 ou .FC32 ou .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 : format Audio stereo
.saveToFile(filename);
  • Example:
radio.setRxCenterFreq( 466 );
var IQ = radio.Capture( 10000 );
IQ.dump();
IQ.saveToFile('capture.cf32') ;

.appendToFile

Similar to .saveToFile() except appends to data to file if exisiting.

Following formats are handled by recognizing their extension name.

  • .CF32 ou .FC32 ou .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 : format Audio stereo

.getPowerSpectrum

var IQ = radio.Capture( 10000 );
var spectrum = IQ.getPowerSpectrum( fft ) ; 
peaks = spectrum.peaks ;
print('Peaks object:' + JSON.stringify( peaks ));
Peaks object:[{"frequency":0,"value":-99.626,"index":256},{"frequency":-0.038,"value":-114.254,"index":158},{"frequency":-0.047,"value":-114.162,"index":133},...]
"frequency"
"value"
"index"
"peaks"
"minvalue"
"maxvalue"
"maxpos"
"average"

.getAC

.getAC( length , [option:channel]) ;
  • returns autocorrelation object

.getSamples

Extract samples from IQ object, from position 'start'
Array format : a = new Float32Array(2*size)

getSamples(start, array)
  • Example
var o = new IQData('');
o.loadFromFile('/opt/sdrnode/test.cf32');
print(o.getLength() + ' échantillons');
var rawIQ = new Float32Array(1024*2);
var n = o.getSamples( 10, rawIQ );
print('extracted ' + n + ' IQ Pairs');

.setSamples

    duk_push_c_function(ctx, myobject_setSamples, 2 /* index array*/);
    duk_put_prop_string(ctx, -2, "setSamples");

.part

Extract portion of an IQ object

.part(offset_start,size);

.append

Append IQ samples to existing IQ object

.append(IQ_data);
  • Example :
var IQ = DSP.tone( 440, 1000, 12500 );
IQ.append( DSP.tone( 880, 1000, 12500) );
IQ.dump();
IQ.saveToFile('/save/tone.cf32');

.freqShift

Shift center frequency using offset : freq_Hz

.freqShift(freq_Hz);
// load the searched signal
var IQ = new IQData('');
IQ.loadFromFile('/tmp/signal.wav');
// shift the searched signal
IQ.freqShift( -300 );
IQ.dump();

.setAttribute

Associate attibutes to IQ object as a JSON object. Data will be forwarded to queues.

Example :

var IQ = DSP.tone( 440, 1000, 1000 );

var x = { 'field_a' : 4, 'field_b' : 12 } ;
IQ.setAttribute( x );

.getAttribute

Extract attribute associated to IQ datas.

Example :

var q = Queues.create( 'queue');
// Get a block 
var IQ = q.dequeue(true); // blocking mode, we wait to have something 
var x = IQ.getAttribute();

FloatData (real samples)



  class  FloatData {
     constructor Samples( string name );

     getSamples( int start, array ); - where array : a = new Float32Array(size)
     setSamples( int start, array ); 

  }

.getLength

  • Returns samples number
.getLength();

.setLength

  • Define samples number
.setLength(num);

.getSampleRate

  • Returns samplerate
.getSampleRate();

.mean

  • Returns mean (average) value for this object
.mean();

.std

.std();

.setSampleRate

  • Define samplerate
.setSampleRate(num);
var o = new IQData('');
if( !o.loadFromFile('/tmp/dvbs.cs16') ) {
    exit(); 
}
o.setCenterFrequency( 100 );
o.setSampleRate(8e6);

.getDuration

Provide the duration of IQ object.

:!: You have to define the samplerate '' .setSampleRate(SR_Hz)'' first.

.getDuration();
  • Example:
var o = new IQData('/opt/sdrnode/test.cf32');
o.setSampleRate(8e6);
print('Size:' + o.getLength() + "  - SR: "  o.getSampleRate() + "  - duration: " o.getDuration() + ' secs.');

.getSamples

  • Get samples starting from 'index' position.
.getSamples(index,array);

.setSamples

  • Create samples starting from 'index' offset
.setSamples(index,array);

DDC

  • Object: DDC('name')

setOutBandwidth

Create an output stream of 'BW_Hz' bandwidth

slice.setOutBandwidth(BW_Hz);

setCenter

Shif central frequency of +/- Hz

slice.setCenter( Hz ) 

write

slice.write( IQBlock );

read

slice.read( IQdata );

.setSquelchLevel

.setSquelchLevel(rmsdb,on);

Example

Full example using a FIFO RX as input, local file as output :

/*
[RX] ==> [queue ] ==> extract a suddand of 48 kHZ BW @ +176 kHz from center ==> [queue] ==> [file]
*/
// create working queues and objects
var fifo_from_rx = Queues.create( 'input');
var fifo_to_file = Queues.create( 'outut');
var IQBlock = new IQData('iq');
var samples = 0 ;

// open RX 
var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });
if( typeof rx != 'object' ) {
    print('no radio ?');
    exit();
}

if( !rx.isValid()) {
    print('no radio ?');
    exit();
}

if( rx.isAvailable() ) {
   // set sample rate
   if( rx.setRxSampleRate( 1e6 )) {
      print('Sample rate changed');
   }
} else {
   print('device is already used, we do not change Sampling Rate');
}

rx.setRxCenterFreq( 466 );

// create output file
print('create out queue');
fifo_to_file.writeToFile('/tmp/rx.cf32');

print('connect queue to receiver');
// engage streaming
if( !fifo_from_rx.ReadFromRx( rx ) ) {
    print('Cannot stream from rx');
    exit();
}

var slice = new DDC('one');
slice.setOutBandwidth(48e3); // 48 kHz output
slice.setCenter( 176e3 ) ; // receive 48kHz centered at +176 kHz from center

print('starting rx process');
while( fifo_from_rx.isFromRx() ) { // if we have something in the input
   if( IQBlock.readFromQueue( fifo_from_rx ) ) {     // load samples from input queue into IQBlock object
       slice.write( IQBlock );               // write the samples in the DDC object
       var ifdata = slice.read();            // read down converted samples
       while( ifdata.getLength() > 0 ) {         // if we have something
        print('Writing ...');
        fifo_to_file.enqueue( ifdata );         // write the samples in the output queue
        ifdata = slice.read();              // read more
       }        
   }
}

print('finished!');

Capture

.Capture

Will capture a pre-defined number of sample. Capture duration is finite and can't be run permanently.

:!: Resources killer for RAM, we will use only for short captures (less than 1 minutes) because it takes all bandwidth. For advanced use, have a look .captureSubBand command or DDC mode.

:!: Capture don't mean 'store' (refer to example)

  • Example:
    var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });

        if( typeof rx != 'object' ) {
            print('no radio ?');
            exit();
        }

        // set sample rate
        if( rx.setRxSampleRate( 2e6 )) {
            print('Sample rate changed');
        }

        rx.setRxCenterFreq( 466 );

        // capture a block ( 5e6 samples)
        var samples = rx.Capture( 5e6 ) ;

        // save to file
        samples.saveToFile('/tmp/rx.cf32') ;


.captureSubBand

Capture the subband of a stream

Samples is the number of samples to record offset values is related to the center frequency (unit Hz).

    var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
    var IQ = rx.captureSubBand( samples, offset, bandwidth );
  • Example :

Record on disk a CF32 IQ file (input SR: 1e6 output SR: 250e3) centered on 466.150 (RxCenterFreq + 150e3)

var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
rx.setRxCenterFreq( 466 );
rx.setGain( 65 );
rx.setRxSampleRate(1.5e6);

print("Freq : ",rx.getRxCenterFreq().toFixed(0)," MHz");
print("SR : ",rx.getRxSampleRate().toFixed(0));

var IQ = rx.captureSubBand( 1e6, 150e3, 250e3 );
print('Start capture');

IQ.saveToFile('/tmp/capture.cf32') ;
IQ.dump();
exit();

......
Using convertion factors : (native-127.000000)/128.000000 
Exact sample rate is: 1500000.014901 Hz
(boot:0)> Freq : 466 MHz
(boot:0)> SR : 1500000
[INFO] Using format CF32.
Allocating 15 zero-copy buffers
(boot:0)> Start capture
(boot:0)> IQData object dump:
(boot:0)>  name       : no_name
(boot:0)>  sample rate: 250000 Hz
(boot:0)>  length     : 1000000 samples
(boot:0)>  Center Frq : 466.150 MHz
(boot:0)>  Number of channels : 1
(boot:0)>  duration   : 4.000 secs. [4000.0 msecs]
(boot:0)>  Attribute  : not set

AFSK




  • Objet : AFSKModem('name')

.configure

var modem = new AFSKModem('test');
modem.configure( { 'bit_rate': 50, 'low_tone': 1270, 'high_tone': 1440  } ); 
  • bitrate = 300 : low_tone = 1600 Hz, high_tone = 1800 Hz
  • bitrate = 1200 : low_tone = 1200 Hz, high_tone = 2200 Hz

.modulateBits

Example

  • Envoi de 16 octets en AFSK 1200 bds
/ Generate 16 bytes message
var L = 16*8 ;
var msg = new Uint8Array(L) ;
for( var i=0 ; i < L ; i+=2 ) {
    msg[i] = 1 ;
    msg[i+1] = 0 ;
}


var modem = new AFSKModem('test');
modem.configure( { 'bit_rate': 1200  } );  
var IQ = modem.modulateBits( msg );
IQ.dump();

var tx = BladeRF.makeDevice( { 'device_name' : 'tx'} ) ;
tx.setTxGain( 20 );
tx.txOn( 144, 4.8e6 ); 
IQ.setCenterFrequency( .2 ) ; // transmit with carrier at + 200kHZ
tx.txData( IQ );
tx.txOff();

AX25




  • Settings : 300/AFSK, 1200/AFSK, 2400/AFSK and 9600/FSK (G3RUH)

.setFrom

.setTo

.setData

.getBits

modulate

modulateFSK

Example

var frame = new AX25(9600,true);
frame.setFrom('F4GKR', 0);
frame.setTo('F4IAI', 0);

var datas_size = infos_frame.datas.length;
var L = 240 ;
var tc_data = new Uint8Array(L) ;
for( var i=0 ; i < L ; i++ )
    {
    tc_data[i] = 170 ;
    }

frame.setData( tc_data );
var IQ = frame.modulateFSK();
IQ.saveToFile('test.cf32');
IQ.dump();
// tx.txData( IQ );

NBFM




.configure

.modulate

.demodulate

Example :

var audio = new IQData('audio');
if( !audio.loadFromFile('lamableu.wav')) {
     print('file not found.');
     exit();
}
// retrieve channel (mono audio)
var speak = audio.getReal();

// now generate IQ signal from FM audio
var fm = new NBFM('modulator'); 
fm.configure( {'modulation_index': 0.1} );
var IQ = fm.modulate( speak );

FSK Modem




.configure

Configure l'objet FSKModem pour l'émission

.modulate

.modulateBits

.getSamplesPerSymbol

Example

  • BFSK, sending 0/1 pattern
// Generate 16 bytes message
var msg = new Uint8Array(256*32) ;
var count=1;
 while (count < 32) {
    for( var i=0 ; i < 256 ; i++ ) {
    msg[i+(count*256)] = (count*16) ;
    }
for( var i=0 ; i < 64 ; i++ ) {
        msg[i+((count+1)*256)] = 0 ;
        }
    count = count + 2;
    print(count);
    }
var modem = new FSKModem('test');
modem.configure( { 'sps': 4, 'spacing' : 0.35 } ); 
var IQ = modem.modulate( msg );
IQ.setSampleRate(1200);
// we set samplerate = 9600 but sps=4 => 4 samples per symbol
// the real BITrate is then 9600/4 = 2400 symbols/second = 2400 bauds


var tx = BladeRF.makeDevice( {'device_name' : 'blade' });
tx.setTxGain( 55 );
tx.txOn( 435, 4e6 ); 
IQ.setCenterFrequency( .1 ) ; // transmit with carrier at + 200kHZ => on 435.2
tx.txData( IQ );
tx.txOff();

GMSK Modem




ChangeDetector




.setRx

.ignore

.runDetections

Example:

// Configure the change detector
var s = new ChangeDetector(centerFreq, bands);
s.setRx(rx);
s.setPowerThreshold( threshold ) ; // dB threshold
s.ignore(centerFreq - 0.01, centerFreq + 0.01); // Ignore center of rx (dc bias)
// run a fiew iterations to improve reference
for (var i = 0; i < 30; i++) {
    s.updateReference();
}
print('Reference done, run detector.');

for (; ;) {
    var changes = s.runDetections(false);

    if (changes == 0) {
        //print('no change, continue');
        continue;
    }

   ...
}

.clearDetections

.popDetection

.getLastCapture

.getPowerThreshold

.setPowerThreshold

Retourne :

DSP module

DSP.tone

DSP.tone( 440, 1000, 2e6 )
  • Example : create audio WAV file (48000HZ/2 canaux) :
var IQ = DSP.tone(440, 80000, 48e3);
IQ.dump();
IQ.saveToFile('/tmp/tone.wav');
  • Example : create IQ file
var IQ = DSP.tone(440, 1000, 2e6);
IQ.dump();
IQ.saveToFile('/opt/search/tone.cf32');

- generates a 440 Hz complex tone for 1000 samples in a signal sampled at 2MHz and save to file.

DSP.offset

Estimate offset value for input signal

var ffreqOffset = DSP.offset(rfiq);
var rfCentered = DSP.shift(rfiq, ffreqOffset)

DSP.shift

DSP.shift( IQData in, frequency_hz )

DSP.square

IQData out = DSP.square( IQData in );

DSP.quadric

DSP.quadric( IQData in ); 
  • Example :
IQData out = DSP.quadric( IQData in );

DSP.filter

DSP.filter( IQData in, cutoff, decimateby, lofreq HZ) 
IQData out = DSP.filter( IQData in, cutoff, decimateby, lofreq HZ)

DSP.resample

Resample IQ datas : ratio = out sr / in sr

  DSP.resample(IQdata_in, ratio);
  • Example
IQData out = DSP.resample( IQData in, ratio = out sr / in sr );

DSP.decompose

DSP.decompose(IQData in, NBands, lofreq )

[IQOut1....IQOutN] = DSP.decompose( IQData in, NBands, lofreq ) ; 

DSP.fmdemod

DSP.fmdemod(IQData in);

DSP.rmsprofile

   out = DSP.rmsprofile( IQData in , window length samples);

DSP.matchedfilter

DSP.matchedfilter( IQData in, IQData motif, spanfreq )

Example DSP

  • BPSK/QPSK analysis, IQ recording
var rx = Soapy.makeDevice( {'query' : 'driver=rtlsdr' });
var samples = rx.captureSubBand( samples, offset, sub_band_Hz );
samples.saveToFile('/tmp/samples.cf32');

var quadric = DSP.quadric( samples );
var square = DSP.square( samples );


// BPSK/QPSK peaks (JSON-type objects)
var sps2 = square.getPowerSpectrum( 1024 ) ;
var sps4 = quadric.getPowerSpectrum( 1024 ) ;

IQ Queue

construct the JSIQQueue object


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

  }

.feedFromRx

runs until rx is stopped

var options = { 'frequency' : number, 'sample_rate': number } ;
feedFromRx( JSRadio object , options );

.isFeededFromReceiver

bool isFeededFromReceiver();

.feedFromFile

Load a .WAV / .CS16 / .CF32 file

feedFromFile( filename, options ) ;
  • Options :
*
var options = {
                'block_size' : number,
                'sample_rate' : number  if not provided , for CS16 & CF32 for example
            } ;

.isSendingToFile

isSendingToFile();

.toFile

toFile(wavefilename );

.stop

.stop();

Examples

  • Following example demonstates how two different tasks are exchanging IQ data

Data producer :

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


// ecrire IQ dans la Queue
q.enqueue( IQ );
print('bloc envoyé');

Data consumer :

var q = Queues.create( 'queue');
// Get a block 
var IQ = q.dequeue(true); // blocking mode, we wait to have something
IQ.dump();
  • Creating input queue for IQ file :

Using : fifo_from_file.ReadFromFile(fichier, samplerate)

var fifo_from_file = Queues.create( 'input');
var SRinput= {'sample_rate' : input_samplerate};

if( !fifo_from_file.ReadFromFile( '/home/user/myIQ.cf32', SRinput ) ) {
    print('cannot open file:' + file_input );
    exit();
}
  • Creating input queue for SDR device:

Using : fifo_from_file.ReadFromRx(objet radio)

var fifo_from_rx = Queues.create( 'input');
var rx = Soapy.makeDevice( {'driver' : 'rtlsdr' });
rx.setRxSampleRate( 1e6 );
if( !fifo_from_rx.ReadFromRx( rx ) ) {
    print('Cannot stream from rx');
    exit();
}

JSpectrumBlock




.setRx

.runDetections

.clearDetections

.popDetections

.ignore

Example

print('Searching for SoapySDR device...');
var rx = Soapy.makeDevice({'query' : 'driver=rtlsdr' }) ;
if( typeof rx != 'object' ) {
    print('no radio ?');
    exit();
}

if( !rx.isValid()) {
    print('no radio ?');
    exit();
}

if( rx.setRxSampleRate( 2.048e6 )) {
    print('Sample rate changed');
}
// Create a spectrum change detector
// we want to take snapshots, decomposed in 512 subbands ( 4kHz BW)
var s = new JSpectrumBlock( 466, 512 ) ; // Fc=466 MHz
s.setRx( rx ) ; // make it work with the scanner radio
for( i=0 ; i < 100 ; i++ ) {
    var changes = s.runDetections();
    print( changes + ' detected changes');
    if( changes > 0 ) {             
           // investigate detections
            var detection = s.popDetection() ;
            while( typeof detection === 'object' && detection !== null ) {      
            print(JSON.stringify(detection));
            detection = s.popDetection() ;
            }
    }
    //sleep(1000);
}

SQLite




.execSQL

.getLastErrorMsg

.open

.close

Example

var db = new SQLite('base_frequences');
if( !db.open('test.db')) {
   print('cannot open/create database');
   exit();
}

// create table
var sql = "create table IF NOT EXISTS qrg( id int primary key not null, name char(50))" ;
if( db.execSQL( sql ) === false ) {
     print('SQL error:' + db.getLastErrorMsg() );
}

sql = "insert into qrg (id,name) values (1,'test')" ;

if( db.execSQL( sql ) === false ) {
     print('SQL error:' + db.getLastErrorMsg() );
}

var res = db.execSQL('select * from qrg order by name');
if( res.length > 0 ) {
    for( i=0 ; i < res.length ; i++ ) {
     var row = res[i] ;
     print('Row' + i + ': id=' + row.id + ', name:' + row.name );
    }
} else {
   print('SQL error:' + db.getLastErrorMsg() );
}

SerialPort

Read/Write to/from serial port

  • Objet: SerialPort('name')
var p = new SerialPort('ACM0');

.open

.open( String name [, Speed])

open 'name' port at speed 'speed', allowed values : ouvre le port 'name' à la vitesse 'speed', valeurs possibles

  • not specified : vitesse par défaut du périphérique
  • or one of these values : 1200,1800,2400,4800,9600,38400,115200,230400,460800

.close

Close serial port of an object SerialPort

.close();

.hasData

.hasData();

.writePort

.writePort( string );

.readPort

Retrieve serial buffer into text object

.readPort();

.readBytes

Retrieve serial buffer into Uint8Array object

.readBytes();

.readInt16

Retrieve serial buffer into Uint16Array object

.readInt16();

.getLastErrorMsg

getLastErrorMsg();
var p = new SerialPort('toto');
    if( p.open('/dev/ttyUSB0', 9600 ) != true ) {
        print('cannot open port');
        exit();
    }
    p.writePort('Hello world');
    if( p.hasData() ) {
        var rep = p.readPort();
        print('reply:' + rep );
        var raw = p.readBytes();
        for( var i=0 ; i < raw.length, i++ ) {
             print(raw[i]);
        }
    }
    p.close();

end