Board index » delphi » BCD conversion

BCD conversion


2004-02-26 04:09:08 AM
delphi162
I have a BCD value in this datatype:
buf:fer array [ 0 .. 15 ] of uchar;
Each byte contains two numbers. Thus, there are 30 numbers in this array. How do I convert the array to 30 numbers? The equivalent C code is:
for (i=1;i<buflen;i++) { /* reformat buffer from BCD to Char*/
sprintf(bufout,"%02x",buffer[i]); /* load output buffer */
bufout += 2; /* outbuf gets 2 char for every 1 buffer char*/
for (j;j<15;j++){
sprintf(bufout,"02x",0);
bufout += 2;}
}
TIA - nick
 
 

Re:BCD conversion

"Nick Iorio" <XXXX@XXXXX.COM>wrote
Quote
I have a BCD value in this datatype:
buf:fer array [ 0 .. 15 ] of uchar;
Each byte contains two numbers. Thus, there are 30
numbers in this array. How do I convert the array to
30 numbers?
Nick, What is the type of "uchar"? Rgds, JohnH
 

Re:BCD conversion

"John Herbster \(TeamB\)" <herb-sci1_AT_sbcglobal.net>writes:
Quote

"Nick Iorio" <XXXX@XXXXX.COM>wrote
>I have a BCD value in this datatype:
>buf:fer array [ 0 .. 15 ] of uchar;
>Each byte contains two numbers. Thus, there are 30
>numbers in this array. How do I convert the array to
>30 numbers?

Nick, What is the type of "uchar"? Rgds, JohnH

Hi John,
uchar is unsigned character.
- nick
 

Re:BCD conversion

"Nick Iorio" <XXXX@XXXXX.COM>wrote
Quote
>>I have a BCD value in this datatype:
>>buf:fer array [ 0 .. 15 ] of uchar;
>>Each byte contains two numbers. Thus, there are 30
>>numbers in this array. How do I convert the array to
>>30 numbers?
>Nick, What is the type of "uchar"? Rgds, JohnH
uchar is unsigned character.
Nick,
If it is the common 8-bit character type, then in Delphi,
it is called just "char" or more properly AnsiChar. Or
perhaps you mean an array of "byte". If your buffer
array is [0 .. 15] of byte then in Delphi that is 16 bytes
and thus could hold 32 BCD "nibbles" or decimal digits,
which is two more than your 30. I am doing a lot of
guessing here. How about helping me by telling me
where I have guessed right and wrong, so that I can
understand what you are trying to do. Rgds, JohnH
 

Re:BCD conversion

"John Herbster \(TeamB\)" <herb-sci1_AT_sbcglobal.net>writes:
Quote

"Nick Iorio" <XXXX@XXXXX.COM>wrote

>>>I have a BCD value in this datatype:
>>>buf:fer array [ 0 .. 15 ] of uchar;
>>>Each byte contains two numbers. Thus, there are 30
>>>numbers in this array. How do I convert the array to
>>>30 numbers?

>>Nick, What is the type of "uchar"? Rgds, JohnH

>uchar is unsigned character.

Nick,
If it is the common 8-bit character type, then in Delphi,
it is called just "char" or more properly AnsiChar. Or
perhaps you mean an array of "byte". If your buffer
array is [0 .. 15] of byte then in Delphi that is 16 bytes
and thus could hold 32 BCD "nibbles" or decimal digits,
which is two more than your 30. I am doing a lot of
guessing here. How about helping me by telling me
where I have guessed right and wrong, so that I can
understand what you are trying to do. Rgds, JohnH
Hi John,
I have a string called mychar which is length 15 and when I look at it, its value is: '6-56'#0#0#0#0#0#0#0#0'V5\'
This needs to be converted to 30 decimal digits which will then be: 544553540000000000000000865392
So, the question is how do I convert the mychar string to these 30 digits?
Thank you so much for your help. (I have to meet with my boss tomorrow and have this solved. Ugggh!)
- nick
 

Re:BCD conversion

"John Herbster \(TeamB\)" <herb-sci1_AT_sbcglobal.net>writes:
Quote

"Nick Iorio" <XXXX@XXXXX.COM>wrote

>>>I have a BCD value in this datatype:
>>>buf:fer array [ 0 .. 15 ] of uchar;
>>>Each byte contains two numbers. Thus, there are 30
>>>numbers in this array. How do I convert the array to
>>>30 numbers?

>>Nick, What is the type of "uchar"? Rgds, JohnH

>uchar is unsigned character.

Nick,
If it is the common 8-bit character type, then in Delphi,
it is called just "char" or more properly AnsiChar. Or
perhaps you mean an array of "byte". If your buffer
array is [0 .. 15] of byte then in Delphi that is 16 bytes
and thus could hold 32 BCD "nibbles" or decimal digits,
which is two more than your 30. I am doing a lot of
guessing here. How about helping me by telling me
where I have guessed right and wrong, so that I can
understand what you are trying to do. Rgds, JohnH
Clarification:
I actually need to convert the string '6-56'#0#0#0#0#0#0#0#0'V5\' to 544553540000000000000000865392 (hex) where each 2 digits are the ASCII code or decimal digits. So, the final result I am looking for is
TEST00000000865392
- nick
 

Re:BCD conversion

"Nick Iorio" <XXXX@XXXXX.COM>wrote
Quote
I have a string called mychar which is length 15 and
when I look at it, its value is: '6-56'#0#0#0#0#0#0#0#0'V5\'
This needs to be converted to 30 decimal digits which will
then be: 544553540000000000000000865392
So, the question is how do I convert the mychar string
to these 30 digits?
Nick, I think that you still have your numbers mixed up,
but here below is a "quick and dirty". Regards, Johnh
Use it with 2 TEdit boxes and 2 TButtons on a form.
const BCDChars: array [0 .. 15] of char = '0123456789ABCDEF';
function BCDDigitsToCharDigits(BCDDigits: string): string;
var i,n: integer; b: byte;
begin
n := 2*Length(BCDDigits);
SetLength(Result,n);
For i := 0 to Length(BCDDigits) -1 do begin
b := ord(BCDDigits[i + 1]);
Result[2*i + 1] := BCDChars[(b div 16)];
Result[2*i + 2] := BCDChars[(b mod 16)];
end;
end;
function CharDigitsToBCDDigits(CharDigits: string): string;
var i,j,k,n: integer; b: byte; c: char;
begin
n := (Length(CharDigits) + 1) div 2;
SetLength(Result,n);
For i := 1 to length(CharDigits) do begin
c := CharDigits[i];
k := high(BCDChars);
While (k>= 0) and (c <>BCDChars[k]) do dec(k);
If (k < 0)
then if c in [#32 .. #126]
then raise Exception.CreateFmt('Illegal char ("%s") in in
input',[c])
else raise Exception.CreateFmt('Illegal char (0x%2.2x) in in
input',[ord(c)]);
If Odd(i)
then b := k*16
else b := b + k;
j := (i - 1) div 2 + 1;
Result [j] := char(b);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var s, t: string;
begin
s := Edit1.Text;
t := BCDDigitsToCharDigits(s);
Edit2.Text := t;
end;
procedure TForm1.Button2Click(Sender: TObject);
var s, t: string;
begin
s := Edit2.Text;
t := CharDigitsToBCDDigits(s);
Edit1.Text := t;
end;
 

Re:BCD conversion

"John Herbster \(TeamB\)" <herb-sci1_AT_sbcglobal.net>writes:
Quote

"Nick Iorio" <XXXX@XXXXX.COM>wrote
>I have a string called mychar which is length 15 and
>when I look at it, its value is: '6-56'#0#0#0#0#0#0#0#0'V5\'
>This needs to be converted to 30 decimal digits which will
>then be: 544553540000000000000000865392
>So, the question is how do I convert the mychar string
>to these 30 digits?

Nick, I think that you still have your numbers mixed up,
but here below is a "quick and dirty". Regards, Johnh

Use it with 2 TEdit boxes and 2 TButtons on a form.

const BCDChars: array [0 .. 15] of char = '0123456789ABCDEF';

function BCDDigitsToCharDigits(BCDDigits: string): string;
var i,n: integer; b: byte;
begin
n := 2*Length(BCDDigits);
SetLength(Result,n);
For i := 0 to Length(BCDDigits) -1 do begin
b := ord(BCDDigits[i + 1]);
Result[2*i + 1] := BCDChars[(b div 16)];
Result[2*i + 2] := BCDChars[(b mod 16)];
end;
end;

function CharDigitsToBCDDigits(CharDigits: string): string;
var i,j,k,n: integer; b: byte; c: char;
begin
n := (Length(CharDigits) + 1) div 2;
SetLength(Result,n);
For i := 1 to length(CharDigits) do begin
c := CharDigits[i];
k := high(BCDChars);
While (k>= 0) and (c <>BCDChars[k]) do dec(k);
If (k < 0)
then if c in [#32 .. #126]
then raise Exception.CreateFmt('Illegal char ("%s") in in
input',[c])
else raise Exception.CreateFmt('Illegal char (0x%2.2x) in in
input',[ord(c)]);
If Odd(i)
then b := k*16
else b := b + k;
j := (i - 1) div 2 + 1;
Result [j] := char(b);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var s, t: string;
begin
s := Edit1.Text;
t := BCDDigitsToCharDigits(s);
Edit2.Text := t;
end;

procedure TForm1.Button2Click(Sender: TObject);
var s, t: string;
begin
s := Edit2.Text;
t := CharDigitsToBCDDigits(s);
Edit1.Text := t;
end;



Hi John,
Thanks so much for your help! The code works great except for one problem that I have when I add it to my application. I am calling the BCDDigitsToCharDigits from within a Socket component event. When that event gets more than one "record" it calls the BCDDigitsToCharDigits repeatedly. The BCDDigitsToCharDigits fails at the line:
SetLength(Result,n);
I initialized Result before this line and then it fails on the initialization line. I have stepped thru the code and n is the same value each time.
This code does not fail if I run it stand alone. I can not reproduce the error now because I no longer have access to the Socket interface device.
Also, I noticed that you used functions that I did not know existed. I searched Delphi Help for many hours trying to find functions and help on doing fractional byte processing but could not. For future use, how would I have found the functions that you used in BCDDigitsToCharDigits?
thank you! nick
 

Re:BCD conversion

"Nick Iorio" <XXXX@XXXXX.COM>wrote
<over-quoted stuff removed>
Quote
The code works great except for ... I am calling the
BCDDigitsToCharDigits from within a Socket component
event. When that event gets more than one "record" it
calls the BCDDigitsToCharDigits repeatedly. The
BCDDigitsToCharDigits fails at the line:
SetLength(Result,n);
This code does not fail if I run it stand alone. ...
Nick,
Do you have more than one task running in your application?
If the data blocks are *always* the same length, then I
would replace the string types with fixed length array blocks.
Quote
Also, I noticed that you used functions that I did not know
existed. I searched Delphi Help for many hours trying to
find functions and help on doing fractional byte processing
... how would I have found the functions that you used ...
I deliberately used the different types to expose you to the
lesser used functions. Besides the usual Help "Index", I
suggest that you try the "Contents" and "Find "features.
I just used the Find to find a section called "Logical
(bit-wise) operators" that has some of what you needed.
There used to be a printed LRM (Language Reference
Manual) with the older Delphi editions that made good
bed-time reading. <g>In later editions, it is called the
"Delphi Language Guide". You may be able to find it
on the "Companion Tools CD" that you may have
received with Delphi.
If you can find, even an older, printed copy of the LRM
or DLG, I'd buy it. Regards, JohnH
 

Re:BCD conversion

"John Herbster \(TeamB\)" <herb-sci1_AT_sbcglobal.net>writes:
Quote

"Nick Iorio" <XXXX@XXXXX.COM>wrote

<over-quoted stuff removed>

>The code works great except for ... I am calling the
>BCDDigitsToCharDigits from within a Socket component
>event. When that event gets more than one "record" it
>calls the BCDDigitsToCharDigits repeatedly. The
>BCDDigitsToCharDigits fails at the line:
>SetLength(Result,n);

>This code does not fail if I run it stand alone. ...

Nick,
Do you have more than one task running in your application?
If the data blocks are *always* the same length, then I
would replace the string types with fixed length array blocks.

>Also, I noticed that you used functions that I did not know
>existed. I searched Delphi Help for many hours trying to
>find functions and help on doing fractional byte processing
>... how would I have found the functions that you used ...

I deliberately used the different types to expose you to the
lesser used functions. Besides the usual Help "Index", I
suggest that you try the "Contents" and "Find "features.
I just used the Find to find a section called "Logical
(bit-wise) operators" that has some of what you needed.

There used to be a printed LRM (Language Reference
Manual) with the older Delphi editions that made good
bed-time reading. <g>In later editions, it is called the
"Delphi Language Guide". You may be able to find it
on the "Companion Tools CD" that you may have
received with Delphi.

If you can find, even an older, printed copy of the LRM
or DLG, I'd buy it. Regards, JohnH
John,
Not sure what you mean by another task running. The only thing I can think of is the Socket components are probably running, always checking for new incoming data.
So, you're saying if I don't have to set the length of Result then the problem would go away? Would it be better if I made the procedure explicitly return the result (I assume I can do that but may need help) rather than using Result?
thanks - nick
 

Re:BCD conversion

"Nick Iorio" <XXXX@XXXXX.COM>wrote
Quote
>>The code works great except for ... I am calling the
>>BCDDigitsToCharDigits from within a Socket component
>>event. When that event gets more than one "record"
>>it calls the BCDDigitsToCharDigits repeatedly. The
>>BCDDigitsToCharDigits fails at the line:
>>SetLength(Result,n);
>>This code does not fail if I run it stand alone.
Not sure what you mean by another task running. The
only thing I can think of is the Socket components
are probably running, always checking for new incoming
data.
Nick,
(1) Which Socket components are you using?
(2) Is this code running inside an event of a
Socket component?
(3) Do you have any Application.ProcessMessages
calls in the Socket event handler?
Quote
So, you're saying if I don't have to set the
length of Result then the problem would go
away?
Not necessarily. Since I don't know how your
program works, I am only guessing as solutions.
Because strings are allocated from memory on
the heap whenever SetLength() is done, I am
suggesting that fixed buffer blocks may be
better. Ex:
Type
TMyBCDBuf15: array [0 .. 14] of byte;
TMyChrBuf30: array [0 .. 29] of char;
procedure Bcd15ToChr30 (
Bcd: TMyBCDBuf15;
Chr: TMyChrBuf30);
Regards, JohnH