GattServer
GattServer 是 GattServices 的集合。这些服务包含连接到设备的对等体可以读取或写入的特征。这些特征还可能在订阅客户端的值发生更改时发出更新。
服务器布局
应用程序代码可以在函数 addService() 的帮助下将 GattService 对象添加到服务器。该函数注册服务中包含的所有 GattCharacteristics,以及这些特性包含的所有特征描述符(请参阅 GattAttribute)。服务注册为作为服务一部分的各种属性分配唯一句柄。用户必须使用此句柄来读取或写入这些组件。
没有定义的原语可以删除单个服务;但是,调用函数 reset() 会删除先前在 GattServer 中注册的所有服务。
特征和属性访问
在注册服务时,必须通过分配给它们的句柄访问 GattServer 中存在的特性和特征描述符的值。GattServer 类提供了几种类型的 read() 和 write() 函数,用于检索或改变属性值。
您可以通过调用函数 areUpdatesEnabled() 来查询服务器,以查明客户端是否已订阅给定特征的值更新。
事件
您可以使用 GattServer 注册多个事件处理程序,它将调用它来通知您客户端(连接到服务器的远程应用程序)和服务器活动:
onDataSent
: 向 GattServer 注册一个事件处理程序,它将调用它以在向客户端发送特征值更新时通知您。onDataWriten
: 向 GattServer 注册事件处理程序,当客户端编写服务器属性时,它将调用该处理程序以通知您。onDataRead
: 向 GattServer 注册一个事件处理程序,当客户端读取服务器的属性时,它将调用该处理程序来通知您。onUpdatesEnabled
: 向 GattServer 注册一个事件处理程序,当客户端订阅特征的更新时,它会调用该处理程序来通知您。onUpdatesDisabled
: 向 GattServer 注册一个事件处理程序,当客户端取消订阅特征的更新时,它会调用该处理程序来通知您。onConfimationReceived
: 向 GattServer 注册事件处理程序,当客户端确认特征值通知时,它将调用该处理程序以通知您。
当启动的服务器的性质不相关时,术语特征值更新表示特征值通知和特征值指示。
GattServer 类参考
公共类型 | |
typedef FunctionPointerWithContext< unsigned > | DataSentCallback_t |
typedef CallChainOfFunctionPointersWithContext< unsigned > | DataSentCallbackChain_t |
typedef FunctionPointerWithContext< const GattWriteCallbackParams * > | DataWrittenCallback_t |
typedef CallChainOfFunctionPointersWithContext< const GattWriteCallbackParams * > | DataWrittenCallbackChain_t |
typedef FunctionPointerWithContext< const GattReadCallbackParams * > | DataReadCallback_t |
typedef CallChainOfFunctionPointersWithContext< const GattReadCallbackParams * > | DataReadCallbackChain_t |
typedef FunctionPointerWithContext< const GattServer * > | GattServerShutdownCallback_t |
typedef CallChainOfFunctionPointersWithContext< const GattServer * > | GattServerShutdownCallbackChain_t |
typedef FunctionPointerWithContext< GattAttribute::Handle_t > | EventCallback_t |
公共成员函数 | |
virtual ble_error_t | addService (GattService &service) |
virtual ble_error_t | read (GattAttribute::Handle_t attributeHandle, uint8_t buffer[], uint16_t *lengthP) |
virtual ble_error_t | read (Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP) |
virtual ble_error_t | write (GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly=false) |
virtual ble_error_t | write (Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly=false) |
virtual ble_error_t | areUpdatesEnabled (const GattCharacteristic &characteristic, bool *enabledP) |
virtual ble_error_t | areUpdatesEnabled (Gap::Handle_t connectionHandle, const GattCharacteristic &characteristic, bool *enabledP) |
virtual bool | isOnDataReadAvailable () const |
void | onDataSent (const DataSentCallback_t &callback) |
template<typename T > | |
void | onDataSent (T *objPtr, void(T::*memberPtr)(unsigned count)) |
DataSentCallbackChain_t & | onDataSent () |
void | onDataWritten (const DataWrittenCallback_t &callback) |
template<typename T > | |
void | onDataWritten (T *objPtr, void(T::*memberPtr)(const GattWriteCallbackParams *context)) |
DataWrittenCallbackChain_t & | onDataWritten () |
ble_error_t | onDataRead (const DataReadCallback_t &callback) |
template<typename T > | |
ble_error_t | onDataRead (T *objPtr, void(T::*memberPtr)(const GattReadCallbackParams *context)) |
DataReadCallbackChain_t & | onDataRead () |
void | onShutdown (const GattServerShutdownCallback_t &callback) |
template<typename T > | |
void | onShutdown (T *objPtr, void(T::*memberPtr)(const GattServer *)) |
GattServerShutdownCallbackChain_t & | onShutdown () |
void | onUpdatesEnabled (EventCallback_t callback) |
void | onUpdatesDisabled (EventCallback_t callback) |
void | onConfirmationReceived (EventCallback_t callback) |
virtual ble_error_t | reset (void) |
受保护的成员函数 | |
GattServer () | |
void | handleDataWrittenEvent (const GattWriteCallbackParams *params) |
void | handleDataReadEvent (const GattReadCallbackParams *params) |
void | handleEvent (GattServerEvents::gattEvent_e type, GattAttribute::Handle_t attributeHandle) |
void | handleDataSentEvent (unsigned count) |
受保护的属性 | |
uint8_t | serviceCount |
uint8_t | characteristicCount |
GattServer 示例
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "platform/Callback.h"
#include "events/EventQueue.h"
#include "platform/NonCopyable.h"
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/GattClient.h"
#include "ble/GapAdvertisingParams.h"
#include "ble/GapAdvertisingData.h"
#include "ble/GattServer.h"
#include "BLEProcess.h"
using mbed::callback;
/**
* A Clock service that demonstrate the GattServer features.
*
* The clock service host three characteristics that model the current hour,
* minute and second of the clock. The value of the second characteristic is
* incremented automatically by the system.
*
* A client can subscribe to updates of the clock characteristics and get
* notified when one of the value is changed. Clients can also change value of
* the second, minute and hour characteristric.
*/
class ClockService {
typedef ClockService Self;
public:
ClockService() :
_hour_char("485f4145-52b9-4644-af1f-7a6b9322490f", 0),
_minute_char("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0),
_second_char("8dd6a1b7-bc75-4741-8a26-264af75807de", 0),
_clock_service(
/* uuid */ "51311102-030e-485f-b122-f8f381aa84ed",
/* characteristics */ _clock_characteristics,
/* numCharacteristics */ sizeof(_clock_characteristics) /
sizeof(_clock_characteristics[0])
),
_server(NULL),
_event_queue(NULL)
{
// update internal pointers (value, descriptors and characteristics array)
_clock_characteristics[0] = &_hour_char;
_clock_characteristics[1] = &_minute_char;
_clock_characteristics[2] = &_second_char;
// setup authorization handlers
_hour_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
_minute_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
_second_char.setWriteAuthorizationCallback(this, &Self::authorize_client_write);
}
void start(BLE &ble_interface, events::EventQueue &event_queue)
{
if (_event_queue) {
return;
}
_server = &ble_interface.gattServer();
_event_queue = &event_queue;
// register the service
printf("Adding demo service\r\n");
ble_error_t err = _server->addService(_clock_service);
if (err) {
printf("Error %u during demo service registration.\r\n", err);
return;
}
// read write handler
_server->onDataSent(as_cb(&Self::when_data_sent));
_server->onDataWritten(as_cb(&Self::when_data_written));
_server->onDataRead(as_cb(&Self::when_data_read));
// updates subscribtion handlers
_server->onUpdatesEnabled(as_cb(&Self::when_update_enabled));
_server->onUpdatesDisabled(as_cb(&Self::when_update_disabled));
_server->onConfirmationReceived(as_cb(&Self::when_confirmation_received));
// print the handles
printf("clock service registered\r\n");
printf("service handle: %u\r\n", _clock_service.getHandle());
printf("\thour characteristic value handle %u\r\n", _hour_char.getValueHandle());
printf("\tminute characteristic value handle %u\r\n", _minute_char.getValueHandle());
printf("\tsecond characteristic value handle %u\r\n", _second_char.getValueHandle());
_event_queue->call_every(1000 /* ms */, callback(this, &Self::increment_second));
}
private:
/**
* Handler called when a notification or an indication has been sent.
*/
void when_data_sent(unsigned count)
{
printf("sent %u updates\r\n", count);
}
/**
* Handler called after an attribute has been written.
*/
void when_data_written(const GattWriteCallbackParams *e)
{
printf("data written:\r\n");
printf("\tconnection handle: %u\r\n", e->connHandle);
printf("\tattribute handle: %u", e->handle);
if (e->handle == _hour_char.getValueHandle()) {
printf(" (hour characteristic)\r\n");
} else if (e->handle == _minute_char.getValueHandle()) {
printf(" (minute characteristic)\r\n");
} else if (e->handle == _second_char.getValueHandle()) {
printf(" (second characteristic)\r\n");
} else {
printf("\r\n");
}
printf("\twrite operation: %u\r\n", e->writeOp);
printf("\toffset: %u\r\n", e->offset);
printf("\tlength: %u\r\n", e->len);
printf("\t data: ");
for (size_t i = 0; i < e->len; ++i) {
printf("%02X", e->data[i]);
}
printf("\r\n");
}
/**
* Handler called after an attribute has been read.
*/
void when_data_read(const GattReadCallbackParams *e)
{
printf("data read:\r\n");
printf("\tconnection handle: %u\r\n", e->connHandle);
printf("\tattribute handle: %u", e->handle);
if (e->handle == _hour_char.getValueHandle()) {
printf(" (hour characteristic)\r\n");
} else if (e->handle == _minute_char.getValueHandle()) {
printf(" (minute characteristic)\r\n");
} else if (e->handle == _second_char.getValueHandle()) {
printf(" (second characteristic)\r\n");
} else {
printf("\r\n");
}
}
/**
* Handler called after a client has subscribed to notification or indication.
*
* @param handle Handle of the characteristic value affected by the change.
*/
void when_update_enabled(GattAttribute::Handle_t handle)
{
printf("update enabled on handle %d\r\n", handle);
}
/**
* Handler called after a client has cancelled his subscription from
* notification or indication.
*
* @param handle Handle of the characteristic value affected by the change.
*/
void when_update_disabled(GattAttribute::Handle_t handle)
{
printf("update disabled on handle %d\r\n", handle);
}
/**
* Handler called when an indication confirmation has been received.
*
* @param handle Handle of the characteristic value that has emitted the
* indication.
*/
void when_confirmation_received(GattAttribute::Handle_t handle)
{
printf("confirmation received on handle %d\r\n", handle);
}
/**
* Handler called when a write request is received.
*
* This handler verify that the value submitted by the client is valid before
* authorizing the operation.
*/
void authorize_client_write(GattWriteAuthCallbackParams *e)
{
printf("characteristic %u write authorization\r\n", e->handle);
if (e->offset != 0) {
printf("Error invalid offset\r\n");
e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
return;
}
if (e->len != 1) {
printf("Error invalid len\r\n");
e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
return;
}
if ((e->data[0] >= 60) ||
((e->data[0] >= 24) && (e->handle == _hour_char.getValueHandle()))) {
printf("Error invalid data\r\n");
e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
return;
}
e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
/**
* Increment the second counter.
*/
void increment_second(void)
{
uint8_t second = 0;
ble_error_t err = _second_char.get(*_server, second);
if (err) {
printf("read of the second value returned error %u\r\n", err);
return;
}
second = (second + 1) % 60;
err = _second_char.set(*_server, second);
if (err) {
printf("write of the second value returned error %u\r\n", err);
return;
}
if (second == 0) {
increment_minute();
}
}
/**
* Increment the minute counter.
*/
void increment_minute(void)
{
uint8_t minute = 0;
ble_error_t err = _minute_char.get(*_server, minute);
if (err) {
printf("read of the minute value returned error %u\r\n", err);
return;
}
minute = (minute + 1) % 60;
err = _minute_char.set(*_server, minute);
if (err) {
printf("write of the minute value returned error %u\r\n", err);
return;
}
if (minute == 0) {
increment_hour();
}
}
/**
* Increment the hour counter.
*/
void increment_hour(void)
{
uint8_t hour = 0;
ble_error_t err = _hour_char.get(*_server, hour);
if (err) {
printf("read of the hour value returned error %u\r\n", err);
return;
}
hour = (hour + 1) % 24;
err = _hour_char.set(*_server, hour);
if (err) {
printf("write of the hour value returned error %u\r\n", err);
return;
}
}
private:
/**
* Helper that construct an event handler from a member function of this
* instance.
*/
template<typename Arg>
FunctionPointerWithContext<Arg> as_cb(void (Self::*member)(Arg))
{
return makeFunctionPointer(this, member);
}
/**
* Read, Write, Notify, Indicate Characteristic declaration helper.
*
* @tparam T type of data held by the characteristic.
*/
template<typename T>
class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic {
public:
/**
* Construct a characteristic that can be read or written and emit
* notification or indication.
*
* @param[in] uuid The UUID of the characteristic.
* @param[in] initial_value Initial value contained by the characteristic.
*/
ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) :
GattCharacteristic(
/* UUID */ uuid,
/* Initial value */ &_value,
/* Value size */ sizeof(_value),
/* Value capacity */ sizeof(_value),
/* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ |
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE,
/* Descriptors */ NULL,
/* Num descriptors */ 0,
/* variable len */ false
),
_value(initial_value) {
}
/**
* Get the value of this characteristic.
*
* @param[in] server GattServer instance that contain the characteristic
* value.
* @param[in] dst Variable that will receive the characteristic value.
*
* @return BLE_ERROR_NONE in case of success or an appropriate error code.
*/
ble_error_t get(GattServer &server, T& dst) const
{
uint16_t value_length = sizeof(dst);
return server.read(getValueHandle(), &dst, &value_length);
}
/**
* Assign a new value to this characteristic.
*
* @param[in] server GattServer instance that will receive the new value.
* @param[in] value The new value to set.
* @param[in] local_only Flag that determine if the change should be kept
* locally or forwarded to subscribed clients.
*/
ble_error_t set(
GattServer &server, const uint8_t &value, bool local_only = false
) const {
return server.write(getValueHandle(), &value, sizeof(value), local_only);
}
private:
uint8_t _value;
};
ReadWriteNotifyIndicateCharacteristic<uint8_t> _hour_char;
ReadWriteNotifyIndicateCharacteristic<uint8_t> _minute_char;
ReadWriteNotifyIndicateCharacteristic<uint8_t> _second_char;
// list of the characteristics of the clock service
GattCharacteristic* _clock_characteristics[3];
// demo service
GattService _clock_service;
GattServer* _server;
events::EventQueue *_event_queue;
};
int main() {
BLE &ble_interface = BLE::Instance();
events::EventQueue event_queue;
ClockService demo_service;
BLEProcess ble_process(event_queue, ble_interface);
ble_process.on_init(callback(&demo_service, &ClockService::start));
// bind the event queue to the ble interface, initialize the interface
// and start advertising
ble_process.start();
// Process the event queue.
event_queue.dispatch_forever();
return 0;
}