C语言CRC-16 DNP格式校验函数

2023-11-23 00:11

本文主要是介绍C语言CRC-16 DNP格式校验函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C语言CRC-16 DNP格式校验函数

CRC-16校验产生2个字节长度的数据校验码,通过计算得到的校验码和获得的校验码比较,用于验证获得的数据的正确性。基本的CRC-16校验算法实现,参考: C语言标准CRC-16校验函数。

不同应用规范通过对输入数据前处理和输出数据后处理的方式不同,又产生了不同的应用规范校验函数,这里介绍DNP格式的CRC-16校验函数。DNP格式对输入数据,按照单个字节进行位反序。对于输出的校验码,进行整体位反序, 然后异或0xFFFF。

生成多项式为x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1

正向算法

正向算法是符合标准CRC-16的计算理论,从左向右计算,也即计算过程中移位时,向左移出。几种正向算法的实现如下:

CRC-16 DNP格式校验函数一(8位输入数据格式,64位装载计算):

#include <stdio.h>
#include <stdlib.h>
uint16_t PY_CRC_16_DNP(uint8_t *di, uint32_t len)
{uint32_t crc_poly = 0x00013D65;  //x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1 total 17 effective bits. Computed total data shall be compensated 16-bit '0' before CRC computing.uint8_t *datain;uint64_t cdata = 0; //Computed total datauint32_t data_t = 0; //Process data of CRC computinguint16_t index_t = 63;  ///bit shifting index for initial '1' searchinguint16_t index = 63;    //bit shifting index for CRC computinguint8_t rec = 0; //bit number needed to be compensated for next CRC computinguint32_t cn=(len+2)/6;uint32_t cr=(len+2)%6;uint32_t j;datain = malloc(len+2);for(j=0;j<len;j++){datain[j] = 0;for(uint8_t m=0; m<=7; m++){datain[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;}}datain[len] = 0; datain[len+1] = 0;//Compensate 16-bit '0' for input dataif(len<=6)   //Mount data for only one segment{for(j=0;j<=(len+1);j++){cdata = (cdata<<8);cdata = cdata|datain[j];}cn = 1;}else{if(cr==0){cr = 6;}else if(cr==1){cr = 7;}else if(cr==2){cr = 8;}else{cn++;}for(j=0;j<cr;j++){cdata = (cdata<<8);cdata = cdata|datain[j];}}do{cn--;while(index_t>0){if( (cdata>>index_t)&1 ){index = index_t;index_t = 0;data_t |= (cdata>>(index-16));{data_t = data_t ^ crc_poly;}while((index!=0x5555)&&(index!=0xaaaa)){for(uint8_t n=1;n<17;n++){if ((data_t>>(16-n))&1) {rec = n;break;}if (n==16) rec=17;}if((index-16)<rec){data_t = data_t<<(index-16);data_t |=  (uint32_t)((cdata<<(64-(index-16)))>>(64-(index-16)));index = 0x5555;}else{for(uint8_t i=1;i<=rec;i++){data_t = (data_t<<1)|((cdata>>(index-16-i))&1) ;}if(rec!= 17){data_t = data_t ^ crc_poly;index -= rec;}else{data_t = 0;index_t = index-16-1;index = 0xaaaa;}}}if(index==0x5555) break;}else{index_t--;if(index_t<16) break;}}if(cn>0) //next segment{cdata = data_t&0x00ffff;for(uint8_t k=0;k<6;k++){cdata = (cdata<<8);cdata = cdata|datain[j++];}data_t = 0;index_t = 63;  ///bit shifting index for initial '1' searchingindex = 63;    //bit shifting index for CRC computingrec = 0; //bit number needed to be compensated for next CRC computing}}while(cn>0);free(datain);uint16_t i_data_t = 0;for(uint8_t n=0; n<=15; n++){i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;}return i_data_t ^ 0xFFFF;
}

CRC-16 DNP格式校验函数二(8位输入数据格式):

uint16_t PY_CRC_16_S_DNP(uint8_t *di, uint32_t len)
{uint16_t crc_poly = 0x3D65;  //x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1 total 16 effective bits without X^16. Computed total data shall be compensated 16-bit '0' before CRC computing.uint32_t clen = len+2;uint8_t cdata[clen] ;for(uint32_t j=0;j<len;j++){cdata[j] = 0;for(uint8_t m=0; m<=7; m++){cdata[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;}}cdata[len]=0; cdata[len+1]=0;uint16_t data_t = (((uint16_t)cdata[0]) << 8) + cdata[1]; //CRC registerfor (uint32_t i = 2; i < clen; i++){for (uint8_t j = 0; j <= 7; j++){if(data_t&0x8000)data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ^ crc_poly;elsedata_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ;}}uint16_t i_data_t = 0;for(uint8_t n=0; n<=15; n++){i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;}return i_data_t ^ 0xFFFF;
}

CRC-16 DNP格式校验函数三(16位输入数据格式):

uint16_t PY_CRC_16_T16_DNP(uint16_t *di, uint32_t len)
{uint16_t crc_poly = 0x3D65;  //x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1 total 16 effective bits without X^16. uint16_t data_t = 0; //CRC registeruint16_t cdata[len];for(uint32_t j=0;j<len;j++){cdata[j] = 0;for(uint8_t m=0; m<=7; m++){cdata[j] |= ( ( ( (di[j]>>8)>>(7-m) ) & 1 ) << m ) | ( ( ( ( (di[j]&0x00ff)>>(7-m) ) & 1 ) << m ) <<8 );}}for(uint32_t i = 0; i < len; i++){data_t ^= cdata[i]; //16-bit datafor (uint8_t j = 0; j < 16; j++){if (data_t & 0x8000)data_t = (data_t << 1) ^ crc_poly;elsedata_t <<= 1;}}uint16_t i_data_t = 0;for(uint8_t n=0; n<=15; n++){i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;}return i_data_t ^ 0xFFFF;
}

CRC-16 DNP格式校验函数四(8位输入数据格式):

uint16_t PY_CRC_16_T8_DNP(uint8_t *di, uint32_t len)
{uint16_t crc_poly = 0x3D65;  //x^16 + x^13 + x^12 + x^11 + x^10 + x^8 + x^6 + x^5 + x^2 + 1 total 16 effective bits without X^16. uint16_t data_t = 0; //CRC registeruint8_t cdata[len];for(uint32_t j=0;j<len;j++){cdata[j] = 0;for(uint8_t m=0; m<=7; m++){cdata[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;}}for(uint32_t i = 0; i < len; i++){data_t ^= cdata[i]<<8; //8-bit datafor (uint8_t j = 0; j < 8; j++){if (data_t & 0x8000)data_t = (data_t << 1) ^ crc_poly;elsedata_t <<= 1;}}uint16_t i_data_t = 0;for(uint8_t n=0; n<=15; n++){i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;}return i_data_t ^ 0xFFFF;
}

反向算法

反向算法是从由右向左计算,也即计算过程中移位时,向右移出。而计算过程中的输入数据高优先计算位和校验参数的对齐关系不变。因此把一个字节放在CRC计算寄存器的最低字节时,对于DNP格式,最右侧最低位实际上是高优先计算位,而校验参数要相应倒序,从而计算位置对照关系不变。

CRC-16 DNP格式校验函数五(反向算法,8位输入数据格式):

uint16_t PY_CRC_16_T8_DNP_i(uint8_t *di, uint32_t len)
{uint16_t crc_poly = 0xA6BC; //Bit sequence inversion of 0x3D65uint16_t data_t = 0; //CRC registerfor(uint32_t i = 0; i < len; i++){data_t ^= di[i]; //8-bit datafor (uint8_t j = 0; j < 8; j++){if (data_t & 0x0001)data_t = (data_t >> 1) ^ crc_poly;elsedata_t >>= 1;}}return data_t ^ 0xFFFF;
}

算法验证

5种算法结果相同:
在这里插入图片描述

通过在线CRC工具对照验证成功:
在这里插入图片描述

–End–

这篇关于C语言CRC-16 DNP格式校验函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/413920

相关文章

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

C#实现将Office文档(Word/Excel/PDF/PPT)转为Markdown格式

《C#实现将Office文档(Word/Excel/PDF/PPT)转为Markdown格式》Markdown凭借简洁的语法、优良的可读性,以及对版本控制系统的高度兼容性,逐渐成为最受欢迎的文档格式... 目录为什么要将文档转换为 Markdown 格式使用工具将 Word 文档转换为 Markdown(.

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以