/MEng/System/CQC/Runtime/CRCHelpers

ClassPath:MEng.System.CQC.Runtime.CRCHelpers
Parent ClassPath:MEng.Object
Copyable:No
Final:Yes

MEng.System.CQC.Runtime.CRCHelpers provides some helper methods for doing common CRC and checksum operations. These operations are very common in communications protocols, so they will often be needed in CQC device drivers. CML, though not horrendously inefficient, is not currently an optimizing compiler and can be a little piggy when it comes to CRCs for messages of non-trivial size, because they often do a per-byte loop, so the CRC inner loop can be 4 or 8 or 16 or more times the number of bytes in the message. This makes them sometimes fairly compute intensive. 

This class provides some commonly used CRC and checksum algorithms as CML wrapped C++ code, so they will be significantly more efficient than the CML version. CQC tries to be fairly sensitive to CPU usage, so as to comfortably coexist on smaller systems which are being used for other things. So though the overhead of doing a CRC in CML is not a huge problem, the common use of them makes it worth providing these optimized helpers.

If you have a CRC algorithm that isn't supported here, feel free to contact us and we can add it if that is warranted.

 

Constructors:

Constructor();

There is just a default constructor available.

 

Final, Const Methods:

CheckSum1([In] MemBuf SrcBuf, [In] Card4 Start, [In] Card4 End) Returns Card1;
CheckSum2([In] MemBuf SrcBuf, [In] Card4 Start, [In] Card4 End) Returns Card2;
CheckSum4([In] MemBuf SrcBuf, [In] Card4 Start, [In] Card4 End) Returns Card4;

These methods calculate a checksum on the passed source memory buffer object, starting at the Start index and ending at the End index, inclusive. There are versions to calculate the checksum into a Card1, Card2, or Card4 value, with overflow being discarded, so it is the checksum modulo 0xFF, 0xFFFF, and 0xFFFFFFFF, respectively.

CRC1Full
(
    [In] MemBuf SrcBuf
    , [In] Card4 Start
    , [In] Card4 End
    , [In] Card2 Polynomial
    , [In] Card4 LoopCount
);
CRC1InnerLoop
(
    In] Card2 CRCVal, [In] Card2 Polynomial, [In] Card4 LoopCount
);
CRC1PerByte(In] Card2 CRCVal, [In] Card2 Polynomial);

These methods do a calculation of a fairly common 16 bit (Card2) CRC algorithm. In order to make it as useful as possible, the full algorithm, the inner loop, and per-byte calculation are provided, so that you can still use parts of the algorithm, even if your required calculation doesn't follow the full standard format.

The CML code for the full algorithm would look like this:

Method CalcCRC([In]   MEng.System.Runtime.MemBuf SrcBuf
               , [In] MEng.Card4  StartInd
               , [In] MEng.Card4  EndInd
               , [In] MEng.Card2  Polynomial
               , [In] MEng.Card4  LoopCount) Returns Card2
Begin
    Locals=
        Card2   CRCVal(0);
        Card4   ByteInd(StartInd);
        Card4   LoopInd;
        Boolean Flag;
    EndLocals;

    While (ByteInd <= EndInd)
        CRCVal ^= TypeCast
        (
            MEng.Card2, SrcBuf.GetCard1At(ByteInd)
        );
        LoopInd := 0;
        While (LoopInd < LoopCount)
            Flag := (CRCVal & 0x1) != 0;
            CRCVal.ShiftRight(1);
            If (Flag)
                CRCVal ^= Polynomial;
            EndIf;
            LoopInd++;
        EndWhile;
        ByteInd++;
    EndWhile;
    Return CRCVal;
EndMethod;

So it loops from the start byte to the end byte, casting each byte to a Card2 value and XORing it with the current CRC value, then does an indicated number of loops on each byte, scrambling the bytes via a standard mask and shift algorithm.

The inner version of course does does the inner while loop of the CRC algorithm, operating on the incoming CRC value and returning a new one, looping for the indicated loop count. So if you need to some outer  loop processing different from the full algorithm, you can still benefit substantially by getting the inner loop out of line.

The per-byte version does the algorithm inside the inner loop, i.e. the test of the 0th bit, the shift, and optional XOR. Even just getting this inner loop out of line can make a difference in performance on a big message.