First commit

This commit is contained in:
ktownsend 2013-11-29 14:42:22 +00:00
commit ef8c4ede68
12 changed files with 1067 additions and 0 deletions

48
blecharacteristic.cpp Normal file
View file

@ -0,0 +1,48 @@
#include <stdio.h>
#include <string.h>
#include "blecharacteristic.h"
/**************************************************************************/
/*!
@brief Creates a new BLECharacteristic using the specified 16-bit
UUID, value length, and properties
@note The UUID value must be unique in the service and is normally >1
@param[in] id
The 16-bit UUID to use for this characteristic
@param[in] minLen
The min length in bytes of this characteristic's value
@param[in] maxLen
The max length in bytes of this characteristic's value
@param[in] props
The 8-bit bit field containing the characteristic's
properties
@section EXAMPLE
@code
// UUID = 0x2A19, Min length 2, Max len = 2, Properties = write
BLECharacteristic c = BLECharacteristic( 0x2A19, 2, 2, 0x08 );
@endcode
*/
/**************************************************************************/
BLECharacteristic::BLECharacteristic(uint16_t id, uint16_t minLen, uint16_t maxLen, uint8_t props)
{
uuid = id;
memcpy(&properties, &props, 1);
lenMin = minLen;
lenMax = maxLen;
}
/**************************************************************************/
/*!
Destructor
*/
/**************************************************************************/
BLECharacteristic::~BLECharacteristic(void)
{
}

33
blecharacteristic.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef __BLE_CHARACTERISTIC_H__
#define __BLE_CHARACTERISTIC_H__
#include "blecommon.h"
#include "uuid.h"
class BLECharacteristic
{
private:
public:
BLECharacteristic(uint16_t uuid, uint16_t minLen, uint16_t maxLen, uint8_t properties);
virtual ~BLECharacteristic(void);
uint16_t uuid; /* Characteristic UUID */
uint16_t lenMin; /* Minimum length of the value */
uint16_t lenMax; /* Maximum length of the value */
uint8_t index;
struct Properties
{
/* Standard properties */
uint8_t broadcast :1; /**< Broadcasting of value permitted. */
uint8_t read :1; /**< Reading value permitted. */
uint8_t write_wo_resp :1; /**< Writing value with Write Command permitted. */
uint8_t write :1; /**< Writing value with Write Request permitted. */
uint8_t notify :1; /**< Notications of value permitted. */ // https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
uint8_t indicate :1; /**< Indications of value permitted. */ // https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
uint8_t auth_signed_wr :1; /**< Writing value with Signed Write Command permitted. */
} properties;
};
#endif

239
blecommon.h Normal file
View file

@ -0,0 +1,239 @@
#ifndef __BLE_COMMON_H__
#define __BLE_COMMON_H__
#include <stdint.h>
typedef enum ble_error_e
{
BLE_ERROR_NONE = 0
} ble_error_t;
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
typedef enum ble_gap_char_appearance_e
{
BLE_GAP_CHAR_APPEARANCE_UNKNOWN = 0,
BLE_GAP_CHAR_APPEARANCE_GENERIC_PHONE = 64,
BLE_GAP_CHAR_APPEARANCE_GENERIC_COMPUTER = 128,
BLE_GAP_CHAR_APPEARANCE_GENERIC_WATCH = 192,
BLE_GAP_CHAR_APPEARANCE_WATCH_SPORTS_WATCH = 193,
BLE_GAP_CHAR_APPEARANCE_GENERIC_CLOCK = 256,
BLE_GAP_CHAR_APPEARANCE_GENERIC_DISPLAY = 320,
BLE_GAP_CHAR_APPEARANCE_GENERIC_REMOTE_CONTROL = 384,
BLE_GAP_CHAR_APPEARANCE_GENERIC_EYE_GLASSES = 448,
BLE_GAP_CHAR_APPEARANCE_GENERIC_TAG = 512,
BLE_GAP_CHAR_APPEARANCE_GENERIC_KEYRING = 576,
BLE_GAP_CHAR_APPEARANCE_GENERIC_MEDIA_PLAYER = 640,
BLE_GAP_CHAR_APPEARANCE_GENERIC_BARCODE_SCANNER = 704,
BLE_GAP_CHAR_APPEARANCE_GENERIC_THERMOMETER = 768,
BLE_GAP_CHAR_APPEARANCE_THERMOMETER_EAR = 769,
BLE_GAP_CHAR_APPEARANCE_GENERIC_HEART_RATE_SENSOR = 832,
BLE_GAP_CHAR_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT = 833,
BLE_GAP_CHAR_APPEARANCE_GENERIC_BLOOD_PRESSURE = 896,
BLE_GAP_CHAR_APPEARANCE_BLOOD_PRESSURE_ARM = 897,
BLE_GAP_CHAR_APPEARANCE_BLOD_PRESSURE_WRIST = 898,
BLE_GAP_CHAR_APPEARANCE_HUMAN_INTERFACE_DEVICE_HID = 960,
BLE_GAP_CHAR_APPEARANCE_KEYBOARD = 961,
BLE_GAP_CHAR_APPEARANCE_MOUSE = 962,
BLE_GAP_CHAR_APPEARANCE_JOYSTICK = 963,
BLE_GAP_CHAR_APPEARANCE_GAMEPAD = 964,
BLE_GAP_CHAR_APPEARANCE_DIGITIZER_TABLET = 965,
BLE_GAP_CHAR_APPEARANCE_CARD_READER = 966,
BLE_GAP_CHAR_APPEARANCE_DIGITAL_PEN = 967,
BLE_GAP_CHAR_APPEARANCE_BARCODE_SCANNER = 968,
BLE_GAP_CHAR_APPEARANCE_GENERIC_GLUCOSE_METER = 1024,
BLE_GAP_CHAR_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR = 1088,
BLE_GAP_CHAR_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE = 1089,
BLE_GAP_CHAR_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE = 1090,
BLE_GAP_CHAR_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP = 1091,
BLE_GAP_CHAR_APPEARANCE_GENERIC_CYCLING = 1152,
BLE_GAP_CHAR_APPEARANCE_CYCLING_CYCLING_COMPUTER = 1153,
BLE_GAP_CHAR_APPEARANCE_CYCLING_SPEED_SENSOR = 1154,
BLE_GAP_CHAR_APPEARANCE_CYCLING_CADENCE_SENSOR = 1155,
BLE_GAP_CHAR_APPEARANCE_CYCLING_POWER_SENSOR = 1156,
BLE_GAP_CHAR_APPEARANCE_CYCLING_SPEED_AND_CADENCE_SENSOR = 1157,
BLE_GAP_CHAR_APPEARANCE_PULSE_OXIMETER_GENERIC = 3136,
BLE_GAP_CHAR_APPEARANCE_PULSE_OXIMETERFINGERTIP = 3137,
BLE_GAP_CHAR_APPEARANCE_PULSE_OXIMETERWRIST_WORN = 3138,
BLE_GAP_CHAR_APPEARANCE_OUTDOOR_GENERIC = 5184,
BLE_GAP_CHAR_APPEARANCE_OUTDOOR_LOCATION_DISPLAY_DEVICE = 5185,
BLE_GAP_CHAR_APPEARANCE_OUTDOOR_LOCATION_AND_NAVIGATION_DISPLAY_DEVICE = 5186,
BLE_GAP_CHAR_APPEARANCE_OUTDOOR_LOCATION_POD = 5187,
BLE_GAP_CHAR_APPEARANCE_OUTDOOR_LOCATION_AND_NAVIGATION_POD = 5188
} ble_gap_char_appearance_t;
// https://developer.bluetooth.org/gatt/units/Pages/default.aspx
typedef enum ble_gatt_unit_e
{
BLE_GATT_UNIT_NONE = 0x2700,
BLE_GATT_UNIT_LENGTH_METRE = 0x2701,
BLE_GATT_UNIT_MASS_KILOGRAM = 0x2702,
BLE_GATT_UNIT_TIME_SECOND = 0x2703,
BLE_GATT_UNIT_ELECTRIC_CURRENT_AMPERE = 0x2704,
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_KELVIN = 0x2705,
BLE_GATT_UNIT_AMOUNT_OF_SUBSTANCE_MOLE = 0x2706,
BLE_GATT_UNIT_LUMINOUS_INTENSITY_CANDELA = 0x2707,
BLE_GATT_UNIT_AREA_SQUARE_METRES = 0x2710,
BLE_GATT_UNIT_VOLUME_CUBIC_METRES = 0x2711,
BLE_GATT_UNIT_VELOCITY_METRES_PER_SECOND = 0x2712,
BLE_GATT_UNIT_ACCELERATION_METRES_PER_SECOND_SQUARED = 0x2713,
BLE_GATT_UNIT_WAVENUMBER_RECIPROCAL_METRE = 0x2714,
BLE_GATT_UNIT_DENSITY_KILOGRAM_PER_CUBIC_METRE = 0x2715,
BLE_GATT_UNIT_SURFACE_DENSITY_KILOGRAM_PER_SQUARE_METRE = 0x2716,
BLE_GATT_UNIT_SPECIFIC_VOLUME_CUBIC_METRE_PER_KILOGRAM = 0x2717,
BLE_GATT_UNIT_CURRENT_DENSITY_AMPERE_PER_SQUARE_METRE = 0x2718,
BLE_GATT_UNIT_MAGNETIC_FIELD_STRENGTH_AMPERE_PER_METRE = 0x2719,
BLE_GATT_UNIT_AMOUNT_CONCENTRATION_MOLE_PER_CUBIC_METRE = 0x271A,
BLE_GATT_UNIT_MASS_CONCENTRATION_KILOGRAM_PER_CUBIC_METRE = 0x271B,
BLE_GATT_UNIT_LUMINANCE_CANDELA_PER_SQUARE_METRE = 0x271C,
BLE_GATT_UNIT_REFRACTIVE_INDEX = 0x271D,
BLE_GATT_UNIT_RELATIVE_PERMEABILITY = 0x271E,
BLE_GATT_UNIT_PLANE_ANGLE_RADIAN = 0x2720,
BLE_GATT_UNIT_SOLID_ANGLE_STERADIAN = 0x2721,
BLE_GATT_UNIT_FREQUENCY_HERTZ = 0x2722,
BLE_GATT_UNIT_FORCE_NEWTON = 0x2723,
BLE_GATT_UNIT_PRESSURE_PASCAL = 0x2724,
BLE_GATT_UNIT_ENERGY_JOULE = 0x2725,
BLE_GATT_UNIT_POWER_WATT = 0x2726,
BLE_GATT_UNIT_ELECTRIC_CHARGE_COULOMB = 0x2727,
BLE_GATT_UNIT_ELECTRIC_POTENTIAL_DIFFERENCE_VOLT = 0x2728,
BLE_GATT_UNIT_CAPACITANCE_FARAD = 0x2729,
BLE_GATT_UNIT_ELECTRIC_RESISTANCE_OHM = 0x272A,
BLE_GATT_UNIT_ELECTRIC_CONDUCTANCE_SIEMENS = 0x272B,
BLE_GATT_UNIT_MAGNETIC_FLEX_WEBER = 0x272C,
BLE_GATT_UNIT_MAGNETIC_FLEX_DENSITY_TESLA = 0x272D,
BLE_GATT_UNIT_INDUCTANCE_HENRY = 0x272E,
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_CELSIUS = 0x272F,
BLE_GATT_UNIT_LUMINOUS_FLUX_LUMEN = 0x2730,
BLE_GATT_UNIT_ILLUMINANCE_LUX = 0x2731,
BLE_GATT_UNIT_ACTIVITY_REFERRED_TO_A_RADIONUCLIDE_BECQUEREL = 0x2732,
BLE_GATT_UNIT_ABSORBED_DOSE_GRAY = 0x2733,
BLE_GATT_UNIT_DOSE_EQUIVALENT_SIEVERT = 0x2734,
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_KATAL = 0x2735,
BLE_GATT_UNIT_DYNAMIC_VISCOSITY_PASCAL_SECOND = 0x2740,
BLE_GATT_UNIT_MOMENT_OF_FORCE_NEWTON_METRE = 0x2741,
BLE_GATT_UNIT_SURFACE_TENSION_NEWTON_PER_METRE = 0x2742,
BLE_GATT_UNIT_ANGULAR_VELOCITY_RADIAN_PER_SECOND = 0x2743,
BLE_GATT_UNIT_ANGULAR_ACCELERATION_RADIAN_PER_SECOND_SQUARED = 0x2744,
BLE_GATT_UNIT_HEAT_FLUX_DENSITY_WATT_PER_SQUARE_METRE = 0x2745,
BLE_GATT_UNIT_HEAT_CAPACITY_JOULE_PER_KELVIN = 0x2746,
BLE_GATT_UNIT_SPECIFIC_HEAT_CAPACITY_JOULE_PER_KILOGRAM_KELVIN = 0x2747,
BLE_GATT_UNIT_SPECIFIC_ENERGY_JOULE_PER_KILOGRAM = 0x2748,
BLE_GATT_UNIT_THERMAL_CONDUCTIVITY_WATT_PER_METRE_KELVIN = 0x2749,
BLE_GATT_UNIT_ENERGY_DENSITY_JOULE_PER_CUBIC_METRE = 0x274A,
BLE_GATT_UNIT_ELECTRIC_FIELD_STRENGTH_VOLT_PER_METRE = 0x274B,
BLE_GATT_UNIT_ELECTRIC_CHARGE_DENSITY_COULOMB_PER_CUBIC_METRE = 0x274C,
BLE_GATT_UNIT_SURFACE_CHARGE_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274D,
BLE_GATT_UNIT_ELECTRIC_FLUX_DENSITY_COULOMB_PER_SQUARE_METRE = 0x274E,
BLE_GATT_UNIT_PERMITTIVITY_FARAD_PER_METRE = 0x274F,
BLE_GATT_UNIT_PERMEABILITY_HENRY_PER_METRE = 0x2750,
BLE_GATT_UNIT_MOLAR_ENERGY_JOULE_PER_MOLE = 0x2751,
BLE_GATT_UNIT_MOLAR_ENTROPY_JOULE_PER_MOLE_KELVIN = 0x2752,
BLE_GATT_UNIT_EXPOSURE_COULOMB_PER_KILOGRAM = 0x2753,
BLE_GATT_UNIT_ABSORBED_DOSE_RATE_GRAY_PER_SECOND = 0x2754,
BLE_GATT_UNIT_RADIANT_INTENSITY_WATT_PER_STERADIAN = 0x2755,
BLE_GATT_UNIT_RADIANCE_WATT_PER_SQUARE_METRE_STERADIAN = 0x2756,
BLE_GATT_UNIT_CATALYTIC_ACTIVITY_CONCENTRATION_KATAL_PER_CUBIC_METRE = 0x2757,
BLE_GATT_UNIT_TIME_MINUTE = 0x2760,
BLE_GATT_UNIT_TIME_HOUR = 0x2761,
BLE_GATT_UNIT_TIME_DAY = 0x2762,
BLE_GATT_UNIT_PLANE_ANGLE_DEGREE = 0x2763,
BLE_GATT_UNIT_PLANE_ANGLE_MINUTE = 0x2764,
BLE_GATT_UNIT_PLANE_ANGLE_SECOND = 0x2765,
BLE_GATT_UNIT_AREA_HECTARE = 0x2766,
BLE_GATT_UNIT_VOLUME_LITRE = 0x2767,
BLE_GATT_UNIT_MASS_TONNE = 0x2768,
BLE_GATT_UNIT_PRESSURE_BAR = 0x2780,
BLE_GATT_UNIT_PRESSURE_MILLIMETRE_OF_MERCURY = 0x2781,
BLE_GATT_UNIT_LENGTH_ANGSTROM = 0x2782,
BLE_GATT_UNIT_LENGTH_NAUTICAL_MILE = 0x2783,
BLE_GATT_UNIT_AREA_BARN = 0x2784,
BLE_GATT_UNIT_VELOCITY_KNOT = 0x2785,
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_NEPER = 0x2786,
BLE_GATT_UNIT_LOGARITHMIC_RADIO_QUANTITY_BEL = 0x2787,
BLE_GATT_UNIT_LENGTH_YARD = 0x27A0,
BLE_GATT_UNIT_LENGTH_PARSEC = 0x27A1,
BLE_GATT_UNIT_LENGTH_INCH = 0x27A2,
BLE_GATT_UNIT_LENGTH_FOOT = 0x27A3,
BLE_GATT_UNIT_LENGTH_MILE = 0x27A4,
BLE_GATT_UNIT_PRESSURE_POUND_FORCE_PER_SQUARE_INCH = 0x27A5,
BLE_GATT_UNIT_VELOCITY_KILOMETRE_PER_HOUR = 0x27A6,
BLE_GATT_UNIT_VELOCITY_MILE_PER_HOUR = 0x27A7,
BLE_GATT_UNIT_ANGULAR_VELOCITY_REVOLUTION_PER_MINUTE = 0x27A8,
BLE_GATT_UNIT_ENERGY_GRAM_CALORIE = 0x27A9,
BLE_GATT_UNIT_ENERGY_KILOGRAM_CALORIE = 0x27AA,
BLE_GATT_UNIT_ENERGY_KILOWATT_HOUR = 0x27AB,
BLE_GATT_UNIT_THERMODYNAMIC_TEMPERATURE_DEGREE_FAHRENHEIT = 0x27AC,
BLE_GATT_UNIT_PERCENTAGE = 0x27AD,
BLE_GATT_UNIT_PER_MILLE = 0x27AE,
BLE_GATT_UNIT_PERIOD_BEATS_PER_MINUTE = 0x27AF,
BLE_GATT_UNIT_ELECTRIC_CHARGE_AMPERE_HOURS = 0x27B0,
BLE_GATT_UNIT_MASS_DENSITY_MILLIGRAM_PER_DECILITRE = 0x27B1,
BLE_GATT_UNIT_MASS_DENSITY_MILLIMOLE_PER_LITRE = 0x27B2,
BLE_GATT_UNIT_TIME_YEAR = 0x27B3,
BLE_GATT_UNIT_TIME_MONTH = 0x27B4,
BLE_GATT_UNIT_CONCENTRATION_COUNT_PER_CUBIC_METRE = 0x27B5,
BLE_GATT_UNIT_IRRADIANCE_WATT_PER_SQUARE_METRE = 0x27B6
} ble_gatt_unit_t;
// http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
typedef enum ble_gatt_format_e
{
BLE_GATT_FORMAT_RFU = 0x00, /**< Reserved For Future Use. */
BLE_GATT_FORMAT_BOOLEAN = 0x01, /**< Boolean. */
BLE_GATT_FORMAT_2BIT = 0x02, /**< Unsigned 2-bit integer. */
BLE_GATT_FORMAT_NIBBLE = 0x03, /**< Unsigned 4-bit integer. */
BLE_GATT_FORMAT_UINT8 = 0x04, /**< Unsigned 8-bit integer. */
BLE_GATT_FORMAT_UINT12 = 0x05, /**< Unsigned 12-bit integer. */
BLE_GATT_FORMAT_UINT16 = 0x06, /**< Unsigned 16-bit integer. */
BLE_GATT_FORMAT_UINT24 = 0x07, /**< Unsigned 24-bit integer. */
BLE_GATT_FORMAT_UINT32 = 0x08, /**< Unsigned 32-bit integer. */
BLE_GATT_FORMAT_UINT48 = 0x09, /**< Unsigned 48-bit integer. */
BLE_GATT_FORMAT_UINT64 = 0x0A, /**< Unsigned 64-bit integer. */
BLE_GATT_FORMAT_UINT128 = 0x0B, /**< Unsigned 128-bit integer. */
BLE_GATT_FORMAT_SINT8 = 0x0C, /**< Signed 2-bit integer. */
BLE_GATT_FORMAT_SINT12 = 0x0D, /**< Signed 12-bit integer. */
BLE_GATT_FORMAT_SINT16 = 0x0E, /**< Signed 16-bit integer. */
BLE_GATT_FORMAT_SINT24 = 0x0F, /**< Signed 24-bit integer. */
BLE_GATT_FORMAT_SINT32 = 0x10, /**< Signed 32-bit integer. */
BLE_GATT_FORMAT_SINT48 = 0x11, /**< Signed 48-bit integer. */
BLE_GATT_FORMAT_SINT64 = 0x12, /**< Signed 64-bit integer. */
BLE_GATT_FORMAT_SINT128 = 0x13, /**< Signed 128-bit integer. */
BLE_GATT_FORMAT_FLOAT32 = 0x14, /**< IEEE-754 32-bit floating point. */
BLE_GATT_FORMAT_FLOAT64 = 0x15, /**< IEEE-754 64-bit floating point. */
BLE_GATT_FORMAT_SFLOAT = 0x16, /**< IEEE-11073 16-bit SFLOAT. */
BLE_GATT_FORMAT_FLOAT = 0x17, /**< IEEE-11073 32-bit FLOAT. */
BLE_GATT_FORMAT_DUINT16 = 0x18, /**< IEEE-20601 format. */
BLE_GATT_FORMAT_UTF8S = 0x19, /**< UTF-8 string. */
BLE_GATT_FORMAT_UTF16S = 0x1A, /**< UTF-16 string. */
BLE_GATT_FORMAT_STRUCT = 0x1B /**< Opaque Structure. */
} ble_gatt_format_t;
struct UTF8String
{
uint16_t length; /**< String length. */
uint8_t str[32]; /**< String data. */
};
struct UTF16String
{
uint16_t length; /**< String length. */
uint16_t str[32]; /**< String data. */
};
struct SecurityMode
{
uint8_t mode; /**< Security Mode (1 or 2), 0 for no permissions at all. */
uint8_t level; /**< Level (1, 2 or 3), 0 for no permissions at all. */
};
// See https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
struct PresentationFormat
{
uint8_t format; /**< Format of the value, see @ref ble_gatt_format_t. */
int8_t exponent; /**< Exponent for integer data types. */
uint16_t unit; /**< UUID from Bluetooth Assigned Numbers, see @ref ble_gatt_unit_t. */
uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
};
#endif

116
bleservice.cpp Normal file
View file

@ -0,0 +1,116 @@
#include <stdio.h>
#include <string.h>
#include "bleservice.h"
/**************************************************************************/
/*!
@brief Creates a new BLEService using the specified 16 byte UUID
@note The UUID value must be unique on the device
@param[in] uuid
The 16 byte (128-bit) UUID to use for this characteristic
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
BLEService::BLEService(uint8_t base_uuid[16])
{
primaryServiceID.update(base_uuid);
characteristicCount = 0;
memset(&characteristics, 0, sizeof(serialisedChar_t) * BLE_SERVICE_MAX_CHARACTERISTICS);
index = 0;
}
/**************************************************************************/
/*!
@brief Creates a new BLEService using the specified 2 byte BLE UUID
@param[in] ble_uuid
The standardised 16-bit (2 byte) BLE UUID to use for this
characteristic
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
BLEService::BLEService(uint16_t ble_uuid)
{
primaryServiceID.update( ble_uuid );
characteristicCount = 0;
memset(&characteristics, 0, sizeof(serialisedChar_t) * BLE_SERVICE_MAX_CHARACTERISTICS);
index = 0;
}
/**************************************************************************/
/*!
@brief Destructor
*/
/**************************************************************************/
BLEService::~BLEService(void)
{
}
/**************************************************************************/
/*!
@brief Adds a BLECharacterisic to the service, serialising the
essential data for the characteristic.
@note The BLEService does not store a reference to the source
BLECharacteristic, only a serialised version of the key
properties required to create the characteristic on the
target radio board.
@note This function will update the .index field in the
BLECharacteristic to indicate where this characteristic was
stored in the BLEService's characteristic array.
@param[in] characteristic
The BLECharacteristic object describing the characteristic
to add to this service
@returns BLE_ERROR_NONE (0) if everything executed correctly, or an
error code if there was a problem
@retval BLE_ERROR_NONE
Everything executed correctly
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
ble_error_t BLEService::addCharacteristic(BLECharacteristic & characteristic)
{
/* ToDo: Make sure we don't overflow the array, etc. */
/* ToDo: Make sure this characteristic UUID doesn't already exist */
/* ToDo: Basic validation */
serialisedChar_t c;
/* Serialise the source BLECharacteristic */
memcpy(&c.id, &characteristic.uuid, 2);
memcpy(&c.lenMin, &characteristic.lenMin, 2);
memcpy(&c.lenMax, &characteristic.lenMax, 2);
memcpy(&c.properties, &characteristic.properties, 2);
memset(&c.reserved, 0, 1);
/* Insert the serialised object into the buffer */
memcpy(&characteristics[characteristicCount], &c, sizeof(serialisedChar_t));
/* Update the index value */
characteristic.index = characteristicCount;
characteristicCount++;
return BLE_ERROR_NONE;
}

36
bleservice.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef __BLE_SERVICE_H__
#define __BLE_SERVICE_H__
#include "blecommon.h"
#include "uuid.h"
#include "blecharacteristic.h"
#define BLE_SERVICE_MAX_CHARACTERISTICS (5)
class BLEService
{
private:
public:
typedef struct
{
uint16_t id;
uint16_t lenMin;
uint16_t lenMax;
uint8_t properties;
uint8_t reserved;
} serialisedChar_t;
BLEService(uint8_t[16]); /* 128-bit Base UUID */
BLEService(uint16_t); /* 16-bit BLE UUID */
virtual ~BLEService(void);
UUID primaryServiceID;
uint8_t characteristicCount;
serialisedChar_t characteristics[BLE_SERVICE_MAX_CHARACTERISTICS];
uint8_t index;
ble_error_t addCharacteristic(BLECharacteristic &);
};
#endif

31
hw/bleradio.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __BLE_RADIO_H__
#define __BLE_RADIO_H__
#include "blecommon.h"
#include "bleservice.h"
class BLERadio
{
public:
typedef enum radio_event_e
{
RADIO_EVENT_CONNECT = 0x01,
RADIO_EVENT_DISCONNECT = 0x02,
RADIO_EVENT_WRITE = 0x03,
RADIO_EVENT_RADIOERROR = 0x80
} radioEvent_t;
uint8_t serviceCount;
/* ToDo: Force constructor with event handler callback */
/* These functions must be defined in the sub-class */
virtual ble_error_t attach(void (*fptr)(void));
virtual ble_error_t addService(BLEService &) = 0;
virtual ble_error_t updateValue(uint8_t, uint8_t, uint8_t[], uint16_t) = 0;
virtual ble_error_t start(void) = 0;
virtual ble_error_t stop(void) = 0;
virtual ble_error_t reset(void) = 0;
};
#endif

212
hw/nrf51822.cpp Normal file
View file

@ -0,0 +1,212 @@
#include "nrf51822.h"
#include "mbed.h"
/**************************************************************************/
/*!
@brief UART callback function
*/
/**************************************************************************/
void nRF51822::uartCallback(void)
{
/* ToDo: Check responses and set a flag for success/error/etc. */
/* Read serial to clear the RX interrupt */
uart.getc();
}
/**************************************************************************/
/*!
@brief Constructor
@args fptr[in] Pointer to the callback function when any radio
event is raised by the radio HW.
*/
/**************************************************************************/
nRF51822::nRF51822() : uart(P0_4, P0_0)
{
/* Setup the nRF UART interface */
uart.baud(9600);
/* Echo data on the debug CDC port */
uart.attach(this, &nRF51822::uartCallback);
/* Add flow control for UART (required by the nRF51822) */
uart.set_flow_control(Serial::RTSCTS, P0_6, P0_8);
/* Reset the service counter */
serviceCount = 0;
}
/**************************************************************************/
/*!
@brief Destructor
*/
/**************************************************************************/
nRF51822::~nRF51822(void)
{
}
/**************************************************************************/
/*!
*/
/**************************************************************************/
ble_error_t nRF51822::attach(void (*fptr)(void))
{
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
*/
/**************************************************************************/
ble_error_t nRF51822::addService(BLEService & service)
{
/* ToDo: Make sure we don't overflow the array, etc. */
/* ToDo: Make sure this service UUID doesn't already exist (?) */
/* ToDo: Basic validation */
/* Add the service to the nRF51 */
if (service.primaryServiceID.type == UUID::UUID_TYPE_SHORT)
{
/* 16-bit BLE UUID */
uart.printf("10 01 00 04 01 02 %02X %02X\r\n",
service.primaryServiceID.value & 0xFF,
service.primaryServiceID.value >> 8);
}
else
{
/* 128-bit Custom UUID */
uart.printf("10 01 00 12 01 10 %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
service.primaryServiceID.base[0],
service.primaryServiceID.base[1],
service.primaryServiceID.base[2],
service.primaryServiceID.base[3],
service.primaryServiceID.base[4],
service.primaryServiceID.base[5],
service.primaryServiceID.base[6],
service.primaryServiceID.base[7],
service.primaryServiceID.base[8],
service.primaryServiceID.base[9],
service.primaryServiceID.base[10],
service.primaryServiceID.base[11],
service.primaryServiceID.base[12],
service.primaryServiceID.base[13],
service.primaryServiceID.base[14],
service.primaryServiceID.base[15]);
}
/* ToDo: Check response */
wait(0.1);
/* Add characteristics to the service */
for (uint8_t i = 0; i < service.characteristicCount; i++)
{
/* Command ID = 0x0002 */
uart.printf("10 02 00 0F 01 02 %02X %02X 04 02 %02X %02X 05 02 %02X %02X 03 01 %02X\r\n",
service.characteristics[i].id & 0xFF,
service.characteristics[i].id >> 8,
service.characteristics[i].lenMin & 0xFF,
service.characteristics[i].lenMin >> 8,
service.characteristics[i].lenMax & 0xFF,
service.characteristics[i].lenMax >> 8,
service.characteristics[i].properties);
/* ToDo: Check response */
wait(0.1);
}
/* Update the service index value */
service.index = serviceCount;
serviceCount++;
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
@brief Updates the value of a characteristic, based on the service
and characteristic index fields
@param[in] sIndex
The BLEService's index value (.index)
@param[in] cIndex
The BLECharacteristic's index value (.index)
@param[in] buffer
Data to use when updating the characteristic's value
(raw byte array in LSB format)
@param[in] len
The number of bytes in buffer
*/
/**************************************************************************/
ble_error_t nRF51822::updateValue(uint8_t sIndex, uint8_t cIndex, uint8_t buffer[], uint16_t len)
{
/* Command ID = 0x0006, Payload = Service ID, Characteristic ID, Value */
uart.printf("10 06 00 %02X %02X %02X", len + 2, cIndex, sIndex);
for (uint16_t i = 0; i<len; i++)
{
uart.printf(" %02X", buffer[i]);
}
uart.printf("\r\n");
/* ToDo: Check response */
wait(0.1);
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
@brief Starts the BLE HW, initialising any services that were
added before this function was called.
@note All services must be added before calling this function!
*/
/**************************************************************************/
ble_error_t nRF51822::start(void)
{
/* Command ID = 0x0003, No payload */
uart.printf("10 03 00 00\r\n");
/* ToDo: Check response */
wait(0.5);
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
@brief Stops the BLE HW and disconnects from any devices
*/
/**************************************************************************/
ble_error_t nRF51822::stop(void)
{
/* Command ID = 0x0004, No payload */
uart.printf("10 04 00 00\r\n");
/* ToDo: Check response */
wait(0.1);
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
@brief Resets the BLE HW, removing any existing services and
characteristics
*/
/**************************************************************************/
ble_error_t nRF51822::reset(void)
{
/* Command ID = 0x0005, No payload */
uart.printf("10 05 00 00\r\n");
/* Reset the service counter */
serviceCount = 0;
/* Wait for the radio to come back up */
wait(1);
return BLE_ERROR_NONE;
}

30
hw/nrf51822.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef __NRF51822_H__
#define __NRF51822_H__
#include "mbed.h"
#include "blecommon.h"
#include "bleservice.h"
#include "bleradio.h"
class nRF51822 : public BLERadio
{
public:
nRF51822();
virtual ~nRF51822(void);
/* Functions that mus be implemented from NRFRadio */
virtual ble_error_t attach(void (*fptr)(void));
virtual ble_error_t addService(BLEService &);
virtual ble_error_t updateValue(uint8_t, uint8_t, uint8_t[], uint16_t);
virtual ble_error_t start(void);
virtual ble_error_t stop(void);
virtual ble_error_t reset(void);
/* nRF51 Functions */
void uartCallback(void);
private:
Serial uart;
};
#endif

114
main.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "mbed.h"
#include "uuid.h"
#include "bleservice.h"
#include "blecharacteristic.h"
#include "hw/nrf51822.h"
DigitalOut myled ( LED1 );
/* Radio HW abstraction layer */
nRF51822 radio;
/* Battery Level Service */
/* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml */
BLEService battService ( 0x180F );
BLECharacteristic battLevel ( 0x2A19, 1, 1, 0x10 | 0x02); /* Read + Notify */
/* Heart Rate Monitor Service */
/* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml */
BLEService hrmService ( 0x180D );
BLECharacteristic hrmRate ( 0x2A37, 2, 3, 0x10 ); /* Notify */
BLECharacteristic hrmLocation ( 0x2A39, 1, 1, 0x02 ); /* Read */
/* Health Thermometer Service */
/* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml */
BLEService thermService ( 0x1809 );
BLECharacteristic thermTemp ( 0x2A1C, 5, 13, 0x20 ); /* Indicate */
BLECharacteristic thermType ( 0x2A1D, 1, 1, 0x02 ); /* Read */
BLECharacteristic thermInterval ( 0x2A21, 2, 2, 0x02 ); /* Read */
/* Notify = device (server) sends data when it changes */
/* Indicate = device (server) sends data when it changes and client confirms reception */
int main()
{
/* Add the battery level characteristic to the battery service */
/* Note: This will also update the characteristic's .index field */
/* so that we know where it's stored in the BLEService.characteristics */
/* array. */
battService.addCharacteristic(battLevel);
/* Add the heart rate and sensor location chars to the HRM service */
hrmService.addCharacteristic(hrmRate);
hrmService.addCharacteristic(hrmLocation);
/* Add the Health Thermometer server characteristics */
thermService.addCharacteristic(thermTemp);
thermService.addCharacteristic(thermType);
thermService.addCharacteristic(thermInterval);
/* Reset the BLE hardware to make sure we get a clean start */
wait(2);
radio.reset();
/* Add the services to the radio HAL */
radio.addService(battService);
radio.addService(hrmService);
radio.addService(thermService);
/* Start the services so that we can start pushing data out */
radio.start();
/* Set the heart rate monitor location (one time only) */
/* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml */
uint8_t location = 0x01; /* Chest */
radio.updateValue(hrmService.index, hrmLocation.index, (uint8_t*)&location, sizeof(location));
/* Update the battery level */
/* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.battery_level.xml */
uint8_t batt = 72; /* Percentage (0..100) */
radio.updateValue(battService.index, battLevel.index, (uint8_t*)&batt, sizeof(batt));
/* Update the fixed health thermometer characteristics */
/* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_type.xml */
uint8_t thermLocation = 6; /* Location = mouth */
radio.updateValue(thermService.index, thermType.index, (uint8_t*)&thermLocation, sizeof(thermLocation));
/* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.measurement_interval.xml */
uint16_t thermDelay = 5;
radio.updateValue(thermService.index, thermInterval.index, (uint8_t*)&thermDelay, sizeof(thermDelay));
/* Blinky + value updates */
uint8_t hrmCounter = 100;
while(1)
{
myled = 1;
wait(0.1);
myled = 0;
wait(0.1);
/* Update the HRM measurement */
/* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */
/* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */
hrmCounter++;
if (hrmCounter == 175) hrmCounter = 100;
uint8_t bpm[2] = { 0x00, hrmCounter };
radio.updateValue(hrmService.index, hrmRate.index, bpm, 2);
/* Update the Health Thermometer measurement */
// NOTE: This is an IEEE-11073 32-bit float NOT a IEEE-754 float (standard single precision float type) !!!
// See: Section 2.2 of https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961
// Example:
// Consider a temperature measurement of 36.4 degrees Celsius with precision of 0.1 degrees Celsius.
// The FLOAT-Type representation is a 32-bit value consisting of an exponent of an 8-bit signed integer
// followed by a mantissa of a 24-bit signed integer; here, the exponent is -1 (0xFF) and the mantissa
// is 364 (0x00016C). Therefore, the FLOAT-Type representation of 36.4 is 0xFF00016C.
uint8_t temperature[5] = { 0x00, 0x00, 0x00, 0x00, 0xFF };
// Use the hrm counter to provide a shifting temperature value (175 = 17.5C, etc.)
memcpy (temperature+1, &hrmCounter, 1);
radio.updateValue(thermService.index, thermTemp.index, temperature, 5);
}
}

1
mbed-src-flowcontrol.lib Normal file
View file

@ -0,0 +1 @@
http://mbed.org/users/bogdanm/code/mbed-src-flowcontrol/#8804ac57fc7e

177
uuid.cpp Normal file
View file

@ -0,0 +1,177 @@
#include <stdio.h>
#include <string.h>
#include "uuid.h"
/**************************************************************************/
/*!
@brief Creates an empty 128-bit UUID
@note This UUID must be assigned a valid value via the 'update'
function before it can be safely used!
*/
/**************************************************************************/
UUID::UUID(void)
{
memset(base, 0, 16);
value = 0;
type = UUID_TYPE_SHORT;
}
/**************************************************************************/
/*!
@brief Creates a new 128-bit UUID
@note The UUID is a unique 128-bit (16 byte) ID used to identify
different service or characteristics on the BLE device.
@note When creating a UUID, the constructor will check if all bytes
except bytes 2/3 are equal to 0. If only bytes 2/3 have a
value, the UUID will be treated as a short/BLE UUID, and the
.type field will be set to UUID::UUID_TYPE_SHORT. If any
of the bytes outside byte 2/3 have a non-zero value, the UUID
will be considered a 128-bit ID, and .type will be assigned
as UUID::UUID_TYPE_LONG.
@param[in] uuid_base
The 128-bit (16-byte) UUID value. For 128-bit values,
assign all 16 bytes. For 16-bit values, assign the
16-bits to byte 2 and 3, and leave the rest of the bytes
as 0.
@section EXAMPLE
@code
// Create a short UUID (0x180F)
uint8_t shortID[16] = { 0, 0, 0x0F, 0x18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
UUID ble_uuid = UUID(shortID);
// ble_uuid.type = UUID_TYPE_SHORT
// ble_uuid.value = 0x180F
// Creeate a long UUID
uint8_t longID[16] = { 0x00, 0x11, 0x22, 0x33,
0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF };
UUID custom_uuid = UUID(longID);
// custom_uuid.type = UUID_TYPE_LONG
// custom_uuid.value = 0x3322
// custom_uuid.base = 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
@endcode
*/
/**************************************************************************/
UUID::UUID(uint8_t const uuid_base[16])
{
memcpy(base, uuid_base, 16);
value = (uint16_t)((uuid_base[3] << 8) | (uuid_base[2]));
/* Check if this is a short of a long UUID */
if (uuid_base[0] + uuid_base[1] +
uuid_base[4] + uuid_base[5] + uuid_base[6] + uuid_base[7] +
uuid_base[8] + uuid_base[9] + uuid_base[10] + uuid_base[11] +
uuid_base[12] + uuid_base[13] + uuid_base[14] + uuid_base[15] == 0)
{
type = UUID_TYPE_SHORT;
}
else
{
type = UUID_TYPE_LONG;
}
}
/**************************************************************************/
/*!
@brief Creates a short (16-bit) UUID
@param[in] ble_uuid
The 16-bit BLE UUID value.
*/
/**************************************************************************/
UUID::UUID(uint16_t const ble_uuid)
{
memset(base, 0, 16);
memcpy(base+2, (uint8_t *)&ble_uuid, 2);
value = ble_uuid;
type = UUID_TYPE_SHORT;
}
/**************************************************************************/
/*!
@brief UUID destructor
*/
/**************************************************************************/
UUID::~UUID(void)
{
}
/**************************************************************************/
/*!
@brief Updates the value of the UUID
@args[in] uuid_base
The 128-bit value to use when updating the UUID. For
16-bit IDs, insert the ID in bytes 2/3 in LSB format.
@returns BLE_ERROR_NONE (0) if everything executed correctly, or an
error code if there was a problem
@retval BLE_ERROR_NONE
Everything executed correctly
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
ble_error_t UUID::update(uint8_t const uuid_base[16])
{
memcpy(base, uuid_base, 16);
value = (uint16_t)((uuid_base[3] << 8) | (uuid_base[2]));
/* Check if this is a short of a long UUID */
if (uuid_base[0] + uuid_base[1] +
uuid_base[4] + uuid_base[5] + uuid_base[6] + uuid_base[7] +
uuid_base[8] + uuid_base[9] + uuid_base[10] + uuid_base[11] +
uuid_base[12] + uuid_base[13] + uuid_base[14] + uuid_base[15] == 0)
{
type = UUID_TYPE_SHORT;
}
else
{
type = UUID_TYPE_LONG;
}
return BLE_ERROR_NONE;
}
/**************************************************************************/
/*!
@brief Updates the value of the UUID
@args[in] ble_uuid
The 16-bit value to use when updating the UUID.
@returns BLE_ERROR_NONE (0) if everything executed correctly, or an
error code if there was a problem
@retval BLE_ERROR_NONE
Everything executed correctly
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
ble_error_t UUID::update(uint16_t const ble_uuid)
{
memset(base, 0, 16);
memcpy(base+2, (uint8_t *)&ble_uuid, 2);
value = ble_uuid;
type = UUID_TYPE_SHORT;
return BLE_ERROR_NONE;
}

30
uuid.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef __UUID_H__
#define __UUID_H__
#include "blecommon.h"
class UUID
{
private:
public:
enum
{
UUID_TYPE_SHORT = 0, // Short BLE UUID
UUID_TYPE_LONG = 1 // Full 128-bit UUID
};
UUID(void);
UUID(uint8_t const[16]);
UUID(uint16_t const);
virtual ~UUID(void);
uint8_t type; // UUID_TYPE_SHORT or UUID_TYPE_LONG
uint8_t base[16]; // in case of custom
uint16_t value; // 16 bit uuid (byte 2-3 using with base)
ble_error_t update(uint8_t const[16]);
ble_error_t update(uint16_t const);
};
#endif