title: How to read a BLE Characteristic Float in Swift
body: <p>I am trying to connect to a Bluetooth LE / Bluetooth Smart / BLE health device's Health Thermometer Service (0x1809), as officially described here: <a href="https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml" rel="nofollow">https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml</a>.  Specifically, I'm requesting notifications from the Health Thermometer Characteristic (0x2A1C), with description here:  <a href="https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml" rel="nofollow">https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml</a>.  </p>
  
  <p>I have a decent Swift 2 background, but I've never worked this closely with NSData, bytes, or bitwise operators and I'm completely new to Little Endian vs. Big Endian, so this is pretty new for me and I could use some help.  The characteristic has some logic built in that determines what data you will receive.  I have received data in the order of Flags, Temperature Measurement Value and Time Stamp 100% of the time so far, but unfortunately I'm always going to get control logic of "010" which means I'm reading the flags incorrectly.  In truth, I think I'm bringing in everything shy of the timestamp incorrectly.  I'm including what data I'm seeing in the code comments.</p>
  
  <p>I've tried multiple ways of obtaining this binary data.  The flags are a single byte with bit operators.  The temperature measurement itself is a Float, which it took me some time to realize that it's not a Swift Float, but rather a ISO/IEEE Standard "IEEE-11073 32-bit FLOAT" with what the BLE spec says has "NO EXPONENT VALUE" here:  <a href="https://www.bluetooth.com/specifications/assigned-numbers/format-types" rel="nofollow">https://www.bluetooth.com/specifications/assigned-numbers/format-types</a>.  I don't even know what that means.  Here is my code from the didUpdateValueForCharacteristic() function where you can view my multiple attempts that I commented out as I tried a new one:</p>
  
  <pre><code>// Parse Characteristic Response
  let stream = NSInputStream( data: characteristic.value! )
  stream.open()    // IMPORTANT
  
  // Retrieve Flags
  var readBuffer = Array&lt;UInt8&gt;( count: 1, repeatedValue: 0 )
  stream.read( &amp;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&lt;UInt8&gt;( count: 4, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  var tempData = UnsafePointer&lt;Float&gt;( 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&lt;Float&gt;( 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(&amp;f, readBuffer, 4, 4)
  print( "TEMP: \( f )" )
  var f2:Float = 0.0
  memccpy(&amp;f2, readBuffer2, 4, 4)
  print( "TEMP: \( f2 )" )
  
  // Attempt 4 - Trying to Read an Exponent and a Mantissa - Didn't work
  readBuffer = Array&lt;UInt8&gt;( count: 1, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let exponent = UnsafePointer&lt;Int8&gt;( readBuffer ).memory
  
  readBuffer = Array&lt;UInt8&gt;( count: 3, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let mantissa = UnsafePointer&lt;Int16&gt;( readBuffer ).memory
  
  let temp = NSDecimalNumber( mantissa: mantissa, exponent: exponent, isNegative: false )
  print( "TEMP: \( temp )" )
  
  // Attempt 5 - Invert bytes - Doesn't work
  readBuffer = Array&lt;UInt8&gt;( count: 4, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let exponentBuffer = [ readBuffer[ 3 ] ]
  let mantissaBuffer = [ readBuffer[ 2 ], readBuffer[ 1 ], readBuffer[ 0 ] ]
  let exponent = UnsafePointer&lt;Int16&gt;( exponentBuffer ).memory
  let mantissa = UnsafePointer&lt;UInt64&gt;( 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&lt;UInt8&gt;( count: 4, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  
  var bitBuffer: [String] = Array&lt;String&gt;( count:4, repeatedValue: "" )
  for var i = 0; i &lt; 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&lt;UInt8&gt;( count: 4, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let value = UnsafePointer&lt;UInt32&gt;( readBuffer ).memory
  let tempData = CFSwapInt32LittleToHost( value )
  
  let exponent = tempData &gt;&gt; 24
  let mantissa = tempData &amp; 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&lt;UInt8&gt;( count: 1, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  
  readBuffer = Array&lt;UInt8&gt;( count: 3, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let tempValue = UnsafePointer&lt;Float&gt;( readBuffer ).memory
  print( "TEMP: \( tempValue )" )
  
  // Example data:
  // ["00110110", "00000001", "00000000", "11111111"]
  //
  // Only the first byte appears to ever change.
  */
  
  
  // Timestamp - Year - works
  readBuffer = Array&lt;UInt8&gt;( count: 2, repeatedValue: 0 )
  stream.read( &amp;readBuffer, maxLength: readBuffer.count )
  let year = UnsafePointer&lt;UInt16&gt;( readBuffer ).memory
  
  // Timestamp Remainder - works
  readBuffer = Array&lt;UInt8&gt;( count: 5, repeatedValue: 0 )
  stream.read( &amp;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 )" )
  </code></pre>
  
  <p>I've found this example in Objective C, which I don't know (<a href="https://github.com/AngelSensor/angel-sdk/blob/b7459d9c86c6a5c72d8e58b696345b642286b876/iOS/SDK/Services/HealthThermometer/ANHTTemperatureMeasurmentCharacteristic.m" rel="nofollow">https://github.com/AngelSensor/angel-sdk/blob/b7459d9c86c6a5c72d8e58b696345b642286b876/iOS/SDK/Services/HealthThermometer/ANHTTemperatureMeasurmentCharacteristic.m</a>), and I've tried to work from it, but it's not clear to me what exactly is going on:</p>
  
  <pre><code>    // 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 &gt;&gt; 24);
      int32_t mantissa = (int32_t)(tempData &amp; 0x00FFFFFF);
  
      if (tempData == 0x007FFFFF) {
          return;
      }
  
      float tempValue = (float)(mantissa*pow(10, exponent));
  </code></pre>
  
  <p>If someone could help me out with how to pull the flags and thermometer measurements from this BLE Characteristic, I would be very grateful.  Thanks.</p>
  
  <p>I was asked to give sample data below.  Here's my sample data (12 bytes total):</p>
  
  <pre><code>["00000010", "00110011", "00000001", "00000000", "11111111", "11100000", "00000111", "00000100", "00001111", "00000001", "00000101", "00101100"]
  
  -OR-
  
  &lt;025e0100 ffe00704 0f11150f&gt;
  </code></pre>