packages feed

ble-0.4.1: examples/HeartRateClient.hs

module Main (main) where

import Bluetooth
import Control.Concurrent
import Data.Bits          (testBit)
import Data.Word          (Word16)

import qualified Data.ByteString as BS
import qualified Data.Serialize  as S


-- This example contains a demonstration of a client that interacts with a
-- Heart Rate Service.

main :: IO ()
main = do
  res <- connect >>= runBluetoothM go
  case res of
    Left e -> error $ show e
    Right () -> threadDelay 1000000000000

  where
    go = do
      mhrs <- getService "0000180d-0000-1000-8000-00805f9b34fb"
      let handler = case mhrs of
            Nothing  -> error "No heart rate service found!"
            Just hrs -> case filter
              (\x -> x ^. uuid == heartRateMeasurementUUID)
              (hrs ^. characteristics) of
              [] -> error "Couldn't find expected characteristics"
              measurementChar:_ -> measurementChar
      handleNotify handler

    handleNotify rmeasurement = startNotify rmeasurement $
      \x -> case deserializeMeasurement x of
        Nothing -> putStrLn "Error decoding value"
        Just v  -> do
          putStrLn $ "Received Heart Rate: " ++ show v

-- * Types

-- Heart rate in bpm
newtype HeartRate = HeartRate Integer
  deriving (Eq, Show, Read)

-- See https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
deserializeMeasurement :: BS.ByteString -> Maybe HeartRate
deserializeMeasurement bs = do
  (flags, dat) <- BS.uncons bs
  if not $ testBit flags 0
    -- Uses uint8
    then HeartRate . toInteger . fst <$> BS.uncons dat
    -- Uses uint16
    else case S.decode $ BS.take 2 dat of
      Left e -> error $ show e
      Right (v :: Word16) -> Just $ HeartRate $ toInteger v

-- * Constants

heartRateMeasurementUUID :: UUID
heartRateMeasurementUUID = "00002a37-0000-1000-8000-00805f9b34fb"