BLE Hands on Working with Characteristics Solution - joe-possum/IoT-Developer-Boot-Camp GitHub Wiki

#include "em_common.h"
#include "app_assert.h"
#include "sl_bluetooth.h"
#include "gatt_db.h"
#include "app.h"
#include "sl_sensor_rht.h"

// The advertising set handle allocated from Bluetooth stack.
static uint8_t advertising_set_handle = 0xff;
uint32_t nextMeasurementTick;
uint32_t interval;
uint8_t temperature_measurement_config;
uint8_t connection;

struct __attribute__((packed)) {
  uint8_t flags;
  uint32_t encodedValue;
} measurementData;

uint32_t encodeValue(float value) {
  uint8_t exponent = -3;
  int32_t number = 1000*value;
  return (0x00ffffff & number) | (exponent << 24);
}

/**************************************************************************//**
 * Application Init.
 *****************************************************************************/
void app_init(void)
{
  interval = sl_sleeptimer_get_timer_frequency();
  temperature_measurement_config = 0;
  sl_sensor_rht_init();
}

/**************************************************************************//**
 * Application Process Action.
 *****************************************************************************/
void app_process_action(void)
{
  uint32_t now = sl_sleeptimer_get_tick_count();
  if (now > nextMeasurementTick) {
      nextMeasurementTick = now + interval;
      if(2 == temperature_measurement_config) {
          sl_status_t sc;
          int32_t temperature = 0;
          uint32_t humidity = 0;
          // Measure temperature; units are % and milli-Celsius.
          sc = sl_sensor_rht_get(&humidity, &temperature);
          if(SL_STATUS_OK == sc) {
              measurementData.flags = 0;
              measurementData.encodedValue = encodeValue(1e-3 * temperature);
              sl_bt_gatt_server_send_indication(connection, gattdb_temperature_measurement, 5, (uint8_t*)&measurementData);
          }
      }
  }
}

/**************************************************************************//**
 * Bluetooth stack event handler.
 * This overrides the dummy weak implementation.
 *
 * @param[in] evt Event coming from the Bluetooth stack.
 *****************************************************************************/
void sl_bt_on_event(sl_bt_msg_t *evt)
{
  sl_status_t sc;
  bd_addr address;
  uint8_t address_type;
  uint8_t system_id[8];

  switch (SL_BT_MSG_ID(evt->header)) {
    // -------------------------------
    // This event indicates the device has started and the radio is ready.
    // Do not call any stack command before receiving this boot event!
    case sl_bt_evt_system_boot_id:
      // Extract unique ID from BT Address.
      sc = sl_bt_system_get_identity_address(&address, &address_type);
      app_assert_status(sc);

      // Pad and reverse unique ID to get System ID.
      system_id[0] = address.addr[5];
      system_id[1] = address.addr[4];
      system_id[2] = address.addr[3];
      system_id[3] = 0xFF;
      system_id[4] = 0xFE;
      system_id[5] = address.addr[2];
      system_id[6] = address.addr[1];
      system_id[7] = address.addr[0];

      sc = sl_bt_gatt_server_write_attribute_value(gattdb_system_id,
                                                   0,
                                                   sizeof(system_id),
                                                   system_id);
      app_assert_status(sc);

      // Create an advertising set.
      sc = sl_bt_advertiser_create_set(&advertising_set_handle);
      app_assert_status(sc);

      // Set advertising interval to 100ms.
      sc = sl_bt_advertiser_set_timing(
        advertising_set_handle,
        160, // min. adv. interval (milliseconds * 1.6)
        160, // max. adv. interval (milliseconds * 1.6)
        0,   // adv. duration
        0);  // max. num. adv. events
      app_assert_status(sc);
      // Start general advertising and enable connections.
      sc = sl_bt_advertiser_start(
        advertising_set_handle,
        sl_bt_advertiser_general_discoverable,
        sl_bt_advertiser_connectable_scannable);
      app_assert_status(sc);
      break;

    // -------------------------------
    // This event indicates that a new connection was opened.
    case sl_bt_evt_connection_opened_id:
      connection = evt->data.evt_connection_opened.connection;
      break;

    // -------------------------------
    // This event indicates that a connection was closed.
    case sl_bt_evt_connection_closed_id:
      temperature_measurement_config = 0; // no more indications after close
      // Restart advertising after client has disconnected.
      sc = sl_bt_advertiser_start(
        advertising_set_handle,
        sl_bt_advertiser_general_discoverable,
        sl_bt_advertiser_connectable_scannable);
      app_assert_status(sc);
      break;

    case sl_bt_evt_gatt_server_characteristic_status_id:
      if(gattdb_temperature_measurement == evt->data.evt_gatt_server_characteristic_status.characteristic) {
          if(1 == evt->data.evt_gatt_server_characteristic_status.status_flags) {
              temperature_measurement_config = evt->data.evt_gatt_server_characteristic_status.client_config_flags;
          }
      }
      break;


    ///////////////////////////////////////////////////////////////////////////
    // Add additional event handlers here as your application requires!      //
    ///////////////////////////////////////////////////////////////////////////

    // -------------------------------
    // Default event handler.
    default:
      break;
  }
}
⚠️ **GitHub.com Fallback** ⚠️