/*
This file is part of the ArduinoBLE library.
Copyright (c) 2018 Arduino SA. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "BLEProperty.h"
#include "local/BLELocalCharacteristic.h"
#include "remote/BLERemoteCharacteristic.h"
#include "BLECharacteristic.h"
extern "C" int strcasecmp(char const *a, char const *b);
BLECharacteristic::BLECharacteristic() :
BLECharacteristic((BLELocalCharacteristic*)NULL)
{
}
BLECharacteristic::BLECharacteristic(BLELocalCharacteristic* local) :
_local(local),
_remote(NULL)
{
if (_local) {
_local->retain();
}
}
BLECharacteristic::BLECharacteristic(BLERemoteCharacteristic* remote) :
_local(NULL),
_remote(remote)
{
if (_remote) {
_remote->retain();
}
}
BLECharacteristic::BLECharacteristic(const char* uuid, uint16_t permissions, int valueSize, bool fixedLength) :
BLECharacteristic(new BLELocalCharacteristic(uuid, permissions, valueSize, fixedLength))
{
}
BLECharacteristic::BLECharacteristic(const char* uuid, uint16_t permissions, const char* value) :
BLECharacteristic(new BLELocalCharacteristic(uuid, permissions, value))
{
}
BLECharacteristic::BLECharacteristic(const BLECharacteristic& other)
{
_local = other._local;
if (_local) {
_local->retain();
}
_remote = other._remote;
if (_remote) {
_remote->retain();
}
}
BLECharacteristic::~BLECharacteristic()
{
if (_local && _local->release() == 0) {
delete _local;
}
if (_remote && _remote->release() == 0) {
delete _remote;
}
}
const char* BLECharacteristic::uuid() const
{
if (_local) {
return _local->uuid();
}
if (_remote) {
return _remote->uuid();
}
return "";
}
uint8_t BLECharacteristic::properties() const
{
if (_local) {
return _local->properties();
}
if (_remote) {
return _remote->properties();
}
return 0;
}
int BLECharacteristic::valueSize() const
{
if (_local) {
return _local->valueSize();
}
if (_remote) {
return _remote->valueLength();
}
return 0;
}
const uint8_t* BLECharacteristic::value() const
{
if (_local) {
return _local->value();
}
if (_remote) {
return _remote->value();
}
return NULL;
}
int BLECharacteristic::valueLength() const
{
if (_local) {
return _local->valueLength();
}
if (_remote) {
return _remote->valueLength();
}
return 0;
}
uint8_t BLECharacteristic::operator[] (int offset) const
{
if (_local) {
return (*_local)[offset];
}
if (_remote) {
return (*_remote)[offset];
}
return 0;
}
int BLECharacteristic::readValue(uint8_t value[], int length)
{
int bytesRead = 0;
if (_local) {
bytesRead = min(length, _local->valueLength());
memcpy(value, _local->value(), bytesRead);
}
if (_remote) {
// trigger a read if the updated value (notification/indication)
// has already been read and the characteristic is readable
if (_remote->updatedValueRead() && canRead()) {
if (!read()) {
// read failed
return 0;
}
}
bytesRead = min(length, _remote->valueLength());
memcpy(value, _remote->value(), bytesRead);
}
return bytesRead;
}
int BLECharacteristic::readValue(void* value, int length)
{
return readValue((uint8_t*)value, length);
}
int BLECharacteristic::readValue(uint8_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::readValue(int8_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::readValue(uint16_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::readValue(int16_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::readValue(uint32_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::readValue(int32_t& value)
{
value = 0;
return readValue((uint8_t*)&value, sizeof(value));
}
int BLECharacteristic::writeValue(const uint8_t value[], int length, bool withResponse)
{
if (_local) {
return _local->writeValue(value, length);
}
if (_remote) {
return _remote->writeValue(value, length, withResponse);
}
return 0;
}
int BLECharacteristic::writeValue(const void* value, int length, bool withResponse)
{
return writeValue((const uint8_t*)value, length, withResponse);
}
int BLECharacteristic::writeValue(const char* value, bool withResponse)
{
if (_local) {
return _local->writeValue(value);
}
if (_remote) {
return _remote->writeValue(value, withResponse);
}
return 0;
}
int BLECharacteristic::writeValue(uint8_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::writeValue(int8_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::writeValue(uint16_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::writeValue(int16_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::writeValue(uint32_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::writeValue(int32_t value, bool withResponse)
{
return writeValue((uint8_t*)&value, sizeof(value), withResponse);
}
int BLECharacteristic::broadcast()
{
if (_local) {
return _local->broadcast();
}
return 0;
}
bool BLECharacteristic::written()
{
if (_local) {
return _local->written();
}
return false;
}
bool BLECharacteristic::subscribed()
{
if (_local) {
return _local->subscribed();
}
return false;
}
bool BLECharacteristic::valueUpdated()
{
if (_remote) {
return _remote->valueUpdated();
}
return false;
}
void BLECharacteristic::addDescriptor(BLEDescriptor& descriptor)
{
if (_local) {
return _local->addDescriptor(descriptor);
}
}
BLECharacteristic::operator bool() const
{
return (_local != NULL) || (_remote != NULL);
}
BLELocalCharacteristic* BLECharacteristic::local()
{
return _local;
}
void BLECharacteristic::setEventHandler(int event, BLECharacteristicEventHandler eventHandler)
{
if (_local) {
_local->setEventHandler((BLECharacteristicEvent)event, eventHandler);
}
if (_remote) {
_remote->setEventHandler((BLECharacteristicEvent)event, eventHandler);
}
}
int BLECharacteristic::descriptorCount() const
{
if (_remote) {
return _remote->descriptorCount();
}
return 0;
}
bool BLECharacteristic::hasDescriptor(const char* uuid) const
{
return hasDescriptor(uuid, 0);
}
bool BLECharacteristic::hasDescriptor(const char* uuid, int index) const
{
if (_remote) {
int count = 0;
int numDescriptors = _remote->descriptorCount();
for (int i = 0; i < numDescriptors; i++) {
BLERemoteDescriptor* d = _remote->descriptor(i);
if (strcasecmp(uuid, d->uuid()) == 0) {
if (count == index) {
return true;
}
count++;
}
}
}
return false;
}
BLEDescriptor BLECharacteristic::descriptor(int index) const
{
if (_remote) {
return BLEDescriptor(_remote->descriptor(index));
}
return BLEDescriptor();
}
BLEDescriptor BLECharacteristic::descriptor(const char * uuid) const
{
return descriptor(uuid, 0);
}
BLEDescriptor BLECharacteristic::descriptor(const char * uuid, int index) const
{
if (_remote) {
int count = 0;
int numDescriptors = _remote->descriptorCount();
for (int i = 0; i < numDescriptors; i++) {
BLERemoteDescriptor* d = _remote->descriptor(i);
if (strcasecmp(uuid, d->uuid()) == 0) {
if (count == index) {
return BLEDescriptor(d);
}
count++;
}
}
}
return BLEDescriptor();
}
bool BLECharacteristic::canRead()
{
if (_remote) {
return (properties() & BLERead) != 0;
}
return false;
}
bool BLECharacteristic::read()
{
if (_remote) {
return _remote->read();
}
return false;
}
bool BLECharacteristic::canWrite()
{
if (_remote) {
return (properties() & (BLEWrite | BLEWriteWithoutResponse)) != 0;
}
return false;
}
bool BLECharacteristic::canSubscribe()
{
if (_remote) {
return (properties() & (BLENotify | BLEIndicate)) != 0;
}
return false;
}
bool BLECharacteristic::subscribe()
{
if (_remote) {
return _remote->writeCccd((properties() & BLEIndicate) ? 0x0002 : 0x0001);
}
return false;
}
bool BLECharacteristic::canUnsubscribe()
{
return canSubscribe();
}
bool BLECharacteristic::unsubscribe()
{
if (_remote) {
return _remote->writeCccd(0x0000);
}
return false;
}