Sunday, November 22, 2015

Как в C# сделать подсчет контрольной суммы CRC16 используя CCITT2 -полином

Что то везет в последнее время на "качество оформленную документацию". И вот новая "стезя", работа с ИКС-маркетом и драйвером под виндоуз (хотя сейчас стало интересно, исправили ли они глюки в своем, может я даром долбаюсь????)

Вот вырезке из их документации:
Контрольная сумма CRC16 использует CCITT2
-полином (х16 + х12 + х5
+ 1) и расчитывается по
полям Номер, Код, Параметры, CS и ETX без дублирующих и заключительного DLE. В ответном пакете
CRC16 подсчитывается аналогично.
ЭККР записывает полученный Номер и Код в ответное сообщение. Если ЭККР получает
сообщение, в котором совпадают значения полей Номер и Код со значениями предыдущего
сообщения, то он не выполняет команду, а повторяет передачу предыдущего сообщения.
Пример вычисления CRC16 на Си:
void CalcCRC16(BYTE *Buf, WORD Size, WORD *CRC16)
{char V;
while(Size--) {
V = *Buf++;
INT_HI(*CRC16) ^= V;
V = (INT_HI(*CRC16) << 4) ^ INT_HI(*CRC16); INT_HI(*CRC16) = (V >> 4) ^ (V << 3) ^ INT_LO(*CRC16); INT_LO(*CRC16) = (V >> 5) ^ V;
}
}
Пример вычисления CRC16 на Паскале:
function CalcCRC16(DataByte: Byte; CRC16: word): word;
var
a:word;
begin
CRC16 := CRC16 xor DataByte;
a:=(CRC16 xor (CRC16 shl 4)) and $00FF;
Result:=(CRC16 shr 8) xor (a shl 8) xor (a shl 3) xor (a shr 4);
end;
Вопрос, что так тяжело описать что и зачем используете??? Какой полином??? В общем спасибо за сутки разбора...
Решение было сделано так:
0. спасибо утилите serial port monitor, за то что удалось посмотреть, как обмениваться между собой аппарат и утилита ИКС
1.найден был сайт с online калькулятором расчета CRC.
2. Благодаря калькулятору удалось понять какой метод шифрования необходимо использовать - CRC-CCITT (Kermit), ИКС что так сложно описать???
3. Найдено решение спасибо гугл и stackoverflow

оставлю код для необходимости:




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            byte ETX = 0x03;
            byte DLE = 0x10;
            byte STX = 0x02;
            byte ASK = 0x06;
            //Crc16Ccitt crc16 = new Crc16Ccitt(x);
            //    10 02 46 00 ba 10 03 a8 a8                        ..F.є..ЁЁ        
            //    10 02 56 00 aa 10 03 98 fe                        ..V.Є..˜ю 
            //    10 02 60 00 a0 10 03 80 04..`. ..Ђ. 
            //    10 02 6b 32 00 00 00 00 63 10 03 3a e8            ..k2....c..:и
            //    10 02 6a 00 96 10 03 5c 3a                        ..j.–..\:        
            //    10 02 73 32 00 00 09 00 52 10 03 e7 c8            ..s2....R..зИ    
            //    10 02 5f 32 00 00 09 00 66 10 03 b7 94            .._2....f..·”    
            //    10 02 74 00 8c 10 03 5e 3f                        ..t.Њ..^?        
            //    10 02 75 32 00 00 00 00 59 10 03 9d c8            ..u2....Y..ќИ    
            //    10 02 76 32 00 00 01 00 57 10 03 e6 c4            ..v2....W..жД    

            //Array<byte[]> myList = new Array<byte[]>();            
            //myList.Add({ 0x10, 0x02, 0x46, 0x00, 0xba, 0x10, 0x03, 0xa8, 0xa8 });
            //byte[] temp = { 0x10, 0x02, 0x56, 0x00, 0xaa, 0x10, 0x03, 0x98, 0xfe }; 
            ArrayList myList = new ArrayList();
            byte[] arrayofbytes = { 0x10, 0x02, 0x46, 0x00, 0xba, 0x10, 0x03, 0xa8, 0xa8 };            
            myList.Add(arrayofbytes);
            arrayofbytes = new byte[] { 0x10, 0x02, 0x56, 0x00, 0xaa, 0x10, 0x03, 0x98, 0xfe };
            myList.Add(arrayofbytes);
            arrayofbytes = new byte[] { 0x10, 0x02, 0x76, 0x32, 0x00, 0x00, 0x01, 0x00, 0x57, 0x10, 0x03, 0xe6, 0xc4 };
            myList.Add(arrayofbytes);
            byte[] bytebegin = { DLE, STX};
            byte[] byteend = {DLE, ETX};

            Crc16 testCRC16 = new Crc16(Crc16Mode.CcittKermit);

            //ushort max = ushort.MaxValue;
            //for (ushort x = 0; x <= max - 1; x++)
            //{
                //Console.WriteLine(x);
                foreach (byte[] tempa in myList)
                {
                    //Console.WriteLine(PrintByteArray(tempa));
                    byte[] tempb = returnWithOutDublicateETX(tempa);
                    var searchBegin = PatternAt(tempb, bytebegin);
                    if (searchBegin == null)
                        continue;

                    var searchEnd = PatternAt(tempb, byteend);
                    if (searchEnd == null)
                        continue;
                        
                    var newArr = tempb.Skip((int)searchBegin+2).Take((int)searchEnd-2).ToArray();
                                                           
                    byte[] a = new byte[newArr.Length+1];
                    newArr.CopyTo(a, 0);                    
                    a[newArr.Length] = ETX;
                    //Console.WriteLine(PrintByteArray(a));

                    var control = tempb.Skip((int)searchEnd+2).Take(2).ToArray();
                    //Console.WriteLine(PrintByteArray(control));


                    //byte[] crc = BitConverter.GetBytes(compute_fcs(a, x));
                    
                    byte[] crc = testCRC16.ComputeChecksumBytes(a);

                    if ((crc[0] == control[0]) && (crc[1] == control[1]))                    
                    {
                        Console.WriteLine(PrintByteArray(tempa));
                        Console.WriteLine(PrintByteArray(a));
                        Console.WriteLine(PrintByteArray(control));
                       // Console.WriteLine(x);                        
                        Console.WriteLine(PrintByteArray(crc));
                        Console.ReadKey();
                       //break;
                    }
                }
                //break;
            //}
            Console.WriteLine("The End!!!!");
            Console.ReadKey();
        }

        static byte[] returnWithOutDublicateETX(byte[] source)
        {
            return returnWithOutDublicate(source, new byte[] { 0x10, 0x10 });
        }

        static byte[] returnWithOutDublicate(byte[] source, byte[] pattern)
        {
            
            List<byte> tReturn  =new List<byte>();
            int sLenght = source.Length;
            for (int i = 0; i < sLenght; i++)
            {
                if (source.Skip(i).Take(pattern.Length).SequenceEqual(pattern))
                {
                    tReturn.Add(source[i]);
                    i++;                    
                }
                else
                {
                    tReturn.Add(source[i]);
                }
            }
            return (byte[])tReturn.ToArray();
        }

        static int? PatternAt(byte[] source, byte[] pattern)
        {
            for (int i = 0; i < source.Length; i++)
            {
                if (source.Skip(i).Take(pattern.Length).SequenceEqual(pattern))
                {
                    return i;
                }
            }
            return null;
        }

        static string PrintByteArray(byte[] bytes)
        {
            var sb = new StringBuilder("new byte[] { ");
            foreach (var b in bytes)
            {
                sb.AppendFormat("{0:x2}", b);
                sb.Append(" ");
            }
            sb.Append("}");
            return sb.ToString();
        }

        ///

        public enum Crc16Mode : ushort { Standard = 0xA001, CcittKermit = 0x8408 }

        public class Crc16
        {
            static ushort[] table = new ushort[256];

            public ushort ComputeChecksum(params byte[] bytes)
            {
                ushort crc = 0;
                for (int i = 0; i < bytes.Length; ++i)
                {
                    byte index = (byte)(crc ^ bytes[i]);
                    crc = (ushort)((crc >> 8) ^ table[index]);
                }
                return crc;
            }

            public byte[] ComputeChecksumBytes(params byte[] bytes)
            {
                ushort crc = ComputeChecksum(bytes);
                return BitConverter.GetBytes(crc);
            }

            public Crc16(Crc16Mode mode)
            {
                ushort polynomial = (ushort)mode;
                ushort value;
                ushort temp;
                for (ushort i = 0; i < table.Length; ++i)
                {
                    value = 0;
                    temp = i;
                    for (byte j = 0; j < 8; ++j)
                    {
                        if (((value ^ temp) & 0x0001) != 0)
                        {
                            value = (ushort)((value >> 1) ^ polynomial);
                        }
                        else
                        {
                            value >>= 1;
                        }
                        temp >>= 1;
                    }
                    table[i] = value;
                }
            }
        }


        ////

    }

}