Engee documentation
Notebook

Engee.Integration and SOCKET

This example focuses on the possibilities of working with SOCKET, an interface for data exchange between processes in Engee and your PC. In Engee, it functions on the client program side through a subsystem Engee.Интеграции, allowing a model or script in the browser to exchange data with external programs and hardware. We will demonstrate the operation of this tool using the example of requesting the firmware version for RHYTHM SDR USRP.

The installation and initialization of components is performed as follows:

Here is a corrected version of this paragraph:

  • engee.package.install("Engee-Device-Manager") — installs the basic support package for connecting to the hardware, and also provides a link to the PC program.

    image.png
  • engee.package.start("Engee-Device-Manager") — Runs this package to link Engee to a client program on your computer.

    ![Unnamed.png](attachment:Without a name.png)

  • using .EngeeDeviceManager.Devices.SOCKET — connects the module SOCKET in Julia's code, providing access to functions for creating sockets and exchanging data.

In [ ]:
engee.package.install("Engee-Device-Manager")
engee.package.start("Engee-Device-Manager")
using .EngeeDeviceManager.Devices.SOCKET

Next, let's look at a simple example of interaction with the RHYTHM SDR USRP — we will get the firmware version. Let's start by creating a socket object:

  • SDR_IP — sets the IP address of the KPM RHYTHM device in the local network (the address of the RHYTHM SDR USRP server).
  • SDR_PORT — Defines the control port. 12345 is the standard port for the RHYTHM SDR USRP command interface.
In [ ]:
SDR_IP = "192.168.2.70"
SDR_PORT = 12345
socket = SOCKET.Socket("AF_INET", "SOCK_STREAM")

The next step after creating a socket is to establish a connection to the server using the method SOCKET.connect(). It activates the created network object and starts two-way data exchange.

In [ ]:
SOCKET.connect(socket, SDR_IP, SDR_PORT)
Out[0]:
1828

The command below sends a request to get the SDR version. Method SOCKET.send() converts a command string into a byte array of the type Vector{UInt8} and transmits it through the created socket object to the SDR USRP SERVER. Flag true specifies that all data must be sent in full, which ensures reliable transmission of the command.

In [ ]:
SOCKET.send(socket, Vector{UInt8}("COMMAND:GET_SDR_SERVER_VERSION"), true)

This code receives a response from the SDR. Method SOCKET.receive(socket, 35) tries to read up to 35 bytes from the socket. If the data is received (response !== nothing), they are converted from a byte array to a string. The received response contains useful information (for example, SDR_SERVER_VERSION=v5.1.5), but also includes service symbols (\r\n) and zero bytes (\0), which fill the rest of the buffer.

In [ ]:
response = SOCKET.receive(socket, 35)
answer = response === nothing ? "" : String(response.data)
Out[0]:
"COMMAND:SDR_SERVER_VERSION=v5.1.5\r\n"

The command below terminates the network connection. Method SOCKET.close(socket) frees up all system resources associated with the socket object and makes the object socket unsuitable for further use.

After executing this command, you need to create a new socket for subsequent connections.

In [ ]:
SOCKET.close(socket)
image.png

The complete log of the interaction, including all commands sent and responses received, is available for analysis in the Engee logs.Integration. You can see them by running ./engee-device-manager.exe -d for example, through Git Bash.

image.png

In the log fragment below, when requesting a version, we see:

  1. Initialization of a socket — creation of an object for network interaction.
  2. Connection establishment — successful connection to 192.168.2.70:12345.
  3. Sending a command — transmitting 30 bytes corresponding to the string "COMMAND:GET_SDR_SERVER_VERSION" (the log is represented as an array of ASCII codes).
  4. Receiving a response is receiving 100 bytes of data from the server.
  5. Closing the connection — end of the communication session.
image.png

Logging at the DEBUG level allows you to monitor each stage of data exchange in detail, which is a valuable tool for debugging and verifying the correctness of your systems.

The part of the code below extracts the server version from the response. She finds the marker "COMMAND:SDR_SERVER_VERSION=", takes the text after it and cuts off the service characters (\r, \n, \0) to the first non-printable character, returning a blank version string.

In [ ]:
if occursin("COMMAND:SDR_SERVER_VERSION=", answer)
    start_idx = findfirst("COMMAND:SDR_SERVER_VERSION=", answer).stop + 1
    version = ""
    for char in answer[start_idx:end]
        (char == '\r' || char == '\n' || char == '\0') && break
        isprint(char) && (version *= char)
    end
    return strip(version)
end
Out[0]:
"v5.1.5"

Conclusion

The considered example demonstrates how to use SOCKET in Engee to organize client-server interaction with RHYTHM SDR USRP. The process includes creating a socket, connecting to a given IP and port, sending a command, receiving a response, processing it later, and closing the connection.

Logging at the DEBUG level via engee-device-manager.exe -d It allows you to track all stages of data exchange in detail, which simplifies debugging and hardware integration into your projects.

Based on the considered basic operations (Socket, connect, send, receive, close) and the principles of data postprocessing the entire library is built ritm_sdr_core.jl. Each RHYTHM SDR USRP control command is implemented according to a single pattern:

  1. Forming a team in the protocol format ("COMMAND:...").
  2. Reliable sending via SOCKET.send().
  3. Receiving a response via SOCKET.receive().
  4. Parsing and validation of the response.
  5. Return the result in a typed form.