Author Topic: SOLVED - Davis CRC formula  (Read 2863 times)

0 Members and 1 Guest are viewing this topic.

Offline Josiah

  • Add-InWx Software Author
  • Forecaster
  • *****
  • Posts: 449
    • Add-InWx
SOLVED - Davis CRC formula
« on: March 30, 2015, 08:29:52 PM »
Hey guys,

I'm at the point In my programming efforts where I need to send data (eg Date and Time) to a Davis Console. I've figured out how to build a byte array with all the Month, Day, Year, Hour, Minute and second values in it, but what I'm trying to figure out now is how to calculate the CRC for it.

Anybody know how to do that?
« Last Edit: May 04, 2015, 06:16:42 PM by Josiah »

Offline ericfynne

  • Contributor
  • ***
  • Posts: 139
Re: Davis CRC formula
« Reply #1 on: March 31, 2015, 03:31:18 AM »
I thought that the Davis protocol was documented - by Davis? Surely it tells you how to calculate a CRC?

Eric

Offline Josiah

  • Add-InWx Software Author
  • Forecaster
  • *****
  • Posts: 449
    • Add-InWx
Re: Davis CRC formula
« Reply #2 on: March 31, 2015, 08:28:51 AM »
Eric,
Yes it is documented, and I have the documentation sitting in front of me. It does tell me how to calculate the CRC for data sent from the Console, eg the LOOP packet. That part I understand *I think* and have well, copied out of the Doc and it works just fine. What I'm not understanding is the part about sending a CRC.

I had an idea as to one of the things that I might be doing wrong, so I'm going to try it and see if that gets it working.

Offline ericfynne

  • Contributor
  • ***
  • Posts: 139
Re: Davis CRC formula
« Reply #3 on: March 31, 2015, 09:00:10 AM »
You generate a CRC in exactly the same way as when validating a CRC. When generating, you run the calculation on the data without the CRC (obviously, as you don't have the CRC yet); the result is a 16-bit number which you tack on the end of the data (MSB first). When validating, you carry on past the actual data and include the CRC. The result is zero if the data check succeeds (because XORing a number with itself gives zero, and the number you have just before processing the CRC bytes should be the CRC itself).

Eric.

Offline Josiah

  • Add-InWx Software Author
  • Forecaster
  • *****
  • Posts: 449
    • Add-InWx
Re: Davis CRC formula
« Reply #4 on: March 31, 2015, 09:35:02 AM »
Thanks Eric,
I got it working and now feel stupid.  :oops:

What I was doing was creating an array of 8 Bytes, putting the Date and Time info in their places then sending that to the CRC function. After getting a ushort (16-bit number) from the CRC function I took the 2 bytes and put them into my "Timearray" at elements 6 and 7 (0 indexed array BTW).
So what was happening is the CRC function would calculate a CRC for all 8 bytes in the array including the 2 that the CRC was going to go into.

What I'm doing now is creating an array of 6 Bytes, putting the Date and Time values in their places, then sending that to the CRC function. After getting the 16-bit CRC from the CRC function I'm resizing the Byte array into 8 elements and putting the 2 Bytes of the CRC into elements 6 and 7.

Best to show you with Code, so here's what I was doing: This is wrong
Code: [Select]
public static Boolean SetTime(DateTime time)
        {
            Byte[] TimeArray = new Byte[8]; //this should be created with 6 not 8 elements
            TimeArray[0] = (Byte)time.Second;
            TimeArray[1] = (Byte)time.Minute;
            TimeArray[2] = (Byte)time.TimeOfDay.Hours;
            TimeArray[3] = (Byte)time.Day;
            TimeArray[4] = (Byte)time.Month;
            TimeArray[5] = (Byte)(time.Year - 2000);

            Byte[] tempCRC = BitConverter.GetBytes(CRC_Check(ref TimeArray));

            // need to resize the Timearray here

            TimeArray[6] = tempCRC[1];
            TimeArray[7] = tempCRC[0];
           
            Console.WriteLine("Sending 'SetTime' command...");
            Byte[][] ComRply = sendCommand(Encoding.ASCII.GetBytes("SetTime\n"), commStream);

            if (ComRply[0][0] == (Byte)6)
            {
                Console.WriteLine("Sending Time...");
                ComRply = sendCommand(TimeArray, commStream);
                if (ComRply[0][0] == (Byte)6)
                {
                    return true;
                }
            }

            return false;
        }

here's the Working code:
Code: [Select]
public static Boolean SetTime(DateTime time)
        {
            Byte[] TimeArray = new Byte[6]; // this is how it should be created
            TimeArray[0] = (Byte)time.Second;
            TimeArray[1] = (Byte)time.Minute;
            TimeArray[2] = (Byte)time.TimeOfDay.Hours;
            TimeArray[3] = (Byte)time.Day;
            TimeArray[4] = (Byte)time.Month;
            TimeArray[5] = (Byte)(time.Year - 2000);

            Byte[] tempCRC = BitConverter.GetBytes(CRC_Check(ref TimeArray));

            Array.Resize(ref TimeArray, 8); // this is added

            TimeArray[6] = tempCRC[1];
            TimeArray[7] = tempCRC[0];
           
            Console.WriteLine("Sending 'SetTime' command...");
            Byte[][] ComRply = sendCommand(Encoding.ASCII.GetBytes("SetTime\n"), commStream);

            if (ComRply[0][0] == (Byte)6)
            {
                Console.WriteLine("Sending Time...");
                ComRply = sendCommand(TimeArray, commStream);
                if (ComRply[0][0] == (Byte)6)
                {
                    return true;
                }
            }

            return false;
        }

and Here's the code that does the actual CRC part. Copied from the Davis documentation.
Code: [Select]
private static ushort CRC_Check(ref byte[] Data_Array)
        {
            ushort crc = 0;

            foreach (byte Tempbyte in Data_Array)
            {
                crc = Convert.ToUInt16(CRC_Table[(crc >> 8) ^ Tempbyte] ^ ((crc & 0xff) << 8));
            }
            return crc;
        }
       
private static readonly ushort[] CRC_Table = {
0x0,0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x210,  0x3273, 0x2252, 0x52b5, 0x4294,
            0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x420,  0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528,
            0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
            0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71,
            0xa50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41, 0xedae, 0xfd8f,
            0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59,
            0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da,
            0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2,
            0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676,
            0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f,
            0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
            0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93,
            0x3eb2, 0xed1,  0x1ef0
};

The one thing that You don't see in the code above is the "sendCommand" function. It takes a Byte Array and an IO.Stream as parameters, sends the byte array over the IO.Stream and returns whatever (if anything) the Console replies with. Now the Byte array it returns is a multi dimensional "jagged" array created by splitting the Consoles reply by the "\n\r" chars. But thats my own choice of implementation.