Search code examples
delphifiremonkeycrc16

firemonkey android crc16 result mismatch with delphi for windows


in two different project i need to use crc16 checksum.one in windows and other in android.i used a code for windows and it worked prefect.

showmessage(  bin2crc16(HexToBin('1234'))    );   //---> 0EC9

here is used function for winsows

function Pow(i, k: Integer): Integer;
var
  j, Count: Integer;
begin
  if k>0 then j:=2
    else j:=1;
  for Count:=1 to k-1 do
    j:=j*2;
  Result:=j;
end;

function BinToDec(Str: string): Integer;
var
  Len, Res, i: Integer;
  Error: Boolean;
begin
  Error:=False;
  Len:=Length(Str);
  Res:=0;
  for i:=1 to Len do
    if (Str[i]='0')or(Str[i]='1') then
      Res:=Res+Pow(2, Len-i)*StrToInt(Str[i])
    else
    begin
      //MessageDlg('It is not a binary number', mtInformation, [mbOK], 0);
      Error:=True;
      Break;
    end;
  if Error=True then Result:=0
    else Result:=Res;
end;
//------------------------------------------------------------------------------
function CRC16CCITT(bytes: array of Byte): Word;
const
  polynomial = $1021;
var
  crc: Word;
  I, J: Integer;
  b: Byte;
  bit, c15: Boolean;
begin
  crc := $FFFF;
  for I := 0 to High(bytes) do
  begin
    b := bytes[I];
    for J := 0 to 7 do
    begin
      bit := (((b shr (7-J)) and 1) = 1);
      c15 := (((crc shr 15) and 1) = 1);
      crc := crc shl 1;
      if ((c15 xor bit) <> false) then crc := crc xor polynomial;
    end;
  end;
  Result := crc and $ffff;
end;
//------------------------------------------------------------------------------
function HexToDec(const Str: string): Integer;
begin
  if (Str <> '') and ((Str[1] = '-') or (Str[1] = '+')) then
    Result := StrToInt(Str[1] + '$' + Copy(Str, 2, MaxInt))
  else
    Result := StrToInt('$' + Str);
end;
//------------------------------------------------------------------------------
function bin2crc16(str: string): string;
var
I:integer;
lengthCount : integer;
crcByteArr : array of Byte;
crcOut : Word;
begin
  lengthCount := Trunc(length(str)/8);
  setlength(crcByteArr , lengthCount );
  for I := 0 to lengthCount-1 do
  begin
    crcByteArr[I] := BinToDec(copy(str, I*8+1, 8));
  end;
  crcOut := CRC16CCITT(crcByteArr);

  result := crcOut.ToHexString;

end;
//------------------------------------------------------------------------------
function HexToBin(Hexadecimal: string): string;
const
  BCD: array [0..15] of string =
    ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
    '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
var
  i: integer;
begin
  Result := '';
  for i := Length(Hexadecimal) downto 1 do
    Result := BCD[StrToInt('$' + Hexadecimal[i])] + Result;
end;

but for android i changed the code to handle zero index string. the result is different

memo2.Lines.Add( bin2crc16(HexToBin('1234')) ); //-----> 1AFa

here is used functions in android

function BinToDec(Str: string): Integer;
var
  Len, Res, i: Integer;
  Error: Boolean;
begin
  Error:=False;
  Len:=Length(Str);
  Res:=0;
  for i:=0 to Len-1 do
    if (Str[i]='0')or(Str[i]='1') then
      Res:=Res+Pow(2, Len-i)*StrToInt(Str[i])
    else
    begin
      Error:=True;
      Break;
    end;
  if Error=True then Result:=0
    else Result:=Res;
end;
//------------------------------------------------------------------------------
function CRC16CCITT(bytes: array of Byte): Word;
const
  polynomial = $1021;
var
  crc: Word;
  I, J: Integer;
  b: Byte;
  bit, c15: Boolean;
begin
  crc := $FFFF;
  for I := 0 to High(bytes) do
  begin
    b := bytes[I];
    for J := 0 to 7 do
    begin
      bit := (((b shr (7-J)) and 1) = 1);
      c15 := (((crc shr 15) and 1) = 1);
      crc := crc shl 1;
      if ((c15 xor bit) <> false) then crc := crc xor polynomial;
    end;
  end;
  Result := crc and $ffff;
end;
//------------------------------------------------------------------------------
function bin2crc16(str: string): string;
var
I:integer;
lengthCount : integer;
crcByteArr : array of Byte;
crcOut : Word;
begin
  lengthCount := Trunc(length(str)/8);
  setlength(crcByteArr , lengthCount );
  for I := 0 to lengthCount-1 do
  begin
    crcByteArr[I] := BinToDec(copy(str, I*8, 8));
  end;
  crcOut := CRC16CCITT(crcByteArr);

  result := crcOut.ToHexString;

end;
//-----------------------------------------------------------------------------------
function HexToBin(Hexadecimal: string): string;
const
  BCD: array [0..15] of string =
    ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
    '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
var
  i: integer;
begin
  Result := '';
  for i := Length(Hexadecimal)-1 downto 0 do
    Result := BCD[StrToInt('$' + Hexadecimal[i])] + Result;
end;
//---------------------------------------------------------------------------------
function Pow(i, k: Integer): Integer;
var
  j, Count: Integer;
begin
  if k>0 then j:=2
    else j:=1;
  for Count:=1 to k-1 do
    j:=j*2;
  Result:=j;
end;

how can i fix my problem !?


Solution

  • You have not adjusted your HexToBin function for zero length strings.

    There is also an issue in your BinToDec function. Your power calculation is wrong because the index into the string has changed. Possibly the simplest way to deal with it is as follows, although you could also adjust the index in the POW function

    function BinToDec(Str: string): Integer;
    var
      Len, Res, i: Integer;
      Error: Boolean;
    begin
      Error:=False;
      Len:=Length(Str);
      Res:=0;
      for i:=1 to Len do
        if (Str[I - 1]='0')or(Str[I - 1]='1') then
          Res:=Res+Pow(2, Len-i)*StrToInt(Str[I - 1])
        else
        begin
          Error:=True;
          Break;
        end;
      if Error=True then Result:=0
        else Result:=Res;
    end;
    

    The last thing to note is that 'Copy' uses One based indexing even on zero based strings, but you have assumed that it is zero indexed. I agree it is confusing, but there it is.