TeslasuitDocumentation
APIs

Read heart rate

C11 · Teslasuit v. 4.7+ · SDK 2.5.1+

Read live heart rate from a Teslasuit photoplethysmography (PPG) node: start raw streaming and print the heart rate as each reading arrives.

Code for heart rate data#

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <ts_api/ts_types.h>

#ifdef _WIN32
#include <Windows.h>
#elif defined(__APPLE__) || defined(__linux__)
#include <dlfcn.h>
#include <unistd.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define API_FUNCTION_NAME(name) name##_func_t

#define DECLARE_API_FUNCTION(ret, name, args)                                  \
  typedef ret(*API_FUNCTION_NAME(name)) args;                                  \
  static API_FUNCTION_NAME(name) name

#define LOAD_API_FUNCTION(lib, name)                                           \
  do {                                                                         \
    name = (API_FUNCTION_NAME(name))api_library_get_function(lib, #name);      \
    if (name == NULL)                                                          \
      return false;                                                            \
  } while (0)

typedef void *SharedLibrary;

static void *api_library_get_function(SharedLibrary lib,
                                      const char *function_name) {
#ifdef _WIN32
  return (void *)GetProcAddress((HMODULE)lib, function_name);
#elif defined(__APPLE__) || defined(__linux__)
  return dlsym(lib, function_name);
#endif
}

static void sleep_ms(int ms) {
#ifdef _WIN32
  Sleep(ms);
#elif defined(__APPLE__) || defined(__linux__)
  usleep(ms * 1000);
#endif
}

// device/session
DECLARE_API_FUNCTION(TsStatusCode, ts_initialize, ());
DECLARE_API_FUNCTION(void, ts_uninitialize, ());
DECLARE_API_FUNCTION(TsStatusCode, ts_get_device_list,
                     (TsDevice *, uint32_t *));
DECLARE_API_FUNCTION(TsDeviceHandle *, ts_device_open, (TsDevice *));
DECLARE_API_FUNCTION(const char *, ts_device_get_name, (TsDeviceHandle *));
DECLARE_API_FUNCTION(void, ts_device_close, (TsDeviceHandle *));
DECLARE_API_FUNCTION(const char *, ts_get_status_code_message, (TsStatusCode));

// ppg
DECLARE_API_FUNCTION(TsStatusCode, ts_ppg_set_update_callback,
                     (TsDeviceHandle *, TsPpgUpdatedCallback, void *));
DECLARE_API_FUNCTION(TsStatusCode, ts_ppg_start_streaming, (TsDeviceHandle *));
DECLARE_API_FUNCTION(TsStatusCode, ts_ppg_stop_streaming, (TsDeviceHandle *));
DECLARE_API_FUNCTION(TsStatusCode, ts_ppg_get_heart_rate,
                     (const TsPpgData, uint8_t, uint32_t *));

static bool load_api_functions(SharedLibrary lib) {
  // device/session
  LOAD_API_FUNCTION(lib, ts_initialize);
  LOAD_API_FUNCTION(lib, ts_uninitialize);
  LOAD_API_FUNCTION(lib, ts_get_device_list);
  LOAD_API_FUNCTION(lib, ts_device_open);
  LOAD_API_FUNCTION(lib, ts_device_get_name);
  LOAD_API_FUNCTION(lib, ts_device_close);
  LOAD_API_FUNCTION(lib, ts_get_status_code_message);

  // ppg
  LOAD_API_FUNCTION(lib, ts_ppg_set_update_callback);
  LOAD_API_FUNCTION(lib, ts_ppg_start_streaming);
  LOAD_API_FUNCTION(lib, ts_ppg_stop_streaming);
  LOAD_API_FUNCTION(lib, ts_ppg_get_heart_rate);
  return true;
}

static bool check_code(TsStatusCode code) {
  if (code != 0) {
    printf("Error: %s\n", ts_get_status_code_message(code));
    return false;
  }
  return true;
}

static void heart_rate_callback(TsDeviceHandle *dev, const TsPpgData ppg_data,
                                void *user_data) {
  (void)dev;
  (void)user_data;

  uint32_t heart_rate = 0;
  // Node 0: this device has one PPG sensor node, so it's always the suit
  // itself.
  if (check_code(ts_ppg_get_heart_rate(ppg_data, 0, &heart_rate))) {
    printf("Heart rate: %u\n", heart_rate);
  }
}

static void run(TsDeviceHandle *dev) {
  check_code(ts_ppg_set_update_callback(dev, heart_rate_callback, NULL));

  if (check_code(ts_ppg_start_streaming(dev))) {
    printf("Press any key to end\n");
    (void)getchar();

    ts_ppg_stop_streaming(dev);
  }
}

#ifdef __cplusplus
}
#endif

int main() {
  const char *api_path = getenv("TESLASUIT_API_LIB_PATH");
  if (api_path == NULL) {
    printf("Error: environment variable TESLASUIT_API_LIB_PATH not set\n");
    return 0;
  }

#ifdef _WIN32
  SharedLibrary lib = (SharedLibrary)LoadLibraryEx(
      api_path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
#elif defined(__APPLE__) || defined(__linux__)
  SharedLibrary lib = (SharedLibrary)dlopen(api_path, RTLD_NOW | RTLD_LOCAL);
#endif
  if (lib == NULL) {
    printf("Error: library was not found\n");
    return 0;
  }

  if (!load_api_functions(lib)) {
    printf("Error: failed to load library functions\n");
    goto unload;
  }

  if (!check_code(ts_initialize())) {
    printf("Error: failed to initialize API\n");
    // Nothing to uninitialize: it never successfully initialized.
    goto unload;
  }

  TsDevice device;
  uint32_t device_count = 0;
  while (device_count == 0) {
    printf("Waiting for a device...\n");
    device_count = 1;
    ts_get_device_list(&device, &device_count);
    sleep_ms(100);
  }

  TsDeviceHandle *dev = ts_device_open(&device);
  if (dev == NULL) {
    printf("Error: failed to get device\n");
    goto deinitialize;
  }
  printf("Using device: %s\n", ts_device_get_name(dev));

  run(dev);

  ts_device_close(dev);

deinitialize:
  ts_uninitialize();

unload:
#ifdef _WIN32
  FreeLibrary((HMODULE)lib);
#elif defined(__APPLE__) || defined(__linux__)
  dlclose(lib);
#endif
  return 0;
}

Expected output#

Waiting for a device...
Using device: Teslasuit XR-5
Press any key to end
Heart rate: 72
Heart rate: 74
...

Explore these references and guides to build on this example and get the most out of Teslasuit PPG features:

Essential API references#

Practical guides & examples#

Deeper dives & broader concepts#

  • PPG Main Concept: The conceptual background behind the photoplethysmography subsystem.
  • Teslasuit Main Concepts: Fundamental articles explaining Teslasuit technology and how PPG fits within the larger suite of subsystems.