From ef8c4ede6852b04ad176c998fd82e9bb8727805d Mon Sep 17 00:00:00 2001 From: ktownsend Date: Fri, 29 Nov 2013 14:42:22 +0000 Subject: [PATCH] First commit --- blecharacteristic.cpp | 48 ++++++++ blecharacteristic.h | 33 ++++++ blecommon.h | 239 +++++++++++++++++++++++++++++++++++++++ bleservice.cpp | 116 +++++++++++++++++++ bleservice.h | 36 ++++++ hw/bleradio.h | 31 +++++ hw/nrf51822.cpp | 212 ++++++++++++++++++++++++++++++++++ hw/nrf51822.h | 30 +++++ main.cpp | 114 +++++++++++++++++++ mbed-src-flowcontrol.lib | 1 + uuid.cpp | 177 +++++++++++++++++++++++++++++ uuid.h | 30 +++++ 12 files changed, 1067 insertions(+) create mode 100644 blecharacteristic.cpp create mode 100644 blecharacteristic.h create mode 100644 blecommon.h create mode 100644 bleservice.cpp create mode 100644 bleservice.h create mode 100644 hw/bleradio.h create mode 100644 hw/nrf51822.cpp create mode 100644 hw/nrf51822.h create mode 100644 main.cpp create mode 100644 mbed-src-flowcontrol.lib create mode 100644 uuid.cpp create mode 100644 uuid.h diff --git a/blecharacteristic.cpp b/blecharacteristic.cpp new file mode 100644 index 0000000..80de336 --- /dev/null +++ b/blecharacteristic.cpp @@ -0,0 +1,48 @@ +#include +#include + +#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) +{ +} diff --git a/blecharacteristic.h b/blecharacteristic.h new file mode 100644 index 0000000..4293e4a --- /dev/null +++ b/blecharacteristic.h @@ -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 diff --git a/blecommon.h b/blecommon.h new file mode 100644 index 0000000..f45f643 --- /dev/null +++ b/blecommon.h @@ -0,0 +1,239 @@ +#ifndef __BLE_COMMON_H__ +#define __BLE_COMMON_H__ + +#include + +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 diff --git a/bleservice.cpp b/bleservice.cpp new file mode 100644 index 0000000..6acf48d --- /dev/null +++ b/bleservice.cpp @@ -0,0 +1,116 @@ +#include +#include + +#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; +} diff --git a/bleservice.h b/bleservice.h new file mode 100644 index 0000000..30116a1 --- /dev/null +++ b/bleservice.h @@ -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 diff --git a/hw/bleradio.h b/hw/bleradio.h new file mode 100644 index 0000000..4627f54 --- /dev/null +++ b/hw/bleradio.h @@ -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 diff --git a/hw/nrf51822.cpp b/hw/nrf51822.cpp new file mode 100644 index 0000000..372cc43 --- /dev/null +++ b/hw/nrf51822.cpp @@ -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 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); + } +} diff --git a/mbed-src-flowcontrol.lib b/mbed-src-flowcontrol.lib new file mode 100644 index 0000000..5de2699 --- /dev/null +++ b/mbed-src-flowcontrol.lib @@ -0,0 +1 @@ +http://mbed.org/users/bogdanm/code/mbed-src-flowcontrol/#8804ac57fc7e diff --git a/uuid.cpp b/uuid.cpp new file mode 100644 index 0000000..12d0fae --- /dev/null +++ b/uuid.cpp @@ -0,0 +1,177 @@ +#include +#include + +#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; +} diff --git a/uuid.h b/uuid.h new file mode 100644 index 0000000..dbc4007 --- /dev/null +++ b/uuid.h @@ -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