libdrmconf  0.12.0
A library to program DMR radios.
Classes
Device detection and enumeration.

This module collects classes and functions to discover and select interfaces to connected radios. More...

Collaboration diagram for Device detection and enumeration.:

Classes

struct  USBDeviceHandle
 Combines the USB bus and device number, to address a USB device uniquely. More...
 
class  USBDeviceInfo
 Generic information about a possible radio interface. More...
 
class  USBDeviceDescriptor
 Base class for all radio interface descriptors representing a unique interface to a connected radio. More...
 

Detailed Description

This module collects classes and functions to discover and select interfaces to connected radios.

With an increasing number of supported devices, the issue arises, that auto detection of radios may fail or may even harmful. Some manufacturers simply use generic USB-serial chips within the cable to talk to them over USB. These chips may also be used in other devices that may react harmful to qdmrs attempts to identify them. Moreover, the assumption of the first detected device with a specific VID:PID combination may not be valid. To this end, some means of discovering possible radios and selecting a specific one by the user are needed. Also some radios do not identify themselves before any action is performed (i.e., reading, writing the codeplug or callsign db). Hence, for some devices, the user must specify the type of the radio. The latter concerns the Kydera CDR-300UV, Retevis RT73 and similar devices.

This module specifies the classes and functions to discover possible radios and to address each one uniquely. They allow for an implementation of a semi-automatic device detection. That is, for the majority of radios, if a single matching VID:PID combination is found, it can be assumed that this device is a radio and it can then be identified by sending commands to it. Some radios, however, like the Kydera CDR-300UV, cannot be identified before the actual codeplug read or write operation. They simply do not provide a command for identification.

For a save semi-automatic detection the following steps are performed:

dot_autodetect.png
Semi-automatic radio detection

  1. Search for all USB devices with known VID:PID combinations. This can be done using the USBDeviceDescriptor::detect method. It returns a list of matching device descriptors found. If only one device is found, one may continue with that one if it is save to assume that the device detected is a DMR radio. The latter is not true for radios using generic USB CDC-ACM chips, as other serial devices may be connected. If several devices are found or it is not save to assume a DMR radio, the user must select a device.
  2. Once the USB device is selected, one needs to identify the connected radio. Unfortunately, not all radios can be identified easily by simply sending a command to it. To this end, one first needs to check if the selected device is identifiable. That is, if the protocol provides commands to identify the connected radio. The USBDeviceInfo provides this information. If a device is not identifiable, the user must specify the specific connected radio. This can be done by obtaining all known radios matching the selected USB device (VID:PID) by calling RadioInfo::allRadios, passing the USBDeviceDescriptor.

A example for AnyTone devices

This example tries to detect an AnyTone device and reads the binary codeplug from it. Once the codeplug is read, it is decoded into its generic device independent representation (Config).

#include "libdmrconf/usbdevice.hh"
#include "libdmrconf/anytone_radio.hh"
int main(void)
{
// First, search matching devices (only AnyTones)
// to find all supported devices, call @c USBDescriptor::detect();
QList<USBDeviceDescriptor> devices = AnytoneInterface::detect();
if (1 != devices.count()) {
// Either none or more than one device found...
return -1;
}
// A place to put error messages
// Dedetect the specific radio and get radio descriptor.
// To detect any radio based on the selected descriptor, call @c Radio::detect().
Radio *radio = AnytoneRadio::detect(devices.first(), RadioInfo(), err);
if (nullptr == radio) {
// There went something wrong, check err.
return -1;
}
// Read codeplug from device blocking.
if (! radio->startDownload(true, err)) {
// Some read error, check err.
delete radio;
return -1;
}
// Decode codeplug into generic representation
Config genericCodeplug;
if (! radio->codeplug().decode(&genericCodeplug, err)) {
// Some decoding error, check err.
delete radio;
return -1;
}
// Do whatever you like with the codeplug.
return 0;
}
virtual bool decode(Config *config, const ErrorStack &err=ErrorStack())=0
Decodes a binary codeplug to the given abstract configuration config.
The config class, representing the codeplug configuration.
Definition: config.hh:70
Implements a stack of error messages to provide a pretty formatted error traceback.
Definition: errorstack.hh:41
Provides some information about a radio model.
Definition: radioinfo.hh:16
Base class for all Radio objects.
Definition: radio.hh:32
virtual const Codeplug & codeplug() const =0
Returns the codeplug instance.
static Radio * detect(const USBDeviceDescriptor &descr, const RadioInfo &force=RadioInfo(), const ErrorStack &err=ErrorStack())
Tries to detect the radio connected to the specified interface or constructs the specified radio usin...
Definition: radio.cc:56
virtual bool startDownload(bool blocking=false, const ErrorStack &err=ErrorStack())=0
Starts the download of the codeplug.
static QList< USBDeviceDescriptor > detect()
Searches for all USB serial ports.
Definition: usbserial.cc:133