3

公式にここに記載されているように、Bluetooth LE/Bluetoothスマート/ BLE健康装置サービス(0x1809)に接続しようとしています:https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml。具体的には、Health Thermometer Characteristic(0x2A1C)からの通知をリクエストしています。説明はhttps://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xmlです。スウィフトでBLE特性フロートを読み取る方法

私はまともなスウィフト2の背景を持っていますが、私はこれをNSData、バイト、またはビット演算子と密接に関連付けることはありませんでした。私はリトルエンディアンとビッグエンディアンを全く新しくしています。私はいくつかの助けをすることができます。特性には、受け取るデータを決定するロジックが組み込まれています。これまでのFlags、Temperature Measurement Value、Time Stampの順番で100%のデータを受け取っていますが、残念ながら私は常に "010"の制御ロジックを取得しています。つまり、フラグを誤って読み取っています。実際には、私はタイムスタンプのすべてのことを間違って持ち込んでいると思います。私は、コードのコメントにどのようなデータが含まれているのかを含めています。

このバイナリデータを取得する方法は複数試みました。フラグはビット演算子を持つ1バイトです。温度測定そのものはフロートで、スウィフトフロートではなく、ISO/IEEE規格「IEEE-11073 32ビットFLOAT」で、BLE仕様書には「NO EXPONENT VALUE "ここ:https://www.bluetooth.com/specifications/assigned-numbers/format-types。私はその意味が分からない。ここでは、私は新しいものを試して、私はコメントアウト私の複数の試みを見ることができますdidUpdateValueForCharacteristic()関数からの私のコードは次のとおりです。

// Parse Characteristic Response 
let stream = NSInputStream(data: characteristic.value!) 
stream.open() // IMPORTANT 

// Retrieve Flags 
var readBuffer = Array<UInt8>(count: 1, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
var flags = String(readBuffer[ 0 ], radix: 2) 
flags = String(count: 8 - flags.characters.count, repeatedValue: Character("0")) + flags 
flags = String(flags.characters.reverse()) 
print("FLAGS: \(flags)") 

// Example data: 
// ["01000000"] 
// 
// This appears to be wrong. I should be getting "10000000" according to spec 

// Bluetooth FLOAT-TYPE is defined in ISO/IEEE Std. 11073 
// FLOATs are 32 bit 
// Format [8bit exponent][24bit mantissa] 

/* Attempt 1 - Read in a Float - Doesn't work since it's an IEEE Float 
readBuffer = Array<UInt8>(count: 4, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
var tempData = UnsafePointer<Float>(readBuffer).memory 

// Attempt 2 - Inverted bytes- Doesn't work since it's wrong and it's an IEEE Float 
let readBuffer2 = [ readBuffer[ 3 ], readBuffer[ 2 ], readBuffer[ 1 ], readBuffer[ 0 ] ] 
var tempValue = UnsafePointer<Float>(readBuffer2).memory 
print("TEMP: \(tempValue)") 

// Attempt 3 - Doesn't work for 1 or 2 since it's an IEEE Float 
var f:Float = 0.0 
memccpy(&f, readBuffer, 4, 4) 
print("TEMP: \(f)") 
var f2:Float = 0.0 
memccpy(&f2, readBuffer2, 4, 4) 
print("TEMP: \(f2)") 

// Attempt 4 - Trying to Read an Exponent and a Mantissa - Didn't work 
readBuffer = Array<UInt8>(count: 1, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let exponent = UnsafePointer<Int8>(readBuffer).memory 

readBuffer = Array<UInt8>(count: 3, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let mantissa = UnsafePointer<Int16>(readBuffer).memory 

let temp = NSDecimalNumber(mantissa: mantissa, exponent: exponent, isNegative: false) 
print("TEMP: \(temp)") 

// Attempt 5 - Invert bytes - Doesn't work 
readBuffer = Array<UInt8>(count: 4, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let exponentBuffer = [ readBuffer[ 3 ] ] 
let mantissaBuffer = [ readBuffer[ 2 ], readBuffer[ 1 ], readBuffer[ 0 ] ] 
let exponent = UnsafePointer<Int16>(exponentBuffer).memory 
let mantissa = UnsafePointer<UInt64>(mantissaBuffer).memory 
let temp = NSDecimalNumber(mantissa: mantissa, exponent: exponent, isNegative: false) 
print("TEMP: \(temp)") 

// Attempt 6 - Tried a bitstream frontwards and backwards - Doesn't work 
readBuffer = Array<UInt8>(count: 4, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 

var bitBuffer: [String] = Array<String>(count:4, repeatedValue: "") 
for var i = 0; i < bitBuffer.count; i++ { 
    bitBuffer[ i ] = String(readBuffer[ i ], radix: 2) 
    bitBuffer[ i ] = String(count: 8 - bitBuffer[ i ].characters.count, repeatedValue: Character("0")) + bitBuffer[ i ] 
    //bitBuffer[ i ] = String(bitBuffer[ i ].characters.reverse()) 
} 
print("TEMP: \(bitBuffer)") 

// Attempt 7 - More like the Obj. C code - Doesn't work 
readBuffer = Array<UInt8>(count: 4, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let value = UnsafePointer<UInt32>(readBuffer).memory 
let tempData = CFSwapInt32LittleToHost(value) 

let exponent = tempData >> 24 
let mantissa = tempData & 0x00FFFFFF 

if (tempData == 0x007FFFFF) { 
    print(" *** INVALID *** ") 
    return 
} 

let tempValue = Double(mantissa) * pow(10.0, Double(exponent)) 
print("TEMP: \(tempValue)") 

// Attempt 8 - Saw that BLE spec says "NO Exponent" - Doesnt' work 
readBuffer = Array<UInt8>(count: 1, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 

readBuffer = Array<UInt8>(count: 3, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let tempValue = UnsafePointer<Float>(readBuffer).memory 
print("TEMP: \(tempValue)") 

// Example data: 
// ["00110110", "00000001", "00000000", "11111111"] 
// 
// Only the first byte appears to ever change. 
*/ 


// Timestamp - Year - works 
readBuffer = Array<UInt8>(count: 2, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let year = UnsafePointer<UInt16>(readBuffer).memory 

// Timestamp Remainder - works 
readBuffer = Array<UInt8>(count: 5, repeatedValue: 0) 
stream.read(&readBuffer, maxLength: readBuffer.count) 
let month = readBuffer[ 0 ] 
let day = readBuffer[ 1 ] 
let hour = readBuffer[ 2 ] 
let minute = readBuffer[ 3 ] 
let second = readBuffer[ 4 ] 
print("TIMESTAMP: \(month)/\(day)/\(year) \(hour):\(minute):\(second)") 

私はそうでない、Objective Cの中で、この例を見つけました正確に何が起こっているか(https://github.com/AngelSensor/angel-sdk/blob/b7459d9c86c6a5c72d8e58b696345b642286b876/iOS/SDK/Services/HealthThermometer/ANHTTemperatureMeasurmentCharacteristic.mを)知っている、と私はそれから作業しようとしたが、それは私にははっきりしていない:

// flags 
    uint8_t flags = dataPointer[0]; 
    dataPointer++; 

    // temperature 
    uint32_t tempData = (uint32_t)CFSwapInt32LittleToHost(*(uint32_t *)dataPointer); 
    dataPointer += 4; 

    int8_t exponent = (int8_t)(tempData >> 24); 
    int32_t mantissa = (int32_t)(tempData & 0x00FFFFFF); 

    if (tempData == 0x007FFFFF) { 
     return; 
    } 

    float tempValue = (float)(mantissa*pow(10, exponent)); 

が誰かからフラグと温度計の測定値を引く方法で私を助けることができる場合このBLEの特徴は、私はとても感謝しています。ありがとう。

以下のサンプルデータを入力するように求められました。ここに私のサンプルデータ(12バイトの合計):私はあなたに似たいくつかのものをやった

["00000010", "00110011", "00000001", "00000000", "11111111", "11100000", "00000111", "00000100", "00001111", "00000001", "00000101", "00101100"] 

-OR- 

<025e0100 ffe00704 0f11150f> 
+0

を使用する他のBLEの特性のために必要とするすべてのトリックは、あなたの入力データの例を投稿することができますほとんどのですか? – pbush25

+0

上記に含まれています。あなたが何か他のことを意味するかどうか私に教えてください。ありがとう。 – pennstump

+0

BLEから受け取ったビットから文字列の配列を作成していますか?私はあなたがちょうどあなたが投稿した最後の機能の目的が何であるかについて混乱しています。 – pbush25

答えて

0

をさんは、たぶん...それを掘るこれはまだあなたに関連するが、聞かせている場合...私はわからないんだけど、私のコードはあなたにいくつかの洞察力を与えることができる:

まず、UINT8の配列へのNSDataを取得:

let arr = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)) 

我々は以下の通りです仕様は、この配列の最初の3つの位置は、仮数を表すことになると述べていると最後のものは指数です(-128.1.127の範囲内):

let exponentRaw = input[3] 
    var exponent = Int16(exponentRaw) 

    if exponentRaw > 0x7F { 
     exponent = Int16(exponentRaw) - 0x100 
    } 

    let mantissa = sumBits(Array(input[0...2])) 

    let magnitude = pow(10.0, Float32(exponent)) 
    let value = Float32(mantissa) * magnitude 

...補助機能:

func sumBits(arr: [UInt8]) -> UInt64 { 
    var sum : UInt64 = 0 
    for (idx, val) in arr.enumerate() { 
     sum += UInt64(val) << (8 * UInt64(idx)) 
    } 
    return sum 
} 
2

時々周りを取得するために少しトリッキーなことができますが、ここに私の単純な実装です、それがバイトを変換し、ほとんどの方法に今

private func parseThermometerReading(withData someData : NSData?) { 
    var pointer = UnsafeMutablePointer<UInt8>(someData!.bytes) 
    let flagsValue = Int(pointer.memory) //First 8 bytes are the flag 

    let temperatureUnitisCelsius = (flagsValue & 0x01) == 0 
    let timeStampPresent   = (flagsValue & 0x02) > 0 
    let temperatureTypePresent = ((flagsValue & 0x04) >> 2) > 0 

    pointer = pointer.successor() //Jump over the flag byte (pointer is 1 bytes, so successor will automatically hot 8 bits), you can also user pointer = pointer.advanceBy(1), which is the same 

    let measurementValue : Float32 = self.parseFloat32(withPointer: pointer) //the parseFloat32 method is where the IEEE float conversion magic happens 
    pointer = pointer.advancedBy(4) //Skip 32 bits (Since pointer holds 1 byte (8 bits), to skip over 32 bits we need to jump 4 bytes (4 * 8 = 32 bits), we are now jumping over the measurement FLOAT 

    var timeStamp : NSDate? 

    if timeStampPresent { 
     //Parse timestamp 
     //ParseDate method is also a simple way to convert the 7 byte timestamp to an NSDate object, see it's implementation for more details 
     timeStamp = self.parseDate(withPointer: pointer) 
     pointer = pointer.advancedBy(7) //Skip over 7 bytes of timestamp 
    } 

    var temperatureType : Int = -1 //Some unknown value 

    if temperatureTypePresent { 
     //Parse measurement Type 
     temperatureType = Int(pointer.memory)) 
    } 
} 

をあなたを役に立てば幸いIEEEフロート

internal func parseFloat32(withPointer aPointer : UnsafeMutablePointer<UInt8>) -> Float32 { 
    // aPointer is 8bits long, we need to convert it to an 32Bit value 
    var rawValue = UnsafeMutablePointer<UInt32>(aPointer).memory //rawValue is now aPointer, but with 32 bits instead of just 8 
    let tempData = Int(CFSwapInt32LittleToHost(rawValue)) //We need to convert from BLE Little endian to match the current host's endianness 

    // The 32 bit value consists of a 8 bit exponent and a 24 bit mantissa 
    var mantissa : Int32 = Int32(tempData & 0x00FFFFFF) //We get the mantissa using bit masking (basically we mask out first 8 bits) 

    //UnsafeBitCast is the trick in swift here, since this is the only way to convert an UInt8 to a signed Int8, this is not needed in the ObjC examples that you'll see online since ObjC supports SInt* types 
    let exponent = unsafeBitCast(UInt8(tempData >> 24), Int8.self) 
    //And we get the exponent by shifting 24 bits, 32-24 = 8 (the exponent) 
    var output : Float32 = 0 

    //Here we do some checks for specific cases of Negative infinity/infinity, Reserved MDER values, etc.. 
    if mantissa >= Int32(FIRST_RESERVED_VALUE.rawValue) && mantissa <= Int32(ReservedFloatValues.MDER_NEGATIVE_INFINITY.rawValue) { 
     output = Float32(RESERVED_FLOAT_VALUES[mantissa - Int32(FIRST_S_RESERVED_VALUE.rawValue)]) 
    }else{ 
     //This is not a special reserved value, do the normal mathematical calculation to get the float value using mantissa and exponent. 
     if mantissa >= 0x800000 { 
      mantissa = -((0xFFFFFF + 1) - mantissa) 
     } 
     let magnitude = pow(10.0, Double(exponent)) 
     output = Float32(mantissa) * Float32(magnitude) 
    } 
    return output 
} 

そしてここでは、日付がNSDateオブジェクト

に解析する方法であります
internal func parseDate(withPointer aPointer : UnsafeMutablePointer<UInt8>) -> NSDate { 

    var bytePointer = aPointer //The given Unsigned Int8 pointer 
    var wordPointer = UnsafeMutablePointer<UInt16>(bytePointer) //We also hold a UInt16 pointer for the year, this is optional really, just easier to read 
    var year  = Int(CFSwapInt16LittleToHost(wordPointer.memory)) //This gives us the year 
    bytePointer  = bytePointer.advancedBy(2) //Skip 2 bytes (year) 
    //bytePointer  = wordPointer.successor() //Or you can do this using the word Pointer instead (successor will make it jump 2 bytes) 

    //The rest here is self explanatory 
    var month  = Int(bytePointer.memory) 
    bytePointer  = bytePointer.successor() 
    var day   = Int(bytePointer.memory) 
    bytePointer  = bytePointer.successor() 
    var hours  = Int(bytePointer.memory) 
    bytePointer  = bytePointer.successor() 
    var minutes  = Int(bytePointer.memory) 
    bytePointer  = bytePointer.successor() 
    var seconds  = Int(bytePointer.memory) 

    //Timestamp components parsed, create NSDate object 
    var calendar   = NSCalendar.currentCalendar() 
    var dateComponents  = calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: NSDate()) 
    dateComponents.year  = year 
    dateComponents.month = month 
    dateComponents.day  = day 
    dateComponents.hour  = hours 
    dateComponents.minute = minutes 
    dateComponents.second = seconds 

    return calendar.dateFromComponents(dateComponents)! 
} 

これはあなたにもFLOATタイプ

関連する問題