/*
 * BLEHIDDevice.cpp
 *
 *  Created on: Jan 03, 2018
 *      Author: chegewara
 */
#include "soc/soc_caps.h"
#if SOC_BLE_SUPPORTED

#include "sdkconfig.h"
#if defined(CONFIG_BLUEDROID_ENABLED)

#include "BLEHIDDevice.h"
#include "BLE2904.h"


BLEHIDDevice::BLEHIDDevice(BLEServer* server) {
	/*
	 * Here we create mandatory services described in bluetooth specification
	 */
	m_deviceInfoService = server->createService(BLEUUID((uint16_t) 0x180a));
	m_hidService = server->createService(BLEUUID((uint16_t) 0x1812), 40);
	m_batteryService = server->createService(BLEUUID((uint16_t) 0x180f));

	/*
	 * Mandatory characteristic for device info service
	 */
	m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, BLECharacteristic::PROPERTY_READ);

	/*
	 * Mandatory characteristics for HID service
	 */
	m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, BLECharacteristic::PROPERTY_READ);
	m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, BLECharacteristic::PROPERTY_READ);
	m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR);
	m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ);

	/*
	 * Mandatory battery level characteristic with notification and presence descriptor
	 */
	BLE2904* batteryLevelDescriptor = new BLE2904();
	batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8);
	batteryLevelDescriptor->setNamespace(1);
	batteryLevelDescriptor->setUnit(0x27ad);

	m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
	m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor);
	BLE2902 *batLevelIndicator = new BLE2902();
	// Battery Level Notification is ON by default, making it work always on BLE Pairing and Bonding
	batLevelIndicator->setNotifications(true);
	m_batteryLevelCharacteristic->addDescriptor(batLevelIndicator);

	/*
	 * This value is setup here because its default value in most usage cases, its very rare to use boot mode
	 * and we want to simplify library using as much as possible
	 */
	const uint8_t pMode[] = { 0x01 };
	protocolMode()->setValue((uint8_t*) pMode, 1);
}

BLEHIDDevice::~BLEHIDDevice() {
}

/*
 * @brief
 */
void BLEHIDDevice::reportMap(uint8_t* map, uint16_t size) {
	m_reportMapCharacteristic->setValue(map, size);
}

/*
 * @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service
 */
void BLEHIDDevice::startServices() {
	m_deviceInfoService->start();
	m_hidService->start();
	m_batteryService->start();
}

/*
 * @brief Create manufacturer characteristic (this characteristic is optional)
 */
BLECharacteristic* BLEHIDDevice::manufacturer() {
	m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ);
	return m_manufacturerCharacteristic;
}

/*
 * @brief Set manufacturer name
 * @param [in] name manufacturer name
 */
void BLEHIDDevice::manufacturer(String name) {
	m_manufacturerCharacteristic->setValue(name);
}

/*
 * @brief
 */
void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) {
	uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version };
	m_pnpCharacteristic->setValue(pnp, sizeof(pnp));
}

/*
 * @brief
 */
void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
	uint8_t info[] = { 0x11, 0x1, country, flags };
	m_hidInfoCharacteristic->setValue(info, sizeof(info));
}

/*
 * @brief Create input report characteristic that need to be saved as new characteristic object so can be further used
 * @param [in] reportID input report ID, the same as in report map for input object related to created characteristic
 * @return pointer to new input report characteristic
 */
BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) {
	BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
	BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));
	BLE2902* p2902 = new BLE2902();
	inputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
	inputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
	p2902->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);

	uint8_t desc1_val[] = { reportID, 0x01 };
	inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
	inputReportCharacteristic->addDescriptor(p2902);
	inputReportCharacteristic->addDescriptor(inputReportDescriptor);

	return inputReportCharacteristic;
}

/*
 * @brief Create output report characteristic that need to be saved as new characteristic object so can be further used
 * @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic
 * @return Pointer to new output report characteristic
 */
BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) {
	BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
	BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));
	outputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
	outputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);

	uint8_t desc1_val[] = { reportID, 0x02 };
	outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
	outputReportCharacteristic->addDescriptor(outputReportDescriptor);

	return outputReportCharacteristic;
}

/*
 * @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used
 * @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic
 * @return Pointer to new feature report characteristic
 */
BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) {
	BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);
	BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908));

	featureReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
	featureReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);

	uint8_t desc1_val[] = { reportID, 0x03 };
	featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
	featureReportCharacteristic->addDescriptor(featureReportDescriptor);

	return featureReportCharacteristic;
}

/*
 * @brief
 */
BLECharacteristic* BLEHIDDevice::bootInput() {
	BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a22, BLECharacteristic::PROPERTY_NOTIFY);
	bootInputCharacteristic->addDescriptor(new BLE2902());

	return bootInputCharacteristic;
}

/*
 * @brief
 */
BLECharacteristic* BLEHIDDevice::bootOutput() {
	return m_hidService->createCharacteristic((uint16_t) 0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
}

/*
 * @brief
 */
BLECharacteristic* BLEHIDDevice::hidControl() {
	return m_hidControlCharacteristic;
}

/*
 * @brief
 */
BLECharacteristic* BLEHIDDevice::protocolMode() {
	return m_protocolModeCharacteristic;
}

void BLEHIDDevice::setBatteryLevel(uint8_t level) {
	m_batteryLevelCharacteristic->setValue(&level, 1);
	m_batteryLevelCharacteristic->notify();	
}
/*
 * @brief Returns battery level characteristic
 * @ return battery level characteristic
 *//*
BLECharacteristic* BLEHIDDevice::batteryLevel() {
	return m_batteryLevelCharacteristic;
}



BLECharacteristic*	 BLEHIDDevice::reportMap() {
	return m_reportMapCharacteristic;
}

BLECharacteristic*	 BLEHIDDevice::pnp() {
	return m_pnpCharacteristic;
}


BLECharacteristic*	BLEHIDDevice::hidInfo() {
	return m_hidInfoCharacteristic;
}
*/
/*
 * @brief
 */
BLEService* BLEHIDDevice::deviceInfo() {
	return m_deviceInfoService;
}

/*
 * @brief
 */
BLEService* BLEHIDDevice::hidService() {
	return m_hidService;
}

/*
 * @brief
 */
BLEService* BLEHIDDevice::batteryService() {
	return m_batteryService;
}

#endif /* CONFIG_BLUEDROID_ENABLED */
#endif /* SOC_BLE_SUPPORTED */
