From 23e46d2de44a3d49063e852a38b020e7407a78bc Mon Sep 17 00:00:00 2001 From: Paul Nettle Date: Sun, 3 Sep 2017 08:15:12 -0500 Subject: The GGK server names are no longer in Globals.h but are now configured by ggkStart() allowing an application to change them based on configuration rather than compilation. Power-off-disconnect errors hacked out of existence. A few log lines that were set to trace converted to debug log levels to reduce logspam. --- README.md | 25 +++++++++++ include/Gobbledegook.h | 36 +++++++++++++++- src/DBusInterface.h | 2 +- src/DBusMethod.h | 3 +- src/DBusObject.cpp | 2 +- src/DBusObject.h | 2 +- src/GattCharacteristic.cpp | 2 +- src/GattDescriptor.cpp | 2 +- src/Globals.h | 32 +------------- src/Gobbledegook.cpp | 39 ++++++++++++++++- src/HciAdapter.cpp | 15 ++++++- src/Init.cpp | 67 +++++++++++++++-------------- src/Mgmt.cpp | 29 ++++--------- src/Mgmt.h | 8 ++-- src/Server.cpp | 47 ++++++++++++++++++--- src/Server.h | 103 ++++++++++++++++++++++++++++++++++++++++++++- src/Utils.cpp | 2 +- src/standalone.cpp | 8 +++- 18 files changed, 318 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 634dac2..75d8491 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,31 @@ Once you've done this, run the following commands to reload these settings and r sudo service bluetooth stop sudo service bluetooth start +### Enabling D-Bus Permissions + +In order for our application to communicate over D-Bus, we'll need to ask D-Bus for an *owned name*, which will in effect be our address on D-Bus. D-Bus must be configured to grant us permissions to do this. We'll grant these permissions to user `root`. + +You'll need to locate the D-Bus permissions on your box. Likely, you'll find a set of files for this in the directory `/etc/dbus-1/system.d`. Create the file `/etc/dbus-1/system.d/gobbledegook.conf` and give it the contents: + + + + + + + + + + + + + + + + + + +Note the `com.gobbledegook` entries in your new `gobbledegook.conf` file. This must match the service name (the first parameter sent to `ggkStart()` in `standalone.cpp`). If you change the service name from `gobbledegook` to `clownface` in that call to `ggkStart()`, then you'll need to edit the `gobbledegook.conf` file and change all occurrances of `com.gobbledegook` to `com.clownface`. + ### Enabling Bluetooth You don't need to do anything. this server will automatically power on the adapter, enable LE with advertisement. diff --git a/include/Gobbledegook.h b/include/Gobbledegook.h index 6213c0f..1914490 100644 --- a/include/Gobbledegook.h +++ b/include/Gobbledegook.h @@ -187,7 +187,41 @@ extern "C" // // Similarly, the pointer to data returned to the data getter should point to non-volatile memory so that the server can use it // safely for an indefinite period of time. - int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS); + // + // serviceName: The name of our server (collectino of services) + // + // !!!IMPORTANT!!! + // + // This name must match tha name configured in the D-Bus permissions. See the Readme.md file for more information. + // + // This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see + // getOwnedName.) + // + // This value will be stored as lower-case only. + // + // Retrieve this value using the `TheServer->getName()` method + // + // advertisingName: The name for this controller, as advertised over LE + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + // + // Retrieve this value using the `getAdvertisingName()` method + // + // advertisingShortName: The short name for this controller, as advertised over LE + // + // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or + // Advertising Data (AD). + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + // + // Retrieve this value using the `getAdvertisingShortName()` method + // + int ggkStart(const char *pServiceName, const char *pAdvertisingName, const char *pAdvertisingShortName, + GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS); // Blocks for up to maxAsyncInitTimeoutMS milliseconds until the server shuts down. // diff --git a/src/DBusInterface.h b/src/DBusInterface.h index 1dc8971..858dc44 100644 --- a/src/DBusInterface.h +++ b/src/DBusInterface.h @@ -38,7 +38,6 @@ #include "TickEvent.h" #include "DBusMethod.h" -#include "DBusObjectPath.h" namespace ggk { @@ -49,6 +48,7 @@ namespace ggk { struct DBusInterface; struct GattProperty; struct DBusObject; +struct DBusObjectPath; // --------------------------------------------------------------------------------------------------------------------------------- // Useful Lambdas diff --git a/src/DBusMethod.h b/src/DBusMethod.h index e63b84b..f081f7b 100644 --- a/src/DBusMethod.h +++ b/src/DBusMethod.h @@ -45,6 +45,7 @@ #include "Globals.h" #include "DBusObjectPath.h" #include "Logger.h" +#include "Server.h" namespace ggk { @@ -104,7 +105,7 @@ struct DBusMethod return; } - Logger::trace(SSTR << "Calling method: [" << path << "]:[" << interfaceName << "]:[" << methodName << "]"); + Logger::info(SSTR << "Calling method: [" << path << "]:[" << interfaceName << "]:[" << methodName << "]"); callback(*static_cast(pOwner), pConnection, methodName, pParameters, pInvocation, pUserData); } diff --git a/src/DBusObject.cpp b/src/DBusObject.cpp index 49d715a..0bfd2d3 100644 --- a/src/DBusObject.cpp +++ b/src/DBusObject.cpp @@ -238,7 +238,7 @@ std::string DBusObject::generateIntrospectionXML(int depth) const } xml += prefix + "\n"; - xml += prefix + " \n"; + xml += prefix + " \n"; for (std::shared_ptr interface : interfaces) { diff --git a/src/DBusObject.h b/src/DBusObject.h index 79564ba..2d74e3c 100644 --- a/src/DBusObject.h +++ b/src/DBusObject.h @@ -37,7 +37,6 @@ #include #include -#include "DBusInterface.h" #include "DBusObjectPath.h" namespace ggk { @@ -45,6 +44,7 @@ namespace ggk { struct GattProperty; struct GattService; struct GattUuid; +struct DBusInterface; struct DBusObject { diff --git a/src/GattCharacteristic.cpp b/src/GattCharacteristic.cpp index 9bfafd9..a10c04d 100644 --- a/src/GattCharacteristic.cpp +++ b/src/GattCharacteristic.cpp @@ -172,7 +172,7 @@ bool GattCharacteristic::callOnUpdatedValue(GDBusConnection *pConnection, void * return false; } - Logger::trace(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'"); + Logger::debug(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'"); return pOnUpdatedValueFunc(*this, pConnection, pUserData); } diff --git a/src/GattDescriptor.cpp b/src/GattDescriptor.cpp index bd29889..c5ecf67 100644 --- a/src/GattDescriptor.cpp +++ b/src/GattDescriptor.cpp @@ -173,7 +173,7 @@ bool GattDescriptor::callOnUpdatedValue(GDBusConnection *pConnection, void *pUse return false; } - Logger::trace(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'"); + Logger::debug(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'"); return pOnUpdatedValueFunc(*this, pConnection, pUserData); } diff --git a/src/Globals.h b/src/Globals.h index 02b7fa0..8476659 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -34,38 +34,10 @@ #include -// The name for this controller, as advertised over LE -// -// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set BOTH -// kCustomGlobalAdvertisingName and kCustomGlobalAdvertisingShortName to as empty string ("") to prevent setting the advertising -// name. -#define kCustomGlobalAdvertisingName std::string("Gobbledegook") - -// The short name for this controller, as advertised over LE -// -// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or -// Advertising Data (AD). -// -// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set BOTH -// kCustomGlobalAdvertisingName and kCustomGlobalAdvertisingShortName to as empty string ("") to prevent setting the advertising -// name. -#define kCustomGlobalAdvertisingShortName std::string("Gobbledegook") - -// The name of our server (collectino of services) -// -// This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for -// consistency.) -#define kServerName std::string("gobbledegook") - -// Our owned name -// -// D-Bus uses owned names to locate servers on the bus. Think of this as a namespace within D-Bus. Building this with the server -// name, though it's not necessary to do so. We can call this anything we want, really. -#define kServerOwnedName (std::string("com.") + kServerName) - // // Custom defined errors // + // In order to avoid confusion, we should use the owned name here, so errors are like extensions to that name. This way, if a // client gets one of these errors, it'll be clear which server it came from. -#define kErrorNotImplemented (kServerOwnedName + ".NotImplemented") +#define kErrorNotImplemented (TheServer->getOwnedName() + ".NotImplemented") diff --git a/src/Gobbledegook.cpp b/src/Gobbledegook.cpp index 43e7e76..f2e3ef8 100644 --- a/src/Gobbledegook.cpp +++ b/src/Gobbledegook.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -403,7 +404,41 @@ int ggkWait() // // Similarly, the pointer to data returned to the data getter should point to non-volatile memory so that the server can use it // safely for an indefinite period of time. -int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS) +// +// pServiceName: The name of our server (collectino of services) +// +// !!!IMPORTANT!!! +// +// This name must match tha name configured in the D-Bus permissions. See the Readme.md file for more information. +// +// This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see +// getOwnedName.) +// +// This value will be stored as lower-case only. +// +// Retrieve this value using the `getName()` method +// +// pAdvertisingName: The name for this controller, as advertised over LE +// +// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set +// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising +// name. +// +// Retrieve this value using the `getAdvertisingName()` method +// +// pAdvertisingShortName: The short name for this controller, as advertised over LE +// +// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or +// Advertising Data (AD). +// +// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set +// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising +// name. +// +// Retrieve this value using the `getAdvertisingShortName()` method +// +int ggkStart(const char *pServiceName, const char *pAdvertisingName, const char *pAdvertisingShortName, + GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS) { // // Start by capturing the GLib output @@ -446,7 +481,7 @@ int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyn Logger::info("Starting GGK server"); // Allocate our server - TheServer = std::make_shared(getter, setter); + TheServer = std::make_shared(pServiceName, pAdvertisingName, pAdvertisingShortName, getter, setter); // Start our server thread try diff --git a/src/HciAdapter.cpp b/src/HciAdapter.cpp index 6d99d69..9000709 100644 --- a/src/HciAdapter.cpp +++ b/src/HciAdapter.cpp @@ -344,10 +344,23 @@ bool HciAdapter::filterAndValidateEvents(uint16_t commandCode, std::vectorheader.dataSize; if (dataLength > buffer.size()) { - Logger::error(SSTR << " + Not enough data for the current event"); + Logger::error(" + Not enough data for the current event"); return false; } + // !HACK! - If the device is connected, then powering off (Command Code 0x0005) returns a Device Disconnect Event (Event + // Code 0xC) rather than a Command Complete Event (0x1) like it should. + // + // We'll fake it here, converting that condition into a Command Complete Event (0x1). + if (commandCode == 0x0005 && pEvent->header.code == 0xC) + { + Logger::debug("!HACK! Converting invalid Disconect Event to Command Complete Event for power-off command"); + pEvent->header.code = 1; + buffer = {0x1, 0x0, 0x0, 0x0, 0x7, 0x0, 0x5, 0x0, 0x0, 0x2, 0x6, 0x0, 0x0}; + pEvent = reinterpret_cast(buffer.data()); + dataLength = sizeof(Header) + pEvent->header.dataSize; + } + // Check the event type if (pEvent->header.code < kMinEventType || pEvent->header.code > kMaxEventType) { diff --git a/src/Init.cpp b/src/Init.cpp index 436a4fa..867b166 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -176,7 +176,7 @@ bool idleFunc(void *pUserData) // Is it a characteristic? if (std::shared_ptr pCharacteristic = TRY_GET_CONST_INTERFACE_OF_TYPE(pInterface, GattCharacteristic)) { - Logger::trace(SSTR << "Processing updated value for interface '" << interfaceName << "' at path '" << objectPath << "'"); + Logger::debug(SSTR << "Processing updated value for interface '" << interfaceName << "' at path '" << objectPath << "'"); pCharacteristic->callOnUpdatedValue(pBusConnection, pUserData); } } @@ -422,7 +422,7 @@ GVariant *onGetProperty return nullptr; } - Logger::trace(SSTR << "Calling property getter: " << propertyPath); + Logger::info(SSTR << "Calling property getter: " << propertyPath); GVariant *pResult = pProperty->getGetterFunc()(pConnection, pSender, objectPath.c_str(), pInterfaceName, pPropertyName, ppError, pUserData); if (nullptr == pResult) @@ -467,7 +467,7 @@ gboolean onSetProperty return false; } - Logger::trace(SSTR << "Calling property getter: " << propertyPath); + Logger::info(SSTR << "Calling property getter: " << propertyPath); if (!pProperty->getSetterFunc()(pConnection, pSender, objectPath.c_str(), pInterfaceName, pPropertyName, pValue, ppError, pUserData)) { g_set_error(ppError, G_IO_ERROR, G_IO_ERROR_FAILED, ("Property(set) failed: " + propertyPath).c_str(), pSender); @@ -492,7 +492,7 @@ gboolean onSetProperty void setRetryFailure() { retryTimeStart = time(nullptr); - Logger::debug(SSTR << " + Will retry this failed operation in about " << kRetryDelaySeconds << " seconds"); + Logger::warn(SSTR << " + Will retry the failed operation in about " << kRetryDelaySeconds << " seconds"); } // --------------------------------------------------------------------------------------------------------------------------------- @@ -534,7 +534,7 @@ void doRegisterApplication() else { g_variant_unref(pVariant); - Logger::trace(SSTR << "Application registered"); + Logger::debug(SSTR << "GATT application registered with BlueZ"); bApplicationRegistered = true; } @@ -664,7 +664,7 @@ void configureAdapter() Mgmt mgmt; // Find out what our current settings are - Logger::trace(SSTR << "Getting device information"); + Logger::debug(SSTR << "Getting device information"); Mgmt::ControllerInformation *pInfo = mgmt.getControllerInformation(); if (nullptr == pInfo) { @@ -675,7 +675,7 @@ void configureAdapter() // We need it off to start with if ((pInfo->currentSettings & Mgmt::EHciPowered) != 0) { - Logger::trace(SSTR << "Powering off"); + Logger::debug(SSTR << "Powering off"); if (!mgmt.setPowered(false)) { setRetryFailure(); @@ -687,7 +687,7 @@ void configureAdapter() bool bredrCurrentState = (pInfo->currentSettings & Mgmt::EHciBasicRate_EnhancedDataRate) != 0 ? true:false; if (TheServer->getEnableBREDR() != bredrCurrentState) { - Logger::trace(SSTR << (TheServer->getEnableBREDR() ? "Enabling":"Disabling") << " BR/EDR"); + Logger::debug(SSTR << (TheServer->getEnableBREDR() ? "Enabling":"Disabling") << " BR/EDR"); if (!mgmt.setBredr(TheServer->getEnableBREDR())) { setRetryFailure(); @@ -699,7 +699,7 @@ void configureAdapter() bool scCurrentState = (pInfo->currentSettings & Mgmt::EHciSecureConnections) != 0 ? true:false; if (TheServer->getEnableSecureConnection() != scCurrentState) { - Logger::trace(SSTR << (TheServer->getEnableSecureConnection() ? "Enabling":"Disabling") << " Secure Connections"); + Logger::debug(SSTR << (TheServer->getEnableSecureConnection() ? "Enabling":"Disabling") << " Secure Connections"); if (!mgmt.setSecureConnections(TheServer->getEnableSecureConnection() ? 1 : 0)) { setRetryFailure(); @@ -711,7 +711,7 @@ void configureAdapter() bool bondableCurrentState = (pInfo->currentSettings & Mgmt::EHciBondable) != 0 ? true:false; if (TheServer->getEnableBondable() != bondableCurrentState) { - Logger::trace(SSTR << (TheServer->getEnableBondable() ? "Enabling":"Disabling") << " Bondable"); + Logger::debug(SSTR << (TheServer->getEnableBondable() ? "Enabling":"Disabling") << " Bondable"); if (!mgmt.setBondable(TheServer->getEnableBondable())) { setRetryFailure(); @@ -723,7 +723,7 @@ void configureAdapter() bool connectableCurrentState = (pInfo->currentSettings & Mgmt::EHciConnectable) != 0 ? true:false; if (TheServer->getEnableConnectable() != connectableCurrentState) { - Logger::trace(SSTR << (TheServer->getEnableConnectable() ? "Enabling":"Disabling") << " Connectable"); + Logger::debug(SSTR << (TheServer->getEnableConnectable() ? "Enabling":"Disabling") << " Connectable"); if (!mgmt.setConnectable(TheServer->getEnableConnectable())) { setRetryFailure(); @@ -734,7 +734,7 @@ void configureAdapter() // Enable the LE state (we always set this state if it's not set) if ((pInfo->currentSettings & Mgmt::EHciLowEnergy) == 0) { - Logger::trace(SSTR << "Enabling LE"); + Logger::debug(SSTR << "Enabling LE"); if (!mgmt.setLE(true)) { setRetryFailure(); @@ -746,7 +746,7 @@ void configureAdapter() bool advertisingCurrentState = (pInfo->currentSettings & Mgmt::EHciAdvertising) != 0 ? true:false; if (TheServer->getEnableAdvertising() != advertisingCurrentState) { - Logger::trace(SSTR << (TheServer->getEnableAdvertising() ? "Enabling":"Disabling") << " Advertising"); + Logger::debug(SSTR << (TheServer->getEnableAdvertising() ? "Enabling":"Disabling") << " Advertising"); if (!mgmt.setAdvertising(TheServer->getEnableAdvertising() ? 1 : 0)) { setRetryFailure(); @@ -755,22 +755,25 @@ void configureAdapter() } // Set the name? - if (kCustomGlobalAdvertisingName.length() != 0 || kCustomGlobalAdvertisingShortName.length() != 0) + if (TheServer->getAdvertisingName().length() != 0 || TheServer->getAdvertisingShortName().length() != 0) { - if (Mgmt::truncateName(kCustomGlobalAdvertisingName) != pInfo->name || - Mgmt::truncateShortName(kCustomGlobalAdvertisingShortName) != pInfo->shortName) + std::string advertisingName = Mgmt::truncateName(TheServer->getAdvertisingName()); + std::string advertisingShortName = Mgmt::truncateShortName(TheServer->getAdvertisingShortName()); + + if (advertisingName != pInfo->name || advertisingShortName != pInfo->shortName) { - Logger::trace(SSTR << "Setting name to '" << kCustomGlobalAdvertisingName << "'"); - if (!mgmt.setName(kCustomGlobalAdvertisingName.c_str(), kCustomGlobalAdvertisingName.c_str())) + if (!mgmt.setName(advertisingName.c_str(), advertisingShortName.c_str())) { setRetryFailure(); return; } } + + Logger::info(SSTR << "BLE advertising name set to '" << advertisingName << "' (with short name: '" << advertisingShortName << "')"); } // Turn it back on - Logger::trace(SSTR << "Powering on"); + Logger::debug(SSTR << "Powering on"); if (!mgmt.setPowered(true)) { setRetryFailure(); @@ -944,9 +947,9 @@ void doOwnedNameAcquire() ownedNameId = g_bus_own_name_on_connection ( - pBusConnection, // GDBusConnection *connection - kServerOwnedName.c_str(), // const gchar *name - G_BUS_NAME_OWNER_FLAGS_NONE, // GBusNameOwnerFlags flags + pBusConnection, // GDBusConnection *connection + TheServer->getOwnedName().c_str(), // const gchar *name + G_BUS_NAME_OWNER_FLAGS_NONE, // GBusNameOwnerFlags flags // GBusNameAcquiredCallback name_acquired_handler [](GDBusConnection *, const gchar *, gpointer) @@ -973,16 +976,16 @@ void doOwnedNameAcquire() // Bus name lost bOwnedNameAcquired = false; - // If we don't have a periodicTimeout (which we use for error recovery) then we're done + // If we don't have a periodicTimeout (which we use for error recovery) then we're sunk if (0 == periodicTimeoutId) { - Logger::fatal(SSTR << "Unable to acquire an owned name ('" << kServerOwnedName << "') on the bus"); + Logger::fatal(SSTR << "Unable to acquire an owned name ('" << TheServer->getOwnedName() << "') on the bus"); setServerHealth(EFailedInit); shutdown(); } else { - Logger::warn(SSTR << "Owned name ('" << kServerOwnedName << "') lost"); + Logger::warn(SSTR << "Owned name ('" << TheServer->getOwnedName() << "') lost"); setRetryFailure(); return; } @@ -1060,7 +1063,7 @@ void initializationStateProcessor() // if (nullptr == pBusConnection) { - Logger::trace(SSTR << "Acquiring bus connection"); + Logger::debug(SSTR << "Acquiring bus connection"); doBusAcquire(); return; } @@ -1070,7 +1073,7 @@ void initializationStateProcessor() // if (!bOwnedNameAcquired) { - Logger::trace(SSTR << "Acquiring owned name: '" << kServerOwnedName << "'"); + Logger::debug(SSTR << "Acquiring owned name: '" << TheServer->getOwnedName() << "'"); doOwnedNameAcquire(); return; } @@ -1090,7 +1093,7 @@ void initializationStateProcessor() // if (bluezGattManagerInterfaceName.empty()) { - Logger::trace(SSTR << "Finding BlueZ GattManager1 interface"); + Logger::debug(SSTR << "Finding BlueZ GattManager1 interface"); findAdapterInterface(); return; } @@ -1100,7 +1103,7 @@ void initializationStateProcessor() // if (!bAdapterConfigured) { - Logger::trace(SSTR << "Configuring BlueZ adapter '" << bluezGattManagerInterfaceName << "'"); + Logger::debug(SSTR << "Configuring BlueZ adapter '" << bluezGattManagerInterfaceName << "'"); configureAdapter(); return; } @@ -1110,7 +1113,7 @@ void initializationStateProcessor() // if (registeredObjectIds.empty()) { - Logger::trace(SSTR << "Registering with D-Bus"); + Logger::debug(SSTR << "Registering with D-Bus"); registerObjects(); return; } @@ -1118,7 +1121,7 @@ void initializationStateProcessor() // Register our appliation with the BlueZ GATT manager if (!bApplicationRegistered) { - Logger::trace(SSTR << "Registering application with BlueZ GATT manager"); + Logger::debug(SSTR << "Registering application with BlueZ GATT manager"); doRegisterApplication(); return; @@ -1167,7 +1170,7 @@ void runServerThread() // There are alternatives, but using async methods is the recommended way. initializationStateProcessor(); - Logger::trace(SSTR << "Starting main loop"); + Logger::debug(SSTR << "Starting GLib main loop"); pMainLoop = g_main_loop_new(NULL, FALSE); // Add the idle function diff --git a/src/Mgmt.cpp b/src/Mgmt.cpp index c956e99..34537f0 100644 --- a/src/Mgmt.cpp +++ b/src/Mgmt.cpp @@ -139,8 +139,8 @@ Mgmt::ControllerInformation *Mgmt::getControllerInformation() // Set the adapter name and short name // // The inputs `name` and `shortName` may be truncated prior to setting them on the adapter. To ensure that `name` and -// `shortName` conform to length specifications prior to calling this method, see the constants `kMaxNameLength` and -// `kMaxShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful. +// `shortName` conform to length specifications prior to calling this method, see the constants `kMaxAdvertisingNameLength` and +// `kMaxAdvertisingShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful. // // Returns true on success, otherwise false bool Mgmt::setName(std::string name, std::string shortName) @@ -179,7 +179,7 @@ bool Mgmt::setName(std::string name, std::string shortName) return false; } - Logger::trace(SSTR << " + Name set to '" << request.name << "', short name set to '" << request.shortName << "'"); + Logger::info(SSTR << " + Name set to '" << request.name << "', short name set to '" << request.shortName << "'"); return true; } @@ -214,24 +214,13 @@ bool Mgmt::setState(const char *pSettingName, uint16_t commandCode, uint16_t con SResponse response; if (!hciAdapter.sendCommand(request, response, sizeof(response))) { - // Setting power to 0 doesn't actually return a response event if it's connected (it receives a disconnect instead). - // - // This is a failure on the part of GGK because it should be handling events more correctly. For now, though, we'll just - // turn those failures into debug log messages so our logs aren't cluttered up with false failures. - if (commandCode == 0x0005) - { - Logger::debug(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast(newState)); - } - else - { - Logger::info(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast(newState)); - } + Logger::warn(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast(newState)); return false; } response.toHost(); - Logger::trace(SSTR << " + " << pSettingName << " set to " << static_cast(newState) << ": " << controllerSettingsString(response.currentSettings)); + Logger::debug(SSTR << " + " << pSettingName << " set to " << static_cast(newState) << ": " << controllerSettingsString(response.currentSettings)); return true; } @@ -331,24 +320,24 @@ std::string Mgmt::controllerSettingsString(uint32_t bits) // `name` is returned. std::string Mgmt::truncateName(const std::string &name) { - if (name.length() <= kMaxNameLength) + if (name.length() <= kMaxAdvertisingNameLength) { return name; } - return name.substr(0, kMaxNameLength); + return name.substr(0, kMaxAdvertisingNameLength); } // Truncates the string `name` to the maximum allowed length for an adapter short-name. If `name` needs no truncation, a copy // of `name` is returned. std::string Mgmt::truncateShortName(const std::string &name) { - if (name.length() <= kMaxShortNameLength) + if (name.length() <= kMaxAdvertisingShortNameLength) { return name; } - return name.substr(0, kMaxShortNameLength); + return name.substr(0, kMaxAdvertisingShortNameLength); } }; // namespace ggk \ No newline at end of file diff --git a/src/Mgmt.h b/src/Mgmt.h index dfd5b95..23315a5 100644 --- a/src/Mgmt.h +++ b/src/Mgmt.h @@ -50,10 +50,10 @@ struct Mgmt // // The length of the controller's name (not including null terminator) - static const int kMaxNameLength = 248; + static const int kMaxAdvertisingNameLength = 248; // The length of the controller's short name (not including null terminator) - static const int kMaxShortNameLength = 10; + static const int kMaxAdvertisingShortNameLength = 10; // // Types @@ -127,8 +127,8 @@ struct Mgmt // Set the adapter name and short name // // The inputs `name` and `shortName` may be truncated prior to setting them on the adapter. To ensure that `name` and - // `shortName` conform to length specifications prior to calling this method, see the constants `kMaxNameLength` and - // `kMaxShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful. + // `shortName` conform to length specifications prior to calling this method, see the constants `kMaxAdvertisingNameLength` and + // `kMaxAdvertisingShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful. // // Returns true on success, otherwise false bool setName(std::string name, std::string shortName); diff --git a/src/Server.cpp b/src/Server.cpp index a369b32..87b3279 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -62,8 +62,6 @@ // used to generate both: (1) the D-Bus object hierarchy and (2) the BlueZ services that occupy that hierarchy. In addition, we'll // take that a step further by including the implementation right inside the description. Everything in one place. // -// Well, almost one place (hint: Take a quick look at Globals.h - that's where your server name is.) -// // >> // >>> MANAGING SERVER DATA // >> @@ -160,6 +158,8 @@ // https://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/glib/glib-GVariantType.html // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#include + #include "Server.h" #include "ServerUtils.h" #include "Utils.h" @@ -171,6 +171,7 @@ #include "GattUuid.h" #include "GattCharacteristic.h" #include "GattDescriptor.h" +#include "Logger.h" namespace ggk { @@ -195,11 +196,45 @@ std::shared_ptr TheServer = nullptr; // Object implementation // --------------------------------------------------------------------------------------------------------------------------------- -// Create (and completely describe) a server +// Our constructor builds our entire server description +// +// serviceName: The name of our server (collectino of services) +// +// This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see +// getOwnedName.) +// +// This value will be stored as lower-case only. +// +// Retrieve this value using the `getName()` method. +// +// advertisingName: The name for this controller, as advertised over LE // -// For details, head up to the top of this file. -Server::Server(GGKServerDataGetter getter, GGKServerDataSetter setter) +// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set +// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising +// name. +// +// Retrieve this value using the `getAdvertisingName()` method. +// +// advertisingShortName: The short name for this controller, as advertised over LE +// +// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or +// Advertising Data (AD). +// +// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set +// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising +// name. +// +// Retrieve this value using the `getAdvertisingShortName()` method. +// +Server::Server(const std::string &serviceName, const std::string &advertisingName, const std::string &advertisingShortName, + GGKServerDataGetter getter, GGKServerDataSetter setter) { + // Save our names + this->serviceName = serviceName; + std::transform(this->serviceName.begin(), this->serviceName.end(), this->serviceName.begin(), ::tolower); + this->advertisingName = advertisingName; + this->advertisingShortName = advertisingShortName; + // Register getter & setter for server data dataGetter = getter; dataSetter = setter; @@ -216,7 +251,7 @@ Server::Server(GGKServerDataGetter getter, GGKServerDataSetter setter) // // Create the root D-Bus object and push it into the list - objects.push_back(DBusObject(DBusObjectPath() + "com" + kServerName)); + objects.push_back(DBusObject(DBusObjectPath() + "com" + getServiceName())); // We're going to build off of this object, so we need to get a reference to the instance of the object as it resides in the // list (and not the object that would be added to the list.) diff --git a/src/Server.h b/src/Server.h index 8312022..d6154dc 100644 --- a/src/Server.h +++ b/src/Server.h @@ -35,11 +35,13 @@ #pragma once +#include #include +#include #include #include -#include "DBusInterface.h" +#include "../include/Gobbledegook.h" #include "DBusObject.h" namespace ggk { @@ -49,6 +51,9 @@ namespace ggk { // struct GattProperty; +struct GattCharacteristic; +struct DBusInterface; +struct DBusObjectPath; // // Implementation @@ -91,12 +96,77 @@ struct Server // Returns our registered data setter GGKServerDataSetter getDataSetter() const { return dataSetter; } + // advertisingName: The name for this controller, as advertised over LE + // + // This is set from the constructor. + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + const std::string &getAdvertisingName() const { return advertisingName; } + + // advertisingShortName: The short name for this controller, as advertised over LE + // + // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or + // Advertising Data (AD). + // + // This is set from the constructor. + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + const std::string &getAdvertisingShortName() const { return advertisingShortName; } + + // serviceName: The name of our server (collectino of services) + // + // This is set from the constructor. + // + // This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for + // consistency.) + const std::string &getServiceName() const { return serviceName; } + + // Our owned name + // + // D-Bus uses owned names to locate servers on the bus. Think of this as a namespace within D-Bus. We building this with the + // server name to keep things simple. + std::string getOwnedName() const { return std::string("com.") + getServiceName(); } + // // Initialization // // Our constructor builds our entire server description - Server(GGKServerDataGetter getter, GGKServerDataSetter setter); + // + // serviceName: The name of our server (collectino of services) + // + // This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see + // getOwnedName.) + // + // This value will be stored as lower-case only. + // + // Retrieve this value using the `getName()` method. + // + // advertisingName: The name for this controller, as advertised over LE + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + // + // Retrieve this value using the `getAdvertisingName()` method. + // + // advertisingShortName: The short name for this controller, as advertised over LE + // + // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or + // Advertising Data (AD). + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + // + // Retrieve this value using the `getAdvertisingShortName()` method. + // + Server(const std::string &serviceName, const std::string &advertisingName, const std::string &advertisingShortName, + GGKServerDataGetter getter, GGKServerDataSetter setter); // // Utilitarian @@ -142,6 +212,35 @@ private: // The setter callback that is responsible for storing current server data that is shared over Bluetooth GGKServerDataSetter dataSetter; + + // advertisingName: The name for this controller, as advertised over LE + // + // This is set from the constructor. + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + std::string advertisingName; + + // advertisingShortName: The short name for this controller, as advertised over LE + // + // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or + // Advertising Data (AD). + // + // This is set from the constructor. + // + // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set + // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising + // name. + std::string advertisingShortName; + + // serviceName: The name of our server (collectino of services) + // + // This is set from the constructor. + // + // This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for + // consistency.) + std::string serviceName; }; // Our one and only server. It's a global. diff --git a/src/Utils.cpp b/src/Utils.cpp index ca3aaa5..2ced142 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -180,7 +180,7 @@ std::string Utils::hex(const uint8_t *pData, int count) asciiData.push_back(line); } - std::string result = "\n"; + std::string result = ""; size_t dataSize = hexData.size(); for (size_t i = 0; i < dataSize; ++i) { diff --git a/src/standalone.cpp b/src/standalone.cpp index c8af5d6..3c4968c 100644 --- a/src/standalone.cpp +++ b/src/standalone.cpp @@ -293,7 +293,13 @@ int main(int argc, char **ppArgv) // Start the server's ascync processing // // This starts the server on a thread and begins the initialization process - if (!ggkStart(dataGetter, dataSetter, kMaxAsyncInitTimeoutMS)) + // + // !!!IMPORTANT!!! + // + // This first parameter (the service name) must match tha name configured in the D-Bus permissions. See the Readme.md file + // for more information. + // + if (!ggkStart("gobbledegook", "Gobbledegook", "Gobbledegook", dataGetter, dataSetter, kMaxAsyncInitTimeoutMS)) { return -1; } -- cgit v1.2.3