ASTM checksum calculation - c#

I need to understand how device is calculating checksum for below ASTM string
<STX2P|1|||||||||||||||||||||||||||||||||<CR><ETX>3B<CR><LF>
This string shows that the checksum is "3B", while I am trying to find checksum through below code
public static string ConvertStringToHex(string asciiString)
{
string hex = "";
foreach (char c in asciiString)
{
int tmp = c;
hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
}
return hex;
}
But I am getting "3C" as output. Please help me out how could I find checksum.

How to compute the Checksum in ASTM...
The checksum is computed by adding the binary values of the characters,
keeping the least significant eight bits of the result.
Each character in the message text is added to the checksum (modulo 256).
The checksum is an integer represented by eight bits, it can be considered as two groups of four bits.
The groups of four bits are converted to the ASCII characters of the hexadecimal representation.
The two ASCII characters are transmitted as the checksum, with the most significant character first.
I put the line in the file 3B and ran the script which I'll post below this section. I had to add the > sign to fix the STX String.
leopard:astm rene$ ./astm.sh ./3B Starting ./astm.sh ...
2P|1|||||||||||||||||||||||||||||||||3B
1000100111011 L8B= 111011
LSB used to calculate the MOD 256 L8B
MOD= 00111011
and the checksum is.......
MOD= 00111011 M4B= 0011
--->L4B= 1011
Checksum=3B
#! /bin/ksh
#set -x
#
############################# Variables #######################
#
integer i=0
HEX=00
integer LEN=0
integer FROM=0
MESSAGE=$1
#blind=0 Not blind
#blind=1 blind, it does not see any astm character till it can see again (blind=0)
HEXTMP=/tmp/hex.tmp
BINTMP=/tmp/bin.tmp
#
############################# Functions #######################
#
astm_checksum() {
print"
# The checksum is computed by adding the binary values of the characters,
# keeping the least significant eight bits of the result.
# Each character in the message text is added to the checksum (modulo 256).
# The checksum is an integer represented by eight bits, it can be considered as two groups of four bits.
# The groups of four bits are converted to the ASCII characters of the hexadecimal representation.
# The two ASCII characters are transmitted as the checksum, with the most significant character first.
"
#converting text in Variable VAR to binairy ...
}
code2hex() { #Read and convert text written with codes in ASCII like <STX>
printf "\n\n"
awk '
!/^#/ {
gsub(/<NUL>/,"\x00",$0 )
gsub(/<SOH>/,"\x01",$0 )
gsub(/<STX>/,"\x02",$0 )
gsub(/<ETX>/,"\x03",$0 )
gsub(/<EOT>/,"\x04",$0 )
gsub(/<ENQ>/,"\x05",$0 )
gsub(/<ACK>/,"\x06",$0 )
gsub( /<LF>/,"\x0A",$0 )
gsub( /<FF>/,"\x0C",$0 )
gsub( /<CR>/,"\x0D",$0 )
gsub(/<NAK>/,"\x15",$0 )
gsub(/<SYN>/,"\x16",$0 )
gsub(/<ETB>/,"\x17",$0 )
gsub(/<CAN>/,"\x18",$0 )
gsub(/<ESC>/,"\x1B",$0 )
printf( $0 "\n" )
}
' ${MESSAGE} | hd | cut -c11-58 | tr [:lower:] [:upper:] | xargs | tee ${HEXTMP} | awk '
#example output, one line due to xargs
#02 31 48 7C 5C 5E 26 7C 7C 7C 50 5E 31 7C 7C 7C 7C 7C 7C 7C 50 7C 31 7C 0D 03 31 35 0D 0A
#--- first part to filter out control data from real data ---
BEGIN{ RS=" "; blind = 0 ; printf "ibase=16 ; obase=2 ;scale=0;" }
/0A/ { next } # <LF>
/02/ { printf("00+"); blind = 0 # <STX>
} #Eyes are opened (again), after <STX> we start counting
!/02/ && !/03/ { if ( blind == 0 )
printf( $0"+" )
} #This also includes the <CR> (0D) BEFORE the ETX or ETB!!!
/03/ || /17/ { if ( blind == 0 ) {
printf( $0"\n" )
blind = 1 } #The \n = end line and calculate
} #Blind.. we see nothing till a <STX> is passing again
'| sed 's/+$/\n/p' | tee -a ${HEXTMP} | bc -q | tee ${BINTMP} | while read BIN
do
# The two files tee writes to is for debugging only.
#
# % in bc is modulo but is not described clearly in the man page
# scale is default set to 0 but I set it anyway to be sure.
#
#Binairy
printf "BIN= %08d\n" ${BIN}
#Calculate from where we need to cut the string of bits to have the LSB 8 bits
LEN=$(echo ${BIN} | wc -c ) #Not supported by the QNX Shell
FROM=$(( LEN - 8 )) #Not supported by the QNX Shell
L8B=$(echo ${BIN} | cut -c ${FROM}- )
printf "L8B=%${LEN}d\n" ${L8B}
printf "LSB used to calculate the MOD 256\n"
MOD=$( echo "ibase=2 ; obase=2 ; ${L8B} % 100000000" | bc -q ) #LSB SUM
printf "L8B MOD= %08d\n" ${MOD}
printf "--------------------------- and the checksum is....... \n"
printf "MOD= %08d\n" ${MOD}
M4B=$( printf "%08d\n" ${MOD} | cut -c -4 )
L4B=$( printf "%08d\n" ${MOD} | cut -c 5- )
printf "M4B= $M4B\n--->L4B= $L4B\n"
CD1=$(printf "ibase=2 ; obase=10000 ; ${M4B}\n" | bc -q )
CD2=$(printf "ibase=2 ; obase=10000 ; ${L4B}\n" | bc -q )
printf "Checksum=${CD1}${CD2}\n\n"
done
}
############################# main part ################################
test -r "${MESSAGE}" && (echo "Starting $0 ...";cat ${MESSAGE};code2hex) || echo "ERROR: Cannot read file ${MESSAGE}."

Check this link: https://www.hendricksongroup.com/code_003.aspx
It explains well. Make sure, you use the load-data after STX and including ETX.
E.g. in the line belof:
<STX><Frame Data><CR><ETX><CHECKSUM 1><CHECKSUM 2><CR><LF>
use this part of the data used to calculate the MOD 256 checksum
<Frame Data><CR><ETX>
(sum all load chars and modulo by 256)
EDIT
There are few websites, where you can calculate mod 256 (among others) check sums. e.g.: https://www.scadacore.com/tools/programming-calculators/online-checksum-calculator/
Let's take the string used in the question as the example:
<STX2P|1|||||||||||||||||||||||||||||||||<CR><ETX>3B<CR><LF>
As the string is not correct, there is no closing > after STX, w correct it, though it is not relevant for the checksum calculation.
<STX>2P|1|||||||||||||||||||||||||||||||||<CR><ETX>3B<CR><LF>
Now, the checksum in ASTM 1381 uses the data after and till the checksum including , this part:
P|1|||||||||||||||||||||||||||||||||<CR><ETX>
Let's go to the site and paste the string in the "ASCII Input" text field. As the are replacement for binary data, which can't be displayed as ASCII text, REMOVE <CR><ETX> and press the button AnalyseDataAscii. You will see below calculated chechsum which is wrong as the data is missing <CR><ETX>. Ignore the checksum for the first.
The Hex-Input text field is also updated and displays binary data in the HEX-notation. So add the data for <CR><ETX> at the end of the hex-string in the HEX Input. In Hex CR is 0D and ETX is 03, so add 0D03 and press now the other button AnalyseDataHex:
Now you see the correct checksum, which is indeed 3B, exactly as in the message example.
Obviously the code provided by the question author used not correct part of the string and did't replace the placeholders , by their hexadecimal representations.

Related

parse hex incoming / create outgoing strings

I've modified an example to send & receive from serial, and that works fine.
The device I'm connecting to has three commands I need to work with.
My experience is with C.
MAP - returns a list of field_names, (decimal) values & (hex) addresses
I can keep track of which values are returned as decimal or hex.
Each line is terminated with CR
:: Example:
MEMBERS:10 - number of (decimal) member names
NAME_LENGTH:15 - (decimal) length of each name string
NAME_BASE:0A34 - 10 c-strings of (15) characters each starting at address (0x0A34) (may have junk following each null terminator)
etc.
GET hexaddr hexbytecount - returns a list of 2-char hex values starting from (hexaddr).
The returned bytes are a mix of bytes/ints/longs, and null terminated c-strings terminated with CR
:: Example::
get 0a34 10 -- will return
0A34< 54 65 73 74 20 4D 65 20 4F 75 74 00 40 D3 23 0B
This happens to be 'Test Me Out'(00) followed by junk
etc.
PUT hexaddr hexbytevalue {{value...} {value...}} sends multiple hex byte values separated by spaces starting at hex address, terminated by CR/LF
These bytes are a mix of bytes/ints/longs, and null terminated c-strings :: Example:
put 0a34 50 75 73 68 - (ascii Push)
Will replace the first 4-chars at 0x0A34 to become 'Push Me Out'
SAVED OK
See my answer previously about serial handling, which might be useful Serial Port Polling and Data handling
to convert your response to actual text :-
var s = "0A34 < 54 65 73 74 20 4D 65 20 4F 75 74 00 40 D3 23 0B";
var hex = s.Substring(s.IndexOf("<") + 1).Trim().Split(new char[] {' '});
var numbers = hex.Select(h => Convert.ToInt32(h, 16)).ToList();
var toText = String.Join("",numbers.TakeWhile(n => n!=0)
.Select(n => Char.ConvertFromUtf32(n)).ToArray());
Console.WriteLine(toText);
which :-
skips through the string till after the < character, then splits the rest into hex string
then, converts each hex string into ints ( base 16 )
then, takes each number till it finds a 0 and converts each number to text (using UTF32 encoding)
then, we join all the converted strings together to recreate the original text
alternatively, more condensed
var hex = s.Substring(s.IndexOf("<") + 1).Trim().Split(new char[] {' '});
var bytes = hex.Select(h => (byte) Convert.ToInt32(h, 16)).TakeWhile(n => n != 0);
var toText = Encoding.ASCII.GetString(bytes.ToArray());
for converting to hex from a number :-
Console.WriteLine(123.ToString("X"));
Console.WriteLine(123.ToString("X4"));
Console.WriteLine(123.ToString("X8"));
Console.WriteLine(123.ToString("x4"));
also you will find playing with hex data is well documented at https://msdn.microsoft.com/en-us/library/bb311038.aspx

How to filter hidden characters in a String using C#

I am new to C# and trying to lean how to filter data that I read from a file. I have a file that I read from that has data similer to the follwoing:
3 286 858 95.333 0.406 0.427 87.00 348 366 4 b
9 23 207 2.556 0.300 1.00 1.51 62 207 41 a
9 37 333 4.111 0.390 0.811 2.03 130 270 64 a
10 21 210 2.100 0.348 0.757 3.17 73 159 23 a
9 79 711 8.778 0.343 0.899 2.20 244 639 111 a
10 66 660 6.600 0.324 0.780 2.25 214 515 95 a
When I read these data, some of them have Carriage return Or Line Feed characters hidden in them. Can you please tell me if there is a way to remove them. For example, one of my variable may hold the the following value due to a newline character in them:
mystringval = "9
"
I want this mystringval variable to be converted back to
mystringval = "9"
If you want to get rid of all special characters, you can learn regular expressions and use Regex.Replace.
var value = "&*^)#abcd.";
var filtered = System.Text.RegularExpressions.Regex.Replace(value, #"[^\w]", "");
REGEXPLANATION
the # before the string means that you're using a literal string and c# escape sequences don't work, leaving only the regex escape sequences
[^abc] matches all characters that are not a, b, or c(to replace them with empty space)
\w is a special regex code that means a letter, number, or underscore
you can also use #"[^A-Za-z0-9\.]" which will filter letters, numbers and decimal. See http://rubular.com/ for more details.
As well as using RegEx, you can use LINQ to do something like
var goodCharacters = input
.Replace("\r", " ")
.Replace("\n", " ")
.Where(c => char.IsLetterOrDigit(c) || c == ' ' || c == '.')
.ToArray();
var result = new string(goodCharacters).Trim();
The first two Replace calls will guard against having a number at the end of one line and a number at the start of the next, e.g. "123\r\n987" would otherwise be "123987", whereas I assume you want "123 987".
Try my sample here on ideone.com.

remove 4 byte UTF8 characters

I'd like to remove 4 byte UTF8 characters which starts with \xF0 (the char with the ASCII code 0xF0) from a string and tried
sText = Regex.Replace (sText, "\xF0...", "");
This doesn't work. Using two backslashes did not work neither.
The exact input is the content of https://de.wikipedia.org/w/index.php?title=Spezial:Exportieren&action=submit&pages=Unicode The 4 byte character ist the one after the text "[[Violinschlüssel]] ", in hex notation: .. 0x65 0x6c 0x5d 0x5d 0x20 0xf0 0x9d 0x84 0x9e 0x20 .. The expected output is 0x65 0x6c 0x5d 0x5d 0x20 0x20 ..
What's wrong?
Such characters will be surrogate pairs in .NET which uses UTF-16. Each of them will be two UTF-16 code units, that is two char values.
To just remove them, you can do (using System.Linq;):
sText = string.Concat(sText.Where(x => !char.IsSurrogate(x)));
(uses an overload of Concat introduced in .NET 4.0 (Visual Studio 2010)).
Late addition: It may give better performance to use:
sText = new string(sText.Where(x => !char.IsSurrogate(x)).ToArray());
even if it looks worse. (Works in .NET 3.5 (Visual Studio 2008).)
You are trying to search for byte values but C# strings are made from char values. The C# language spec at section "2.4.4.4 Character literals" states:
A character literal represents a single character, and usually consists of a character in quotes, as in 'a'.
...
A hexadecimal escape sequence represents a single Unicode character, with the value formed by the hexadecimal number following \x.
Hence the search for "\xF0..." is searching for the character U+F0 which would be represented by the bytes C3 B0.
If you want find replace all Unicode characters whose first byte is 0xF0 then I believe you need to search for the character values whose first byte if 0xFO.
The character U+10000 is represented as F0 90 80 80 (the preceding code is U+FFFF which is EF BF BF). The first code with F1 .... .. is U+40000 which is F1 80 80 80 and the value before it is U+3FFFF which is F0 BF BF BF.
Hence you need to remove characters in the range U+10000 to U+3FFFF. This should be possible with a regular expression such as
sText = Regex.Replace (sText, "[\\x10000-\\x3FFFF]", "");
The relevant characters from the source quoted in the question have been extracted into the code below. The code then tries to understand how the characters are held in strings.
static void Main(string[] args)
{
string input = "] 𝄞 (";
Console.Write("Input length {0} : '{1}' : ", input.Length, input);
foreach (char cc in input)
{
Console.Write(" {0,2:X02}", (int)cc);
}
Console.WriteLine();
}
The output from the program is as below. This supports the surrogate pair explanation given by #Jeppe in his answer.
Input length 6 : '] ?? (' : 5D 20 D834 DD1E 20 28

Percentage Regex with comma

I have this RegEx for C# ASP.NET MVC3 Model validation:
[RegularExpression(#"[0-9]*\,?[0-9]?[0-9]")]
This works for almost all cases, except if the number is bigger than 100.
Any number greater than 100 should show error.
I already tried use [Range], but it doesn't work with commas.
Valid: 0 / 0,0 / 0,00 - 100 / 100,0 / 100,00.
Invalid (Number > 100).
Not sure if zero's are only optional digits at the end but
# (?:100(?:,0{1,2})?|[0-9]{1,2}(?:,[0-9]{1,2})?)
(?:
100
(?: , 0{1,2} )?
|
[0-9]{1,2}
(?: , [0-9]{1,2} )?
)
Zero's only option at end
# (?:100|[0-9]{1,2})(?:,0{1,2})?
(?:
100
| [0-9]{1,2}
)
(?: , 0{1,2} )?
And, the permutations for no leading zero's except for zero itself
# (?:100(?:,0{1,2})?|(?:0|[1-9][0-9]?)(?:,[0-9]{1,2})?)
(?:
100
(?: , 0{1,2} )?
|
(?:
0
|
[1-9] [0-9]?
)
(?: , [0-9]{1,2} )?
)
# (?:100|0|[1-9][0-9])(?:,0{1,2})?
(?:
100
|
0
|
[1-9] [0-9]
)
(?: , 0{1,2} )?
Here's a RegEx that matches your criteria:
^(?:(?:[0-9]|[1-9]{1,2})(?:,[0-9]{1,2})?|(?:100)(?:,0{1,2})?)$
(Given your use case, I have assumed that your character sequence appears by itself and is not embedded within other content. Please let me know if that is not the case.)
And here's a Perl program that demonstrates that RegEx on a sample data set. (Also see live demo.)
#!/usr/bin/env perl
use strict;
use warnings;
while (<DATA>) {
chomp;
# A1 => An integer between 1 and 99, without leading zeros.
# (Although zero can appear by itself.)
#
# A2 => A optional fractional component that may contain no more
# than two digits.
#
# -OR-
#
# B1 => The integer 100.
#
# B2 => A optional fractional component following that may
# consist of one or two zeros only.
#
if (/^(?:(?:[0-9]|[1-9]{1,2})(?:,[0-9]{1,2})?|(?:100)(?:,0{1,2})?)$/) {
# ^^^^^^^^A1^^^^^^ ^^^^^A2^^^^ ^B1 ^^^B2^^
print "* [$_]\n";
} else {
print " [$_]\n";
}
}
__DATA__
0
01
11
99
100
101
0,0
0,00
01,00
0,000
99,00
99,99
100,0
100,00
100,000
100,01
100,99
101,00
Expected Output
* [0]
[01]
* [11]
* [99]
* [100]
[101]
* [0,0]
* [0,00]
[01,00]
[0,000]
* [99,00]
* [99,99]
* [100,0]
* [100,00]
[100,000]
[100,01]
[100,99]
[101,00]

adding 48 to string number

I have a string in C# like this:
string only_number;
I assigned it a value = 40
When I check only_number[0], I get 52
When I check only_number[1], I get 48
why it is adding 48 to a character at current position? Please suggest
String is basically char[]. So what you are seeing is ASCII value of char 4 and 0.
Proof: Diff between 4 and 0 = Diff between 52 and 48.
Since it is a string so you didn't assigned it 40. Instead you assigned it "40".
What you see is the ASCII code of '4' and '0'.
It's not adding 48 to the character. What you see is the character code, and the characters for digits start at 48 in Unicode:
'0' = 48
'1' = 49
'2' = 50
'3' = 51
'4' = 52
'5' = 53
'6' = 54
'7' = 55
'8' = 56
'9' = 57
A string is a range of char values, and each char value is a 16 bit integer basically representing a code point in the Unicode character set.
When you read from only_number[0] you get a char value that is '4', and the character code for that is 52. So, what you have done is reading a character from the string, and then converted that to an integer before you display it.
So:
char c = only_number[0];
Console.WriteLine(c); // displays 4
int n = (int)only_number[0]; // cast to integer
Console.WriteLine(n); // displays 52
int m = only_number[0]; // the cast is not needed, but the value is cast anyway
Console.WriteLine(m); // displays 52
You are accessing this string and it is outputting the ASCII character codes for each of your two characters, '4' and '0' - please see here:
http://www.theasciicode.com.ar/ascii-control-characters/null-character-ascii-code-0.html
string is the array of chars, so, that;s why you recieved these results, it basicallly display the ASCII of '4' and '0'.

Categories

Resources