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 部分源码分析记录

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mysqlcheck 数据完整性检查与修复

目录 mysqlcheck 命令文档 描述 选项 参数 示例 mysqlcheck 命令文档 mysqlcheck 是MySQL提供的一个工具&#xff0c;用于检查、修复、优化和分析数据库和表的健康状态。你可以使用它来确保数据库表的完整性和性能。 mysqlcheck [options] db_name [tbl_name ...]mysqlch…

德迅蜂巢(容器安全)全面出击

随着云计算的发展&#xff0c;以容器和微服务为代表的云原生技术&#xff0c;受到了人们的广泛关注&#xff0c;德迅云安全德迅蜂巢&#xff08;容器安全&#xff09;是企业容器运行时和容器编排的首要选择。然而&#xff0c;在应用容器过程中&#xff0c;大多数企业都遇到过不…

分数相加减(C语言)

一、流程图&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int fenmu 2;int result 1;int fuhao 1;//执行循环&#xff1b;while (fenmu < 100){//运算&#xff1b;fuhao (-1…

TSINGSEE青犀AI智能分析网关V4酿酒厂安全挂网AI检测算法

在酿酒行业中&#xff0c;安全生产一直是企业经营中至关重要的一环。为了确保酒厂生产过程中的安全&#xff0c;TSINGSEE青犀AI智能分析网关V4的安全挂网AI检测算法发挥了重要作用。 TSINGSEE青犀AI智能分析网关V4的安全挂网检测算法是针对酒厂里酒窖挂网行为进行智能检测与识…

[java基础揉碎]Object类详解

目录 equals方法: hashCode: toString: finalize: equals方法: 和equals对比 1.: 既可以判断基本类型&#xff0c;又可以判断引用类型 2.: 如果判断基本类型&#xff0c;判断的是值是否相等。示例: int i10; double d10.0; 3.:如果判断引用类型&#xff0c;判断的是地址是…

SQLiteC/C++接口详细介绍sqlite3_stmt类简介

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;十八&#xff09; 下一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;一&#xff09; 预准备语句对象 typedef struct sqlite3_stmt sqlite3_stmt…

关于安卓USB开发(一)文件复制,文件夹创建

背景 在安卓应用中&#xff0c;把某个文件&#xff0c;复制到插入的U盘中 开发环境 win10,jdk8,as4 测试机型 红米Note11&#xff0c;android13 源码问题 文末将会提供博主整合好的源码项目连接&#xff0c;以供学习交流 注意 本次实战&#xff0c;u盘格式是fat32&…

弗洛伊德-华沙算法求任意两点之间的最短路径算法

对于弗洛伊德-华沙算法首先是要假设研究的图中是不包含有负边的&#xff0c;对于所给的图中的任意亮点v1&#xff0c;vm&#xff0c;假设两点之间存在一条连通路径&#xff0c;对于该路径中去掉头和尾节点&#xff0c;也就是v1&#xff0c;vm&#xff0c;剩下的节点也就称之为这…

【MySQL】2. 数据库基础

1. 数据库基础&#xff08;重点&#xff09; 1.1 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题 文件不利于数据查询和管理 文件不利于存储海量数据 文件在程序中控制不方便 数据库存储介…

告别紧张,轻松应对!公众演讲的实用技巧

告别紧张&#xff0c;轻松应对&#xff01;公众演讲的实用技巧 公众演讲&#xff0c;对于许多人来说&#xff0c;是一项充满挑战的任务。面对众多的听众&#xff0c;紧张情绪往往难以避免&#xff0c;甚至可能影响到演讲的效果。然而&#xff0c;通过掌握一些实用的技巧&#…

常见的业务场景实现方案

1.解决请求服务器接口跨域的问题 本地项目请求服务器接口时&#xff0c;因为客户端的同源策略&#xff0c;导致了跨域问题 配置允许本地跨域&#xff1a; /api指代我们要请求的接口域名&#xff0c;例如&#xff1a;this.$axios.get(/api/app.php?mApp&cIndex&aind…

一种动态联动的实现方法

安防领域中的联动规则 有安防领域相关的开发经历的人知道&#xff0c;IPCamera可以配置使能“侦测”功能&#xff0c;并且指定仅针对图像传感器的某个区载进行侦测。除了基本的“移动侦测"外&#xff0c;侦测的功能点还有细化的类别&#xff0c;如人员侦测、车辆侦测、烟…

P1042 [NOIP2003 普及组] 乒乓球

题目描述&#xff1a; AC代码&#xff1a; #include<iostream> #include<cmath>using namespace std;const int N 25*250010; int a[N],b[N]; int k[2] {11,21};int main() {int n0;while(1){char c;cin >> c;//方便后面去做计算 if(c W) a[n] 1;if(c…

牛市下 AI + Web3 叙事引关注,Verasity 或成又一黑马项目?

事实上&#xff0c;在 ChatGPT 以及 Sora 大模型被相继提出后&#xff0c;AI 就成为了科技领域重点关注的板块&#xff0c;并引发了一轮又一轮的 AI 投资热潮。在传统科技领域引发的 AI 热潮&#xff0c;正在向加密行业拓展&#xff0c;Web3 领域也涌现出了不少 AIWeb3 概念的项…

单模场哈密顿量推导

满足麦克斯韦方程和边界条件的单模场又下式&#xff08;1&#xff09;&#xff0c;&#xff08;2&#xff09;给出 --------&#xff08;1&#xff09; ---------&#xff08;2&#xff09; , 单模场的经典场能或者哈密顿量又下式给出&#xff1a; &#xff08;3&#xff09…

编译esp32s3的ncnn,并运行mnist 手写数字识别

东哥科技&#xff0c;专注科技研发&#xff0c;wx交流&#xff1a;dg_i688 我的项目代码 https://github.com/cdmstrong/ncnn_on_esp32s3 下载ncnn git clone https://github.com/Tencent/ncnn.git安装idf 环境 这里直接按官网的可执行文件来就好了&#xff0c;直接安装完…

嵌入式Linux 内核的内存管理方法

内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。 虚拟地址的作用 如果用户进程直接操作物理地址会有以下的坏处: 1、 用户进程可以直接操作内核对应的内存,破坏内核运行。 2、 用户进程也会破坏其他进程的运行 …

传统电力运维企业的数字化转型案例

一. 传统电力运维企业面临的主要问题 上海某电力集团企业下属有成套设备公司、电力工程公司&#xff0c;依托于自身的设备制造和工程服务能力&#xff0c;以及多年积累的终端客户资源&#xff0c;几年前该公司成立了电力运维服务公司进入用户侧电力托管运维服务行业。 该公司…

【Linux系统编程】进程程序替换

介绍&#xff1a; 进程程序替换是指将一个进程中正在运行的程序替换为另一个全新的程序的过程&#xff0c;但替换不是创建新进程&#xff0c;只是将对应程序的代码和数据进行替换。具体来说&#xff0c;这个替换过程涉及将磁盘中的新程序加载到内存结构中&#xff0c;并重新建立…

Leetcode 31. 删除无效的括号

心路历程&#xff1a; 一开始看到有点懵&#xff0c;后来发现有点像按照一定规则穷举所有可能情况&#xff0c;想到了排列组合问题&#xff0c;再结合问题长度不固定&#xff0c;无法用已知个for循环表示&#xff0c;从而想到了回溯。这个题相当于需要在一定规则下枚举。 按照…