Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

CRC in COBOL 5

Status
Not open for further replies.

FireStarter1

Programmer
Jun 6, 2003
40
US
Hi,
I am doing project that needs CRC calcualation, it is currently done with a C program that runs on Windows platform, I want to do the same on mainframe in cobol. Can anyone please help to convert the following C program.

typedef unsigned char Byte; /* Byte as unsigned char */
typedef unsigned short Word; /* Word as unsigned short */

Word wBuildCrc (Byte *pbBuf, unsigned wLen, Word wCrc)
{
Byte bCh;
Word j;
char i;


bCh=(Byte)(wCrc & 0x00FF);
wCrc=(wCrc>>8) + (unsigned short)bCh*0x100; /* " */


for (j = 0; j < wLen; j ++)
{
bCh = pbBuf[j];
wCrc=wCrc ^ ((unsigned short) bCh <<8);
for (i=0; i<8; i++)
{
if (wCrc & 0x8000)
wCrc = (wCrc << 1) ^ 0x1021;
else
wCrc = wCrc << 1;
}
}

bCh=(Byte)(wCrc & 0x00FF);
wCrc=(wCrc>>8) + (unsigned short)bCh*0x100; /* &quot; */

return(wCrc);
}


Word cdecl uiBuildCrc (Byte *pbBuf, unsigned wLen, Word wCrc)
{
return(wBuildCrc (pbBuf,wLen,wCrc));
}
 
Hi,
I hoped to find some response from someone who know about the Cyclic Redundancy Check.
 
Firestarter1,
I would suggest posting this in a C forum and asking somebody there to give you an English version of what it's doing. Alternatively, have you got a spec for the C language CRC.

Cyclic Redundancy Checks are usually done when sending data from one environment to another and are performed on both machines in order to check that the data has been sent correctly. If you are running the C program on the Windows platform, you will need to ensure that the exactly the same calculation is occurring on the mainframe.

Marc
 
Firestarter,

I started to reply, but I have no mainframe experience.

Can you give us a hint about what you need help with, rather than just a general please write my program for me?

What mainframe COBOL product are you using?


Tom Morrison
 
Hi Tom and Marc,
I am using VS-COBOL-II. Currently the CRC check is done with the C code I have given above. My problem is I really don't know how to translate the following part
if (wCrc & 0x8000)
wCrc = (wCrc << 1) ^ 0x1021;
*** And
bCh=(Byte)(wCrc & 0x00FF);
wCrc=(wCrc>>8) + (unsigned short)bCh*0x100;
***
I believe that it is trying to shift 8 bits to the left from offset 0x00FF and then the rest is a mystery for me.
Tom no offence here, I really did not ask you to write the program for me I asked if you know, please help me to write it. Anyway I believe it hurts no one to help.
Marc I did put this first on the C forum there was only one response you can check it there.
The program I am working on need to be delivered on Friday. This is only part of the program.
Thank you for the responses.
 
Ok...presuming that 'unsigned short' means a 16-bit number (which seems likely given the code...here are some interpretations. Note that this algorithm is probably using Word as a shortcut to manipulate two octets (characters) at a time, which is how to think of it in COBOL.
Code:
^
indicates logical EXCLUSIVE-OR and
Code:
&
indicates logical AND.

Code:
if (wCrc & 0x8000)
    wCrc = (wCrc << 1) ^ 0x1021;

01  wCrc.
    02  wCrc1 pic x.
        88  wCrc1-high-order-bit-on values 0x80 thru 0xff.
    02  xCrc2 pic x.

...
IF wCrc1-high-order-bit-on
    CALL SHIFT-WORD-LEFT using wCrc
    CALL XOR USING wCrc1, 0x10
    CALL XOR USING wCrc2, 0x21
END-IF
where SHIFT-WORD-LEFT and XOR are subroutines which may be implemented by intrinsic functions (remember, I don't know mainframe details).

In English, if the high-order bit of the 16-bit entity wCrc is on, shift wCrc left one bit and then exclusive-or the result with the 16-bit literal 0x1021.
===
Code:
bCh=(Byte)(wCrc & 0x00FF);                  
   wCrc=(wCrc>>8) + (unsigned short)bCh*0x100;

In English, this is swapping the bytes of wCrc. This is easy to do in COBOL! [bigsmile]
====
If your compiler has no intrinsic function for exclusive-or I would suggest implementing it as a 256x256 table lookup. Likewise the shift function. I can probably dig around and find a table lookup XOR somewhere on my computer.

Tom Morrison
 
Thanks a lot Tom for trying it. I checked the manual for
SHIFT-WORD-LEFT and I couldn't find it. There is a SHIFT-IN and SHIFT-OUT. I did not throughly checked the Manual but sure I will do that. I couldn't find XOR also.
 
I can provide XOR for you. Send an email to:
t.morrison at the domain that should be obvious from my profile.

Tom Morrison
 
FireStarter and I have taken this offline, due to the fact that the table-driven XOR is rather too large to post here.

He is working on a solution and should be back when he has his code ready to show.

Tom Morrison
 
Hi
I did not got a lot of time to check if the following logic is calculating the CRC correctly. But I followed the logic k5tm gave me with the XOR table. The XOR table cannot be posted here as it is about 4000 lines long. If anyone needs the table please contact k5tm or me. Here is the program.
************************************************************
************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. CRCCALC.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WCRC PIC 9(04) BINARY.
01 WCRC-0 REDEFINES WCRC.
02 WCRC1 PIC X(04).
88 WCRC1-HIGH-BIT VALUES X&quot;0080&quot; THRU X&quot;00FF&quot;.
02 WCRC2 PIC X(04).
01 TEMP-CHAR PIC 9(04) BINARY.
77 BCH PIC 999 VALUE ZEROES.
77 I PIC 9.
01 WLEN PIC 9(04).
01 R PIC 9(02) COMP-3.
01 R-1 REDEFINES R PIC X(04).
01 S PIC 9(02) COMP-3.
01 S-1 REDEFINES S PIC X(04).
01 XOR-RESULT PIC 9(04).
01 REC-1 PIC X(100).
01 REC-1-X REDEFINES REC-1.
05 REC-1-Y PIC X OCCURS 8 TIMES INDEXED BY J.
01 REC-2 PIC X(100).
01 REC-2-X REDEFINES REC-2.
05 REC-2-Y PIC X OCCURS 8 TIMES INDEXED BY K.
COPY HEXTABLE.
PROCEDURE DIVISION.
MAIN-PART.
MOVE &quot;THISPROGRAMMAYWORKWELLANDCALCULATECRCONMAINFRAME&quot; TO
REC-1.
UNSTRING REC-1 DELIMITED BY SPACE INTO REC-2 COUNT IN WLEN.
MOVE X&quot;FFFF&quot; TO WCRC1.
MOVE WCRC1 TO TEMP-CHAR.
MOVE WCRC2 TO WCRC1.
MOVE TEMP-CHAR TO WCRC2.
DISPLAY &quot;WCRC: &quot; WCRC.
PERFORM VARYING J FROM 1 BY 1 UNTIL J > WLEN
MOVE REC-1-Y(J) TO BCH
MOVE ZEROES TO R, S
MOVE BCH TO R-1
SET WCRC1-HIGH-BIT TO TRUE
MOVE WCRC1 TO S-1
ADD 1 TO R
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO XOR-RESULT
ADD XOR-RESULT TO WCRC
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 8
IF WCRC1-HIGH-BIT
ADD WCRC TO WCRC
ON SIZE ERROR
CONTINUE
END-ADD
MOVE ZEROES TO R, S
MOVE X&quot;10&quot; TO R-1
MOVE WCRC1 TO S-1
ADD 1 TO R
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO XOR-RESULT
ADD XOR-RESULT TO WCRC
MOVE ZEROES TO R, S
MOVE X&quot;21&quot; TO R-1
MOVE WCRC1 TO S-1
ADD 1 TO R
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO XOR-RESULT
ADD XOR-RESULT TO WCRC
ELSE
ADD WCRC TO WCRC
ON SIZE ERROR
CONTINUE
END-ADD
END-IF
END-PERFORM
END-PERFORM.
DISPLAY &quot;R-1 IS: &quot; R-1.
DISPLAY &quot;S-1 IS: &quot; S-1.
MOVE WCRC1 TO TEMP-CHAR.
MOVE WCRC2 TO WCRC1.
MOVE TEMP-CHAR TO WCRC2.
DISPLAY &quot;WCRC IS: &quot; WCRC.
MAIN-PART-END.
************************************************************
************************************************************
 
First, a typo:
Code:
01  WCRC-0 REDEFINES WCRC.
  02  WCRC1        PIC X(04).
    88  WCRC1-HIGH-BIT VALUES X&quot;0080&quot; THRU X&quot;00FF&quot;.
  02  WCRC2        PIC X(04).
should be::
Code:
01  REDEFINES WCRC.
  02  WCRC1        PIC X.
    88  WCRC1-HIGH-BIT VALUES X&quot;80&quot; THRU X&quot;FF&quot;.
  02  WCRC2        PIC X.

However, I think that the following allows for an undetected flaw:
Code:
ADD WCRC TO WCRC                                     
  ON SIZE ERROR CONTINUE                                           
END-ADD
Consider that this will almost certainly not work if WCRC contains X&quot;8000&quot;.

To fix this, you might use the following (on a mainframe or other big-endian implementation):
Code:
01  WCRC-BIG       PIC 9(9) BINARY.
01  REDEFINES WCRC-BIG.
    02  WCRC-BIG-HI PIC 9(4) BINARY.
    02  WCRC       PIC 9(4) BINARY.
    02  REDEFINES WCRC.
        03  WCRC1  PIC X.
            88  WCRC1-HIGH-BIT 
                VALUES X&quot;80&quot; THRU X&quot;FF&quot;.
        03  WCRC2  PIC X.

Now you may change the previous ADD to:
Code:
MOVE 0 TO WCRC-BIG-HI
ADD WCRC-BIG to WCRC-BIG
There is no need for ON SIZE ERROR clause.

Next correction (again, for mainframe/big-endian implementations):
Code:
01 R               PIC 9(04) BINARY.
01 redefines R.
   02              PIC X.
   01 R-1          PIC X.
01 S               PIC 9(04) BINARY.
01 redefines S.
   02              PIC X.
   01 S-1          PIC X.

There are several places where you ADD rather than MOVE the result of XOR. The original algorithm does not have an ADD, just an XOR. Here is one correction:
Code:
MOVE ZEROES TO R, S
MOVE X&quot;10&quot;  TO R-1
MOVE WCRC1 TO S-1
ADD 1 TO R
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO XOR-RESULT
ADD XOR-RESULT TO WCRC
should be:
Code:
MOVE ZEROES TO R, S
MOVE X&quot;11&quot;  TO R-1
MOVE WCRC1 TO S-1
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO WCRC1
Note that I &quot;optimized away&quot; the ADD 1 TO R by changing the literal value.

Don't know where this came from:
Code:
     SET WCRC1-HIGH-BIT TO TRUE

.... must get back to work...

Tom Morrison
 
Oops, typo on previous post. The level on R-1 and S-1 should be 02, not 01.

Tom Morrison
 
Simple question,
If CRC is calculated for every record then is it necessary to add and then append the value at the end of the file? I am still not well versed with the concept of CRC.
 
Hi,

I have only just happened upon this thread as I only joined the forum(s) yesterday. Although I am not gonna comment on the approach taken, I feel I need to warn you of a potential problem. As the windows box is a little-endian machine, and the mainframe probably isn't, you may not need to do the byte swap before and after the crc calc. For those who don't know, little-endian machines hold the least significant byte of a 16 bit value first !!.
This would mean that to do any bit shifting, you would need to reverse the byte order first, and then put it back the way it was after you have finished.

 
Hi Tom,
I take what I said earlier. I just confirmed that the program need to calculate the CRC for every record and append it at the end of each record.
grangrad I think the byte swap is there at the end of the program.
 
grangrad wrote: As the windows box is a little-endian machine, and the mainframe probably isn't, you may not need to do the byte swap before and after the crc calc.

First, welcome to the cobol forum. [2thumbsup]

Your concern is valid. However, not all COBOL implementations on Windows inflict the Intel hardware representation on the user. Most of us have provided a canonical binary representation that is big-endian, and that is consistent across all platforms, not just Wintel. That is the reason my posting referred to &quot;big-endian implementations&quot; rather than big-endian hardware.

Tom Morrison
 
Here is some more info I just got from the C program. The Starting of the CRC is 0xFFFF not zero. And the WCRC is declared as word which from the program it is clear that it is an unsigned short. From what I know unsigned short is usually 16bits that is 2bytes which is the amount of byte space I will get to add to the end of the record.
Tom are you sure the declartion of WCRC is correct?
 
If you are talking about the modified declaraction for WCRC, I am reasonably sure, based upon my reading of the IBM COBOL manuals, that WCRC will be allocated 16 bits.

WRT setting the beginning CRC to all ones, that should be reasonable trivial to do:
Code:
MOVE 65535 to WCRC-BIG

I guess binary arithmetic is no too much fun in COBOL, but we can do it!

Tom Morrison
 
Concerning IBM and Binary data.

If a field is defined as

Pic 9(04) Binary

the it is true that it will have 2 bytes (16-bits) of storage allocated. HOWEVER, whether all 16 bits are &quot;used&quot; for any specific operation is dependent upon the setting of the TRUNC compiler option. To insure that all 16-bits are used (most of the time) use the

TRUNC(BIN)

compiler option. Alternatively, (with the MOST recent compilers) use

Pic 9(04) Comp-5

to define the field instead. (Particularly useful for &quot;performance sensitive&quot; applications - as the TRUNC(BIN) compiler optin has some pretty BAD performance implications.

To insure that such a SUB-field is set to all binary 1's - move HIGH-VALUES to a group-item above it - and to insure that it is binary zeroes move low-values to the group item.

For more information on the &quot;implications&quot; of the TRUNC ompiler option (in IBM environments) see:

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top