#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <thread>
#include "HciSocket.h"
#include "Logger.h"
#include "Utils.h"
HciSocket::HciSocket()
: fdSocket(-1)
{
}
HciSocket::~HciSocket()
{
disconnect();
}
bool HciSocket::connect()
{
disconnect();
fdSocket = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI);
if (fdSocket < 0)
{
logErrno("Connect(socket)");
return false;
}
struct sockaddr_hci addr;
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = HCI_CHANNEL_CONTROL;
if (bind(fdSocket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) < 0)
{
logErrno("Connect(bind)");
disconnect();
return false;
}
Logger::debug(SSTR << "Connected to HCI control socket (file descriptor = " << fdSocket << ")");
return true;
}
bool HciSocket::isConnected() const
{
return fdSocket >= 0;
}
void HciSocket::disconnect()
{
if (isConnected())
{
close(fdSocket);
fdSocket = -1;
}
}
bool HciSocket::read(std::vector<uint8_t> &response) const
{
response.clear();
uint8_t responseChunk[kResponseChunkSize];
int retryTimeMS = 0;
while (retryTimeMS < kMaxRetryTimeMS && !ggkIsServerRunning())
{
ssize_t bytesRead = ::read(fdSocket, responseChunk, kResponseChunkSize);
if (bytesRead > 0)
{
if (response.size() + bytesRead > kResponseMaxSize)
{
Logger::warn(SSTR << "Response has exceeded maximum size");
return false;
}
std::vector<uint8_t> insertBuf(responseChunk, responseChunk + bytesRead);
response.insert(response.end(), insertBuf.begin(), insertBuf.end());
}
else
{
if (response.size() != 0)
{
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(kRetryIntervalMS));
retryTimeMS += kRetryIntervalMS;
}
if (retryTimeMS >= kMaxRetryTimeMS)
{
logErrno("read(header)");
return false;
}
Logger::debug(SSTR << " + Read " << response.size() << " bytes");
Logger::debug(SSTR << Utils::hex(response.data(), response.size()));
return true;
}
bool HciSocket::write(std::vector<uint8_t> buffer) const
{
return write(buffer.data(), buffer.size());
}
bool HciSocket::write(const uint8_t *pBuffer, size_t count) const
{
Logger::debug(SSTR << " + Writing " << count << " bytes");
Logger::debug(SSTR << Utils::hex(pBuffer, count));
size_t len = ::write(fdSocket, pBuffer, count);
if (len != count)
{
logErrno("write");
return false;
}
return true;
}
void HciSocket::logErrno(const char *pOperation) const
{
Logger::error(SSTR << "" << pOperation << " on Bluetooth management socket error (" << errno << "): " << strerror(errno));
}