# RT-Link

RT-Link is an open link layer transmission protocol. It is designed to achieve stable, secure and efficient point-to-point data transmission between devices, and has a simple interface and is easy to use.

**Directory structure:**

```shell
rtthread
└───components
    └───utilities
        └───rt-link
            ├───inc        // 头文件
            ├───src        // rtlink源码文件
            ├───Kconfig
            └───SConscriptcopymistakeCopy Success
```

**Features:**

* **Stability** : RT-Link has a series of capabilities such as data retransmission, frame sequence number check, and state synchronization to ensure stable transmission;
* **Security** : Supports CRC verification and uses Ethernet verification protocol;
* **Efficient** : The protocol header is very concise, only 4 bytes, and every bit has practical significance;
* **Open** : It has a unified operation API and supports multiple underlying hardware interfaces, such as UART, SPI, and USB.
* **Easy to use** : The API is simple and can easily integrate RT-Link into existing applications, with good portability and compatibility.

## [How it works](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86) <a href="#gong-zuo-yuan-li" id="gong-zuo-yuan-li"></a>

The overall framework of RT-Link is as follows:

![rtlink overall framework](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/rtlink/figures/rtlink%E5%BA%94%E7%94%A8%E6%A1%86%E6%9E%B6.jpg)

* The top layer is **the service layer** , which supports multiple services running on one device at the same time, and the bottom layer uses the same data communication port;
* The second layer is **the rt-link transport layer** , which implements the core functions of rt-link and is used to ensure the reliability and stability of data transmission functions;
* The third layer is **the rt-link\_hw port docking layer** , which is used to connect to the underlying data transmission port;
* The lowest layer is **the transmission port layer** of the device , which is the communication port that actually transmits data, such as UART, SPI, Network, etc.

### [Introduction to service concept](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=service-%e6%a6%82%e5%bf%b5%e4%bb%8b%e7%bb%8d) <a href="#service-gai-nian-jie-shao" id="service-gai-nian-jie-shao"></a>

There can be multiple services in rt-link. For upper layer applications, each service represents a transmission channel, and there can be no association between services. Each service has an independent structure object. For ease of understanding, only the service structure object and related parameter definitions are listed here. Other contents can be `rt-link.h`viewed in the header file. The relevant attributes are as follows:

```c
/* service 结构体对象 */
struct rt_link_service
{
    /* 发送超时时间 */
    rt_int32_t timeout_tx;    
    /* 发送结果回调 */
    void (*send_cb)(struct rt_link_service *service, void *buffer);     
    /* 数据接收回调 */
    void (*recv_cb)(struct rt_link_service *service, void *data, rt_size_t size); 
    void *user_data;

    rt_uint8_t flag;             /* 传输质量标志：是否使用 CRC 和 ACK */ 
    rt_link_service_e service;     /* service 类型标识 */ 
    rt_link_linkstate_e state;   /* 通道链接状态 */ 
    rt_link_err_e err;             /* 错误码 */
};copymistakeCopy Success
```

**timeout\_tx blocking/non-blocking send**

rt-link provides two data transmission modes: **blocking transmission** and **non-blocking transmission** . timeout\_tx can be configured using `RT_WAITING_FOREVER`(blocking) or (non-blocking) during initialization .`RT_WAITING_NO`

In blocking mode, if you need to configure a certain timeout, you can also configure a specific timeout for timeout\_tx. The unit of this value is tick (system clock). In order to prevent a service from occupying the data transmission channel for a long time, there will be a maximum timeout in rt-link. Therefore, in blocking transmission mode, the smaller timeout will be used as the final transmission timeout.

**send\_cb data sending callback**

In non-blocking mode, send\_cb will send a callback notification after the sending is completed, regardless of whether the sending result is "successful" or "failed". The specific sending result can be viewed in the **err** error code in the structure object.

It should be noted that after calling the send interface in **non-blocking mode , the data address space** to be sent will be temporarily used by rt-link. The service application **should not release or modify** the data in this space until it receives the notification from send\_cb and then operates the data address space.

**recv\_cb data receiving callback**

The service receives data by registering a callback. The data space for receiving data is dynamically requested by rt-link. The service application gets the data space address and size in the callback interface. **The subsequent use and release of this space needs to be managed by the service application** .

**flag Transmission quality flag**

In rt-link, you can configure the data transmission quality of the service channel. There are two main configurable items: `RT_LINK_FLAG_ACK`and `RT_LINK_FLAG_CRC`.

When the ACK function is enabled, the data sent by the service channel will have **an ACK response to confirm that the other end has successfully received it, and the retransmission** function will also be enabled .

If you disable the ACK function, the ACK response and timeout retransmission functions will also be disabled. Enabling or disabling only affects this service channel.

When the CRC function is enabled, the sender will calculate the CRC before sending data and fill it at the end of a data frame. After receiving the data, the receiver will calculate and verify the other parts except CRC.

Disabling the ACK and CRC functions can improve transmission efficiency to a certain extent, but the corresponding data transmission quality needs to be guaranteed by the actual data transmission channel.

**service type flag**

Each service object has an independent service channel identifier, and the service type is defined in `rt_link_service_e`. During initialization, you need to `rt_link_service_e`select a type from and configure it to the service structure object.

**state Connection status**

state marks the connection status of the service channel, which is divided into the following three connection states:

| type              | significance          | illustrate                                                                        |
| ----------------- | --------------------- | --------------------------------------------------------------------------------- |
| RT\_LINK\_INIT    | initialization        | The status of the service when it is initialized                                  |
| RT\_LINK\_DISCONN | Disconnection         | The peer's detached state indicates that the peer's service is offline.           |
| RT\_LINK\_CONNECT | Connection successful | The status after the peer is attached, indicating that the peer service is online |

**err error code**

In the service structure object, err marks the error type of the last operation. In the current version, it mainly refers to errors that occur during data transmission. The meanings of the error codes used are as follows:

| type               | illustrate                                                                         |
| ------------------ | ---------------------------------------------------------------------------------- |
| RT\_LINK\_EOK      | success                                                                            |
| RT\_LINK\_ERR      | Common error, usually due to interface parameter problems                          |
| RT\_LINK\_ETIMEOUT | Data sending timeout                                                               |
| RT\_LINK\_ENOMEM   | Insufficient memory, the sent data is too long or the memory space is insufficient |
| RT\_LINK\_EIO      | The underlying IO error, the underlying port sending failed                        |

## [Usage Guidelines](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e4%bd%bf%e7%94%a8%e6%8c%87%e5%8d%97) <a href="#shi-yong-zhi-nan" id="shi-yong-zhi-nan"></a>

### [Configuring RT-Link Components](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e9%85%8d%e7%bd%ae-rt-link-%e7%bb%84%e4%bb%b6) <a href="#pei-zhi-rtlink-zu-jian" id="pei-zhi-rtlink-zu-jian"></a>

Here we take studio as an example, find Components -> Tools -> RT-Link on the configuration page, select Enable and configure, as shown below.

![settings](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/rtlink/figures/settings.jpg)

* Configure the CRC calculation method. The software CRC function is already included in RT-Link. The hardware CRC needs to be connected to the relevant interface according to different platforms.
* Save the settings and you can add RT-Link to the current project. The DEBUG option can be enabled according to debugging needs and is disabled by default.
* [Find the rt-link\_hw](http://packages.rt-thread.org/detail.html?package=rt-link_hw) software package in the software package , software package -> iot -> rt-link\_hw. For a detailed introduction to the software package, see README;

![rt-link\_hw](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/rtlink/figures/rt-link_hw.jpg)

* UART is selected here, and you need to configure the device name and the hardware interface used. If you need to add other ports, you can view [the introduction of the underlying link docking interface](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%ba%95%e5%b1%82%e9%93%be%e8%b7%af%e5%af%b9%e6%8e%a5%e6%8e%a5%e5%8f%a3%e4%bb%8b%e7%bb%8d) ;
* One more thing, don't forget to open the hardware interface you want to use, here I use UART2;

![uart](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/rtlink/figures/uart.jpg)

* Here we select two Pandora development boards to test the running effect. There is [a sample code](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e7%a4%ba%e4%be%8b%e4%bb%a3%e7%a0%81) at the end of the document . The running effect is as follows: ![Transceiver test](https://www.rt-thread.org/document/site/rt-thread-version/rt-thread-standard/programming-manual/rtlink/figures/%E6%94%B6%E5%8F%91%E6%B5%8B%E8%AF%95.jpg)

### [Introduction to upper layer application interface](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e4%b8%8a%e5%b1%82%e5%ba%94%e7%94%a8%e6%8e%a5%e5%8f%a3%e4%bb%8b%e7%bb%8d) <a href="#shang-ceng-ying-yong-jie-kou-jie-shao" id="shang-ceng-ying-yong-jie-kou-jie-shao"></a>

The upper-layer application interface list is shown below, and these interfaces will be introduced in the subsections.

```c
/* rtlink init and deinit */
int rt_link_init(void);
rt_err_t rt_link_deinit(void);
/* rtlink send data interface */
rt_size_t rt_link_send(struct rt_link_service *service, const void *data, rt_size_t size);
/* rtlink service attach and detach */
rt_err_t rt_link_service_attach(struct rt_link_service *service);
rt_err_t rt_link_service_detach(struct rt_link_service *service);copymistakeCopy Success
```

#### [initialization](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%88%9d%e5%a7%8b%e5%8c%96) <a href="#chu-shi-hua" id="chu-shi-hua"></a>

```c
int rt_link_init(void);copymistakeCopy Success
```

The default is automatic initialization. You can decide whether to enable automatic initialization based on the specific application. If you need to disable automatic initialization, you can `rtlink.h`comment out the macro definition in`RT_LINK_AUTO_INIT`

| Return Value | describe                                      |
| ------------ | --------------------------------------------- |
| RT\_EOK      | Initialization successful                     |
| -RT\_ENOMEM  | Insufficient memory, space application failed |
| -RT\_ERROR   | Initialization failed                         |

#### [Deinitialization](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%8e%bb%e5%88%9d%e5%a7%8b%e5%8c%96) <a href="#qu-chu-shi-hua" id="qu-chu-shi-hua"></a>

```c
rt_err_t rt_link_deinit(void);copymistakeCopy Success
```

When RT-Link is not needed, you can execute `rt_link_deinit()`to release system resources.

| Return Value | describe                    |
| ------------ | --------------------------- |
| RT\_EOK      | Deinitialization successful |

#### [Register service to receive callback](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e6%b3%a8%e5%86%8c%e6%9c%8d%e5%8a%a1%e6%8e%a5%e6%94%b6%e5%9b%9e%e8%b0%83) <a href="#zhu-ce-fu-wu-jie-shou-hui-tiao" id="zhu-ce-fu-wu-jie-shou-hui-tiao"></a>

```c
rt_err_t rt_link_service_attach(struct rt_link_service *service);copymistakeCopy Success
```

| parameter        | describe                                                                     |
| ---------------- | ---------------------------------------------------------------------------- |
| service          | The service object to be registered, parameter type`struct rt_link_service*` |
| **Return Value** | --                                                                           |
| RT\_EOK          | Successful registration                                                      |
| -RT\_EINVAL      | Parameter error                                                              |

`struct rt_link_service`The meaning of each member variable in the structure has been explained in the \[Introduction to the service concept]\(#Introduction to the service concept) section .

**Example:**

```c
static void send_cb(struct rt_link_service *service, void *buffer)
{
    LOG_I("send_cb: service (%d) buffer (0x%p) err(%d)", service->service, buffer, service->err);
}

static void recv_cb(struct rt_link_service *service, void *data, rt_size_t size)
{
    LOG_I("service (%d) size (%d) data(0x%p)", service->service, size, data);

    if (size)
    {
        LOG_HEX("example",8,data,size);
        rt_free(data);
    }
}

static struct rt_link_service serv_socket;
int rtlink_exinit(void)
{
    serv_socket.service = RT_LINK_SERVICE_SOCKET;
    serv_socket.timeout_tx = RT_WAITING_FOREVER;
    serv_socket.flag = RT_LINK_FLAG_ACK | RT_LINK_FLAG_CRC;
    serv_socket.recv_cb = recv_cb;
    serv_socket.send_cb = send_cb;
    rt_link_service_attach(&serv_socket);
}copymistakeCopy Success
```

#### [Release the service receiving channel](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e8%a7%a3%e9%99%a4%e6%9c%8d%e5%8a%a1%e6%8e%a5%e6%94%b6%e9%80%9a%e9%81%93) <a href="#jie-chu-fu-wu-jie-shou-tong-dao" id="jie-chu-fu-wu-jie-shou-tong-dao"></a>

```c
rt_err_t rt_link_service_detach(struct rt_link_service *service);copymistakeCopy Success
```

| parameter        | describe                                                                  |
| ---------------- | ------------------------------------------------------------------------- |
| service          | The service object to be removed, parameter type`struct rt_link_service*` |
| **Return Value** | --                                                                        |
| RT\_EOK          | Removed successfully                                                      |
| -RT\_EINVAL      | Parameter error                                                           |

#### [Sending Data](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%8f%91%e9%80%81%e6%95%b0%e6%8d%ae) <a href="#fa-song-shu-ju" id="fa-song-shu-ju"></a>

```c
rt_size_t rt_link_send(struct rt_link_service *service, const void *data, rt_size_t size);copymistakeCopy Success
```

| parameter        | describe                    |
| ---------------- | --------------------------- |
| service          | service structure object    |
| data             | Data sent                   |
| size             | The length of the data      |
| **Return Value** | --                          |
| 0                | Send failed                 |
| size             | The length of the data sent |

### [Introduction to the underlying link connection interface](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%ba%95%e5%b1%82%e9%93%be%e8%b7%af%e5%af%b9%e6%8e%a5%e6%8e%a5%e5%8f%a3%e4%bb%8b%e7%bb%8d) <a href="#di-ceng-lian-lu-dui-jie-jie-kou-jie-shao" id="di-ceng-lian-lu-dui-jie-jie-kou-jie-shao"></a>

The underlying link docking interface is defined in `rtlink_port.h`and needs to be implemented when docking the underlying transmission port.

```c
/* 需要在传输端口中实现的功能 */
rt_err_t rt_link_port_init(void);
rt_err_t rt_link_port_deinit(void);
rt_err_t rt_link_port_reconnect(void);
rt_size_t rt_link_port_send(void *data, rt_size_t length);
/* 当接收到数据并将数据传输到RTLink时调用 */
rt_size_t rt_link_hw_write_cb(void *data, rt_size_t length);copymistakeCopy Success
```

#### [Initialization and Deinitialization](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e5%88%9d%e5%a7%8b%e5%8c%96%e4%b8%8e%e5%8e%bb%e5%88%9d%e5%a7%8b%e5%8c%96) <a href="#chu-shi-hua-yu-qu-chu-shi-hua" id="chu-shi-hua-yu-qu-chu-shi-hua"></a>

```c
int rt_link_port_init(void);
int rt_link_port_deinit(void);copymistakeCopy Success
```

It is mainly used to initialize the resources of the underlying port. It will be called when RT-Link is initialized and deinitialized. This part needs to be implemented by yourself during porting. For UART, SPI, etc., the relevant interfaces provided by the device framework can be used in RT-Thread.

#### [Data transmission](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e6%95%b0%e6%8d%ae%e5%8f%91%e9%80%81) <a href="#shu-ju-fa-song" id="shu-ju-fa-song"></a>

```c
rt_size_t rt_link_port_send(void *data, rt_size_t length);copymistakeCopy Success
```

This function will be called by the core logic of RT-Link to send data through the actual underlying port. For simple **interfaces** such as UART , data can be sent directly without affecting the operation of the system. For more **complex** communication interfaces such as **SPI, USB** , etc., the sending logic can be implemented through mechanisms such as events and mailboxes.

| parameter        | describe                    |
| ---------------- | --------------------------- |
| data             | Data sent                   |
| length           | The length of the data      |
| **Return Value** | --                          |
| 0                | Send failed                 |
| length           | The length of the data sent |

#### [Reconnect](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e9%87%8d%e8%bf%9e) <a href="#zhong-lian" id="zhong-lian"></a>

```c
rt_err_t rt_link_port_reconnect(void);copymistakeCopy Success
```

The function of the reconnection interface is that when rt\_link\_port\_send() fails to send, rt-link will call this interface to try to reconnect the underlying link, and call rt\_link\_port\_send() again to try to send data. For example, if the underlying data link uses a TCP network, if the TCP connection is abnormally disconnected, TCP reconnection can be performed in this interface.

#### [Data Writing](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e6%95%b0%e6%8d%ae%e5%86%99%e5%85%a5) <a href="#shu-ju-xie-ru" id="shu-ju-xie-ru"></a>

```c
rt_size_t rt_link_hw_write_cb(void *data, rt_size_t length);copymistakeCopy Success
```

When the underlying interface receives data, this function can be directly called to send data to RT-Link and provide the received data to the upper layer service. **This function can be directly called in an interrupt.**

| parameter        | describe                              |
| ---------------- | ------------------------------------- |
| data             | Data written                          |
| length           | The length of the data                |
| **Return Value** | --                                    |
| 0                | Write failed                          |
| > 0              | The actual length of the data written |

## [Sample Code](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/rtlink/rtlink?id=%e7%a4%ba%e4%be%8b%e4%bb%a3%e7%a0%81) <a href="#shi-li-dai-ma" id="shi-li-dai-ma"></a>

```c
#include <rtthread.h>
#include <rtlink.h>

#define DBG_ENABLE
#define DBG_TAG "rtlink_exam"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define TEST_CONTEXT    "This message is sent by RT-Link"

static struct rt_link_service serv_socket;

static void send_cb(struct rt_link_service *service, void *buffer)
{
    LOG_I("send_cb: service (%d) buffer (0x%p) err(%d)", service->service, buffer, service->err);
}

static void recv_cb(struct rt_link_service *service, void *data, rt_size_t size)
{
    LOG_I("service (%d) size (%d) data(0x%p)", service->service, size, data);

    if (size)
    {
        LOG_HEX("example",8,data,size); /* 使用此接口打印 16 进制数据需要开启 ulog 组件*/
        rt_free(data);/* data 指向的空间由 rtlink 动态申请，应用层使用完毕后自行释放 */
    }
}

static int rtlink_exsend(int argc, char **argv)
{
    char *data = RT_NULL;
    rt_size_t length = 0;

    if (argc == 1)
    {
        data = rt_malloc(sizeof(TEST_CONTEXT));
        rt_memcpy(data, TEST_CONTEXT, sizeof(TEST_CONTEXT) - 1);
        length = rt_link_send(&serv_socket, data, sizeof(TEST_CONTEXT) - 1);
        LOG_I("send data length: %d.", length);
        rt_free(data);
    }
    return 0;
}
MSH_CMD_EXPORT(rtlink_exsend, rt link layer send test);

int rtlink_exinit(void)
{
    /* service 结构体对象初始化 */
    serv_socket.service = RT_LINK_SERVICE_SOCKET;
    serv_socket.timeout_tx = RT_WAITING_FOREVER;
    serv_socket.flag = RT_LINK_FLAG_ACK | RT_LINK_FLAG_CRC;
    serv_socket.recv_cb = recv_cb;
    serv_socket.send_cb = send_cb;
    rt_link_service_attach(&serv_socket);
    return RT_EOK;
}
MSH_CMD_EXPORT(rtlink_exinit, rt link example init);copymistakeCopy Success
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aic-eec.com/recommended_by_aic/rt-thread-university-program/components/network-components/rt-link.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
