Search code examples
javaandroiddelphimodbuscrc16

Delphi to Java porting issue


I'm aware that java byte is a 8 bits signed variable and to get unsigned (byte) values I will have to do the masking with 0xff everywhere.

Java documentation also says that I can use int to generate unsigned bits by using the procedure previously mentioned.

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

However, whether using the mask or not, it returns the same results.

I've trying changing short into int but no success.

Delphi Code

 procedure TForm1.ReadHoldRegisters(var lst: TList<byte>; deviceaddr: byte;
  RegisterAddress, RegisterLength: word);
begin

  lst.Add(deviceaddr);
  lst.Add(6);
  lst.Add(RegisterAddress div 256);
  lst.Add(RegisterAddress mod 256);
  lst.Add(RegisterLength div 256);
  lst.Add(RegisterLength mod 256);
    Add_CRC16(lst);
end;

 procedure TForm1.Add_CRC16(var Data: TList<byte>);
var
  CRC16Lo, CRC16Hi, CL, CH, SaveHi, SaveLo: byte;
  Flag: Integer;
  b: byte;
begin
  CRC16Lo := $FF;
  CRC16Hi := $FF;
  CL := $1;
  CH := $A0;

  for b in Data do
  begin
    CRC16Lo := CRC16Lo Xor b;

    For Flag := 0 To 7 Do
    Begin
      SaveHi := CRC16Hi;
      SaveLo := CRC16Lo;
      CRC16Hi := CRC16Hi Div 2;
      CRC16Lo := CRC16Lo Div 2;

      If ((SaveHi And $1) = $1) Then
      begin
           CRC16Lo := CRC16Lo Or $80;

      end;


      If ((SaveLo And $1) = $1) Then
      Begin
        CRC16Hi :=  CRC16Hi Xor CH;
        CRC16Lo := CRC16Lo Xor CL;

      End;

    End;


  end;

  Data.Add(CRC16Lo);
  Data.Add(CRC16Hi);

end;

Java Code

public void ReadHoldRegisters(List<Short> lst, byte deviceaddr, char RegisterAddress, char RegisterLength)
{
    lst.add((short) (deviceaddr & 0xff));
    lst.add((short) ((byte) 6 & 0xff));
    lst.add((short) ((RegisterAddress / 256 & 0xff)));
    lst.add((RegisterAddress%256));
    lst.add((RegisterLength/256));
    lst.add(((RegisterLength%256)));
    Add_CRC16(lst);
}

private void Add_CRC16(List<Short> Data)
{
    //Cyclic Redundancy Check 16

    short  SaveLo, SaveHi;
    int flag;

    short CRC16Lo = ((short) 0xFF & 0xff);
    short CRC16Hi = ((short) 0xFF & 0xff);
    short CL      = (short) 0x1 & 0xff;
    short CH      = (short) (0xA0) & 0xff;

    short andop = ((short) 0x80 & 0xff);
    short andop2 = (short) 0x1 & 0xff;

    // início do for in
    for (Short b : Data)
    {
        CRC16Lo ^= b & 0xff;

        for(flag=0;flag<7;flag++)
        {
            SaveHi = (short) ((CRC16Hi) & 0xff);
            SaveLo = (short) ((CRC16Lo) & 0xff);

            CRC16Hi = (short) ((CRC16Hi/2) & 0xff);
            CRC16Lo = (short) ((CRC16Lo/2) & 0xff);

            if((SaveHi & andop2) == andop2 )
                CRC16Lo |= andop & 0xff;

                if(((SaveLo) & (andop2)) == (andop2))
                {
                    CRC16Hi ^= CH & 0xff;
                    CRC16Lo ^= CL & 0xff;
                }
            }

        }

        Data.add((short) (CRC16Lo & 0xff));
        Data.add((short) (CRC16Hi & 0xff));
    }

The correct result to be displayed in this case is "01 06 00 01 00 0A 58 0D"

Any thoughts? Any help?


Solution

  • The most obvious difference is here:

    for(flag=0;flag<7;flag++)
    

    This loops runs one fewer times than the Delphi version. You mean:

    for(flag=0;flag<8;flag++)
    

    On top of that, the Java code was needlessly complex. It can be greatly simplified. This program gives the same output as the Delphi code:

    import java.util.*;
    
    public class test 
    {
    
        public static void ReadHoldRegisters(List<Integer> lst, int deviceaddr, int RegisterAddress, int RegisterLength)
        {
            lst.add(deviceaddr & 0xff);
            lst.add(6);
                lst.add((RegisterAddress >> 8) & 0xff);
                lst.add(RegisterAddress & 0xff);
                lst.add((RegisterLength >> 8) & 0xff);
                lst.add(RegisterLength & 0xff);
            Add_CRC16(lst);
        }
    
        private static void Add_CRC16(List<Integer> Data)
        {
            int SaveLo, SaveHi;
            int CRC16Lo = 0xFF;
            int CRC16Hi = 0xff;
            int CL      = 0x1;
            int CH      = 0xA0;
    
            for (int b : Data)
            {
                CRC16Lo ^= b;
    
                for (int flag=0; flag<8; flag++)
                {
                    SaveHi = CRC16Hi;
                    SaveLo = CRC16Lo;
    
                    CRC16Hi = CRC16Hi/2;
                    CRC16Lo = CRC16Lo/2;
    
                    if((SaveHi & 0x01) == 0x01)
                        CRC16Lo |= 0x80;
    
                    if((SaveLo & 0x01) == 0x01)
                    {
                        CRC16Hi ^= CH;
                        CRC16Lo ^= CL;
                    }
                }
    
            }
    
            Data.add(CRC16Lo & 0xff);
            Data.add(CRC16Hi & 0xff);
        }
    
        public static void main(String[] args) 
        {
            List<Integer> lst = new ArrayList<Integer>();
            ReadHoldRegisters(lst, 1, 1, 10);
            for (int value: lst)
            {
                System.out.print(String.format("%02x", value));
                System.out.print(" ");
            }
        }
    
    }