/* * Copyright 2020-2024 Ryan Powell and * esp-nimble-cpp, NimBLE-Arduino contributors. * * 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. */ #ifndef NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_ #define NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_ #include "nimconfig.h" #if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) # if defined(CONFIG_NIMBLE_CPP_IDF) # include # else # include # endif /**** FIX COMPILATION ****/ # undef min # undef max /**************************/ # include "NimBLEAttribute.h" # include "NimBLEAttValue.h" class NimBLEClient; class NimBLERemoteValueAttribute : public NimBLEAttribute { public: /** * @brief Read the value of the remote attribute. * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. * @return The value of the remote attribute. */ NimBLEAttValue readValue(time_t* timestamp = nullptr) const; /** * @brief Get the length of the remote attribute value. * @return The length of the remote attribute value. */ size_t getLength() const { return m_value.size(); } /** * @brief Get the value of the remote attribute. * @return The value of the remote attribute. * @details This returns a copy of the value to avoid potential race conditions. */ NimBLEAttValue getValue() const { return m_value; } /** * Get the client instance that owns this attribute. */ virtual NimBLEClient* getClient() const = 0; /** * @brief Write a new value to the remote characteristic from a data buffer. * @param [in] data A pointer to a data buffer. * @param [in] length The length of the data in the data buffer. * @param [in] response Whether we require a response from the write. * @return false if not connected or otherwise cannot perform write. */ bool writeValue(const uint8_t* data, size_t length, bool response = false) const; /** * @brief Write a new value to the remote characteristic from a const char*. * @param [in] str A character string to write to the remote characteristic. * @param [in] length (optional) The length of the character string, uses strlen if omitted. * @param [in] response Whether we require a response from the write. * @return false if not connected or otherwise cannot perform write. */ bool writeValue(const char* str, size_t length = 0, bool response = false) const { return writeValue(reinterpret_cast(str), length ? length : strlen(str), response); } # if __cplusplus < 201703L /** * @brief Template to set the remote characteristic value to val. * @param [in] v The value to write. * @param [in] response True == request write response. * @details Only used for types without a `c_str()` and `length()` or `data()` and `size()` method. * size must be evaluatable by `sizeof()` if no length is provided. */ template # ifdef _DOXYGEN_ bool # else typename std::enable_if::value && !Has_c_str_length::value && !Has_data_size::value, bool>::type # endif writeValue(const T& v, bool response = false) const { return writeValue(reinterpret_cast(&v), sizeof(T), response); } /** * @brief Template to set the remote characteristic value to val. * @param [in] s The value to write. * @param [in] response True == request write response. * @details Only used if the has a `c_str()` and `length()` method. */ template # ifdef _DOXYGEN_ bool # else typename std::enable_if::value && !Has_data_size::value, bool>::type # endif writeValue(const T& s, bool response = false) const { return writeValue(reinterpret_cast(s.c_str()), s.length(), response); } /** * @brief Template to set the remote characteristic value to val. * @param [in] v The value to write. * @param [in] response True == request write response. * @details Only used if the has a `data()` and `size()` method. */ template # ifdef _DOXYGEN_ bool # else typename std::enable_if::value, bool>::type # endif writeValue(const T& v, bool response = false) const { return writeValue(reinterpret_cast(v.data()), v.size(), response); } # else /** * @brief Template to set the remote characteristic value to val. * @param [in] s The value to write. * @param [in] response True == request write response. * @note This function is only available if the type T is not a pointer. */ template typename std::enable_if::value, bool>::type writeValue(const T& v, bool response = false) const { if constexpr (Has_data_size::value) { return writeValue(reinterpret_cast(v.data()), v.size(), response); } else if constexpr (Has_c_str_length::value) { return writeValue(reinterpret_cast(v.c_str()), v.length(), response); } else { return writeValue(reinterpret_cast(&v), sizeof(v), response); } } # endif /** * @brief Template to convert the remote characteristic data to . * @tparam T The type to convert the data to. * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). * @return The data converted to or NULL if skipSizeCheck is false and the data is * less than sizeof(). * @details Use: getValue(×tamp, skipSizeCheck); */ template T getValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const { return m_value.getValue(timestamp, skipSizeCheck); } /** * @brief Template to convert the remote characteristic data to . * @tparam T The type to convert the data to. * @param [in] timestamp A pointer to a time_t struct to store the time the value was read. * @param [in] skipSizeCheck If true it will skip checking if the data size is less than sizeof(). * @return The data converted to or NULL if skipSizeCheck is false and the data is * less than sizeof(). * @details Use: readValue(×tamp, skipSizeCheck); */ template T readValue(time_t* timestamp = nullptr, bool skipSizeCheck = false) const { readValue(); return m_value.getValue(timestamp, skipSizeCheck); } protected: /** * @brief Construct a new NimBLERemoteValueAttribute object. */ NimBLERemoteValueAttribute(const ble_uuid_any_t& uuid, uint16_t handle) : NimBLEAttribute(uuid, handle) {} /** * @brief Destroy the NimBLERemoteValueAttribute object. */ virtual ~NimBLERemoteValueAttribute() = default; static int onReadCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg); static int onWriteCB(uint16_t conn_handle, const ble_gatt_error* error, ble_gatt_attr* attr, void* arg); mutable NimBLEAttValue m_value{}; }; #endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */ #endif // NIMBLE_CPP_REMOTE_VALUE_ATTRIBUTE_H_