
-----------------------------------------------------------------------
How to add a new device
-----------------------------------------------------------------------

While perhaps not so interesting for most users, one with interest
in programming and in possession of yet another device might wonder
whether or not it is difficult to add such a device to the list
of supported devices.

In this txt an overview is given of what steps to take
when adding a device to the list of supported devices.


-----------------------------------------------------------------------
The interface
-----------------------------------------------------------------------

The qt-dab software assumes a device to support the interface to
the device implemented as a class derived from the 
class "deviceHandler"

class	deviceHandler: public QObject {
public:
			deviceHandler 	();
virtual			~deviceHandler 	();
virtual		int32_t	getVFOFrequency	();
virtual		int32_t	defaultFrequency();
virtual		bool	restartReader	(int32_t);
virtual		void	stopReader	();
virtual		int32_t	getSamples	(std::complex<float> *, int32_t);
virtual		int32_t	Samples		();
virtual		void	resetBuffer	();
virtual		int16_t	bitDepth	() { return 10;}
virtual		void	show		();
virtual		void	hide		();
virtual		bool	isHidden	();
};

The constructor of the class for the new device driver
is supposed to throw an exception when the device cannot be handled.

The functions setVFOFrequency and getVFOFrequency are pretty obvious,
just set the VFO of the device to a frequency (specified in Hz) and
get the current value.

defaultFrequency may just return a frequency with the range of valid
frequencies for the device.

the function restartReader is supposed to start or restart the generation of 
samples from the device. Note that while not specified explicitly
the assumed samplerate is 2048000, with a bandwidth of 1536000 Hz.
The parameter indicates the frequency to be selected

the function stopReader will do the opposite,
it will stop the generation of the samplestream.

The airspy is one of the devices where the samplerate cannot be set
to 2048000, so in that driver the software takes care of translating the
samplerate to 2048000.

The function Samples will tell the amount of samples currently available,
the qt-dab software will use that function to check whether or not
sufficient samples are available to continue processing. 

getSamples will try to extract the specified amount of samples - I/Q samples
as complex float numbers - from the buffer from the device driver.
It will return the amount actually read, in case the buffer in the
device driver contains less than the requested amount, it will not wait.
It assumes that the samplerate is just 2048000, i.e. rate conversions
need to be done in the device handler.

The function resetBuffer will clear the buffer in the device driver, it is
used when switching channels.

The function bitDepth returns - as the name suggests - the number of bits
in the (elements of the) sample. E.g dabsticks provide 8 bits, SDRplay 12.
The value is used to scale the Y-axis of the scopes.

The device driver might have a small GUI, with probably a slider or spinbox
for gain, and maybe other settings. See one of the existing device drivers
for examples.

if the driver does contain its own GUI, the function "show" is called
whenever it should be visible, the function "hide" when it should
be hidden and the function "isHidden" to return the status, being hidden or not.

--------------------------------------------------------------------------
Modifications to the file radio.cpp
--------------------------------------------------------------------------

The file radio.cpp needs to be "informed" about the new device.
Let us assume the device driver for the new device is implemented
in a class newDevice, implemented in files new-device.h and new-device.cpp.

step 1.
In the list of includes add
#ifdef	__HAVE_NEWDEVICE__
#include	"new-device.h"
#endif

step 2.
The selectable devices are listed in a combobox on the main GUI. 
Add the lines

#ifdef	__HAVE_NEWDEVICE__
	deviceSelector	-> addItem ("newDevice");
#endif

around line 300.

step 3
Of course, when selection of the device is possible, the device driver
needs to be part of the configuration.

To handle that properly, add in the function setDevice (app line 1022)
the following lines

#ifdef	__HAVE_NEWDEVICE__
	if (s == "newDevice") {
	   try {
              inputDevice       = new newDevice (..parameters..);
              showButtons ();
           }
           catch (int e) {
              QMessageBox::warning (this, tr ("Warning"),
                                   tr ("newDevice not found\n"));
              return nullptr;
           }
        }
        else
#endif

where the appropriate parameters are passed on to the constructor.

That is it, however ...

--------------------------------------------------------------------
Modifying the qt-dab.pro file
---------------------------------------------------------------------

To generate an executable, the qt-dab.pro file (or the CMakeLists.txt file)
needs to be informed on the modified configuration

step 1.

add - around line 273 in the qt-dab file - the line

CONFIG	+= newDevice

step 2.

add - somewhere in the qt-dab.pro file - the section describing the
files needed for handling the new device.
Assuming you created a directory "new-device" in the directory "devices",
and assuming the GUI file is desscribed in the xml file newdevice-widget.ui,
the paragraph would look like

newDevice  {
        DEFINES         += HAVE_NEWDEVICE
        INCLUDEPATH     += ./devices/new-device
        HEADERS         += ./devices/new-device/new-device.h \
	                    .. add further includes to development files
        SOURCES         += ./devices/new-device/new-device.cpp 
        FORMS           += ./devices/new-device/newdevice-widget.ui
        LIBS            += .. add here libraries to be included
}


Modifications for the CMakeLists.txt are left as an exercise.


