#include <string.h>
#include "HciAdapter.h"
#include "HciSocket.h"
#include "Utils.h"
#include "Mgmt.h"
#include "Logger.h"
namespace ggk {
std::thread HciAdapter::eventThread;
const char * const HciAdapter::kCommandCodeNames[kMaxCommandCode + 1] =
{
"Invalid Command",
"Read Version Information Command",
"Read Supported Commands Command",
"Read Controller Index List Command",
"Read Controller Information Command",
"Set Powered Command",
"Set Discoverable Command",
"Set Connectable Command",
"Set Fast Connectable Command",
"Set Bondable Command",
"Set Link Security Command",
"Set Secure Simple Pairing Command",
"Set High Speed Command",
"Set Low Energy Command",
"Set Device Class",
"Set Local Name Command",
"Add UUID Command",
"Remove UUID Command",
"Load Link Keys Command",
"Load Long Term Keys Command",
"Disconnect Command",
"Get Connections Command",
"PIN Code Reply Command",
"PIN Code Negative Reply Command",
"Set IO Capability Command",
"Pair Device Command",
"Cancel Pair Device Command",
"Unpair Device Command",
"User Confirmation Reply Command",
"User Confirmation Negative Reply Command",
"User Passkey Reply Command",
"User Passkey Negative Reply Command",
"Read Local Out Of Band Data Command",
"Add Remote Out Of Band Data Command",
"Remove Remote Out Of Band Data Command",
"Start Discovery Command",
"Stop Discovery Command",
"Confirm Name Command",
"Block Device Command",
"Unblock Device Command",
"Set Device ID Command",
"Set Advertising Command",
"Set BR/EDR Command",
"Set Static Address Command",
"Set Scan Parameters Command",
"Set Secure Connections Command",
"Set Debug Keys Command",
"Set Privacy Command",
"Load Identity Resolving Keys Command",
"Get Connection Information Command",
"Get Clock Information Command",
"Add Device Command",
"Remove Device Command",
"Load Connection Parameters Command",
"Read Unconfigured Controller Index List Command",
"Read Controller Configuration Information Command",
"Set External Configuration Command",
"Set Public Address Command",
"Start Service Discovery Command",
"Read Local Out Of Band Extended Data Command",
"Read Extended Controller Index List Command",
"Read Advertising Features Command",
"Add Advertising Command",
"Remove Advertising Command",
"Get Advertising Size Information Command",
"Start Limited Discovery Command",
"Read Extended Controller Information Command",
"Set Appearance Command"
};
const char * const HciAdapter::kEventTypeNames[kMaxEventType + 1] =
{
"Invalid Event",
"Command Complete Event",
"Command Status Event",
"Controller Error Event",
"Index Added Event",
"Index Removed Event",
"New Settings Event",
"Class Of Device Changed Event",
"Local Name Changed Event",
"New Link Key Event",
"New Long Term Key Event",
"Device Connected Event",
"Device Disconnected Event",
"Connect Failed Event",
"PIN Code Request Event",
"User Confirmation Request Event",
"User Passkey Request Event",
"Authentication Failed Event",
"Device Found Event",
"Discovering Event",
"Device Blocked Event",
"Device Unblocked Event",
"Device Unpaired Event",
"Passkey Notify Event",
"New Identity Resolving Key Event",
"New Signature Resolving Key Event",
"Device Added Event",
"Device Removed Event",
"New Connection Parameter Event",
"Unconfigured Index Added Event",
"Unconfigured Index Removed Event",
"New Configuration Options Event",
"Extended Index Added Event",
"Extended Index Removed Event",
"Local Out Of Band Extended Data Updated Event",
"Advertising Added Event",
"Advertising Removed Event",
"Extended Controller Information Changed Event"
};
const char * const HciAdapter::kStatusCodes[kMaxStatusCode + 1] =
{
"Success",
"Unknown Command",
"Not Connected",
"Failed",
"Connect Failed",
"Authentication Failed",
"Not Paired",
"No Resources",
"Timeout",
"Already Connected",
"Busy",
"Rejected",
"Not Supported",
"Invalid Parameters",
"Disconnected",
"Not Powered",
"Cancelled",
"Invalid Index",
"RFKilled",
"Already Paired",
"Permission Denied",
};
HciAdapter::AdapterSettings HciAdapter::getAdapterSettings()
{
return adapterSettings;
}
HciAdapter::ControllerInformation HciAdapter::getControllerInformation()
{
return controllerInformation;
}
HciAdapter::VersionInformation HciAdapter::getVersionInformation()
{
return versionInformation;
}
HciAdapter::LocalName HciAdapter::getLocalName()
{
return localName;
}
void runEventThread()
{
HciAdapter::getInstance().runEventThread();
}
void HciAdapter::runEventThread()
{
Logger::trace("Entering the HciAdapter event thread");
while (ggkGetServerRunState() <= ERunning)
{
std::vector<uint8_t> responsePacket = std::vector<uint8_t>();
if (!hciSocket.read(responsePacket))
{
break;
}
if (responsePacket.size() < 2)
{
Logger::error(SSTR << "Invalid command response: too short");
continue;
}
uint16_t eventCode = Utils::endianToHost(*reinterpret_cast<uint16_t *>(responsePacket.data()));
if (eventCode < HciAdapter::kMinEventType || eventCode > HciAdapter::kMaxEventType)
{
Logger::error(SSTR << "Invalid command response: event code (" << eventCode << ") out of range");
continue;
}
switch(eventCode)
{
case Mgmt::ECommandCompleteEvent:
{
CommandCompleteEvent event = *reinterpret_cast<CommandCompleteEvent *>(responsePacket.data());
event.toHost();
Logger::debug(event.debugText());
uint8_t *data = responsePacket.data() + sizeof(CommandCompleteEvent);
size_t dataLen = responsePacket.size() - sizeof(CommandCompleteEvent);
switch(event.commandCode)
{
case Mgmt::EReadVersionInformationCommand:
{
if (dataLen != sizeof(VersionInformation))
{
Logger::error("Invalid data length");
return;
}
versionInformation = *reinterpret_cast<VersionInformation *>(data);
versionInformation.toHost();
Logger::debug(versionInformation.debugText());
break;
}
case Mgmt::EReadControllerInformationCommand:
{
if (dataLen != sizeof(ControllerInformation))
{
Logger::error("Invalid data length");
return;
}
controllerInformation = *reinterpret_cast<ControllerInformation *>(data);
controllerInformation.toHost();
Logger::debug(controllerInformation.debugText());
break;
}
case Mgmt::ESetLocalNameCommand:
{
if (dataLen != sizeof(LocalName))
{
Logger::error("Invalid data length");
return;
}
localName = *reinterpret_cast<LocalName *>(data);
Logger::info(localName.debugText());
break;
}
case Mgmt::ESetPoweredCommand:
case Mgmt::ESetBREDRCommand:
case Mgmt::ESetSecureConnectionsCommand:
case Mgmt::ESetBondableCommand:
case Mgmt::ESetConnectableCommand:
case Mgmt::ESetLowEnergyCommand:
case Mgmt::ESetAdvertisingCommand:
{
if (dataLen != sizeof(AdapterSettings))
{
Logger::error("Invalid data length");
return;
}
adapterSettings = *reinterpret_cast<AdapterSettings *>(data);
adapterSettings.toHost();
Logger::debug(adapterSettings.debugText());
break;
}
}
break;
}
case Mgmt::ECommandStatusEvent:
{
CommandStatusEvent event = *reinterpret_cast<CommandStatusEvent *>(responsePacket.data());
event.toHost();
Logger::debug(event.debugText());
break;
}
case Mgmt::EDeviceConnectedEvent:
{
DeviceConnectedEvent event = *reinterpret_cast<DeviceConnectedEvent *>(responsePacket.data());
event.toHost();
Logger::debug(event.debugText());
activeConnections += 1;
break;
}
case Mgmt::EDeviceDisconnectedEvent:
{
DeviceDisconnectedEvent event = *reinterpret_cast<DeviceDisconnectedEvent *>(responsePacket.data());
event.toHost();
Logger::debug(event.debugText());
activeConnections -= 1;
break;
}
default:
{
if (eventCode >= kMinEventType && eventCode <= kMaxEventType)
{
Logger::error("Unsupported response event type: " + Utils::hex(eventCode) + " (" + kEventTypeNames[eventCode] + ")");
}
else
{
Logger::error("Invalid event type response: " + Utils::hex(eventCode));
}
}
}
}
Logger::trace("Leaving the HciAdapter event thread");
}
void HciAdapter::sync(uint16_t controllerIndex)
{
HciAdapter::HciHeader request;
request.code = Mgmt::EReadVersionInformationCommand;
request.controllerId = HciAdapter::kNonController;
request.dataSize = 0;
if (!HciAdapter::getInstance().sendCommand(request))
{
Logger::error("Failed to get version information");
}
request.code = Mgmt::EReadControllerInformationCommand;
request.controllerId = controllerIndex;
request.dataSize = 0;
if (!HciAdapter::getInstance().sendCommand(request))
{
Logger::error("Failed to get current settings");
}
}
bool HciAdapter::connect()
{
if (isConnected())
{
return true;
}
if (!hciSocket.connect())
{
disconnect();
return false;
}
Logger::trace("Starting the HciAdapter thread");
try
{
eventThread = std::thread(ggk::runEventThread);
}
catch(std::system_error &ex)
{
if (ex.code() == std::errc::resource_unavailable_try_again)
{
Logger::error(SSTR << "HciAdapter thread was unable to start: " << ex.what());
disconnect();
return false;
}
}
return true;
}
bool HciAdapter::isConnected() const
{
return hciSocket.isConnected();
}
void HciAdapter::disconnect()
{
if (isConnected())
{
hciSocket.disconnect();
}
if (eventThread.joinable())
{
Logger::trace("Stopping the HciAdapter thread");
pthread_kill(eventThread.native_handle(), SIGINT);
eventThread.join();
}
}
bool HciAdapter::sendCommand(HciHeader &request)
{
if (!connect()) { return false; }
Logger::debug(request.debugText());
request.toNetwork();
uint8_t *pRequest = reinterpret_cast<uint8_t *>(&request);
std::vector<uint8_t> requestPacket = std::vector<uint8_t>(pRequest, pRequest + sizeof(request) + request.dataSize);
if (!hciSocket.write(requestPacket))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
return true;
}
};