Skip to content

Commit fe76b80

Browse files
committed
[Bugfix] Attribute getValue fails with some data types
1 parent 147e79f commit fe76b80

5 files changed

+100
-74
lines changed

src/NimBLEAttValue.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -313,14 +313,10 @@ class NimBLEAttValue {
313313
# endif
314314
}
315315

316-
if (std::is_convertible<NimBLEAttValue, T>::value) {
317-
return *this;
318-
} else {
319-
if (!skipSizeCheck && size() < sizeof(T)) {
320-
return T();
321-
}
322-
return *(reinterpret_cast<const T*>(m_attr_value));
316+
if (!skipSizeCheck && size() < sizeof(T)) {
317+
return T();
323318
}
319+
return *(reinterpret_cast<const T*>(m_attr_value));
324320
}
325321

326322
/*********************** Operators ************************/

src/NimBLELocalValueAttribute.h

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,18 @@ typedef enum {
4848
} NIMBLE_PROPERTY;
4949

5050
# include "NimBLELocalAttribute.h"
51+
# include "NimBLEValueAttribute.h"
5152
# include "NimBLEAttValue.h"
5253
# include <vector>
5354
class NimBLEConnInfo;
5455

55-
class NimBLELocalValueAttribute : public NimBLELocalAttribute {
56+
class NimBLELocalValueAttribute : public NimBLELocalAttribute, public NimBLEValueAttribute {
5657
public:
5758
/**
5859
* @brief Get the properties of the attribute.
5960
*/
6061
uint16_t getProperties() const { return m_properties; }
6162

62-
/**
63-
* @brief Get the length of the attribute value.
64-
* @return The length of the attribute value.
65-
*/
66-
size_t getLength() const { return m_value.size(); }
67-
68-
/**
69-
* @brief Get a copy of the value of the attribute value.
70-
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
71-
* @return A copy of the attribute value.
72-
*/
73-
NimBLEAttValue getValue(time_t* timestamp = nullptr) const { return m_value; }
74-
7563
/**
7664
* @brief Set the value of the attribute value.
7765
* @param [in] data The data to set the value to.
@@ -100,19 +88,6 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute {
10088
m_value.setValue<T>(val);
10189
}
10290

103-
/**
104-
* @brief Template to convert the data to <type\>.
105-
* @tparam T The type to convert the data to.
106-
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
107-
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
108-
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
109-
* @details <b>Use:</b> <tt>getValue<type>(&timestamp, skipSizeCheck);</tt>
110-
*/
111-
template <typename T>
112-
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
113-
return m_value.getValue<T>(timestamp, skipSizeCheck);
114-
}
115-
11691
protected:
11792
friend class NimBLEServer;
11893

@@ -127,8 +102,7 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute {
127102
uint16_t handle,
128103
uint16_t maxLen,
129104
uint16_t initLen = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
130-
: NimBLELocalAttribute(uuid, handle), m_value(initLen, maxLen) {}
131-
105+
: NimBLELocalAttribute(uuid, handle), NimBLEValueAttribute(maxLen, initLen) {}
132106
/**
133107
* @brief Destroy the NimBLELocalValueAttribute object.
134108
*/
@@ -163,8 +137,7 @@ class NimBLELocalValueAttribute : public NimBLELocalAttribute {
163137
*/
164138
void setProperties(uint16_t properties) { m_properties = properties; }
165139

166-
NimBLEAttValue m_value{};
167-
uint16_t m_properties{0};
140+
uint16_t m_properties{0};
168141
};
169142

170143
#endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL

src/NimBLERemoteValueAttribute.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ int NimBLERemoteValueAttribute::onWriteCB(uint16_t conn_handle, const ble_gatt_e
122122
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
123123
* @return The value of the remote characteristic.
124124
*/
125-
NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) const {
125+
NimBLEAttValue NimBLERemoteValueAttribute::readValue(time_t* timestamp) {
126126
NIMBLE_LOGD(LOG_TAG, ">> readValue()");
127127

128128
NimBLEAttValue value{};

src/NimBLERemoteValueAttribute.h

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,19 @@
3232
# undef max
3333
/**************************/
3434

35-
# include "NimBLEAttribute.h"
35+
# include "NimBLEValueAttribute.h"
3636
# include "NimBLEAttValue.h"
3737

3838
class NimBLEClient;
3939

40-
class NimBLERemoteValueAttribute : public NimBLEAttribute {
40+
class NimBLERemoteValueAttribute : public NimBLEValueAttribute, public NimBLEAttribute {
4141
public:
4242
/**
4343
* @brief Read the value of the remote attribute.
4444
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
4545
* @return The value of the remote attribute.
4646
*/
47-
NimBLEAttValue readValue(time_t* timestamp = nullptr) const;
48-
49-
/**
50-
* @brief Get the length of the remote attribute value.
51-
* @return The length of the remote attribute value.
52-
*/
53-
size_t getLength() const { return m_value.size(); }
54-
55-
/**
56-
* @brief Get the value of the remote attribute.
57-
* @return The value of the remote attribute.
58-
* @details This returns a copy of the value to avoid potential race conditions.
59-
*/
60-
NimBLEAttValue getValue() const { return m_value; }
47+
NimBLEAttValue readValue(time_t* timestamp = nullptr);
6148

6249
/**
6350
* Get the client instance that owns this attribute.
@@ -153,20 +140,6 @@ class NimBLERemoteValueAttribute : public NimBLEAttribute {
153140
}
154141
# endif
155142

156-
/**
157-
* @brief Template to convert the remote characteristic data to <type\>.
158-
* @tparam T The type to convert the data to.
159-
* @param [in] timestamp A pointer to a time_t struct to store the time the value was read.
160-
* @param [in] skipSizeCheck If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
161-
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is
162-
* less than <tt>sizeof(<type\>)</tt>.
163-
* @details <b>Use:</b> <tt>getValue<type>(&timestamp, skipSizeCheck);</tt>
164-
*/
165-
template <typename T>
166-
T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
167-
return m_value.getValue<T>(timestamp, skipSizeCheck);
168-
}
169-
170143
/**
171144
* @brief Template to convert the remote characteristic data to <type\>.
172145
* @tparam T The type to convert the data to.
@@ -177,16 +150,16 @@ class NimBLERemoteValueAttribute : public NimBLEAttribute {
177150
* @details <b>Use:</b> <tt>readValue<type>(&timestamp, skipSizeCheck);</tt>
178151
*/
179152
template <typename T>
180-
T readValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
153+
T readValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) {
181154
readValue();
182-
return m_value.getValue<T>(timestamp, skipSizeCheck);
155+
return getValue<T>(timestamp, skipSizeCheck);
183156
}
184157

185158
protected:
186159
/**
187160
* @brief Construct a new NimBLERemoteValueAttribute object.
188161
*/
189-
NimBLERemoteValueAttribute(const ble_uuid_any_t& uuid, uint16_t handle) : NimBLEAttribute(uuid, handle) {}
162+
NimBLERemoteValueAttribute(const ble_uuid_any_t& uuid, uint16_t handle) : NimBLEAttribute{uuid, handle} {}
190163

191164
/**
192165
* @brief Destroy the NimBLERemoteValueAttribute object.
@@ -195,8 +168,6 @@ class NimBLERemoteValueAttribute : public NimBLEAttribute {
195168

196169
static int onReadCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg);
197170
static int onWriteCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg);
198-
199-
mutable NimBLEAttValue m_value{};
200171
};
201172

202173
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */

src/NimBLEValueAttribute.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and
3+
* esp-nimble-cpp, NimBLE-Arduino contributors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef NIMBLE_CPP_VALUE_ATTRIBUTE_H_
19+
#define NIMBLE_CPP_VALUE_ATTRIBUTE_H_
20+
21+
#include "nimconfig.h"
22+
#if defined(CONFIG_BT_ENABLED) && (defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL) || defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL))
23+
24+
# include "NimBLEAttribute.h"
25+
# include "NimBLEAttValue.h"
26+
27+
class NimBLEValueAttribute {
28+
public:
29+
NimBLEValueAttribute(uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN, uint16_t initLen = CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH)
30+
: m_value(initLen, maxLen) {}
31+
32+
/**
33+
* @brief Get a copy of the value of the attribute value.
34+
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
35+
* @return A copy of the attribute value.
36+
*/
37+
NimBLEAttValue getValue(time_t* timestamp) const { return m_value.getValue(timestamp); }
38+
39+
/**
40+
* @brief Get a copy of the value of the attribute value.
41+
* @return A copy of the attribute value.
42+
*/
43+
NimBLEAttValue getValue() const { return m_value; }
44+
45+
/**
46+
* @brief Get the length of the attribute value.
47+
* @return The length of the attribute value.
48+
*/
49+
size_t getLength() const { return m_value.size(); }
50+
51+
/**
52+
* @brief Template to convert the data to <type\>.
53+
* @tparam T The type to convert the data to.
54+
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
55+
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
56+
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
57+
* @details <b>Use:</b> <tt>getValue<type>(&timestamp, skipSizeCheck);</tt>
58+
* Used for types that are trivially copyable and convertible to NimBLEAttValue.
59+
*/
60+
template <typename T>
61+
typename std::enable_if<std::is_trivially_copyable<T>::value, T>::type
62+
getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
63+
return m_value.getValue<T>(timestamp, skipSizeCheck);
64+
}
65+
66+
/**
67+
* @brief Template to convert the data to <type\>.
68+
* @tparam T The type to convert the data to.
69+
* @param [in] timestamp (Optional) A pointer to a time_t struct to get the time the value set.
70+
* @param [in] skipSizeCheck (Optional) If true it will skip checking if the data size is less than <tt>sizeof(<type\>)</tt>.
71+
* @return The data converted to <type\> or NULL if skipSizeCheck is false and the data is less than <tt>sizeof(<type\>)</tt>.
72+
* @details <b>Use:</b> <tt>getValue<type>(&timestamp, skipSizeCheck);</tt>
73+
* Used for types that are not trivially copyable and convertible to NimBLEAttValue via it's operators.
74+
*/
75+
template <typename T>
76+
typename std::enable_if<!std::is_trivially_copyable<T>::value && std::is_convertible<T, NimBLEAttValue>::value, T>::type
77+
getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const {
78+
return m_value;
79+
}
80+
81+
protected:
82+
NimBLEAttValue m_value{};
83+
};
84+
85+
#endif // CONFIG_BT_ENABLED && (CONFIG_BT_NIMBLE_ROLE_PERIPHERAL || CONFIG_BT_NIMBLE_ROLE_CENTRAL)
86+
#endif // NIMBLE_CPP_ATTRIBUTE_H_

0 commit comments

Comments
 (0)