rt-thread之通讯协议modbus软件包的使用记录(lwip+modbus组合)

前言

  1. 使用freemodbus软件包
  2. 使用网口通讯(sal+lwip)
  3. ip地址使用dhcp动态获取

软件包

在这里插入图片描述

相关宏定义

/*-----------------------------------------NET 宏定义-------------------------------------------*/

#define RT_USING_SAL
#define SAL_INTERNET_CHECK
/* Docking with protocol stacks */
#define SAL_USING_LWIP
//#define SAL_USING_TLS
/* end of Docking with protocol stacks */
#define SAL_SOCKETS_NUM 16
#define RT_USING_NETDEV
#define NETDEV_USING_IFCONFIG
#define NETDEV_USING_PING
#define NETDEV_USING_NETSTAT
#define NETDEV_USING_AUTO_DEFAULT
#define NETDEV_IPV4 1
#define NETDEV_IPV6 0
#define RT_USING_LWIP
#define RT_USING_LWIP203
#define RT_USING_LWIP_VER_NUM 0x20003
#define RT_LWIP_MEM_ALIGNMENT 4
#define RT_LWIP_IGMP
#define RT_LWIP_ICMP
#define RT_LWIP_DNS
#define RT_LWIP_DHCP
/* Static IPv4 Address */

#define RT_LWIP_IPADDR "192.168.1.30"
#define RT_LWIP_GWADDR "192.168.1.1"
#define RT_LWIP_MSKADDR "255.255.255.0"
/* end of Static IPv4 Address */
#define RT_LWIP_UDP
#define RT_LWIP_TCP
#define RT_LWIP_RAW
#define RT_MEMP_NUM_NETCONN 8
#define RT_LWIP_PBUF_NUM 16
#define RT_LWIP_RAW_PCB_NUM 4
#define RT_LWIP_UDP_PCB_NUM 4
#define RT_LWIP_TCP_PCB_NUM 4
#define RT_LWIP_TCP_SEG_NUM 40
#define RT_LWIP_TCP_SND_BUF 8196
#define RT_LWIP_TCP_WND 8196
#define RT_LWIP_TCPTHREAD_PRIORITY 10
#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
#define RT_LWIP_TCPTHREAD_STACKSIZE 1024
#define RT_LWIP_ETHTHREAD_PRIORITY 12
#define RT_LWIP_ETHTHREAD_STACKSIZE 1024
#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define SO_REUSE 1
#define LWIP_SO_RCVTIMEO 1
#define LWIP_SO_SNDTIMEO 1
#define LWIP_SO_RCVBUF 1
#define LWIP_SO_LINGER 0
#define LWIP_NETIF_LOOPBACK 0
#define RT_LWIP_USING_PING
/*-----------------------------------------modbus协议----------------------------------------------*/
#define PKG_MODBUS_SLAVE_TCP
#define RT_S_DISCRETE_INPUT_START 0x0
#define RT_S_DISCRETE_INPUT_NDISCRETES 10
#define RT_S_COIL_START 0x0
#define RT_S_COIL_NCOILS 10
#define RT_S_REG_INPUT_START 0x0
#define RT_S_REG_INPUT_NREGS 10
#define RT_S_REG_HOLDING_START 0x0
#define RT_S_REG_HOLDING_NREGS 100

modbus 软件包tcp接口的实现

porttcp的实现



#include "port.h"

#ifdef PKG_MODBUS_SLAVE_TCP
/* ----------------------- Modbus includes ----------------------------------*/
#include "mbport.h"
#include "lwip/sockets.h"

#define DBG_ENABLE
#define DBG_TAG "app.server"
#define DBG_LVL DBG_LOG

#include "rtdbg.h"
/* ----------------------- Defines  -----------------------------------------*/
#define MB_TCP_DEFAULT_PORT     502
#define MB_TCP_BUF_SIZE     ( 256 + 7 )
#define MB_TCP_CLIENT_TIMEOUT  (30*RT_TICK_PER_SECOND)  /*超时时间30s*/
/* ----------------------- Static variables ---------------------------------*/
/**
 * @var local_sock  本地套接字描述符
 */
int local_sock = -1;
/**
 * @var remote_sock 远端套接字描述符
 */
int remote_sock = -1;
/**
 * @var local_listen_port 监听端口号,默认是502
 */
static rt_uint16_t local_listen_port = MB_TCP_DEFAULT_PORT;
/**
 * @var mb_thread 线程指针
 */
static rt_thread_t mb_thread = RT_NULL;
/**
 * @var local_addr 本地套接字地址结构体
 */
static struct sockaddr_in local_addr;
/**
 * @var client_addr 客户端套接字结构体
 */
static struct sockaddr_in client_addr;
/**
 * @var prvvTCPBuf 接收数据缓存区
 */
static UCHAR    prvvTCPBuf[MB_TCP_BUF_SIZE];
/**
 * @var prvvTCPLength 接收数据长度
 */
static USHORT   prvvTCPLength;

static void lwip_server_entry(void *parameter) {
    static rt_tick_t recv_tick = 0;
    int result;
    socklen_t sin_size;
    begin:
    local_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (local_sock < 0) {
        LOG_E("Socket error\n");
        goto __exit;
    }
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = INADDR_ANY;
    local_addr.sin_port = htons(local_listen_port);
    memset(&(local_addr.sin_zero), 0, sizeof(local_addr.sin_zero));
    if (bind(local_sock, (struct sockaddr *) &local_addr, sizeof(struct sockaddr)) == -1) {
        LOG_E("Unable to bind\n");
        goto __exit;
    }
    if (listen(local_sock, 5) == -1) {
        LOG_E("Listen error\n");
        goto __exit;
    }

    while (1) {
        sin_size = sizeof(struct sockaddr_in);
        remote_sock = accept(local_sock, (struct sockaddr *) &client_addr, &sin_size);
        LOG_I("new client connected from (%s, %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        {
            int flag = 1;
            // 不使用Nagle算法
            // Nagle算法的主要目的是为了预防小分组的产生,因为在广域网中,小分组会造成网络拥塞。
            setsockopt(remote_sock, IPPROTO_TCP, TCP_NODELAY, (void *) &flag, sizeof(int));
            flag = 1;
            ioctlsocket(remote_sock, FIONBIO, &flag); /*配置成非阻塞模式*/
        }
        recv_tick = rt_tick_get();
        while (1) {
            result = recv(remote_sock, &prvvTCPBuf, MB_TCP_BUF_SIZE, 0);
            if (result == 0) { /*表示连接关闭*/
                LOG_I("client(%s) disconnected", inet_ntoa(client_addr.sin_addr));
                break;
            } else if (result == -1) { /*表示未接收到数据*/
                if (abs((int) (rt_tick_get() - recv_tick)) > MB_TCP_CLIENT_TIMEOUT) /* set timeout x */
                {
                    LOG_D("timeout close client(%s) connect", inet_ntoa(client_addr.sin_addr));
                    break; /*超时跳出循环*/
                }
                rt_thread_delay(20);
            } else if (result > 0) {
                LOG_D("recv %d len data\n", result);
                prvvTCPLength = result;
                xMBPortEventPost(EV_FRAME_RECEIVED);
            } else {
                LOG_E("unknown error:%d", result);
                break;
            }
            
            /*todo 判断是否网线拔掉的情况?*/
        }
        if (remote_sock >= 0) {
            closesocket(remote_sock);
            remote_sock = -1; /*重置为-1*/
        }
    }
    __exit:
    if (local_sock >= 0) closesocket(local_sock);
    rt_thread_mdelay(1000);/*等待1ms*/
    goto begin;

}


BOOL
xMBTCPPortInit(USHORT usTCPPort)
{
    if (usTCPPort == 0)
        usTCPPort = MB_TCP_DEFAULT_PORT;
    local_listen_port = usTCPPort;
    if (mb_thread == NULL) {
        /*创建任务*/
        mb_thread = rt_thread_create(
                "modbus_thread",
                lwip_server_entry,
                RT_NULL,
                1024,
                15, 10
        );
        if (mb_thread) {
            rt_thread_startup(mb_thread);
        } else {
            LOG_E("modbus thread create error");
            return FALSE;
        }
    }
    return TRUE;
}

void
vMBTCPPortClose(void)
{
    closesocket(local_sock); 
}

void
vMBTCPPortDisable(void)
{
    closesocket(remote_sock);
    remote_sock = -1;
}

BOOL
xMBTCPPortGetRequest(UCHAR **ppucMBTCPFrame, USHORT *usTCPLength)
{
    *ppucMBTCPFrame = &prvvTCPBuf[0];
    *usTCPLength = prvvTCPLength;

    return TRUE;
}

BOOL
xMBTCPPortSendResponse(const UCHAR *pucMBTCPFrame, USHORT usTCPLength)
{
    rt_int16_t ret;
    BOOL bFrameSent = FALSE;
    /*如果远端*/
    if (remote_sock > 0)
    {
        ret = send(remote_sock, (void *) pucMBTCPFrame, usTCPLength, 0);
        if (ret == usTCPLength)
            bFrameSent = TRUE;
    }
    return bFrameSent;
}
#endif

modbus线程的编写

//
// Created by shchl on 2024/3/17.
//
#include "app_config.h"
#include "sal_socket.h"
#include "netdev.h"
#include "mb.h"

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

#define MB_POLL_THREAD_PRIORITY  10
#define MB_POLL_CYCLE_MS 200
static struct netdev *netdev;

static void mb_slave_poll(void *parameter) {
    netdev = netdev_get_by_name("e0");
    if (netdev == NULL) {
        LOG_E("get netdev failed");
    }
    /*等待ip地址和网关配置完成*/
    while (netdev->ip_addr.addr == 0x0 || netdev->gw.addr == 0x0) {
        LOG_W("netdev is not config finished,waiting 1 s");
        rt_thread_mdelay(1000);
    }
    eMBTCPInit(0); /*使用默认端口503*/
    eMBEnable();
    while (1) {
        eMBPoll();
        rt_thread_mdelay(MB_POLL_CYCLE_MS);
    }
}

static int mb_slave_tcp() {
    static rt_uint8_t is_init = 0;
    rt_thread_t tid1 = RT_NULL;
    tid1 = rt_thread_create("mb_slave_tcp", mb_slave_poll, NULL, 1024, MB_POLL_THREAD_PRIORITY, 10);
    if (tid1 != RT_NULL) {
        rt_thread_startup(tid1);
    } else {

    }

    return RT_EOK;

}

INIT_APP_EXPORT(mb_slave_tcp);

modbus tcp 部分源码分析记录

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值