使用netty做硬件测试代码的一般步骤

news2025/2/5 19:56:42

准备工作:搭建netty

1、util文件中准备好数据结构转换,byte[]数组转为int类型

大端写法,从高往低位读

    public static int bytesToInt(byte[] bytes){
        int value;
        value = ((bytes[0] & 0xff)<<24)|
                ((bytes[1] & 0xff)<<16)|
                ((bytes[2] & 0xff)<<8)|
                (bytes[3] & 0xff);
        return value;
    }

2、检查报文首尾是否正确

在这里插入图片描述
其中 public static final byte MEG_SEPARATION_HEAD = (byte) 0x5c;

    public static boolean validate(byte[] message) {
        if ((message[Constants.HEAD_BYTE_01_POS] == Constants.MEG_SEPARATION_HEAD) && (message[Constants.HEAD_BYTE_02_POS] == Constants.MEG_SEPARATION_HEAD) && (message[Constants.HEAD_BYTE_03_POS] == Constants.MEG_SEPARATION_HEAD) && (message[Constants.HEAD_BYTE_04_POS] == Constants.MEG_SEPARATION_HEAD)

                && (message[Constants.MEG_SEPARATION_TAIL_POS1] == Constants.MEG_SEPARATION_TAIL) && (message[Constants.MEG_SEPARATION_TAIL_POS2] == Constants.MEG_SEPARATION_TAIL) && (message[Constants.MEG_SEPARATION_TAIL_POS3] == Constants.MEG_SEPARATION_TAIL) && (message[Constants.MEG_SEPARATION_TAIL_POS4] == Constants.MEG_SEPARATION_TAIL)) {
            return true;
        }
        log.error("报文头尾出现问题请排查");
        return false;
    }

3、处理幂等性问题

处理msgId重复情况,全局存一个变量,与上一次报文进行比较

4、处理报文msgId异常情况

    public static boolean MsgIdCheck(byte[] message) {
        byte[] msgIdBytes = generateTypeInt32(message, Constants.MSG_ID_POS);
        if (HexUtil.encodeHexStr(msgIdBytes).equalsIgnoreCase("ffffffff")) {
            log.error("Modbus总线通讯故障");
            return false;
        }
        return true;
    }

5、打印接收报文 ByteBuf msg

        byte[] bytes = new byte[Constants.MEG_LENGTH];
        msg.readBytes(bytes);
        log.info("接收到转发服务原始报文 - {}", HexUtil.encodeHexStr(bytes));

后续只需要处理byte数组即可

6、处理报文逻辑netty handler中做处理

/**
 * @author lst
 * @date 2023/12/20 14:22
 * @return null
 */
@Slf4j
public class WebHandler extends SimpleChannelInboundHandler<ByteBuf> {
    private Map<Physics, byte[]> previousMessageFields = new LinkedHashMap<>();
    private long lastReceivedTimestamp = System.currentTimeMillis();

    private WebClient webClient;

    public WebHandler(WebClient webClient) {
        this.webClient = webClient;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("连接的Web服务器端地址:" + ctx.channel().remoteAddress());
        }
        super.channelActive(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        byte[] bytes = new byte[Constants.MEG_LENGTH];
        msg.readBytes(bytes);
        log.info("接收到转发服务原始报文 - {}", HexUtil.encodeHexStr(bytes));
        if (!WebUtil.validate(bytes) || !WebUtil.MsgIdCheck(bytes)) {
            // Clear the message buffer to handle potential packet fragmentation
            msg.clear();
            return;
        }
        //当前接受报文
        Map<Physics, byte[]> currentFields = parseFields(bytes);
        // 记录接收时间戳
        long currentTimestamp = System.currentTimeMillis();
        //比较两次报文
        if (!previousMessageFields.isEmpty()) {
            WebUtil.compareAndPrintChanges(previousMessageFields, currentFields);
        }
        //更新报文
        previousMessageFields = currentFields;
        // 更新上一次接收的时间戳
        lastReceivedTimestamp = currentTimestamp;
    }

    private Map<Physics, byte[]> parseFields(byte[] bytes) {
        //解析报文放入map中
        Map<Physics, byte[]> map = new LinkedHashMap<>();
        // Head部分
        map.put(new Physics("HeadByte01", "HeadByte01", HEAD_BYTE_01_POS), WebUtil.generateTypeUInt8(bytes, HEAD_BYTE_01_POS));
// Tail部分
        map.put(new Physics("TailByte01", "TailByte01", TAIL_BYTE_01_POS), WebUtil.generateTypeUInt8(bytes, TAIL_BYTE_01_POS));
        return map;
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.error("运行中与Web服务器断开,重连...");
        // 重连
        webClient.connect();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(cause.getMessage());
        ctx.close();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Plantuml之序列图语法介绍(十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

arcpy工具箱根据个别参数隐藏/显示其他参数

引入 工具箱属性中有验证参数&#xff08;如下图&#xff09;&#xff0c;该部分主要用于工具箱参数是否符合我们的要求&#xff0c;主要包含3方面的函数&#xff0c;分别是在打开工具箱调用的initializeParameters()、修改参数值后调用updateParameters()、为参数设置消息提示…

DevC++ easyx实现悬浮窗放入网格,与在函数分离过程中遇到的BUG下理解 函数的作用时域 以及 初始化与复位的关系。

这次就着上上上篇的悬浮窗代码DevC easyx实现图片拖动&#xff0c;一种悬浮窗实现原理与完整代码-CSDN博客 继续实现效果。 基本背景是搓出来图片拖动了&#xff0c;然后想把图片暂存到另一块。再细说背景的背景就是之前提到Unity复刻瓦片地图&#xff0c;想着整合一个铅笔绘…

web前端 JQuery下拉菜单的案例

浏览器运行结果&#xff1a; JQuery下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/17LXZigLQ8yau0toTGj4P_Q?pwd4332 提取码&#xff1a;4332 代码&#xff1a; <!doctype html> <html> <head> <meta charset"UTF-8"><…

Emu2:37亿参数开创多模态生成新篇章

引言 多模态任务在人工智能领域一直是极具挑战性的「技术高地」。智源研究院最近开源发布的新一代多模态基础模型Emu2&#xff0c;在这一领域取得了突破性进展。Emu2以其庞大的37亿参数规模和强大的多模态生成能力&#xff0c;为AI的多模态理解和生成开启了新的篇章。 模型概…

【重点!!!】【贪心】45.跳跃游戏II

题目 法1&#xff1a;贪心 贪心是最优解法&#xff0c;必须掌握&#xff01;重点理解&#xff0c;看B站视频辅助&#xff01;&#xff01;&#xff01; 在具体的实现中&#xff0c;我们维护当前能够到达的最大下标位置&#xff0c;记为边界。我们从左到右遍历数组&#xff0…

记账导出excel表格,用表格导出账目数据

我们每天都在跟金钱打交道,记账则是更好地管理自己财务的一种方式&#xff0c;传统记账不仅繁琐&#xff0c;还容易出错。那么&#xff0c;有没有简单、高效的记账方式呢&#xff1f;答案是肯定的&#xff01;今天&#xff0c;我们就向大家推荐一款全新的记账软件——晨曦记账本…

Windows系统重启Redis服务

Windows系统 在安装Redis的目录下打开终端 执行 redis-cli.exe shutdown先停止 Redis 服务 然后 执行 redis-server.exe启动Redis服务

数字 IC 设计职位经典笔/面试题,建议收藏!

共100道经典笔试、面试题目&#xff08;文末可全领&#xff09; 什么是同步逻辑和异步逻辑&#xff1f; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。同步时序逻辑电路的特点&#xff1a;各触发器的时钟端全部连接在一起&#xff0c;并接在…

[大厂实践] DoorDash基于eBPF的监控实践

eBPF是监控云原生应用的强大工具&#xff0c;本文介绍了DoorDash构建基于eBPF的监控系统的实践。原文: BPFAgent: eBPF for Monitoring at DoorDash 随着DoorDash在过去几年中经历了快速增长&#xff0c;我们开始看到传统监控方法的局限性。度量、日志和跟踪提供了服务生态系统…

el-table中表头自定义动态渲染

el-table中有时候我们可能遇到需要表头自定义以数组的形式进行循环显示 当我们改变tableHead时我们自定义的表头没有跟随渲染 有人会使用this.$refs.table.doLayout这个只能动态渲染更换数据布局 会对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时&#xff…

论文分享 | SINGFAKE:歌声深度伪造检测

以下文章来源于智能语音新青年 &#xff0c;作者ttslr 论文地址&#xff1a; https://arxiv.org/pdf/2309.07525.pdf 合成歌声的兴起给艺术家和行业利益相关者带来了未经授权使用歌声的严峻挑战。与合成语音不同&#xff0c;合成歌声通常是在含有强烈背景音乐的歌曲中发布的&a…

2024年最新的人工智能工程师证书 已经开始报名了

2024年最新的人工智能工程师证书 已经开始报名了&#xff0c;以下有报考条件和证书样式可做参考&#xff1a; 计算机自然语言及语音处理设计开发工程师&#xff08;中级&#xff09; 计算机视觉处理设计开发工程师&#xff08;中级&#xff09; 1.人工智能工程师证书培训对象 …

Codeforces Round 917 (Div. 2)

Codeforces Round 917 (Div. 2) Codeforces Round 917 (Div. 2) A. Least Product 题意&#xff1a; 给出整数数组a&#xff0c;现在可以执行任意次数以下操作&#xff1a;任意选择数组a的一个元素 a i a_i ai​&#xff0c;若 a i a_i ai​>0可以任意替换为[0, a i a_i…

网络的七层结构模型

网络的七层结构模型&#xff0c;亦称OSI&#xff08;Open Systems Interconnection&#xff09;模型&#xff0c;包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。以下是各层的主要功能&#xff1a; 从下往上分别是1-7&#xff0c;总共7层&#xff0c;每一层…

【NI-RIO入门】记录和监控数据

1.内部存储器 可以使用常规文件 I/O VI 在嵌入式程序中以编程方式访问实时控制器的内部存储。文件路径结构根据控制器运行的实时操作系统 (RTOS) 的不同而有所不同。 该文件路径语法记录在教程&#xff1a;使用实时目标上的文件路径 中。 可以通过在Measurement & Automati…

全国5米土地利用遥感监测数据(GB/T 21010-2017)

全国5米土地利用遥感监测数据 全国5米土地利用类型遥感监测空间分布数据&#xff0c;是基于谷歌高分辨率影像数据人机交互解译形成&#xff0c;并使用POI数据、ROI数据进行数据修正。根据GB/T 21010-2017《土地利用现状分类》将土地利用类型分为12个一级类&#xff0c;73个二级…

SpringBoot 3.2.0 基于Logback定制日志框架

依赖版本 JDK 17 Spring Boot 3.2.0 工程源码&#xff1a;Gitee 日志门面和日志实现 日志门面&#xff08;如Slf4j&#xff09;就是一个标准&#xff0c;同JDBC一样来制定“规则”&#xff0c;把不同的日志系统的实现进行了具体的抽象化&#xff0c;只提供了统一的日志使用接…

SAP ME21/22/23N 创建增强ME_PROCESS_PO_CUST

增强ME_PROCESS_PO_CUST 二、实现方式&#xff1a;实现的方式可以有很多种&#xff0c;这里讲一下用BADI增强ME_PROCESS_PO_CUST实现的方式 第一步&#xff1a;执行事务码se19,在BAdI Name处输入&#xff1a;ME_PROCESS_PO_CUST&#xff0c;然后点“Create Impl”按钮 第二步…

鸿蒙列表,item组件封装传参问题?@ObjectLink 和@Observerd

鸿蒙列表渲染&#xff0c;封装内容组件&#xff0c;进行item传参会报错&#xff1f; class FoodClass {order_id: number 0food_name: string ""food_price: number 0food_count: number 0 }Entry Component struct Demo07 {State message: string Hello World…