电网101、104规约解析(Java)「建议收藏」

电网101、104规约解析(Java)「建议收藏」国家电网101规约解析(Java)最近在研究国家电网的101与104规约,也就是DL/T634.5101-2002和DL/T634.5104-2009。因为要做一个规约解析的软件(基于Android平台的),刚开始接触的也是一头雾水,因为没有接触过这方面的知识,所以就在网上搜索各种技术帖,大神经验什么的。后来在网上找到了一个软件–IEC8705(报文翻译工具).exe,这个##可以解析一…

大家好,又见面了,我是你们的朋友全栈君。

1. 前言

最近在研究广东电网的101与104规约,也就是DL/T634.5101-2002DL/T634.5104-2009。因为要做一个规约解析的软件(基于Android平台的),刚开始接触的也是一头雾水,因为没有接触过这方面的知识,所以就在网上搜索各种技术帖,大神经验什么的。

后来在网上找到了一个软件–IEC8705(报文翻译工具).exe,这个可以解析一些101(平衡式)的实例,效果图贴一下。

但有些还是解析不了,并且在网上也找不到他的源码,所以就很苦恼。也找到一些C++的源码,但是由于技术有限,我看不懂。下面就和大家来看看我写的这个简单的Java语言的规约解析。先贴一下效果图(我就在控制台简单演示一下,没有做可视化界面)。

GitHub地址:https://github.com/mujave/iec 欢迎star哦

2. Java版效果图

3. 规约详细解释

先看一下我总结的关于规约解析的几个图
101的规约总结
在这里插入图片描述
104规约总结
在这里插入图片描述具体的104协议解释也可以参考 https://blog.csdn.net/wojiuguowei/article/details/79413142

4. 名词解释

这里所说的名词解释,并不是对一些名词的定义的解释,因为这不是我的专业领域,下面我主要针对报文所代表的名词在代码里怎样解释(解析)说一下。

  1. 控制域(平衡式)
    在这里插入图片描述
    在报文解析中,我就是按照图里面的取值方法对对应的字节进行取值,然后进行逻辑判断,将结果加到解析结果里面,由于后四位所代表的平衡链路功能码在这里是固定的,所以可以采取枚举或者反射(常量)的方式进行解析
  2. 地址域 (以104的信息体地址为例)
    在规约中地址才用的低前高后(低位在前高位在后)的规则
    例如:68 10 08 00 02 00 09 01 03 00 01 00 01 40 00 2B 02 00(黄色部分为信息体地址)
    在这里插入图片描述
    所以 这个信息体的地址为01 40 00 >> 0x004001=16385
  3. 时标CP56Time2a
    在这里插入图片描述
    解析代码如下
	/**
     * 时标CP56Time2a解析
     *
     * @param b 时标CP56Time2a(长度为7 的int数组)
     * @return 解析结果
     */
    public static String TimeScale(int b[]) {

        StringBuilder result = new StringBuilder();

        int year = b[6] & 0x7F;
        int month = b[5] & 0x0F;
        int day = b[4] & 0x1F;
        int week = (b[4] & 0xE0) / 32;
        int hour = b[3] & 0x1F;
        int minute = b[2] & 0x3F;
        int second = (b[1] << 8) + b[0];

        result.append("时标CP56Time2a:20");
        result.append(year).append("-");
        result.append(String.format("%02d", month)).append("-");
        result.append(String.format("%02d", day)).append(",");
        result.append(hour).append(":").append(minute).append(":");
        result.append(second / 1000 + "." + second % 1000).append("\n");

        return result.toString();
    }
  1. 遥测量的解析
    在101的遥测中定义到有三种类型的值,分别是归一化值,标度值,短浮点数,具体的定义大家可以参考“电力101/104规约中遥测量类型转换”,下面我说一下在Java中怎么解析这三种类型的值。直接上代码了。
public class Main {

    public static void main(String[] args) {
        Telemetry telemetry = new Telemetry();
        System.out.println(telemetry.Bytes2Float_NVA(0xa4, 0x6a));// 报文数据的为A4 6A(低位在前,高位在后) ,为0x6AA4
        System.out.println(telemetry.Bytes2Float_SVA(0xa4, 0x6a));// 报文数据的为A4 6A(低位在前,高位在后) ,为0x6AA4

        System.out.println(telemetry.Bytes2Float_IEEE754("3e0779a6"));
        //报文数据 A6 79 07 3E = 0x3e0779a6 = 0.1323(IEEE754 短浮点数)http://lostphp.com/hexconvert/
    }
}

/**
 * 遥测量解析
 *
 * @author zhangyu
 */

public class Telemetry {

    /**
     * 归一化值
     */
    public static float Bytes2Float_NVA(int low, int high) {
        float fVal;
        int nva = (high << 8) + low;
        // 符号位1位,0为正数,1为负数,后面的为补码表示,
        // 正数的补码和原码相同不需要转换。对于负数,先取反码再加1得到补码的补码,就是原码了。
        int symbol = (high & 0x80);//符号位:0表示正数,1表示负数
        if (symbol == 0x80)
            fVal = -1 * (((nva ^ 0xffff) + 1) & 0x7fff);//  (nva ^ 0xffff) + 1 :补码的补码  ,取出后面的15位数据乘上-1得到值
        else fVal = nva;
        return fVal / 32767;//这里的32767值的是一个量纲,一般这个参数是主站和从站商定的
    }

    /**
     * 标度化值
     */
    public static float Bytes2Float_SVA(int low, int high) {
        float fVal;
        int nva = (high << 8) + low;
        int symbol = (high & 0x80);//0表示正数,1表示负数
        if (symbol == 0x80)
            fVal = -1 * (((nva ^ 0xffff) + 1) & 0x7fff);
        else fVal = nva;
        return fVal;
    }

    /**
     * 短浮点数
     *
     * @param data 从低位到高位按顺序
     * @return
     */
    public static float Bytes2Float_IEEE754(String data) {

        return Float.intBitsToFloat(Integer.valueOf(data, 16));
    }
}

对于短浮点数的计算,在Java的文档里有这样的说明。
在这里插入图片描述
还有一些ASDU里的信息体的解析过程代码,有点多,就不一一贴出来了
代码已经发布到GitHub,需要的伙伴可以直接下载

5.104规约解析遇到的一些难题

  1. 报文类型的区分
    101报文区分定长和变长两种,而104规约都是变长的报文。但是对于104来说,其控制域决定了104报文分别属于三种类型(I帧S帧U帧)。所以在解析104到控制域的时候,是在解析104的第一个难题。我先说一下我自己的区分逻辑。
    在这里插入图片描述
  • 我是用控制域的第一字节去和3做位运算(因为和3做位运算就可以得到第一字节的D1/D0两位),从上面的图中我们可以看到,结果如果是1的话就是S格式,如果是3的话就是U格式,其他 的结果就是I格式的报文。
  • 第二种方式是我在和一个网友交谈中得到的,他是运用奇数或者偶数来区分的,这里我列一个表格 ,这样的话如果第一个字节是偶数就是I帧,否则判断第三字节是0就是U帧。这样也可以区分报文的类型

但是我认为还是做位运算效率会更高,计算奇偶性还需要用到%这样的运算。

类型 第一字节 第二字节 第三字节 第四字节
S帧 奇(1) 0
I帧
U帧 0 0 0
  1. 位运算的运用

在解析规约的时候,我一般都是运用的位运算(&),这样既可以提高程序的效率,也有助于理解。首先在规约的定义中有很多的一个字节中的不同位代表一个含义,这种时候就运用到了位运算,这样就可以直接将对应位的值提取出来,例如那可变结构限定词这个字节来举个例子。最高位的D7代表的是信息元素地址的连续性,其中0不连续1连续,所以我们只需要拿这个字节和128(0x80)做位运算就可以得到D7这一位,如果结果是10000000就说明是1连续。这个地方更直观一点的判断方法就是((B&0x80)>>7)==1?连续 : 不连续。
在这里插入图片描述

  1. 时标的解析

在这里插入图片描述
首先时标这里一共有7个字节,下面对这几个字节的含义以及解析方法做一下解释:

  • 年(byte 7):这里只有后面的7位有效,但是第8位填充的是0,所以这一个字节直接转换形成int就可以了。
  • 月(byte 6):同上
  • 小时(byte 4):同上
  • 分钟(byte 3):同上
  • 日(byte 5[bit 1~5]):第五字节的后5位表示的是日,byte5 & 0x1F 就可以得到(0x1F = 0001 1111),例如第五字节是87(87 = 0x57 = 0101 0111),其中010指的是星期,10111指的是day。这里使用87 & 0x1F就可以得到23。使用87 & 0xE0就可以得到64,然后再用这个结果除以32就可以得到结果,如果说除以32不太理解的话,也可以用结果右移运算64>>5也可以得到结果 。
  • 毫秒(byte 1 and byte 2):这个地方首先是低前高后的问题(这个为题不太明白的可以先翻一下下面的第四个问题),( byte 2 << 8 ) + byte 1 ,这个地方我用一个表格说明一下(例如第一字节是6E,第二字节是2A)。

在这里插入图片描述

/** * 时标CP56Time2a解析 */
public static String TimeScale(int b[]) { 
   

	    String str = "";
	    int year = b[6] & 0x7F;
	    int month = b[5] & 0x0F;
	    int day = b[4] & 0x1F;
	    int week = (b[4] & 0xE0) / 32;
	    // int week = (b[4] & 0xE0) >> 5;
	    int hour = b[3] & 0x1F;
	    int minute = b[2] & 0x3F;
	    int second = (b[1] << 8) + b[0];

    	str += "时标CP56Time2a:" + "20" + year + "-"
	        + String.format("%02d", month) + "-"
	        + String.format("%02d", day) + "," + hour + ":" + minute + ":"
        	+ second / 1000 + "." + second % 1000;
    	return str + "\n";
}


/** * 时间转16进制字符串 */
public static String date2HStr(Date date) { 
   
    
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        StringBuilder builder = new StringBuilder();
        String milliSecond = String.format("%04X", (calendar.get(Calendar.SECOND) * 1000) + calendar.get(Calendar.MILLISECOND));
        builder.append(milliSecond.substring(2, 4));
        builder.append(milliSecond.substring(0, 2));
        builder.append(String.format("%02X", calendar.get(Calendar.MINUTE) & 0x3F));
        builder.append(String.format("%02X", calendar.get(Calendar.HOUR_OF_DAY) & 0x1F));
        int week = calendar.get(Calendar.DAY_OF_WEEK);
        if (week == Calendar.SUNDAY)
            week = 7;
        else week--;
        builder.append(String.format("%02X", (week << 5) + (calendar.get(Calendar.DAY_OF_MONTH) & 0x1F)));
        builder.append(String.format("%02X", calendar.get(Calendar.MONTH) + 1));
        builder.append(String.format("%02X", calendar.get(Calendar.YEAR) - 2000));
        return builder.toString();
    }
  1. 低前高后的问题

这里讲一下低前高后的问题,拿这个104规约的信息对象地址举例。例如34 12 00这是原报文的字节,再具体解析的时候我们要把它转成0x001234=4660,其实这里和上面的毫秒的解析方式一样。
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/151343.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(2)


相关推荐

  • 抓包工具Charles使用教程

    抓包工具Charles使用教程文章目录一、什么是Charles?二、下载安装:三、http抓包:一、什么是Charles?Charles,因产品Icon为青花瓷造型,俗称青花瓷。主要是用来抓取网络流量包,可以分析产生的网络请求、可以配置代理来抓取手机流量包数据。二、下载安装:1、官方渠道,收费版;2、安装破解版,百度网盘地址:https://pan.baidu.com/s/1_ApnyPqoN5EQ6JvHMjnCTQ三、http抓包:1、开始代理配置:目录:Proxy-ProxySettings2、查看电

  • IT该忍者神龟Jquery小工具easyUI物业摘要召回

    IT该忍者神龟Jquery小工具easyUI物业摘要召回

  • pycharm怎么修改快捷键_vb中运行程序的快捷键是什么

    pycharm怎么修改快捷键_vb中运行程序的快捷键是什么在Pycharm中默认运行的快捷键是Ctrl+Shift+F10。如何修改Pycharm运行的快捷键?步骤一:在File中找到Settings.步骤二:找到Keymap,并在搜索框中搜索run,找到对应的【Run】.步骤三:右键点击Run,选择【AddKeyboardShortcut】.步骤四:在此处填入想设置的快捷键即可.最后点击应用和OK即可设置完毕!成功!!!…

  • linux vim :E325 解决办法[通俗易懂]

    linux vim :E325 解决办法[通俗易懂]在终端中输入ls-la找到.swp文件(这个文件是个隐藏文件,所以删除时要加上.),然后rm.你的swp文件。

  • Centos7安装Mysql5.7最全教程[通俗易懂]

    Centos7安装Mysql5.7最全教程[通俗易懂]最近需要在Linux系统上使用MySQL,记录一下安装过程吧,为后来的同学排除一些问题。更新yumyumupdate-y1.安装wget工具我安装到了/export/install这里可以进入你们所想要安装的地方cd/先进入你想安装的位置,此后全部在此文件夹进行操作。sudoyuminstall-ywget2.使用wget下载mysqlyum源:wgethttps://dev.mysql.com/get/mysql80-community-release-el

  • 大数据技术的发展趋势

    大数据技术的发展趋势英国牛津大学教授维克托·迈尔-舍恩伯格在其所撰写的《大数据时代》中表述,大数据时代是“已经发生的未来”,而在这个已经发生的未来里,没有旁观者。作为时代发生的必然产物,大数据正加速渗透至我们的日常生活,正完成对各传统领域的颠覆。本文从大数据时代的特点出发,为读者介绍目前的大数据技术的发展趋势以及大数据的生态体系。大数据时代的特点和市场规模大数据时代两个特点。第一,大数据技术以开源为主,迄今为止,尚未形成绝对技术垄断,即便是IBM、甲骨文等行业巨擘,也同样是集成了开源技术和该公司已有产品而已。开源技

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号