/* * Author: Sven Gothel * Copyright (c) 2020 Gothel Software e.K. * Copyright (c) 2020 ZAFENA AB * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef DBT_DEV_ACCOUNTING_HPP_ #define DBT_DEV_ACCOUNTING_HPP_ #include #include #include namespace direct_bt { /** * Application toolkit providing BT device registration of processed and awaited devices. * The latter on a pattern matching basis, i.e. EUI48Sub or name-sub. */ namespace BTDeviceRegistry { /** * Specifies devices queries to act upon. */ struct DeviceQuery { /** * DeviceQuery type, i.e. EUI48Sub or a std::string name. */ enum class Type : int { /** DeviceQuery type, using a sensor device EUI48Sub. */ EUI48SUB, /** DeviceQuery type, using a sensor device std::string name. */ NAME }; Type type; EUI48Sub addressSub; std::string nameSub; DeviceQuery(const EUI48Sub& as) : type(Type::EUI48SUB), addressSub(as), nameSub() {} DeviceQuery(const std::string& ns) : type(Type::NAME), addressSub(EUI48Sub::ANY_DEVICE), nameSub(ns) {} bool isEUI48Sub() const noexcept { return Type::EUI48SUB == type; } std::string toString() const { if( Type::EUI48SUB == type ) { return "[a: "+addressSub.toString()+"]"; } else { return "[n: '"+nameSub+"']"; } } }; void addToWaitForDevices(const std::string& addrOrNameSub) noexcept; bool isWaitingForAnyDevice() noexcept; size_t getWaitForDevicesCount() noexcept; std::string getWaitForDevicesString() noexcept; /** * Returns the reference of the current list of DeviceQuery, not a copy. */ jau::darray& getWaitForDevices() noexcept; /** * Clears internal list */ void clearWaitForDevices() noexcept; /** * Specifies unique device identities, * using {@link BDAddressAndType} as key. */ struct DeviceID { BDAddressAndType addressAndType; std::string name; DeviceID(const BDAddressAndType& a, const std::string& n) : addressAndType(a), name(n) {} DeviceID() : addressAndType(), name() {} /** * {@inheritDoc} *

* Implementation simply returns the BDAddressAndType hash code, * `name` is ignored. *

*/ std::size_t hash_code() const noexcept { return addressAndType.hash_code(); } std::string toString() const { return "["+addressAndType.toString()+", '"+name+"']"; } }; /** * {@inheritDoc} *

* Implementation simply tests the {@link BDAddressAndType} fields for equality, * `name` is ignored. *

*/ inline bool operator==(const DeviceID& lhs, const DeviceID& rhs) noexcept { if( &lhs == &rhs ) { return true; } return lhs.addressAndType == rhs.addressAndType; } inline bool operator!=(const DeviceID& lhs, const DeviceID& rhs) noexcept { return !(lhs == rhs); } void addToProcessedDevices(const BDAddressAndType &a, const std::string& n) noexcept; bool isDeviceProcessed(const BDAddressAndType & a) noexcept; size_t getProcessedDeviceCount() noexcept; std::string getProcessedDevicesString() noexcept; /** * Returns a copy of the current collection of processed DeviceID. */ jau::darray getProcessedDevices() noexcept; /** * Clears internal list */ void clearProcessedDevices() noexcept; /** * Function for user defined BTDeviceRegistry::DeviceQuery matching criteria and algorithm. *

* Return {@code true} if the given {@code address} and/or {@code name} matches * with the BTDeviceRegistry::DeviceQuery::addressSub and/or * BTDeviceRegistry::DeviceQuery::nameSub. *

*

* Example (lambda): *

         *    [](const EUI48& a, const std::string& n, const DeviceQuery& q)->bool {
         *       return q.isEUI48Sub() ? a.contains(q.addressSub) : n.find(q.nameSub) != std::string::npos;
         *    });
         * 
*

*/ typedef bool (*DeviceQueryMatchFunc)(const EUI48& address, const std::string& name, const DeviceQuery& q); /** * Returns {@code true} if the given {@code address} and/or {@code name} * matches any of the BTDeviceRegistry::addToWaitForDevices() awaited devices. *

* Matching criteria and algorithm is defined by the given BTDeviceRegistry::DeviceQueryMatchFunc. *

* @see BTDeviceRegistry::isWaitingForDevice() */ bool isWaitingForDevice(const EUI48 &address, const std::string &name, DeviceQueryMatchFunc m) noexcept; /** * Returns {@code true} if the given {@code address} and/or {@code name} * matches any of the BTDeviceRegistry::addToWaitForDevices() awaited devices. *

* Matching criteria is either the awaited device's BTDeviceRegistry::DeviceQuery::addressSub * or BTDeviceRegistry::DeviceQuery::nameSub, whichever is set. *

*

* Matching algorithm is a simple {@code contains} pattern match, * i.e. the given {@code address} or {@code name} contains the corresponding BTDeviceRegistry::DeviceQuery element. *

* @see BTDeviceRegistry::isWaitingForDevice() */ inline bool isWaitingForDevice(const EUI48 &address, const std::string &name) noexcept { return isWaitingForDevice(address, name, [](const EUI48& a, const std::string& n, const DeviceQuery& q)->bool { return q.isEUI48Sub() ? a.contains(q.addressSub) : n.find(q.nameSub) != std::string::npos; }); } /** * Returns {@code true} if all addToWaitForDevices() awaited devices * have been addToProcessedDevices() processed. *

* Matching criteria and algorithm is defined by the given BTDeviceRegistry::DeviceQueryMatchFunc. *

* @see BTDeviceRegistry::areAllDevicesProcessed() */ bool areAllDevicesProcessed(DeviceQueryMatchFunc m) noexcept; /** * Returns {@code true} if all addToWaitForDevices() awaited devices * have been addToProcessedDevices() processed. *

* Matching criteria is either the awaited device's BTDeviceRegistry::DeviceQuery::addressSub * or BTDeviceRegistry::DeviceQuery::nameSub, whichever is set. *

*

* Matching algorithm is a simple {@code contains} pattern match, * i.e. the processed BTDeviceRegistry::DeviceID contains one element of BTDeviceRegistry::DeviceQuery. *

* @see BTDeviceRegistry::areAllDevicesProcessed() */ inline bool areAllDevicesProcessed() noexcept { return areAllDevicesProcessed( [](const EUI48& a, const std::string& n, const DeviceQuery& q)->bool { return q.isEUI48Sub() ? a.contains(q.addressSub) : n.find(q.nameSub) != std::string::npos; }); } void addToProcessingDevices(const BDAddressAndType &a, const std::string& n) noexcept; bool removeFromProcessingDevices(const BDAddressAndType &a) noexcept; bool isDeviceProcessing(const BDAddressAndType & a) noexcept; size_t getProcessingDeviceCount() noexcept; /** * Returns a copy of the current collection of processing DeviceID. */ jau::darray getProcessingDevices() noexcept; /** * Clears internal list */ void clearProcessingDevices() noexcept; } } // namespace direct_bt // injecting specialization of std::hash to namespace std of our types above namespace std { template<> struct hash { std::size_t operator()(direct_bt::BTDeviceRegistry::DeviceID const& a) const noexcept { return a.hash_code(); } }; } #endif /* DBT_DEV_ACCOUNTING_HPP_ */