Internally, the communication with the adapter is implemented by sending data blocks to and from the adapter. These blocks of data represent commands, responses and events.
You do not need to understand all these data structures to write your application. Most of functionality is encapsulated in the regular C-style functions (for example, DlnOpenUsbDevice(), DlnI2cMasterTransfer(), etc.). All you need to do is to call these functions and the rest of the work will be done by the dln.dll
shared library and the device driver.
If you want to benefit from the event-driven interface, or to optimize the speed of the data transfer between your application and the adapter by using asynchronous interface, you can return and read the corresponding chapters later.
DLN API is designed for a maximum flexibility. It allows to build simple applications that interface a single device with only a few lines of code. It also provides a lot of functions to build more complex applications, which can interface several adapters simultaneously, even if they are connected to different computers. There is a number of approaches to distinguish between different adapters, different types of adapters, and check what subset of the functionality the particular adapter supports.
We will cover all the details in the following subsections. Some information may seem to be complex in the beginning. Feel free to skip it and move to the next chapter. Most of the applications need to call a single function to establish a connection with the DLN series adapter - DlnOpenUsbDevice() (or DlnOpenBleDevice()
, DlnOpenTcpDevice()
, etc.).
When the device is opened, the DLN library allocates resources required to maintain the connection and associates a device handle with this device. Most of the functions in the dln.dll
library expects this handle to be passed as the first parameter. It is used to identify the adapter.
You can open the same adapter several times by calling one of the DlnOpenXXX() functions. We do not recommend this approach and in most cases changing the application architecture eliminates the necessity to open the same hardware repeatedly. Each time you call one of those functions, a new handle is associated with the same hardware and additional resources to manage this handle are allocated. If application design requires you to open the same device multiple times, it is important to close all handles when you don't need them. The C++ programmers can use our C++11-like unique_hdln
class to manage the device handle.
The device handle is represented by the HDLN
type which is defined in the dln.h
file as:
typedef uint16_t HDLN;
The allocated resources are automatically cleared up when the application terminates. Nevertheless, it is a good practice to explicitly close the device handle by calling the DlnCloseHandle() function.
The DlnOpenDevice() function allows you to open all available devices in a loop. This function accepts two parameters - an index number of the adapter to open and the pointer to the variable that receives the device handle. The deviceNumber parameter is zero-based.
You can call the DlnGetDeviceCount() function to obtain the number of available devices, and then call the DlnOpenDevice() function in a loop to open all devices as illustrated in the following code snippet:
HDLN handle; DLN_RESULT result = DlnOpenDevice(0, &handle);
You should make no assumptions about the association between deviceNumber
parameter and the specific hardware. You can call the DlnGetDeviceSn() or DlnGetDeviceId() function to identify the device after it is open, or use one of the functions listed in the next chapters to open a specific device.
The DlnOpenDevice() and DlnGetDeviceCount() functions enumerate and open devices currently accessible to the DLN library - the device should be accessible to the computer where the DLN Server is running and your application should be connected to this DLN Server. In case of Direct Mode, the library itself establishes connections to the devices accessible to local PC. You can treat this as if the library is connected to the DLN Server running on the same PC where the application is launched.
The connection to the DLN Server is established by calling the DlnConnect() function, providing server IP and TCP port. After connection is established you get access to all devices accessible to the PC where the server is running:
Devices connected to the USB port of this computer.
Devices located in the range of Bluetooth Low Energy (BLE) connectivity to this computer.
Every DLN-series adapter has a unique serial number, allocated during the manufacturing. You can obtain the serial number of the device by calling the DlnGetDeviceSn() function. Use the DlnOpenUsbDeviceBySn()
function to open the device with the specific serial number.
The device serial number can’t be changed. We do not recommend to use it to distinguish between the devices that are expected to perform different actions. Using the serial number tightly couples your application to the specific hardware.
There is a much more scalable approach. You can assign an ID number to any DLN-series adapter and then use it to identify the specific hardware. To assign the ID number use our DeviceId.exe application or call the DlnSetDeviceId() function. The ID number is stored in the internal non-volatile memory. It remains the same even when the adapter is connected to another computer.
When you know the ID number of the specific adapter, you can open it with the DlnOpenDeviceById() function.
DLN series include a number of different devices. All these devices support API described in the current manual, but their available functionality may slightly differ. For example, they can support different SPI and I2C bus frequencies, not all of the adapters implement I2C/SPI slave interfaces, etc.
If you know that your application needs a specific DLN-series device, you can check the hardware type of the adapter by calling the DlnGetHardwareType() function. The hardware type constants are defined in the
dln_generic.h
file as follows:
#define DLN_HW_TYPE uint32_t #define DLN_HW_TYPE_DLN5 ((DLN_HW_TYPE)0x0500) #define DLN_HW_TYPE_DLN4M ((DLN_HW_TYPE)0x0401) #define DLN_HW_TYPE_DLN4S ((DLN_HW_TYPE)0x0402) #define DLN_HW_TYPE_DLN3 ((DLN_HW_TYPE)0x0300) #define DLN_HW_TYPE_DLN2 ((DLN_HW_TYPE)0x0200) #define DLN_HW_TYPE_DLN1 ((DLN_HW_TYPE)0x0100)
You can use the DlnOpenDeviceByHwType() function to open the adapter with the predefined hardware type.
Instead of checking the specific device type, you can check if the adapter implements the required functionality. DLN API provides you with a number of ways to do this.
You can interface the DLN series adapters either directly or through the DLN server application. The DLN server is a Windows Service or Linux / Mac OS X Daemon. The applications communicate with the DLN server through TCP/IP. The most prominent difference between the Direct and the Server Based interfaces is that the Direct Interface can provide you with the higher bandwidth when you transfer a large amount of data, while the Server Based Interface allows several applications to communicate with the same adapter simultaneously. For additional details please refer to the Interface Types chapter in the User Manual.
Without going into details (the details are described in the Server Base Interface implementation chapter), you need to connect to the DLN server if you use the Server Based Interface. The connection is established by calling the DlnConnect() function. The DLN Server IP address and TCP port number are passed to this function as parameters.
If the DLN series adapter is connected to the computer where you launch your application, and you don’t change the default port configuration, you can use the DlnConnectDefault()
function to connect to the DLN server.
As with most of the functions that allocate resources, the established connection can be closed by calling the DlnDisconnect() function with the same parameters. Use the DlnDisconnectDefault()
function to close the connection established with the DlnConnectDefault()
function. If you want to close all currently opened connections, call the DlnDisconnectAll() function.
The dln.dll library for the Direct Interface does not require the connection to the DLN server. It is designed to directly communicate with DLN-series adapters connected to the computer where the application is running. You are not required to call the DlnConnect()
, DlnDisconnect()
and DlnDisconnectAll()
functions in the Direct Interface, but you can do this to make your code compatible with the Server Based Interface. These functions do nothing in the Direct Interface, they simply return the successful result code
The DLN API is logically divided into modules. Each module contains a set of functions and declarations for the specific interface (for example, GPIO, I2C Master interface, I2C Slave interface, etc.).
You can check if the specific interface is supported by the connected adapter by calling the corresponding DlnXXXGetPortCount()
function.
All these functions return the DLN_RESULT
value. If the interface is supported, the corresponding function returns the DLN_RES_SUCCESS
value. Otherwise the return code is equal to DLN_RES_NOT_IMPLEMENTED
.
If these functions succeed, they fill in the count parameter with the number of available ports.
The example below prints the number of I2C master ports supported by the connected DLN-series adapter:
DlnConnect("localhost", DLN_DEFAULT_SERVER_PORT); HDLN device; DlnOpenDevice(0, &device); uint8_t count; DLN_RESULT result = DlnI2cMasterGetPortCount(device, &count); if (DLN_SUCCEEDED(result)) printf("The adapter has %d I2C master ports.\n", count); else printf("The adapter does not support an I2C master interface\n");
The GPIO ports consist of 8 pins. If the number of available GPIO pins is not multiple of 8, the last port (with the highest index) can have less that 8 pins. Use the DlnGpioGetPinCount()
function to obtain the number of GPIO pins for the current DLN-series adapter.
In the previous chapter we saw how you can use the return value of the DlnXXXGetPortCount()
function to check if the corresponding interface is implemented by the DLN-series adapter. The same approach can be applied for all functions from the DLN API.
For example, some of the adapters have internal pull-up resistors on GPIO pins, while others do not. Moreover, the pull-up resistors may be available only for a subset of GPIO pins. You can enable these pull-ups with the DlnGpioPinPullupEnable()
function. This function, as well as all other DLN API functions, returns the DLN_RESULT
value. If the return value is equal to DLN_RES_NOT_IMPLEMENTED
, you can’t enable the internal pull-up resistor for current pin.
This approach of checking for the available functionality sometimes has an undesirable side effect. If the function succeeds, it performs an action (for example, DlnGpioPinPullupEnable()
function enables the pull-up resistor if it can do so). If you need to check the supported functionality, but not to perform an action, use the DlnGetCommandRestriction()
function. As you will see in the following section, this function may also provide some additional information about the requested functionality.
As described in the corresponding section of the User Manual, the event driven interface can save your computational and USB resources and increase the application responsibility.
Each module has its own set of available events. The examples of how to handle and configure these events are provided in the corresponding parts of the current manual.
In the following sections we examine the general approach of DLN event processing and review two examples. The first example handles device connection/disconnection events and prints the corresponding messages at the standard output (stdout). The second example can be used as a generic events monitor. In addition to handling device connection/disconnection, it also processes all other event types. It dumps the event data at the standard output (stdout).
The DLN library may notify the user application when new messages arrive from the device.
There are 4 different types of notifications:
Callback function.
Event object.
Window message.
Thread message.
You can configure the same notification settings for all the messages. To do so, call the DlnRegisterNotification()
function and specify HDLN_ALL_DEVICES(0)
value as a handle. In this case the DLN library will notify the user application about messages from all devices.
The DLN library may notify the application about messages from a specific device. To configure such notification settings, call the DlnRegisterNotification()
function and specify the handle of the device. Streams (like devices) have their own handles. So, you may configure the notification settings for a specific stream as well.
You can use the DlnRegisterNotification()
function several times, specifying various notification settings for different devices (streams). For example, if you have 4 devices, you may register certain notification settings for one device and different settings for other devices. When a device sends a message, the library checks the notification settings for current device. If the library finds such settings, the notification is generated. If there are no settings for current device, the library checks the notification settings for all devices. If there are no such settings either, the notification isn't generated and the message isn't pushed into the queue.
Sometimes it is useful when messages aren't pushed into the queue. It is most convenient for those who use only synchronous communication. During the synchronous communication the application doesn't call the DlnGetMessage()
function. Thus the messages aren't removed from the queue. It leads to memory leak and eventually to memory overflow. If you don't want messages to be enqueued, you shouldn't register any notification settings.
If you want the messages to be enqueued without notification, do the following. Call the DlnRegisterNotification()
function and specify DLN_NOTIFICATION_TYPE_NO_NOTIFICATION
value as the notification type. In this case the messages will be pushed into the queue without notification to the user application. The messages can be obtained with the help of the DlnGetMessage()
function.
To unregister the notification settings call the DlnUnregisterNotification()
function.
The communication with a device is performed by the use of messages. A message is a packet of data that is sent from the library to a device and vice versa. The DLN adapters utilize three types of messages:
commands;
responses;
events.
Here is a short comparison to make things more logical and simple.
Name | Sender | Recepient | Description | |
Command | DLN_DO_SOME_ACTION_CMD | User application | Device | Contains an instruction to a device. |
Response | DLN_DO_SOME_ACTION_RSP | Device | User application | Contains information about some changes that took place. |
Event | DLN_SOMETHING_CHANGED_EV | Device | User application | Contains information about some changes that took place. |
Commands are sent from the user application to a device. They contain some instructions to the device. You may instruct the device to perform an action (for example, to change voltage on a pin) or to configure the settings of the device. Each command has corresponding response.
A response is sent from the device to the user application after a command execution. A response always returns the result of the command execution. If the command was successfully executed, the response informs the user application about this. If it is impossible to complete the command, the response returns the error code. Some commands request specific data (for example, the serial number of a device or the total number of connected adapters). In this case the response returns the requested data in addition to the result of the command execution.
Events are sent from the device to the user application. They contain information about some changes that have taken place. A user can predefine the condition of an event generation. For example, an event may be generated when a new device is connected or when voltage changes on an input pin.
All the messages are transferred through the DLN library.
The messages (commands, responses and events) are delivered with the help of three functions:
DlnSendMessage() - sends a specified message (an asynchronous command) to the device.
DlnGetMessage() - retrieves messages (responses and events) sent by the device.
DlnTransaction() - sends a synchronous command, waits for a response and returns the response details. Messages sent by the device (responses and events) are pushed into the DLN library message queue. The user may call the DlnGetMessage() function to get the message from the queue.
The DlnGetMessage() function removes the message from the queue and passes the message details to the user application.
The following example shows how to open DLN device, get its main parameters (hardware version, identifier and serial number), print them to console and close device. You can find the complete example in the “..\Program Files\Diolan\DLN\examples\c_cpp\examples\simple
” folder after DLN setup package installation.
#include "..\..\..\common\dln_generic.h" #pragma comment(lib, "..\\..\\..\\bin\\dln.lib") int main(int argc, char* argv[]) { // Open device HDLN device; DlnOpenUsbDevice(&device); // Get device parameters DLN_VERSION version; uint32_t sn, id; DlnGetVersion(device, &version); DlnGetDeviceSn(device, &sn); DlnGetDeviceId(device, &id); // Print it printf("Device HwType = 0x%x, SN = 0x%x, ID = 0x%x\n", version.hardwareType, sn, id); // Close device DlnCloseHandle(device); return 0; }
Line 1:#include "..\..\..\common\dln_generic.h"
The dln_generic..h
header file declares functions and data structures for the generic interface.
Line 2:#pragma comment(lib, "..\\..\\..\\bin\\dln.lib")
Use dln.lib
library while project linking.
Line 8: DlnOpenUsbDevice(&device);
The function establishes the connection with the DLN adapter. This application uses the USB connectivity of the adapter. For additional options, refer to the Device Opening & Identification section.
Line 13:DlnGetVersion(device, &version);
This function assigns device parameters to the DLN_VERSION
type structure variable.
Line 14:DlnGetDeviceSn(device, &sn);
This function assigns device serial number to the provided pointer to 32-bit integer type variable. Serial number is unchangeable for each device and assigned once during device production.
Line 15:DlnGetDeviceId(device, &id);
This function assigns device id to the provided pointer to 32-bit integer type variable. Id number can be assigned by user by calling DlnSetDeviceId() function.
Line 18:printf("Device HwType = 0x%x, SN = 0x%x, ID = 0x%x\n", version.hardwareType, sn, id);
Printing the results. In the console you will see hardware type, serial number and id of the connected device.
Line 21:DlnCloseHandle(device);
Closing handle to the previously opened DLN-series adapter.
You can use the following functions to establish communication with DLN series adapters, identify them using ID and serial numbers, and obtain version information for all components involved in the communication.
The DlnConnect()
function establishes the connection to the DLN server.
The DlnDisconnect()
function closes the connection to the specified DLN server.
The DlnDisconnectAll()
function closes connections to all servers at once.
The DlnGetDeviceCount()
function retrieves the total number of DLN devices available. If connection is established with several DLN servers, this function will return the total number of DLN adapters, connected to all servers.
The DlnOpenDevice()
function opens the specified device. This function uses an index number of the device. This number is randomly system-assigned to each connected device. It cannot be used to identify the device. If you need to open a specific device, use the DlnOpenDeviceBySn() or DlnOpenDeviceById() functions.
The DlnOpenDeviceById()
function opens the device defined by its ID number.
The DlnOpenDeviceBySn()
function opens the device defined by its serial number. A device serial number is factory-assigned and cannot be changed.
The DlnOpenDeviceByHwType()
function opens the DLN-series device defined by its type.
The DlnOpenUsbDevice()
function opens the device connected to the USB port of local PC. Use this function if your application is intended to work with single device. It cannot be used to select the specific device when multiple devices are connected. If you need to open a specific device, use the DlnOpenUsbDeviceBySn() or DlnOpenUsbDeviceById() functions.
The DlnOpenUsbDeviceById()
function opens the device, connected to the USB bus of the local computer, with ID number equal to the value passed in the id
parameter.
The DlnOpenUsbDeviceBySn()
function opens the device, connected to the USB bus of the local computer, with serial number equal to the value passed in the sn
parameter. A device serial number is factory-assigned and cannot be changed.
The DlnOpenUsbDeviceByHwType()
function opens the DLN-series device, connected to the USB bus of the local computer, defined by its type.
The DlnCloseHandle()
function closes the handle to an opened DLN-series adapter (stream).
The DlnCloseAllHandles()
function closes handles to all opened DLN-series adapters and streams.
The DlnGetVersion()
function retrieves the following data about the DLN-series adapter:
Hardware type - the type of the device (for example, DLN-4M).
Hardware version - the version of the hardware, used in the device.
Firmware version - the version of the firmware, installed in the device.
Server version - the version of the server.
Library version - the version of the DLN-library.
The DlnGetHardwareType()
function determines the type of the connected DLN device.
The DlnGetDeviceId()
function retrieves the device ID number.
The DlnSetDeviceId()
function sets a new ID number to the DLN-series adapter.
The DlnGetDeviceSn()
function retrieves the device serial number. A serial number is factory-assigned and cannot be changed.
The DlnGetPinCfg()
function retrieves the current configuration of the specified pin of the DLN adapter.
The DlnRegisterNotification()
function registers notification settings.
The DlnUnregisterNotification()
function unregisters notification settings.
The DlnGetMessage()
function retrieves a message (response or event) sent by the device.
The DlnSendMessage()
function sends a specified message (an asynchronous command) to the device.
The DlnTransaction()
function sends a synchronous command, waits for a response and returns the response details.
The DlnRestart()
function restarts the currently opened DLN-series device by its handle.
The DlnGetCommandRestriction()
function retrieves the command restrictions under the current conditions. This allows to avoid errors when executing functions. For details, read Specific Command Restrictions.