Swift Corebluetooth Reading a Float Array from Ble

Swift CoreBluetooth Reading a float array from BLE

Edit: this is the code I used for testing getting an array of floats from Data representation :

    let arr: [Float] = [32.0, 4.0, 1.2]
let data = Data(buffer: UnsafeBufferPointer(start: arr, count: arr.count))
print("---> data: \(data)")

var myFloatArray = Array<Float>(repeating: 0, count: data.count/MemoryLayout<Float>.stride)
myFloatArray.withUnsafeMutableBytes { data.copyBytes(to: $0) }

print("---> myFloatArray: \(myFloatArray)")

Properly reading 4 bytes in -Hex- NSData form into its proper data type (float or int) in Swift

After a while of research and community polling, I have found the answer from one of the community members at: http://forum.rfduino.com/index.php?topic=727.15#msg3393 So credit goes to him.

The code that properly translates the data into a UInt32 and then into a float is this:

  var test:UInt32 = 0

data.getBytes(&test, length: sizeof(NSInteger))
var floatVal:Float = unsafeBitCast(reversed, Float.self)
println(floatVal)

Assuming you have your 'data' variable as an NSData.

However if you have a similar problem but you need to flip the bytes before converting them into floats the code changes to this:

  var test:UInt32 = 0          
data.getBytes(&test, length: sizeof(NSInteger))
var reversed = test.byteSwapped
var floatVal:Float = unsafeBitCast(reversed, Float.self)
println(floatVal)

This solution accounts for both Endianness. Big thanks to Bill for providing this solution

An even smaller/better solution would be:

  var floatVal:Float = 0.0;
data.getBytes(&floatVal, length:sizeof(Float))
println(floatVal)

This one would does not flip bits tho, so if it doesn't need to swap bytes then this would be the safer/better route.

How to extract SFLOAT value from Bluetooth LE data for 1822 PulseOximeter using CoreBluetooth

Here it is:

Xcode 9.4.1 or Xcode 10.0 beta 3

iOS 11.4.1 or iOS 12.0 beta 3

Swift 4.1.2 or Swift 4.2

func floatFromTwosComplementUInt16(_ value: UInt16, havingBitsInValueIncludingSign bitsInValueIncludingSign: Int) -> Float {
// calculate a signed float from a two's complement signed value
// represented in the lowest n ("bitsInValueIncludingSign") bits
// of the UInt16 value
let signMask: UInt16 = UInt16(0x1) << (bitsInValueIncludingSign - 1)
let signMultiplier: Float = (value & signMask == 0) ? 1.0 : -1.0

var valuePart = value
if signMultiplier < 0 {
// Undo two's complement if it's negative
var valueMask = UInt16(1)
for _ in 0 ..< bitsInValueIncludingSign - 2 {
valueMask = valueMask << 1
valueMask += 1
}
valuePart = ((~value) & valueMask) &+ 1
}

let floatValue = Float(valuePart) * signMultiplier

return floatValue
}

func extractSFloat(values: [UInt8], startingIndex index: Int) -> Float {
// IEEE-11073 16-bit SFLOAT -> Float
let full = UInt16(values[index+1]) * 256 + UInt16(values[index])

// Check special values defined by SFLOAT first
if full == 0x07FF {
return Float.nan
} else if full == 0x800 {
return Float.nan // This is really NRes, "Not at this Resolution"
} else if full == 0x7FE {
return Float.infinity
} else if full == 0x0802 {
return -Float.infinity // This is really negative infinity
} else if full == 0x801 {
return Float.nan // This is really RESERVED FOR FUTURE USE
}

// Get exponent (high 4 bits)
let expo = (full & 0xF000) >> 12
let expoFloat = floatFromTwosComplementUInt16(expo, havingBitsInValueIncludingSign: 4)

// Get mantissa (low 12 bits)
let mantissa = full & 0x0FFF
let mantissaFloat = floatFromTwosComplementUInt16(mantissa, havingBitsInValueIncludingSign: 12)

// Put it together
let finalValue = mantissaFloat * pow(10.0, expoFloat)

return finalValue
}

The extraSFloat method takes a Uint8 array and an index into that array to indicate where the SFLOAT is. For example, if the array was two bytes (just the two bytes of the SFLOAT), then you would say:

let floatValue = extractSFloat(values: array, startingIndex: 0)

I did it this way because when working with Bluetooth data I always ended up with an array of UInt8 values containing the data I needed to decode.

How to send float data over BLE and display it properly on the UART (nRF Toolbox)

Reading the documentation of ble_nus_data_send helps:

Function for sending a data to the peer.
This function sends the input string as an RX characteristic notification to the peer.

Parameters
[in] p_nus Pointer to the Nordic UART Service structure.
[in] p_data String to be sent.
[in,out] p_length Pointer Length of the string. Amount of sent bytes.
[in] conn_handle Connection Handle of the destination client.

What you do is to cast a float pointer to uint8, thus, you

  1. transfer only one byte from the float bit representation
  2. transfer raw data which might be interpreted as string somewhere

You could use sprintf to convert your float to a valid string.

Or you try to violate the API (ugly) and convert your float raw data to uint8, meaning that one float results in probably 4 bytes. Now hope that the underlying code does not interpret something as string, for example 0 terminator or so.



Related Topics



Leave a reply



Submit