关于IEC61499 的数据交换信息抽象语法ASN.1
前言
IEC61499 是一个分布式控制系统功能块标准。多个设备之间,和其它外部设备之间都有信息交换。这种信息交换通过通信功能块来实现。通信功能块包括:
单向通信功能块:Publish/Subscribe
双向通信功能块:Client/Server
设备之间的消息是功能块的数据(IEC61499-FBDATA),它们由类型和值构成。通信功能块可能涉及多个数据的输入输出。每个输入输出数据可以是简单的单值数据类型,也可以是数组类型(Constructed)。所以它们要交换多个数据。多个数据的信息抽象标识采用了ASN.1 的编解码方式。
ASN.1
ASN.1抽象语法标记(Abstract Syntax Notation One)是国际标准ISO 8825-1。使用紧凑的方式抽象标识计算机内部的数据,比如 整型数,布尔数,浮点数等等。正是由于ASN.1 是一个通用的语言,所以采用了描述的语法。初学起来感觉十分的复杂。在IEC61499 标准中只是采用了ISO8825-1 中的基本编码规则。并且在IEC61499-1 标准的附录E 信息交换 中做了进一步的规范和描述。结合起来学习就比较清晰了。
ASN.1 基本编码规则
一个数据值的编码由四个部分构成
标识八比特组(identifier octets)
长度八比特组(length octets)
内容八比特组(contents octets)
内容结束八比特组(end of content octets)
内容结束八比特组是可以缺省的。所以大多数情况下是三段式标识
| identifier octets | length octets | contents octets |
有时也称为TLV三元组<Type,Length, Value>
identifier 标识的定义
第8,第7位代表了tag 的类
在IEC61499-1 附录E 中,对FBDATA 的ASN.1 编码规则做了进一步的规范
-tag 的类为Application。所有8,7 为0,1
-基本数据类型的tag number
BOOL0 0
BOOL1 1
SINT 2
INT 3
DINT 4
LINT 5
USINT 7
UDINT 8
ULINT 9
REAL 10
LREAL 11
TIME 12
DATE 13
TIME_OF_DAY 14
DATE_AND_TIME 15
BYTE 17
WORD 18
DWORD 19
LWORD 20
WSTRING 21
数组
ArrayVariable 22
IEC61499 FBDATA 的ASN.1 编码
(IEC61499-1 附录E)中说可以是两种:
-基本(BASIC) 编码
符合ISO/IEC 8825-1 的基本编码规则
-紧凑(COMPACT)编码
4DIAC 中使用的是ComPACT 编码。
对于上面的数据类型省却了长度(length octets),不同数据类型的长度是默认的。
简单类型数据编码
采用compact 编码,多个数据连续排列。
例如 4个 INT
tag=01000011=0x43 其中class=01,P/Construct=0,tag number=3=00011
最后的编码
0x43 0x00,0x00, 0x43 0x00,0x00, 0x43 0x00,0x00, 0x43 0x00,0x00
数组类型的编码
-tag 第6位为 1 Constructed
- length 编码成为 UINT ,16位无符号数
- 数组的第一个元素带有tag (COMPACT Encoding),后面的元素缺省了tag
例如 LREAL[2] 的编码为
tag = 0x76=011 10110 其中
class=01,P/Constructed =1 ,tag number=22=10110
length=x0002
contents=8 octetX2
第一个元素(LREAL)的tag为
tag=01001011=0x4b 其中 class =01 /Construct=0,tag number=11=0x0b=01011
0x4b 是LREAL 类型。后面是两个LREAL,每个64位,8 个字节)。
最后的编码为
0x76,0x00,0x02,0x4b,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00 ,0x00,0x00,0x00,0x00
程序实例
使用这个简单软件,可以显示出Client 功能块发送的ASN.1 编码的FBDATA
package main
import (
"fmt"
"net"
"os"
)
func main() {
arguments := os.Args
if len(arguments) == 1 {
fmt.Println("Please provide a port number!")
return
}
PORT := ":" + arguments[1]
s, err := net.ResolveUDPAddr("udp4", PORT)
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
if err != nil {
fmt.Println(err)
return
}
defer connection.Close()
buffer := make([]byte, 1024)
serveraddr, _ := net.ResolveUDPAddr("udp", "192.168.31.108:8881")
client, _ := net.DialUDP("udp4", nil, serveraddr)
for {
// n, addr, err := connection.ReadFromUDP(buffer)
n, _, _ := connection.ReadFromUDP(buffer)
txbuf := make([]byte, n)
for i:=0;i<n;i++ {
fmt.Printf("0x%02x ",buffer[i])
txbuf[i]=buffer[i]
}
fmt.Printf("length=%d\n",n)
_, err := client.Write(txbuf)
if err != nil {
fmt.Println(err)
return
}
}
}
相信我将IEC61499 标准的FBDATA ASN.1 编解码解释清楚了。没有去大幅介绍ASN.1 的抽象概念。当然,为了写清楚这些,我还特意化了点小钱,下载了ISO8825-1 2008 版标准。
写博客,深入简出非常重要。