Calculating the checksum of an ASTM document

Environment: C#, VB, C++ .NET

Using the ASTM protocol to communicate with a laboratory instrument can be an interesting project, and one of the finer points of ASTM is calculating the checksum on transmitted and received documents.  Each segment (row of message) of data includes a checksum when either the laboratory instrument or the LIS (Laboratory Information System) transmits the document.  The benefits are obvious in a mission (life) critical application to ensure what was sent is exactly what is received.

Following is an example of a frame of ASTM data transmitted from a laboratory instrument:

5R|2|^^^1.0000+950+1.0|15|||^5^||V||34001637|20080516153540|20080516153602|34001637\r3D\r\n


The format of an ASTM frame: <STX><Frame Data><CR><ETX><CHECKSUM 1><CHECKSUM 2><CR><LF>

The frame starts with a <STX> character (0x02) and ends with a <ETX> character (0x03), or a <ETB> if a partial frame.  Just prior to the <ETX> is a carriage return \r (no newline character), The C# escape sequences \r and \n are used purely to be able to display the string in a web page, but you will have to replace the  \r  with an ASCII 13 or HEX 0D. In addition the trailing \r\n characters must be replaced with ASCII 13 and ASCII 10 or HEX 0D 0A. That being said you can run the string above through the C# method shown below and the escape sequences will be translated correctly.

All of the characters AFTER the <STX> and up to and including the <ETX> (or <ETB>) character is the data used to calculate the checksum for this message.  The following C# method calculates the checksum by adding the ASCII values of each character in the string and then performing a mod 256 calculation on the total value for all characters in the ASTM frame.  The checksum is then appended to the end of the message, and in this case the value is 3D. Remember the checksum is displayed as a 2 byte HEX string of characters.

Following is the HEX representation of the same ASTM frame with the control and checksum characters noted:
ASTM Binary View

Important: The maximum character limit for a frame in ASTM is 247 characters (including overhead). If a given message is less than 240 characters, it is sent in an end frame with a <ETX>, checksum, and a <CR><LF>. If a message is greater than 240 characters, the message is sent in intermediate frames containing this sequence <ETB>, checksum, and a <CR><LF>.
 
To use this method you must include the following classes in the project
public class T
{
    public const byte ENQ = 5;
    public const byte ACK = 6;
    public const byte NAK = 21;
    public const byte EOT = 4;
    public const byte ETX = 3;
    public const byte ETB = 23;
    public const byte STX = 2;
    public const byte NEWLINE = 10;
    public static byte[] ACK_BUFF = { ACK };
    public static byte[] ENQ_BUFF = { ENQ };
    public static byte[] NAK_BUFF = { NAK };
    public static byte[] EOT_BUFF = { EOT };
}



The class T above defines most of the control characters required to communicate in ASTM protocol. Following is a simple C# method to calculate the checksum of an ASTM frame of data.


/// <summary>
/// Reads checksum of an ASTM frame, calculates characters after STX,
/// up to and including the ETX or ETB. Method assumes the frame contains an ETX or ETB.
/// </summary>
/// <param name="frame">frame of ASTM data to evaluate</param>
/// <returns>string containing checksum</returns>
public string GetCheckSumValue(string frame)
{
    string checksum = "00";

    int byteVal = 0;
    int sumOfChars = 0;
    bool complete = false;
    
    //take each byte in the string and add the values
    for (int idx = 0; idx < frame.Length; idx++)
    {
        byteVal = Convert.ToInt32(frame[idx]);
        
        switch (byteVal)
        {
            case T.STX:
                sumOfChars = 0;
                break;
            case T.ETX:
            case T.ETB:
                sumOfChars += byteVal;
                complete = true;
                break;
            default:
                sumOfChars += byteVal;
                break;
        }

        if (complete)
            break;
    }

    if (sumOfChars > 0)
    {
        //hex value mod 256 is checksum, 
        //return as hex value in upper case
        checksum = Convert.ToString(sumOfChars % 256, 16).ToUpper();
    }
    
    //if checksum is only 1 char then prepend a 0
    return (checksum.Length == 1 ? checksum.PadLeft("0", 2) : checksum);
}