diff --git a/src/hardware/BLEMIDI_Client_ESP32.h b/src/hardware/BLEMIDI_Client_ESP32.h index a92d9f8..badbdce 100644 --- a/src/hardware/BLEMIDI_Client_ESP32.h +++ b/src/hardware/BLEMIDI_Client_ESP32.h @@ -8,179 +8,116 @@ #define DEBUGCLIENT(_text_) ; #endif - -/* -############################################# -########## USER DEFINES BEGINNING ########### -####### Modify only these parameters ######## -############################################# -*/ - -/* -##### BLE DEVICE NAME ##### -*/ - -/** - * Set always the same name independently of name server - */ -//#define BLEMIDI_CLIENT_FIXED_NAME "BleMidiClient" - -#ifndef BLEMIDI_CLIENT_FIXED_NAME //Not modify -/** - * When client tries to connect to specific server, BLE name is composed as follows: - * BLEMIDI_CLIENT_NAME_PREFIX + + BLEMIDI_CLIENT_NAME_SUBFIX - * - * example: - * BLEMIDI_CLIENT_NAME_PREFIX "Client-" - * "AX-Edge" - * BLEMIDI_CLIENT_NAME_SUBFIX "-Midi1" - * - * Result: "Client-AX-Edge-Midi1" - */ -#define BLEMIDI_CLIENT_NAME_PREFIX "C-" -#define BLEMIDI_CLIENT_NAME_SUBFIX "" - -/** - * When client tries to connect to the first midi server found: - */ -#define BLEMIDI_CLIENT_DEFAULT_NAME "BLEMIDI-CLIENT" -#endif //Not modify - -/* -###### TX POWER ##### -*/ -/** - * Set power transmision - * - * ESP_PWR_LVL_N12 // Corresponding to -12dbm Minimum - * ESP_PWR_LVL_N9 // Corresponding to -9dbm - * ESP_PWR_LVL_N6 // Corresponding to -6dbm - * ESP_PWR_LVL_N3 // Corresponding to -3dbm - * ESP_PWR_LVL_N0 // Corresponding to 0dbm - * ESP_PWR_LVL_P3 // Corresponding to +3dbm - * ESP_PWR_LVL_P6 // Corresponding to +6dbm - * ESP_PWR_LVL_P9 // Corresponding to +9dbm Maximum -*/ - -#define BLEMIDI_TX_PWR ESP_PWR_LVL_P9 - -/* -###### SECURITY ##### -*/ - -/** Set the IO capabilities of the device, each option will trigger a different pairing method. - * BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing - * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing - * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing - */ -#define BLEMIDI_CLIENT_SECURITY_CAP BLE_HS_IO_NO_INPUT_OUTPUT - -/** Set the security method. - * bonding - * man in the middle protection - * pair. secure connections - * - * More info in nimBLE lib - * - * Uncomment what you need - * These are the default values. - * You can select some simultaneously. - */ -#define BLEMIDI_CLIENT_BOND -//#define BLEMIDI_CLIENT_MITM -#define BLEMIDI_CLIENT_PAIR - -/** - * This callback function defines what will be done when server requieres PassKey. - * Add your custom code here. - */ -static uint32_t userOnPassKeyRequest() -{ - //FILL WITH YOUR CUSTOM AUTH METHOD CODE or PASSKEY - //FOR EXAMPLE: - uint32_t passkey = 123456; - - //Serial.println("Client Passkey Request"); - - /** return the passkey to send to the server */ - return passkey; -}; - - /* -###### BLE COMMUNICATION PARAMS ###### -*/ - /** Set connection parameters: - * If you only use one connection, put recomended BLE server param communication - * (you may scan it ussing "nRF Connect" app or other similar apps). - * - * If you use more than one connection adjust, for example, settings like 15ms interval, 0 latency, 120ms timout. - * These settings may be safe for 3 clients to connect reliably, set faster values if you have less - * connections. - * - * Min interval (unit: 1.25ms): 12 * 1.25ms = 15 ms, - * Max interval (unit: 1.25ms): 12 * 1.25ms = 15, - * 0 latency (Number of intervals allowed to skip), - * TimeOut (unit: 10ms) 51 * 10ms = 510ms. Timeout should be minimum 100ms. - */ -#define BLEMIDI_CLIENT_COMM_MIN_INTERVAL 6 // 7.5ms -#define BLEMIDI_CLIENT_COMM_MAX_INTERVAL 35 // 40ms -#define BLEMIDI_CLIENT_COMM_LATENCY 0 // -#define BLEMIDI_CLIENT_COMM_TIMEOUT 200 //2000ms - -/* -###### BLE FORCE NEW CONNECTION ###### -*/ - -/** - * This parameter force to skip the "soft-reconnection" and force to create a new connection after a disconnect event. - * "Soft-reconnection" save some time and energy in comparation with performming a new connection, but some BLE devices - * don't support or don't perform correctly a "soft-reconnection" after a disconnection event. - * Uncomment this define if your device doesn't work propertily after a reconnection. - * -*/ -//#define BLEMIDI_FORCE_NEW_CONNECTION - -/** - * -*/ - -/* -############################################# -############ USER DEFINES END ############### -############################################# -*/ - // Headers for ESP32 nimBLE #include BEGIN_BLEMIDI_NAMESPACE -#ifdef BLEMIDI_CLIENT_BOND -#define BLEMIDI_CLIENT_BOND_DUMMY BLE_SM_PAIR_AUTHREQ_BOND -#else -#define BLEMIDI_CLIENT_BOND_DUMMY 0x00 -#endif +using PasskeyRequestCallback = uint32_t (*)(void); -#ifdef BLEMIDI_CLIENT_MITM -#define BLEMIDI_CLIENT_MITM_DUMMY BLE_SM_PAIR_AUTHREQ_MITM -#else -#define BLEMIDI_CLIENT_MITM_DUMMY 0x00 -#endif +static uint32_t defautlPasskeyRequest() +{ + // FILL WITH YOUR CUSTOM AUTH METHOD CODE or PASSKEY + // FOR EXAMPLE: + uint32_t passkey = 123456; -#ifdef BLEMIDI_CLIENT_PAIR -#define BLEMIDI_CLIENT_PAIR_DUMMY BLE_SM_PAIR_AUTHREQ_SC -#else -#define BLEMIDI_CLIENT_PAIR_DUMMY 0x00 -#endif + // Serial.println("Client Passkey Request"); -/** Set the security method. + /** return the passkey to send to the server */ + return passkey; +}; + +struct DefaultSettingsClient : public BLEMIDI_NAMESPACE::DefaultSettings +{ + + /* + ##### BLE DEVICE NAME ##### + */ + /** + * Set name of ble device (not affect to connection with server) + * max 16 characters + */ + static constexpr char *name = "BleMidiClient"; + + /* + ###### TX POWER ##### + */ + /** + * Set power transmision + * + * ESP_PWR_LVL_N12 // Corresponding to -12dbm Minimum + * ESP_PWR_LVL_N9 // Corresponding to -9dbm + * ESP_PWR_LVL_N6 // Corresponding to -6dbm + * ESP_PWR_LVL_N3 // Corresponding to -3dbm + * ESP_PWR_LVL_N0 // Corresponding to 0dbm + * ESP_PWR_LVL_P3 // Corresponding to +3dbm + * ESP_PWR_LVL_P6 // Corresponding to +6dbm + * ESP_PWR_LVL_P9 // Corresponding to +9dbm Maximum + */ + static const esp_power_level_t clientTXPwr = ESP_PWR_LVL_P9; + + /* + ###### SECURITY ##### + */ + /** Set the IO capabilities of the device, each option will trigger a different pairing method. + * BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing + * BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing + * BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing + */ + static const uint8_t clientSecurityCapabilities = BLE_HS_IO_NO_INPUT_OUTPUT; + + /** Set the security method. * bonding * man in the middle protection * pair. secure connections - * + * * More info in nimBLE lib */ -#define BLEMIDI_CLIENT_SECURITY_AUTH (BLEMIDI_CLIENT_BOND_DUMMY | BLEMIDI_CLIENT_MITM_DUMMY | BLEMIDI_CLIENT_PAIR_DUMMY) + static const bool clientBond = true; + static const bool clientMITM = false; + static const bool clientPair = true; + + /** + * This callback function defines what will be done when server requieres PassKey. + * Add your custom code here. + */ + static constexpr PasskeyRequestCallback userOnPassKeyRequest = defautlPasskeyRequest; + + /* + ###### BLE COMMUNICATION PARAMS ###### + */ + /** Set connection parameters: + * If you only use one connection, put recomended BLE server param communication + * (you may scan it ussing "nRF Connect" app or other similar apps). + * + * If you use more than one connection adjust, for example, settings like 15ms interval, 0 latency, 120ms timout. + * These settings may be safe for 3 clients to connect reliably, set faster values if you have less + * connections. + * + * Min interval (unit: 1.25ms): 12 * 1.25ms = 15 ms, + * Max interval (unit: 1.25ms): 12 * 1.25ms = 15, + * 0 latency (Number of intervals allowed to skip), + * TimeOut (unit: 10ms) 51 * 10ms = 510ms. Timeout should be minimum 100ms. + */ + static const uint16_t commMinInterval = 6; // 7.5ms + static const uint16_t commMaxInterval = 35; // 40ms + static const uint16_t commLatency = 0; // + static const uint16_t commTimeOut = 200; // 2000ms + + /* + ###### BLE FORCE NEW CONNECTION ###### + */ + + /** + * This parameter force to skip the "soft-reconnection" and force to create a new connection after a disconnect event. + * "Soft-reconnection" save some time and energy in comparation with performming a new connection, but some BLE devices + * don't support or don't perform correctly a "soft-reconnection" after a disconnection event. + * Set to "true" if your device doesn't work propertily after a reconnection. + * + */ + static const bool forceNewConnection = false; +}; + /** Define a class to handle the callbacks when advertisments are received */ class AdvertisedDeviceCallbacks : public NimBLEAdvertisedDeviceCallbacks @@ -239,7 +176,7 @@ private: BLEAdvertising *_advertising = nullptr; BLERemoteCharacteristic *_characteristic = nullptr; BLERemoteService *pSvc = nullptr; - bool firstTimeSend = true; //First writeValue get sends like Write with reponse for clean security flags. After first time, all messages are send like WriteNoResponse for increase transmision speed. + bool firstTimeSend = true; // First writeValue get sends like Write with reponse for clean security flags. After first time, all messages are send like WriteNoResponse for increase transmision speed. BLEMIDI_Transport, _Settings> *_bleMidiTransport = nullptr; @@ -307,7 +244,7 @@ protected: void scan(); bool connect(); -public: +public: void connected() { if (_bleMidiTransport->_connectedCallback) @@ -338,19 +275,21 @@ protected: uint32_t onPassKeyRequest() { - return userOnPassKeyRequest(); + //if (nullptr != _Settings::userOnPassKeyRequest) + return _Settings::userOnPassKeyRequest(); + //return 0; }; - void onConnect(BLEClient*) + void onConnect(BLEClient *pClient) { DEBUGCLIENT("##Connected##"); - //pClient->updateConnParams(BLEMIDI_CLIENT_COMM_MIN_INTERVAL, BLEMIDI_CLIENT_COMM_MAX_INTERVAL, BLEMIDI_CLIENT_COMM_LATENCY, BLEMIDI_CLIENT_COMM_TIMEOUT); + //pClient->updateConnParams(_Settings::commMinInterval, _Settings::commMaxInterval, _Settings::commLatency, _Settings::commTimeOut); vTaskDelay(1); if (_bluetoothEsp32) _bluetoothEsp32->connected(); }; - void onDisconnect(BLEClient*) + void onDisconnect(BLEClient *pClient) { DEBUGCLIENT(pClient->getPeerAddress().toString().c_str()); DEBUGCLIENT(" Disconnected - Starting scan"); @@ -358,38 +297,34 @@ protected: if (_bluetoothEsp32) { _bluetoothEsp32->disconnected(); -#ifdef BLEMIDI_FORCE_NEW_CONNECTION - // Try reconnection or search a new one - _bluetoothEsp32->scan(); -#endif // BLEMIDI_FORCE_NEW_CONNECTION } -#ifdef BLEMIDI_FORCE_NEW_CONNECTION +if (_Settings::forceNewConnection) +{ // Renew Client NimBLEDevice::deleteClient(pClient); - NimBLEDevice::createClient(); pClient = nullptr; -#endif // BLEMIDI_FORCE_NEW_CONNECTION +} - //Try reconnection or search a new one + // Try reconnection or search a new one NimBLEDevice::getScan()->start(1, scanEndedCB); } - bool onConnParamsUpdateRequest(NimBLEClient *pClient, const ble_gap_upd_params *params) + bool onConnParamsUpdateRequest(NimBLEClient *pClient, const ble_gap_upd_params *params) { - if (params->itvl_min < BLEMIDI_CLIENT_COMM_MIN_INTERVAL) + if (params->itvl_min < _Settings::commMinInterval) { /** 1.25ms units */ return false; } - else if (params->itvl_max > BLEMIDI_CLIENT_COMM_MAX_INTERVAL) + else if (params->itvl_max > _Settings::commMaxInterval) { /** 1.25ms units */ return false; } - else if (params->latency > BLEMIDI_CLIENT_COMM_LATENCY) + else if (params->latency > _Settings::commLatency) { /** Number of intervals allowed to skip */ return false; } - else if (params->supervision_timeout > BLEMIDI_CLIENT_COMM_TIMEOUT) + else if (params->supervision_timeout > _Settings::commMinInterval) { /** 10ms units */ return false; } @@ -415,24 +350,18 @@ bool BLEMIDI_Client_ESP32<_Settings>::begin(const char *deviceName, BLEMIDI_Tran { myAdvCB.specificTarget = false; myAdvCB.nameTarget = ""; - -#ifdef BLEMIDI_CLIENT_FIXED_NAME - strDeviceName = BLEMIDI_CLIENT_FIXED_NAME; -#else - strDeviceName = BLEMIDI_CLIENT_DEFAULT_NAME; -#endif } else // Connect to a specific name or address { myAdvCB.specificTarget = true; myAdvCB.nameTarget = strDeviceName; - -#ifdef BLEMIDI_CLIENT_FIXED_NAME - strDeviceName = BLEMIDI_CLIENT_FIXED_NAME; -#else - strDeviceName = BLEMIDI_CLIENT_NAME_PREFIX + strDeviceName + BLEMIDI_CLIENT_NAME_SUBFIX; -#endif } + + static char array[16] = "patata"; + + memcpy(array, _Settings::name, 16); + strDeviceName = array; + DEBUGCLIENT(strDeviceName.c_str()); NimBLEDevice::init(strDeviceName); @@ -441,11 +370,11 @@ bool BLEMIDI_Client_ESP32<_Settings>::begin(const char *deviceName, BLEMIDI_Tran // Core_0 runs here, core_1 runs the BLE stack mRxQueue = xQueueCreate(_Settings::MaxBufferSize, sizeof(uint8_t)); - NimBLEDevice::setSecurityIOCap(BLEMIDI_CLIENT_SECURITY_CAP); // Attention, it may need a passkey - NimBLEDevice::setSecurityAuth(BLEMIDI_CLIENT_SECURITY_AUTH); + NimBLEDevice::setSecurityIOCap(_Settings::clientSecurityCapabilities); // Attention, it may need a passkey + NimBLEDevice::setSecurityAuth(_Settings::clientBond, _Settings::clientMITM, _Settings::clientPair); /** Optional: set the transmit power, default is 3db */ - NimBLEDevice::setPower(BLEMIDI_TX_PWR); /** +9db */ + NimBLEDevice::setPower(_Settings::clientTXPwr); /** +9db */ myAdvCB.enableConnection = true; scan(); @@ -456,37 +385,36 @@ bool BLEMIDI_Client_ESP32<_Settings>::begin(const char *deviceName, BLEMIDI_Tran template bool BLEMIDI_Client_ESP32<_Settings>::available(byte *pvBuffer) { - if (myAdvCB.enableConnection) + if (!myAdvCB.enableConnection) { - if (_client == nullptr || !_client->isConnected()) //Try to connect/reconnect + return false; + } + + if (_client == nullptr || !_client->isConnected()) // Try to connect/reconnect + { + if (myAdvCB.doConnect) { - if (myAdvCB.doConnect) - { - myAdvCB.doConnect = false; - if (!connect()) - { - scan(); - } - } - else if (myAdvCB.scanDone) + myAdvCB.doConnect = false; + if (!connect()) { scan(); } } - // return 1 byte from the Queue - return xQueueReceive(mRxQueue, (void *)pvBuffer, 0); // return immediately when the queue is empty - } - else - { - return false; + else if (myAdvCB.scanDone) + { + scan(); + } } + + // return 1 byte from the Queue + return xQueueReceive(mRxQueue, (void *)pvBuffer, 0); // return immediately when the queue is empty } /** Notification receiving handler callback */ template void BLEMIDI_Client_ESP32<_Settings>::notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) { - if (this->_characteristic == pRemoteCharacteristic) //Redundant protection + if (this->_characteristic == pRemoteCharacteristic) // Redundant protection { receive(pData, length); } @@ -517,7 +445,9 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() { using namespace std::placeholders; //<- for bind funtion in callback notification -#ifndef BLEMIDI_FORCE_NEW_CONNECTION +//Retry to connecto to last one +if (!_Settings::forceNewConnection) +{ /** Check if we have a client we should reuse first * Special case when we already know this device * This saves considerable time and power. @@ -533,7 +463,7 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() { if (_characteristic->subscribe(true, std::bind(&BLEMIDI_Client_ESP32::notifyCB, this, _1, _2, _3, _4))) { - //Re-connection SUCCESS + // Re-connection SUCCESS return true; } } @@ -549,7 +479,8 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() NimBLEDevice::deleteClient(_client); _client = nullptr; } -#endif //BLEMIDI_FORCE_NEW_CONNECTION +} + if (NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) { @@ -562,7 +493,7 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() _client->setClientCallbacks(new MyClientCallbacks<_Settings>(this), false); - _client->setConnectionParams(BLEMIDI_CLIENT_COMM_MIN_INTERVAL, BLEMIDI_CLIENT_COMM_MAX_INTERVAL, BLEMIDI_CLIENT_COMM_LATENCY, BLEMIDI_CLIENT_COMM_TIMEOUT); + _client->setConnectionParams(_Settings::commMinInterval,_Settings::commMaxInterval, _Settings::commLatency, _Settings::commTimeOut); /** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */ _client->setConnectTimeout(15); @@ -586,10 +517,10 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() } DEBUGCLIENT("Connected to: " + myAdvCB.advDevice.getName().c_str() + " / " + _client->getPeerAddress().toString().c_str()); - + DEBUGCLIENT("RSSI: "); DEBUGCLIENT(_client->getRssi()); - + /** Now we can read/write/subscribe the charateristics of the services we are interested in */ pSvc = _client->getService(SERVICE_UUID); if (pSvc) /** make sure it's not null */ @@ -602,14 +533,14 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() { if (_characteristic->subscribe(true, std::bind(&BLEMIDI_Client_ESP32::notifyCB, this, _1, _2, _3, _4))) { - //Connection SUCCESS + // Connection SUCCESS return true; } } } } - //If anything fails, disconnect and delete client + // If anything fails, disconnect and delete client _client->disconnect(); NimBLEDevice::deleteClient(_client); _client = nullptr; @@ -619,7 +550,7 @@ bool BLEMIDI_Client_ESP32<_Settings>::connect() /** Callback to process the results of the last scan or restart it */ void scanEndedCB(NimBLEScanResults results) { - DEBUGCLIENT("Scan Ended"); + // DEBUGCLIENT("Scan Ended"); } END_BLEMIDI_NAMESPACE @@ -627,7 +558,7 @@ END_BLEMIDI_NAMESPACE /*! \brief Create a custom instance for ESP32 named , and advertise it like "Prefix + + Subfix" It will try to connect to a specific server with equal name or addr than . If is "", it will connect to first midi server */ -#define BLEMIDI_CREATE_CUSTOM_INSTANCE(DeviceName, Name, _Settings) \ +#define BLEMIDI_CREATE_CUSTOM_INSTANCE(DeviceName, Name, _Settings) \ BLEMIDI_NAMESPACE::BLEMIDI_Transport, _Settings> BLE##Name(DeviceName); \ MIDI_NAMESPACE::MidiInterface, _Settings>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport, _Settings> &)BLE##Name); @@ -635,9 +566,9 @@ END_BLEMIDI_NAMESPACE It will try to connect to a specific server with equal name or addr than . If is "", it will connect to first midi server */ #define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \ - BLEMIDI_CREATE_CUSTOM_INSTANCE (DeviceName, Name, BLEMIDI_NAMESPACE::DefaultSettings) + BLEMIDI_CREATE_CUSTOM_INSTANCE(DeviceName, Name, BLEMIDI_NAMESPACE::DefaultSettingsClient) -/*! \brief Create a default instance for ESP32 named BLEMIDI-CLIENT. +/*! \brief Create a default instance for ESP32 named BLEMIDI-CLIENT. It will try to connect to first midi ble server found. */ #define BLEMIDI_CREATE_DEFAULT_INSTANCE() \