Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/NimBLECharacteristic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ void NimBLECharacteristic::updatePeerStatus(const NimBLEConnInfo& peerInfo) cons
* @brief Handle a read event from a client.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
*/
void NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
m_pCallbacks->onRead(this, connInfo);
int NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
return m_pCallbacks->onReadStatus(this, connInfo);
} // readEvent

/**
Expand All @@ -432,9 +432,17 @@ void NimBLECharacteristic::readEvent(NimBLEConnInfo& connInfo) {
* @param [in] len The length of the data written by the client.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
*/
void NimBLECharacteristic::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
int NimBLECharacteristic::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
// Commit before the callback so getValue() reflects the new value inside it
// (onWriteStatus defaults to calling the legacy onWrite), but snapshot first
// so a rejected write can be rolled back and never becomes observable state.
NimBLEAttValue previous = m_value;
setValue(val, len);
m_pCallbacks->onWrite(this, connInfo);
const int rc = m_pCallbacks->onWriteStatus(this, connInfo);
if (rc != 0) {
m_value = previous;
}
return rc;
} // writeEvent

/**
Expand Down
33 changes: 31 additions & 2 deletions src/NimBLECharacteristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ class NimBLECharacteristic : public NimBLELocalValueAttribute {
friend class NimBLEService;

void setService(NimBLEService* pService);
void readEvent(NimBLEConnInfo& connInfo) override;
void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
int readEvent(NimBLEConnInfo& connInfo) override;
int writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
bool sendValue(const uint8_t* value,
size_t length,
bool is_notification = true,
Expand Down Expand Up @@ -319,6 +319,35 @@ class NimBLECharacteristicCallbacks {
virtual ~NimBLECharacteristicCallbacks() {}
virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);
virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo);

/**
* @brief Read request callback that can reject the read with an ATT error.
* @param [in] pCharacteristic The characteristic that is the source of the event.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
* @return 0 to accept the read, or a BLE_ATT_ERR_* code to reject it.
* @details Defaults to calling onRead() and accepting. Override this instead of onRead()
* when you need to reject a read from the application.
*/
virtual int onReadStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
onRead(pCharacteristic, connInfo);
return 0;
}

/**
* @brief Write request callback that can reject the write with an ATT error.
* @param [in] pCharacteristic The characteristic that is the source of the event.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
* @return 0 to accept the write, or a BLE_ATT_ERR_* code to reject it.
* @details Defaults to calling onWrite() and accepting. Override this instead of onWrite()
* when you need to reject a write from the application. A rejection only reaches the peer
* when it used write-with-response; a write-without-response (ATT Write Command) is
* unacknowledged, so the code is dropped by the stack.
*/
virtual int onWriteStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) {
onWrite(pCharacteristic, connInfo);
return 0;
}

virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code); // deprecated
virtual void onStatus(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, int code);
virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue);
Expand Down
7 changes: 5 additions & 2 deletions src/NimBLEDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,16 @@ std::string NimBLEDescriptor::toString() const {
return res;
} // toString

void NimBLEDescriptor::readEvent(NimBLEConnInfo& connInfo) {
int NimBLEDescriptor::readEvent(NimBLEConnInfo& connInfo) {
// Descriptor callbacks have no status-returning variant; always accept.
m_pCallbacks->onRead(this, connInfo);
return 0;
} // readEvent

void NimBLEDescriptor::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
int NimBLEDescriptor::writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) {
setValue(val, len);
m_pCallbacks->onWrite(this, connInfo);
return 0;
} // writeEvent

/**
Expand Down
4 changes: 2 additions & 2 deletions src/NimBLEDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class NimBLEDescriptor : public NimBLELocalValueAttribute {
friend class NimBLEService;

void setCharacteristic(NimBLECharacteristic* pChar);
void readEvent(NimBLEConnInfo& connInfo) override;
void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;
int readEvent(NimBLEConnInfo& connInfo) override;
int writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override;

NimBLEDescriptorCallbacks* m_pCallbacks{nullptr};
NimBLECharacteristic* m_pCharacteristic{nullptr};
Expand Down
6 changes: 4 additions & 2 deletions src/NimBLELocalValueAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,19 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValu
* @brief Callback function to support a read request.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
* @details This function is called by NimBLEServer when a read request is received.
* @return 0 on success, or a BLE_ATT_ERR_* code to reject the read.
*/
virtual void readEvent(NimBLEConnInfo& connInfo) = 0;
virtual int readEvent(NimBLEConnInfo& connInfo) = 0;

/**
* @brief Callback function to support a write request.
* @param [in] val The value to write.
* @param [in] len The length of the value.
* @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.
* @details This function is called by NimBLEServer when a write request is received.
* @return 0 on success, or a BLE_ATT_ERR_* code to reject the write.
*/
virtual void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) = 0;
virtual int writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) = 0;

/**
* @brief Get a pointer to value of the attribute.
Expand Down
8 changes: 5 additions & 3 deletions src/NimBLEServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,10 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
// Don't call readEvent if the buffer len is 0 (this is a follow up to a previous read),
// or if this is an internal read (handle is NONE)
if (ctxt->om->om_len > 0 && connHandle != BLE_HS_CONN_HANDLE_NONE) {
pAtt->readEvent(peerInfo);
int appRc = pAtt->readEvent(peerInfo);
if (appRc != 0) {
return appRc; // application rejected the read
}
}

ble_npl_hw_enter_critical();
Expand Down Expand Up @@ -773,8 +776,7 @@ int NimBLEServer::handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_
next = SLIST_NEXT(next, om_next);
}

pAtt->writeEvent(buf, len, peerInfo);
return 0;
return pAtt->writeEvent(buf, len, peerInfo);
}

default:
Expand Down