簡體   English   中英

二進制PLC通信的校驗和

[英]Checksum for binary PLC communication

我一直在努力計算使用二進制命令與Unitronics PLC通信的校驗和。 他們提供了源代碼,但是它是在僅Windows的C#實現中進行的,除了基本語法之外,對我幾乎沒有幫助。

規格PDF (校驗和計算即將結束)

C#驅動程序源 (Utils.cs中的校驗和計算)

預期結果

以下是字節索引,消息描述和起作用的示例。

#  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 24 25 26 27 28 29 | 30 31 32
# sx--------------- id FE 01 00 00 00 cn 00 specific--------- lengt CHKSM | numbr ot FF addr- | CHKSM ex
# 2F 5F 4F 50 4C 43 00 FE 01 00 00 00 4D 00 00 00 00 00 01 00 06 00 F1 FC | 01 00 01 FF 01 00 | FE FE 5C

該規范要求計算22字節消息頭的累加值,以及分別計算6+字節細節的累加值,得到和模65536的值,然后返回該值的二進制補碼。

嘗試#1

我的理解是Python中的波浪號(〜)運算符直接來自C / C ++。 在寫了一天創建消息的Python之后,我想到了這個(精簡版):

#!/usr/bin/env python

def Checksum( s ):
    x = ( int( s, 16 ) ) % 0x10000
    x = ( ~x ) + 1 
    return hex( x ).split( 'x' )[1].zfill( 4 )

Details = ''
Footer  = ''
Header  = ''
Message = ''

Details += '0x010001FF0100'

Header += '0x2F5F4F504C4300FE010000004D000000000001000600'
Header += Checksum( Header )

Footer += Checksum( Details )
Footer += '5C'

Message +=  Header.split( 'x' )[1].zfill( 4 )
Message += Details.split( 'x' )[1].zfill( 4 )
Message +=  Footer

print Message

訊息: 2F5F4F504C4300FE010000004D000000000001000600600L010001FF010001005C

我在那兒看到了L,這與昨天的結果是不同的,直到今天為止。 如果您需要基於消息其余部分的快速公式結果: Checksum(Header)應該返回F1FC,而Checksum(Details)應該返回FEFE

它返回的值與規范的示例幾乎沒有相同。 我認為,問題可能是一個或兩件事情:校驗方法不正確計算十六進制字符串的總和或Python的~運營商是不是等同於C ++ ~運營商。

嘗試#2

一位朋友給了我有關計算的C ++解釋,我只是無法理解這段代碼,我的C ++知識很少。

short PlcBinarySpec::CalcHeaderChecksum( std::vector<byte>  _header ) {
    short bytesum = 0;
    for ( std::vector<byte>::iterator it = _header.begin(); it != _header.end(); ++it ) {
        bytesum = bytesum + ( *it );
    }
    return ( ~( bytesum % 0x10000 ) ) + 1;
}

我不確定要正確的代碼是什么……但是如果要讓Checksum(Header)返回f705,而返回的是08fb,那就是問題所在:

x = ( ~( x % 0x10000 ) ) + 1

簡短的版本是您想要的:

x = (( ~( x % 0x10000 ) ) + 1) % 0x10000

這里的問題不是~意味着不同。 由於文檔說, ~x回報“的位x倒”,這實際上是它意味着在C同樣的事情(至少在二進制補碼平台,其中包括所有Windows平台)。

您可能會遇到C和Python類型之間的差異的問題(C整數類型是固定大小且有溢出; Python整數類型實際上是無窮大,並根據需要增長)。 但我認為這不是您的問題。

問題僅在於如何將結果轉換為字符串。

在兩個版本中,調用Checksum(Header)的結果Checksum(Header)直至格式)均為-2299或-0x08fb。

在C語言中,您幾乎可以將帶符號整數視為相同大小的無符號整數(盡管在某些情況下,您可能不得不忽略警告)。 確切的功能取決於您的平台,但在2s補碼平台上,帶符號的短-0x08fb與無符號的0xf705逐位等效。 因此,例如,如果您執行sprintf(buf, "%04hx", -0x08fb) ,它就可以正常工作-並且(在大多數平台上,包括所有Windows上)為您提供無符號的等效值f705

但是在Python中,沒有無符號整數。 int -0x08fb與0xf705無關。 如果您執行"%04hx" % -0x08fb ,您將得到-8fb ,並且無法強制“將其強制轉換為未簽名”或類似的東西。

您的代碼實際上執行hex(-0x08fb) ,給您-0x8fb ,然后在xsplit ,給您8fb ,您將其zfill08fb ,這使問題更難注意到(因為看起來很完美)有效的十六進制字節對,而不是減號和三個十六進制數字),但這是相同的問題。

無論如何,您必須明確確定“無符號等效項”的含義,並編寫代碼來做到這一點。 由於您試圖匹配C在2s補碼平台上的功能,因此可以將該顯式轉換寫為% 0x10000 如果執行"%04hx" % (-0x08fb % 0x10000)f705得到f705 ,就像在C中所做的一樣。對於現有代碼也是如此。

這很簡單。 我通過在計算器上手動添加所有標頭字節來檢查您朋友的算法,它產生正確的結果( 0xfcf1 )。

現在,我實際上並不了解python,但是在我看來,這就像您要添加半字節值一樣。 您已使標題字符串如下所示:

Header = '2F5F4F504C4300FE010000004D000000000001000600'

然后,您將十六進制轉換為字符串中的每個字節並將其相加。 這意味着您正在處理0到15之間的值。您需要將每兩個字節視為一對,並將其轉換(值從0到255)。 或者,您需要使用實際的二進制數據而不是二進制數據的文本表示形式。

在算法的最后,如果您不信任它,則實際上不需要執行~運算符。 相反,您可以執行(0xffff - (x % 0x10000)) + 1 請記住,在加1之前,該值實際上可能是0xffff ,因此此后需要對整個結果乘以0x10000 您朋友的C ++版本使用short數據類型,因此根本不需要模,因為short會自然溢出

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM