栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

开发杂谈1(TCP 和 moudlebus)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

开发杂谈1(TCP 和 moudlebus)

使用Java Netty 和串口设备进行数据通信 1、SDK的设计

我们在进行物联网开发的时候,除了自己开发的硬件设备之外,我们还会直接采购其他厂商提供的设备,这时我们就需要根据厂商提供的SDK进行设备控制。
一般来说,每一种设备的数据帧格式格式都是一样的,都遵循moudlebus,通过观察我们发现,帧格式 一般 是由 数据+固定帧格式+crc校验构成,也就是说,我们只需要提供 数据和固定的帧格式组成一条指令就好。所以为了程序的灵活性,我们可以配置指令。

假设指令格式如下:
地址+固定的帧格式+crc
固定的帧格式:
读 固定格式
写 固定格式

如上这种形式,可以看为一个固定的字符串,因此我们可以在数据库中保存,利用json的形式,存为一个json数组。

json数组的处理

我们从数据库中查询获得的,是长得有点像json的 String字符串,举个长这样的例子

[{"Tname":"read","Tlabel":"read","Ttype":"String","Tvalue":"A0400000013"},
{"name":"","label":"","type":"","value":"","Tname":"write","Ttype":"String","Tvalue":"A100008000204E","Tlabel":"write"},
{"name":"","label":"","type":"","value":"","Tname":"switch","Ttype":"String","Tvalue":"A100010000102W","Tlabel":"switch"}]

我们需要的方便处理的是长这样:

{
"read": "A0400000013" ,
"write": "A10008000204E" ,
"switch": "A100010000102W" ,
}

所以为了得到这么一个样子的长得json的String,我们还需要处理上边的那个json数组。
处理代码:

			HashMap map =new HashMap();

            JSONArray array = JSONUtil.parseArray(scDeviceComponent.getConfig());
            for(int i=0; i 

通过hutool工具包,我们可以方便进行转换。最后得到jsonObject 的格式就是我们需要的json格式。
这个时候,我们根据TCP服务是否和业务解耦来选择是否存入redis中。

redisTemplate.boundHashOps("deviceConfig").put(scDeviceComponent.getId().toString(),jsonObject.toString());

这里redisTemplate默认配置的是JDK的序列化器,因此它存放到redis缓存中长这个样子

"{"read":"A0400000013","switch":"A100010000102W","write":"A100008000204E"}"

这是序列化之后的数据,这个时候我们在TCP处用redisTemplate获取,如果获取不到,可以使用StringRedisTemplate,这里是因为序列化的问题。

获取到之后

“{“read”:“A0400000013”,“switch”:“A100010000102W”,“write”:“A100008000204E”}”

这个序列化过的长得像json的字符串,我们还需要转为json对象,这样处理起来才方便。

		configJson = configJson.substring(1, configJson.length() - 1);
        configJson = configJson.replaceAll("\\","");
        JSON json = JSONUtil.parse(configJson);
        String write =(String) json.getByPath("write");       //获取读读指令,格式 address + 固定帧格式 + expect

转换之后我们就可以直接过去对应的值了,然后替换数据和固定的帧格式组成指令即可。
但是在拼接过程中,我们会遇见这种问题。
地址一般是1字节两个16进制数,最多可到十进制的255,我们获得数据是十进制数,我们就需要单独转换为16进制,但是像1~ 15对应的是1~ F,我们需要的是两个16进制数,也就是说,缺位我们需要补零,因此我们这么转换:

 currentAddress = String.format("%02x",Integer.parseInt(currentAddress));

这样 1 转换的就是 01,我们就可以正确拼接指令。
有一些设备规定,要转换为4个16进制数的浮点型数,我们可以这么转换

expectAddress = Integer.toHexString(Float.floatToIntBits(Integer.parseInt(expectAddress)));     //转 4字节16进制浮点数

16进制浮点型转10进制浮点数

String E = parseHextoFloat(Estr).toString(); 

这里附上 crc校验码的算法

package com.ruoyi.tcpserver.util;

import java.math.BigInteger;


public class CRCUtil {

    
    public static String getCRC(byte[] bytes) {
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;
        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= ((int) bytes[i] & 0x000000ff);
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
        return Integer.toHexString(CRC);
    }


    
    private float parseHex2Float(String hexStr) {
        BigInteger bigInteger = new BigInteger(hexStr, 16);
        return Float.intBitsToFloat(bigInteger.intValue());
    }


    
    private String parseFloat2Hex(float data) {
        return Integer.toHexString(Float.floatToIntBits(data));
    }



}

需要注意的是,crc校验码是2个字节4个16进制数,我们在加入crc校验码时,需要注意高低位的问题,以及例如0A32这种的校验码0是不显示的的,所以我们转为字符串的时候,需要加入校验,补全0。

RabbitMq问题

在测试的过程中,使用的是spring的mq,在默认配置下,mq消息再被消费时,如果出现异常,该消息是不会被ack的,会一直不停的消费同一条数据,也就是不停的报错。

以上是近期开发遇见的问题,再此进行总结。功不唐捐,玉汝于成!
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/295517.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号