CRC-16 CCCITT проблема - неправильный расчет - PullRequest
0 голосов
/ 13 февраля 2019

Попытка реализовать эту контрольную сумму CITC CRC16 в моем мобильном приложении Bluetooth ios:

extension Data {

typealias bit_order_16 = (_ value: UInt16) -> UInt16
typealias bit_order_8 = (_ value: UInt8) -> UInt8


func crc16Check() -> UInt16 {
 let data = self as! NSData
    let bytes = UnsafePointer<UInt8>(data.bytes.assumingMemoryBound(to: UInt8.self))
    let length = data.length
    return crc16ccitt(message: bytes, nBytes: length)
}


func straight_16(value: UInt16) -> UInt16 {
    return value
}

func reverse_16(value: UInt16) -> UInt16 {
    var value = value
    var reversed: UInt16 = 0
    for i in stride(from: 0, to: 16, by: 1) {
        reversed <<= 1
        reversed |= (value & 0x1)
        value >>= 1
    }
    return reversed
}

func straight_8(value: UInt8) -> UInt8 {
    return value
}

func reverse_8(value: UInt8) -> UInt8 {
    var value = value
    var reversed: UInt8 = 0
    for i in stride(from: 0, to: 8, by: 1) {
        reversed <<= 1
        reversed |= (value & 0x1)
        value >>= 1
    }
    return reversed
}


func crc16(message: UnsafePointer<UInt8>, nBytes: Int, data_order: bit_order_8, remainder_order: bit_order_16, remainder: UInt16, polynomial: UInt16) -> UInt16 {
    var remainder = remainder

    for byte in stride(from: 0, to: nBytes, by: 1) {

        remainder ^= UInt16(data_order(message[byte]) << 8)
        var bit = 8
        while bit > 0 {
            if (remainder & 0x8000) != 0 {
                remainder = (remainder << 1) ^ 0x1021
            } else {
                remainder = (remainder << 1)
            }
            bit -= 1
        }
    }

    return remainder_order(remainder)
}


func crc16ccitt(message: UnsafePointer<UInt8>, nBytes: Int) -> UInt16 {

    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0xffff, polynomial: 0x1021)

}

func crc16ccitt_xmodem(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0x0000, polynomial: 0x1021)
}

func crc16ccitt_kermit(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    let swap = crc16(message: message, nBytes: nBytes, data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x1021)
    return swap << 8 | swap >> 8
}

func crc16ccitt_1d0f(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: straight_8, remainder_order: straight_16, remainder: 0x1d0f, polynomial: 0x1021)
}

func crc16ibm(message: UnsafeMutablePointer<UInt8>, nBytes: Int) -> UInt16 {
    return crc16(message: message, nBytes: nBytes, data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x8005)
}

}

Я установил фиксированный тип данных

 let tData = Data.init(bytes: [0x05, 0x02, 0x03] as [UInt8], count: 3)

    let crcString = String.init(format: "CRC error, calculated: %04X", tData.crc16Check())
    print(crcString)

// Распечатывает CC9C

CC9C неверен.

Ответ должен быть следующим: 716D

Невозможно найти ошибку в вычислении ccitt crc16.Может кто-нибудь помочь, пожалуйста, определить проблему, поскольку я действительно не уверен, где это не так.Потратил слишком много времени, пытаясь понять это.Буду признателен за любое время помощи со стороны сообщества.Спасибо.

1 Ответ

0 голосов
/ 14 февраля 2019

Ошибка - неправильный порядок операций:

remainder ^= UInt16(data_order(message[byte]) << 8)

8-битное значение data_order(message[byte]) смещено на 8 бит влево - результат всегда будет нулевым.Значение должно быть

remainder ^= UInt16(data_order(message[byte])) << 8

, чтобы число было преобразовано в 16-разрядное значение до смещения влево.

Эта проблема может не возникать ваналогичная C-программа, где все интегральные операнды перед вычислением переводятся в int - такие неявные преобразования типов не выполняются в Swift.

Другая ошибка заключается в том, что ваш func crc16() использует фиксированный полином 0x1021вместо аргумента polynomial.Это приводит к неверному результату для контрольной суммы crc16ibm.

Также обратите внимание, что преобразование в NSData в crc16Check() не требуется.Этот метод может быть упрощен до

func crc16Check() -> UInt16 {
    return self.withUnsafeBytes { [length = self.count] in
        crc16ccitt(message: $0, nBytes: length)
    }
}

Еще лучше: сделать оператор всех методов на self вместо передачи Unsafe(Mutable)Pointer s и длин вокруг:

extension Data {

    typealias bit_order_16 = (_ value: UInt16) -> UInt16
    typealias bit_order_8 = (_ value: UInt8) -> UInt8

    func straight_16(value: UInt16) -> UInt16 {
        return value
    }

    func reverse_16(value: UInt16) -> UInt16 {
        var value = value
        var reversed: UInt16 = 0
        for _ in 0..<16 {
            reversed <<= 1
            reversed |= (value & 0x1)
            value >>= 1
        }
        return reversed
    }

    func straight_8(value: UInt8) -> UInt8 {
        return value
    }

    func reverse_8(value: UInt8) -> UInt8 {
        var value = value
        var reversed: UInt8 = 0
        for _ in 0..<8 {
            reversed <<= 1
            reversed |= (value & 0x1)
            value >>= 1
        }
        return reversed
    }

    func crc16(data_order: bit_order_8, remainder_order: bit_order_16, remainder: UInt16, polynomial: UInt16) -> UInt16 {
        var remainder = remainder

        for byte in self {
            remainder ^= UInt16(data_order(byte)) << 8
            for _ in 0..<8 {
                if (remainder & 0x8000) != 0 {
                    remainder = (remainder << 1) ^ polynomial
                } else {
                    remainder = (remainder << 1)
                }
            }
        }
        return remainder_order(remainder)
    }

    func crc16ccitt() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0xffff, polynomial: 0x1021)
    }

    func crc16ccitt_xmodem() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0x0000, polynomial: 0x1021)
    }

    func crc16ccitt_kermit() -> UInt16 {
        let swap = crc16(data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x1021)
        return swap.byteSwapped
    }

    func crc16ccitt_1d0f() -> UInt16 {
        return crc16(data_order: straight_8, remainder_order: straight_16, remainder: 0x1d0f, polynomial: 0x1021)
    }

    func crc16ibm() -> UInt16 {
        return crc16(data_order: reverse_8, remainder_order: reverse_16, remainder: 0x0000, polynomial: 0x8005)
    }
}

Пример использования:

let tData = Data(bytes: [0x05, 0x02, 0x03])
print(String(format: "crc16ccitt:        %04X", tData.crc16ccitt()))        // 716D
print(String(format: "crc16ccitt_xmodem: %04X", tData.crc16ccitt_xmodem())) // BDF1
print(String(format: "crc16ccitt_kermit: %04X", tData.crc16ccitt_kermit())) // 9638
print(String(format: "crc16ccitt_1d0f:   %04X", tData.crc16ccitt_1d0f()))   // ACFD
print(String(format: "crc16ibm:          %04X", tData.crc16ibm()))          // 6051

Эти цифры совпадают с результатами этого Онлайн-калькулятора CRC .

...