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));
}
 
Bill,

What you say is quite true. The COBOL standard (at least the 1985 standard) requires that decimal rules are applied, even when the item is described as USAGE BINARY.

That having been said, even 16-bit arithmetic will be suspect in this particular application. Twos complement arithmetic is not too fond of 0x8000, for example, and the fast way to do a left shift -- add a number to itself -- would probably run afoul of a misbehaved number all too soon.

For this reason, I included the 16-bit definition within a redefinition of a 32-bit number, and, prior to doing arithmetic, forced the high-order 16 bits of the 32 to zero. This allows well-behaved arithmetic to be done on the 32-bit number, after which we use the lower order 16 bits of result.

COMP-5 is unattractive because it promotes hardware dependencies up to the COBOL programmer, which is usually not done; resulting programs may become nonportable all in the name of an efficiency that may be totally unrealized. In this case, COMP-5 would lead to different results when going from Windows to mainframe. Now, even with all the nasty bits of COMP-5, it was recently added to one vendor's compiler after many heated discussions. [swords]

Tom Morrison
 
I will post the code a little later as I need to do try once more. But one question popped up in my mind, If I am doing a byte swap on WCRC it should change the values in the the variable. But I noticed that it is not doing it.
 
Here is the logic I used. Keep in mind I am converting the file to binary before doing the CRC check. I am not pasting the whole program with the record formating and binary conversion. I am just posting the CRC conversion. In my first test it failed.
I don't know what I am doing wrong. May be someone else will be able to find the mistake.
************************************************************
************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. CRCCALC.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WCRC-BIG PIC 9(9) BINARY.
01 WCRC-A REDEFINES WCRC-BIG.
02 WCRC-BIG-HI PIC 9(4) BINARY.
02 WCRC PIC 9(4) BINARY.
02 WCRC0 REDEFINES WCRC.
03 WCRC1 PIC X.
88 WCRC1-HIGH-BIT
VALUES X&quot;80&quot; THRU X&quot;FF&quot;.
03 WCRC2 PIC X.
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(04) BINARY.
01 redefines R.
02 PIC X.
02 R-1 PIC X.
01 S PIC 9(04) BINARY.
01 redefines S.
02 PIC X.
02 S-1 PIC X.
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 WCRC.
MOVE WCRC-BIG-HI TO TEMP-CHAR.
MOVE WCRC0 TO WCRC-BIG-HI.
MOVE TEMP-CHAR TO 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
MOVE WCRC1 TO S-1
ADD 1 TO R
ADD 1 TO S
MOVE XOR-VALUE(R, S) TO WCRC1
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 8
IF WCRC1-HIGH-BIT
MOVE 0 TO WCRC-BIG-HI
ADD WCRC-BIG to WCRC-BIG
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 WCRC1
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 WCRC1
ELSE
MOVE 0 TO WCRC-BIG-HI
ADD WCRC-BIG to WCRC-BIG
END-IF
END-PERFORM
END-PERFORM.
MOVE WCRC1 TO TEMP-CHAR.
MOVE WCRC2 TO WCRC1.
MOVE TEMP-CHAR TO WCRC2.
MAIN-PART-END.
************************************************************
************************************************************
Tom I am trying to follow the logic given by you.
Thanks
 
Well, this is suspicious:
Code:
     MOVE X&quot;FFFF&quot; TO WCRC.
I would suggest that it is more appropriate to initialize WCRC indirectly as either:
Code:
     MOVE 65535 TO WCRC-BIG
or:
Code:
     MOVE X&quot;FFFF&quot; TO WCRC0
.
Neither of these toys with the arcane rules of moving a nonnumeric literal to a numeric data item.

Then this is not equivalent to the C code:
Code:
     MOVE WCRC-BIG-HI TO TEMP-CHAR.
     MOVE WCRC0 TO WCRC-BIG-HI.
     MOVE TEMP-CHAR TO WCRC.
If you need to byte swap (and it is not clear that you do, especially if both bytes contain X&quot;FF&quot;!), this code won't do it. The C code is exchanging 8-bit bytes, whereas this COBOL is exchanging 16-bit short integers.

Then, this code:
Code:
             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 WCRC1
should actually refer to the low-order byte of WCRC:
Code:
             MOVE X&quot;21&quot;  TO R-1
             MOVE WCRC2 TO S-1
             ADD 1 TO R
             ADD 1 TO S
             MOVE XOR-VALUE(R, S) TO WCRC2

Perhaps these corrections might help...

Tom Morrison
 
Hi Tom
The Following code I believe is doing the Byte swap in the C code, at least that is what the guy from the C forum told me. Anyway I am going to try your logic as I am not fully sure the logic I made is doing anything.
bCh=(Byte)(wCrc & 0x00FF);
wCrc=(wCrc>>8) + (unsigned short)bCh*0x100;
 
Hi Tom,
I am sorry, I made another logic looking into another CRC routine I found on the web, I did not told that earlier. I am pretty much sure now that it is not working.
 
Tom, A star for support and help above and beyond the call of duty. :-D
Marc
 
Marc, many thanks! [thumbsup2]

FireStarter,

First of all, I think that the byte swaps are confusing you. On a mainframe, everything is big-endian, so you shouldn't need any byte swaps.

You seem to know when the CRC routine is not working, but you have not told us how you determine it is not working. We need some cluse here...

Tom Morrison
 
Hi Tom,
The program should calculate CRC and then the file is send to the workstation, where the C application will do a CRC check and it should match. So the question of Big Endian ends there. In the binary conversion I am converting every byte in the file to ASCII binary so that it can be used in the workstation.
I am getting a message saying this when I am running the C application against the file I am creating.
CRC mismatch in record 1: FILE: 1 CALC: 43401
The CALC: is the Calculated CRC the C application Calculates.
 
FireStarter,

Ok....deep breath....

You state: In the binary conversion I am converting every byte in the file to ASCII binary so that it can be used in the workstation.

I don't know what this means. In particular, I find ASCII binary to be self-contradictory. Perhaps I will understand with a bit more in-depth explanation.

Also, I find this result very suspicious:FILE: 1 CALC: 43401 In particular, a CRC of 1 is a result that would occur once in every 65536 messages or so if it were random, but it seems that the value 1 is very nonrandom, and probably the result of a programming error perhaps downstream from the CRC calculation itself.

And, hoping to put a final nail in the coffin of big-endian vs little-endian... One should consider the record you are sending as a message that is a stream of octets, i.e. 8-bit entities. If one views the algorithm as operating on a stream of octets, then all that is left is the question of which octet of the CRC is sent first at the end of the message. I think that the normal way of appending a CRC is to send the high-order octet first. This is a matter of message standards, however, and not a matter of big- vs little-endian.


Tom Morrison
 
May be the binary conversion is wrong and my stupid debugger is not working properly. Anyway, the requirement is that the program should convert the file into binary before sending it to the workstation. As for CRC the message is coming from the C application. Keep in mind I am writing only one record for test into the file. It is possible that the C application is displaying this message meaning that the CRC mismatch happens in 1 record.
I am pretty sure that the logic is calculating the CRC wrong.
I am sorry if I confused you with the binary conversion. My sincere apologies for that.
 
Tom you are right about the following.
&quot;I guess binary arithmetic is no too much fun in COBOL, but we can do it!&quot;
I am getting every number except the CRC value. I don't believe I will be able to get this done anymore. But as I have nothing else I don't have any choice. In these days I might've talked, e-mailed and chatted with maybe 50 programmers who all adviced me not to attempt it in COBOL and that is the fun of it. Trying to do something none ever attempted[medal].
Anyway thanks a lot for all the efforts you all in the forum made trying to help me.
 
Ol' FireStarter and I are communicating on the back channel. We'll report out, probably tomorrow.

I think that this is an interesting programming exercise, so we're gonna see it through! [hammer]

Tom Morrison
 
Sure!! [bigsmile]
Sorry for the frustrated reply earlier. I was [upsidedown] this morning.
 
I can report on one thing I discovered while going over the COBOL program provided by FireStarter1 (I have about 5 minutes before a meeting...)

The byte swapping exhibited is really part of the algorithm. Notice that the bytes from the message stream are introduced at the high-order end of the CRC accumulator. I did not totally appreciate this fact, and its relationship to the apparent byte swapping, that could be mistaken for little-endian correction.

If you go look at the thread that FireStarter began in the C Forum, you will find a reference to a very thorough explanation of CRC algorithms.[smarty] Once I read that, the light dawned.

Okay, off to the meeting. [sad]

Tom Morrison
 
Hi Tom,
I appreciate you taking time to respond. But I heard a bad news this morning, most probably my tech lead may ask for a C implementation. Which of course will take this off me. May be everything off me.[sad]
 
I missed to tell this. Even if there is going to be a C implementation, I personly want to do this COBOL so I am looking at the changes you told.
 
Hi Tom,
Your logic is calculating the CRC lower. I added more ADD lines after the XOR and it is still not equal to the ones the C application is calculating. Anyway I may be able to get another day or two during a meeting tomorrow.
 
I forgot to put this in the earlier message.
This is the result I am getting when I am using your code.
CRC mismatch in record 1: FILE: 19023 CALC: 20298
The CRC in the FILE and the CALC should be equal.
 
I tried all in my arsenel and failed. Looks like the whole XOR logic is wrong.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top