299 lines
9.0 KiB
C++
299 lines
9.0 KiB
C++
#include "CanonBLERemote.h"
|
|
#include <Arduino.h>
|
|
#include <BLEDevice.h>
|
|
|
|
static const char *LOG_TAG = "MySecurity";
|
|
|
|
advdCallback::advdCallback(BLEUUID service_uuid, bool *ready_to_connect, BLEAddress *address_to_connect)
|
|
{
|
|
service_uuid_wanted = service_uuid;
|
|
pready_to_connect = ready_to_connect;
|
|
paddress_to_connect = address_to_connect;
|
|
}
|
|
|
|
void advdCallback::onResult(BLEAdvertisedDevice advertisedDevice)
|
|
{
|
|
if (advertisedDevice.haveServiceUUID())
|
|
{ //Check if device has service UUID available.
|
|
if (service_uuid_wanted.equals(advertisedDevice.getServiceUUID()))
|
|
{
|
|
*paddress_to_connect = advertisedDevice.getAddress();
|
|
*pready_to_connect = true;
|
|
advertisedDevice.getScan()->stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConnectivityState::onConnect(BLEClient *pclient)
|
|
{
|
|
// Serial.println("Device is connected");
|
|
connected = true;
|
|
}
|
|
|
|
void ConnectivityState::onDisconnect(BLEClient *pclient)
|
|
{
|
|
// Serial.println("Device disconnnect");
|
|
connected = false;
|
|
}
|
|
|
|
bool ConnectivityState::isConnected()
|
|
{
|
|
return connected;
|
|
}
|
|
|
|
class SecurityCallback : public BLESecurityCallbacks
|
|
{
|
|
|
|
uint32_t onPassKeyRequest()
|
|
{
|
|
return 123456;
|
|
}
|
|
void onPassKeyNotify(uint32_t pass_key)
|
|
{
|
|
ESP_LOGE(LOG_TAG, "The passkey Notify number:%d", pass_key);
|
|
}
|
|
bool onConfirmPIN(uint32_t pass_key)
|
|
{
|
|
ESP_LOGI(LOG_TAG, "The passkey YES/NO number:%d", pass_key);
|
|
vTaskDelay(5000);
|
|
return true;
|
|
}
|
|
bool onSecurityRequest()
|
|
{
|
|
ESP_LOGI(LOG_TAG, "Security Request");
|
|
return true;
|
|
}
|
|
void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl)
|
|
{
|
|
if (auth_cmpl.success)
|
|
{
|
|
ESP_LOGI(LOG_TAG, "remote BD_ADDR:");
|
|
esp_log_buffer_hex(LOG_TAG, auth_cmpl.bd_addr, sizeof(auth_cmpl.bd_addr));
|
|
ESP_LOGI(LOG_TAG, "address type = %d", auth_cmpl.addr_type);
|
|
}
|
|
ESP_LOGI(LOG_TAG, "pair status = %s", auth_cmpl.success ? "success" : "fail");
|
|
}
|
|
};
|
|
|
|
CanonBLERemote::CanonBLERemote(String name) : SERVICE_UUID("00050000-0000-1000-0000-d8492fffa821"),
|
|
PAIRING_SERVICE("00050002-0000-1000-0000-d8492fffa821"),
|
|
SHUTTER_CONTROL_SERVICE("00050003-0000-1000-0000-d8492fffa821")
|
|
{
|
|
device_name = name;
|
|
// Add our connection callback for state tracking.
|
|
pclient->setClientCallbacks(pconnection_state);
|
|
}
|
|
|
|
void CanonBLERemote::init()
|
|
{
|
|
BLEDevice::init(device_name.c_str());
|
|
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_NO_MITM);
|
|
BLEDevice::setSecurityCallbacks(new SecurityCallback());
|
|
|
|
if (nvs.begin())
|
|
{
|
|
log_e("Initialize NVS Success");
|
|
String address = nvs.getString("cameraaddr");
|
|
|
|
if (address.length() == 17)
|
|
{
|
|
// Serial.printf("Paired camera address: %s\n", address.c_str());
|
|
camera_address = BLEAddress(address.c_str());
|
|
}
|
|
else
|
|
{
|
|
// Serial.println("No camera has been paired yet.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_e("Initialize NVS Failed");
|
|
}
|
|
}
|
|
|
|
// Purpose : Scanning for new BLE devices around.
|
|
// When found -> advdCallback::OnResult
|
|
void CanonBLERemote::scan(unsigned int scan_duration)
|
|
{
|
|
|
|
log_i("Start BLE scan");
|
|
BLEScan *pBLEScan = BLEDevice::getScan();
|
|
advdCallback *advert_dev_callback = new advdCallback(SERVICE_UUID, &ready_to_connect, &camera_address);
|
|
|
|
pBLEScan->setAdvertisedDeviceCallbacks(advert_dev_callback); // Retrieve a Scanner and set the callback we want to use to be informed when we have detected a new device.
|
|
pBLEScan->setActiveScan(true);
|
|
pBLEScan->start(scan_duration); // Specify that we want active scanning and start the scan to run for 30 seconds.
|
|
}
|
|
|
|
BLEAddress CanonBLERemote::getPairedAddress()
|
|
{
|
|
return camera_address;
|
|
}
|
|
|
|
String CanonBLERemote::getPairedAddressString()
|
|
{
|
|
return String(camera_address.toString().c_str());
|
|
}
|
|
|
|
/**
|
|
* Scan and pair camera
|
|
*
|
|
* This function should be called only when you want to pair with the new camera, and the camera is in remote paring screen.
|
|
* After paired, camera mac address will be stored in ESP32 NVS for later connection use.
|
|
*
|
|
* @param scan_duration : Scan duration in seconds
|
|
*/
|
|
|
|
bool CanonBLERemote::pair(unsigned int scan_duration)
|
|
{
|
|
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM);
|
|
log_i("Scanning for camera...");
|
|
scan(scan_duration);
|
|
unsigned long start_ms = millis();
|
|
while (!ready_to_connect && millis() - start_ms < scan_duration * 1000)
|
|
{
|
|
}
|
|
|
|
if (ready_to_connect)
|
|
{
|
|
log_i("Canon device found");
|
|
// Serial.println(camera_address.toString().c_str());
|
|
}
|
|
else
|
|
{
|
|
log_i("Camera not found");
|
|
return false;
|
|
}
|
|
|
|
// Pair camera
|
|
log_i("Pairing..");
|
|
if (pclient->connect(camera_address))
|
|
{
|
|
// Acquire reference to main service
|
|
pRemoteService = pclient->getService(SERVICE_UUID);
|
|
if (pRemoteService != nullptr)
|
|
{
|
|
// Acquire reference to BLE characteristics
|
|
pRemoteCharacteristic_Pairing = pRemoteService->getCharacteristic(PAIRING_SERVICE);
|
|
if ((pRemoteCharacteristic_Pairing != nullptr))
|
|
{
|
|
// Send request on pairing service from external device
|
|
String device_name_ = " " + device_name + " "; //Pairing message to send
|
|
byte cmdPress[device_name_.length()]; // Stocking list of Bytes char of the message
|
|
device_name_.getBytes(cmdPress, device_name_.length()); // message Parser
|
|
cmdPress[0] = {0x03};
|
|
pRemoteCharacteristic_Pairing->writeValue(cmdPress, sizeof(cmdPress), false); // Writing to Canon_pairing_service
|
|
log_e("Camera paring success");
|
|
delay(200);
|
|
disconnect();
|
|
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_NO_MITM);
|
|
delay(200);
|
|
connect();
|
|
nvs.setString("cameraaddr", String(camera_address.toString().c_str()));
|
|
if (nvs.commit())
|
|
{
|
|
log_i("Saving camera's address to NVS success");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
log_e("Storing camera's address to NVS failed");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_e("Couldn't acquire the pairing or shutter service");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_e("Couldn't acquire the remote main service");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_e("Couldn't connect the BLEClient to the device");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CanonBLERemote::connect()
|
|
{
|
|
if (pclient->connect(camera_address))
|
|
{
|
|
pRemoteService = pclient->getService(SERVICE_UUID);
|
|
if (pRemoteService != nullptr)
|
|
{
|
|
// Serial.println("Get remote service OK");
|
|
pRemoteCharacteristic_Trigger = pRemoteService->getCharacteristic(SHUTTER_CONTROL_SERVICE);
|
|
if (pRemoteCharacteristic_Trigger != nullptr)
|
|
{
|
|
log_i("Camera connection Success");
|
|
// disconnect(); // Disconnect remote from the camera every time after action, as the real canon remote did.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
log_e("Get trigger service failed");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_e("Couldn't acquire the remote main service");
|
|
}
|
|
disconnect();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CanonBLERemote::disconnect()
|
|
{
|
|
pclient->disconnect();
|
|
}
|
|
|
|
bool CanonBLERemote::isConnected()
|
|
{
|
|
return pconnection_state->isConnected();
|
|
}
|
|
|
|
/** Trigger Camera
|
|
* If the camera is in photo mode, it will take a single picture.
|
|
* If the camera is in movie mode, it will start/stop movie recording.
|
|
*/
|
|
|
|
bool CanonBLERemote::trigger()
|
|
{
|
|
|
|
if (!isConnected())
|
|
{
|
|
if (!connect())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
byte cmdByte = {MODE_IMMEDIATE | BUTTON_RELEASE}; // Binary OR : Concatenate Mode and Button
|
|
pRemoteCharacteristic_Trigger->writeValue(cmdByte, false); // Set the characteristic's value to be the array of bytes that is actually a string.
|
|
delay(200);
|
|
pRemoteCharacteristic_Trigger->writeValue(MODE_IMMEDIATE, false);
|
|
delay(50);
|
|
return true;
|
|
}
|
|
|
|
bool CanonBLERemote::focus()
|
|
{
|
|
if (!isConnected())
|
|
{
|
|
if (!connect())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
byte cmdByte[] = {MODE_IMMEDIATE | BUTTON_FOCUS}; // Binary OR : Concatenate Mode and Button
|
|
pRemoteCharacteristic_Trigger->writeValue(cmdByte, sizeof(cmdByte)); // Set the characteristic's value to be the array of bytes that is actually a string.
|
|
delay(200);
|
|
pRemoteCharacteristic_Trigger->writeValue(MODE_IMMEDIATE, sizeof(MODE_IMMEDIATE));
|
|
return true;
|
|
}
|