#include <string.h>
#include "Mgmt.h"
#include "Logger.h"
#include "Utils.h"
Mgmt::Mgmt(uint16_t controllerIndex)
: controllerIndex(controllerIndex)
{
}
int Mgmt::getVersion()
{
struct SResponse : HciAdapter::ResponseEvent
{
uint8_t version;
uint16_t revision;
void toHost()
{
revision = Utils::endianToHost(revision);
}
} __attribute__((packed));
HciAdapter::Header request;
request.code = 1;
request.controllerId = kNonController;
request.dataSize = 0;
SResponse response;
if (!hciAdapter.sendCommand(request, response, sizeof(response)))
{
Logger::warn(SSTR << " + Failed to get version information");
return -1;
}
response.toHost();
Logger::info(SSTR << " + Version response has version=" << Utils::hex(response.version) << " and revision=" << Utils::hex(response.revision));
return (response.version << 16) | response.revision;
}
Mgmt::ControllerInformation *Mgmt::getControllerInformation()
{
struct SResponse : HciAdapter::ResponseEvent
{
ControllerInformation info;
void toHost()
{
info.toHost();
}
} __attribute__((packed));
HciAdapter::Header request;
request.code = 4;
request.controllerId = controllerIndex;
request.dataSize = 0;
Logger::debug("Dumping device information after configuration...");
SResponse response;
if (!hciAdapter.sendCommand(request, response, sizeof(response)))
{
Logger::warn(SSTR << " + Failed to get current settings");
return nullptr;
}
response.toHost();
controllerInfo = response.info;
Logger::debug(" + Controller information");
Logger::debug(SSTR << " + Current settings : " << Utils::hex(controllerInfo.currentSettings));
Logger::debug(SSTR << " + Address : " << Utils::bluetoothAddressString(controllerInfo.address));
Logger::debug(SSTR << " + BT Version : " << controllerInfo.bluetoothVersion);
Logger::debug(SSTR << " + Manufacturer : " << Utils::hex(controllerInfo.manufacturer));
Logger::debug(SSTR << " + Supported settings : " << controllerSettingsString(controllerInfo.supportedSettings));
Logger::debug(SSTR << " + Current settings : " << controllerSettingsString(controllerInfo.currentSettings));
Logger::debug(SSTR << " + Name : " << controllerInfo.name);
Logger::debug(SSTR << " + Short name : " << controllerInfo.shortName);
return &controllerInfo;
}
bool Mgmt::setName(std::string name, std::string shortName)
{
name = truncateName(name);
shortName = truncateShortName(shortName);
struct SRequest : HciAdapter::Header
{
char name[249];
char shortName[11];
} __attribute__((packed));
struct SResponse : HciAdapter::ResponseEvent
{
char name[249];
char shortName[11];
} __attribute__((packed));
SRequest request;
request.code = 0x000F;
request.controllerId = controllerIndex;
request.dataSize = sizeof(SRequest) - sizeof(HciAdapter::Header);
memset(request.name, 0, sizeof(request.name));
snprintf(request.name, sizeof(request.name), "%s", name.c_str());
memset(request.shortName, 0, sizeof(request.shortName));
snprintf(request.shortName, sizeof(request.shortName), "%s", shortName.c_str());
SResponse response;
if (!hciAdapter.sendCommand(request, response, sizeof(response)))
{
Logger::warn(SSTR << " + Failed to set name");
return false;
}
Logger::info(SSTR << " + Name set to '" << request.name << "', short name set to '" << request.shortName << "'");
return true;
}
bool Mgmt::setState(const char *pSettingName, uint16_t commandCode, uint16_t controllerId, uint8_t newState)
{
struct SRequest : HciAdapter::Header
{
uint8_t state;
} __attribute__((packed));
struct SResponse : HciAdapter::ResponseEvent
{
uint32_t currentSettings;
void toHost()
{
currentSettings = Utils::endianToHost(currentSettings);
}
} __attribute__((packed));
SRequest request;
request.code = commandCode;
request.controllerId = controllerId;
request.dataSize = sizeof(SRequest) - sizeof(HciAdapter::Header);
request.state = newState;
SResponse response;
if (!hciAdapter.sendCommand(request, response, sizeof(response)))
{
Logger::warn(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast<int>(newState));
return false;
}
response.toHost();
Logger::info(SSTR << " + " << pSettingName << " set to " << static_cast<int>(newState) << ": " << controllerSettingsString(response.currentSettings));
return true;
}
bool Mgmt::setPowered(bool newState)
{
return setState("Powered", 0x0005, controllerIndex, newState ? 1 : 0);
}
bool Mgmt::setBredr(bool newState)
{
return setState("BR/EDR", 0x002A, controllerIndex, newState ? 1 : 0);
}
bool Mgmt::setSecureConnections(uint8_t newState)
{
return setState("SecureConnections", 0x002D, controllerIndex, newState);
}
bool Mgmt::setBondable(bool newState)
{
return setState("SecureConnections", 0x0009, controllerIndex, newState ? 1 : 0);
}
bool Mgmt::setConnectable(bool newState)
{
return setState("Connectable", 0x0007, controllerIndex, newState ? 1 : 0);
}
bool Mgmt::setLE(bool newState)
{
return setState("LowEnergy", 0x000D, controllerIndex, newState ? 1 : 0);
}
bool Mgmt::setAdvertising(uint8_t newState)
{
return setState("Advertising", 0x0029, controllerIndex, newState);
}
std::string Mgmt::controllerSettingsString(uint32_t bits)
{
std::string result = "";
if ((bits & EHciPowered) != 0) { result += "Powered, "; }
if ((bits & EHciConnectable) != 0) { result += "Connectable, "; }
if ((bits & EHciFastConnectable) != 0) { result += "FC, "; }
if ((bits & EHciDiscoverable) != 0) { result += "Discov, "; }
if ((bits & EHciBondable) != 0) { result += "Bondable, "; }
if ((bits & EHciLinkLevelSecurity) != 0) { result += "LLS, "; }
if ((bits & EHciSecureSimplePairing) != 0) { result += "SSP, "; }
if ((bits & EHciBasicRate_EnhancedDataRate) != 0) { result += "BR/EDR, "; }
if ((bits & EHciHighSpeed) != 0) { result += "HS, "; }
if ((bits & EHciLowEnergy) != 0) { result += "LE, "; }
if ((bits & EHciAdvertising) != 0) { result += "Adv, "; }
if ((bits & EHciSecureConnections) != 0) { result += "SC, "; }
if ((bits & EHciDebugKeys) != 0) { result += "DebugKeys, "; }
if ((bits & EHciPrivacy) != 0) { result += "Privacy, "; }
if ((bits & EHciControllerConfiguration) != 0) { result += "ControllerConfig, "; }
if ((bits & EHciStaticAddress) != 0) { result += "StaticAddr, "; }
if (result.length() != 0)
{
result = result.substr(0, result.length() - 2);
}
return result;
}
std::string Mgmt::truncateName(const std::string &name)
{
if (name.length() <= kMaxNameLength)
{
return name;
}
return name.substr(0, kMaxNameLength);
}
std::string Mgmt::truncateShortName(const std::string &name)
{
if (name.length() <= kMaxShortNameLength)
{
return name;
}
return name.substr(0, kMaxShortNameLength);
}