Как преобразовать метод Obj-C с байтами NSData с помощью побитовых операторов в Swift - PullRequest
0 голосов
/ 01 июня 2018

Я пытаюсь преобразовать метод Objective C в Swift, но для этого мне нужна помощь в понимании происходящего.

Для контекста ввод этого метода начинается как NSString, который затем преобразуется в объект NSData с кодировкой utf8.Затем байты этого объекта данных передаются в метод (параметр message).

Возвращаемое значение этого метода затем отправляется через writeData определенной характеристике CBPeripheral.

Вот что я понимаю (с точки зрения Swift).

  • Передаваемое сообщение представляет собой UInt8 байтовый массив: [UInt8]
  • 3 переменные созданыкак UInt32 значения;crcVal, byteVal и mask
  • crcVal затем устанавливаются на максимальное значение UInt32 type
  • каждый байт из байтового массива UInt8, переданного в:затем проходит цикл и выполняется какая-то операция для получения и добавления к окончательному результату значения crcVal, которое в конечном итоге используется для отправки через команду writeData CoreBluetooth в CBPeripheral.

Я не очень разбираюсь в побитовых операторах или в том, почему метод, описанный ниже, делает то, что делает, так как нет документации.Может кто-нибудь помочь прояснить некоторые или все части этого?Я надеюсь написать Swift эквивалентную версию этого метода.Спасибо.

- (uint32_t) computeCRC:(uint8_t *)message len:(NSUInteger)msgLen {

    uint32_t crcVal = 0, byteVal, mask;

    crcVal = 0xFFFFFFFF;
    for (int i=0; i<msgLen; i++) {
        byteVal = message[i];
        crcVal ^= byteVal;
        for (int j=7; j>=0; j--) {
            mask = -(crcVal&1);
            crcVal = (crcVal>>1)^(0xEDB88320 & mask);
        }
    }

    return ~crcVal;
}

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

Для расчета CRC16 вы можете использовать

import Foundation

extension Data {

    enum CRCType {
        case MODBUS
        case ARC
    }

    static func crc16(_ data: [UInt8], type: CRCType) -> UInt16? {
        if data.isEmpty {
            return nil
        }
        let polynomial: UInt16 = 0xA001 // A001 is the bit reverse of 8005
        var accumulator: UInt16
        // set the accumulator initial value based on CRC type
        if type == .ARC {
            accumulator = 0
        } else {
            // default to MODBUS
            accumulator = 0xFFFF
        }
        // main computation loop
        for byte in data {
            var tempByte = UInt16(byte)
            for _ in 0 ..< 8 {
                let temp1 = accumulator & 0x0001
                accumulator = accumulator >> 1
                let temp2 = tempByte & 0x0001
                tempByte = tempByte >> 1
                if (temp1 ^ temp2) == 1 {
                    accumulator = accumulator ^ polynomial
                }
            }
        }
        return accumulator
    }
}

Источник здесь

0 голосов
/ 01 июня 2018

Вместо написания реализации с нуля, почему бы вам не использовать реализацию zlib crc32?:

import zlib

func crc32(from data: Data) -> UInt {
    return data.withUnsafeBytes { (buffer: UnsafePointer<Bytef>) -> UInt in
       return zlib.crc32(0, buffer, uInt(data.count))
    }
}

Однако, чтобы помочь вам понять побитовые операции:

func computeCRC(message: [UInt8]) -> UInt32 {
    var crc: UInt32 = 0xFFFFFFFF

    for byte in message {
        crc ^= UInt32(byte)
        for _ in 0 ..< 8 {
            // negation using 2-complement: -x = ~x + 1
            // use &+ addition with overflow
            let mask = ~(crc & 1) &+ 1
            crc = (crc >> 1) ^ (0xEDB88320 & mask)
        }
    }

    return ~crc
}

Обратите внимание, что нам не нужно передавать число байтов в Swift.Реализации имеют разные сигнатуры и возвращают немного другой тип, но обе они дают одинаковый результат.

...