├── src ├── SerialDebug.h ├── ILCE7M3ExternalGps.ino └── CameraBle.h ├── README.md ├── README_EN.md ├── PROTOCOL.md └── PROTOCOL_EN.md /src/SerialDebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __SERIAL_DEBUG_H_ 2 | #define __SERIAL_DEBUG_H_ 3 | 4 | #ifdef DEBUG_BT_SERIAL 5 | #include "BluetoothSerial.h" 6 | #define SerialDebug SerialBT 7 | #else 8 | #define SerialDebug Serial 9 | #endif 10 | 11 | #ifdef DEBUG_BT_SERIAL 12 | BluetoothSerial SerialBT; 13 | #endif 14 | 15 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [**English Version Click Here**](README_EN.md) 2 | 3 | # ILCE7M3ExternalGps 4 | 5 | 一个给索尼 A7M3 用的基于 ESP32和 通用 GPS 模块(硬件暂时待定)的外置 GPS 模组,通过模仿逆向出来的索尼 Imaging Edge Mobile 手机应用的 BLE 协议与相机进行通信,用来取代通常不甚稳定的手机应用。 6 | 7 | ~~这个项目不保证最后能出来,咕咕~~个人能力原因,此项目已废弃,现存的代码完成于 2021 年,仅供参考,好像能用但是真的很垃圾;配套的硬件板子画得实在太过离谱就不公开了;各位大佬自由发挥随便咋玩吧(用的 TinyGPSPlus 库是 LGPL 协议的要注意,这个仓库就不加 LICENSE 了 8 | 9 | ## 参考 10 | 11 | * [位置信息数据包格式](PROTOCOL.md) 12 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # ILCE7M3ExternalGps 2 | 3 | An external GPS module for Sony ILCE-7M3 that is based on ESP32 and generic GPS module (hardware model is undetermined yet) to substitute for the Imaging Edge Mobile app. Works by emulating reverse engineered BLE location transmission protocol. 4 | 5 | ~~The completion of this project CANNOT be guaranteed for now.~~ Due to personal capacity reasons, this project has been abandoned. The uploaded code was finished in 2021 and is for reference only. It seems to work but it's really really trashy code. The hardware board design is way too bad with multiple issues so I'm not even gonna release it. Feel free to do whatever you want with the current content (note that the TinyGPSPlus library used is under LGPL license, I'm not adding a LICENSE file here to this repo). 6 | 7 | ## References 8 | 9 | * [Location BLE Packet Structure](PROTOCOL_EN.md) 10 | -------------------------------------------------------------------------------- /PROTOCOL.md: -------------------------------------------------------------------------------- 1 | [**English Version Click Here**](PROTOCOL_EN.md) 2 | 3 | ## GATT 服务 4 | 5 | 位置服务 UUID: 8000DD00-DD00-FFFF-FFFF-FFFFFFFFFFFF 6 | 7 | - 写入特性 UUID: 0xDD11 8 | 9 | - 读取特性 UUID: 0xDD21 10 | 11 | ## BLE 配置信息读取数据包例子 12 | 0610009c 02 00 13 | 14 | |偏移|内容|备注| 15 | |-|-|-| 16 | |[0:3]|未知|| 17 | |[4]|某种设置信息【**第二位为 1 则必须回传时区与夏令时偏移数据**】|0x02 & 0x02 = 1 需要回传时区与夏令时偏移| 18 | |[5]|未知|| 19 | 20 | 21 | 22 | ## BLE 位置信息写入数据包例子 23 | 24 | 005d 0802fc 03 0000101010 0bf79e5e 41c385a7 07e40b0504022a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 01e0 0000 25 | 26 | * 全部数据**大端在前(Big Endian)** 27 | 28 | |偏移|内容|备注| 29 | |-|-|-| 30 | |[0:1]|载荷长度(除去这两字节)|0x5D = 93 字节| 31 | |[2:4]|固定数据|0x0802FC| 32 | |[5]|回传时区与夏令时偏移标志(需要回传为 0x03 否则为 0x00)|0x03 需要回传时区与夏令时偏移| 33 | |[6:10]|固定数据|0x0000101010| 34 | |[11:14]|纬度(*10000000)|0x0BF79E5E = 200777310 / 10000000 = 20.077731| 35 | |[15:18]|经度(*10000000)|0x41C385A7 = 1103332775 / 10000000 = 110.3332775| 36 | |[19:20]|UTC年|0x07E4 = 2020| 37 | |[21]|UTC月|0x0B = 11| 38 | |[22]|UTC日|0x05 = 5| 39 | |[23]|UTC时|0x04 = 4| 40 | |[24]|UTC分|0x02 = 2| 41 | |[25]|UTC秒|0x2A = 42| 42 | |[26:90]|零|0x00| 43 | |\*[91:92]|UTC 与当前时区的时差(分钟)|0x01E0 = 480min = 8h (UTC+8)| 44 | |\*[93:94]|当前时区日光节约时间(夏令时)的时差(分钟)|中国不适用夏令时因此为0| 45 | 46 | (标\*的数据在读取的配置信息中 4.2 位为 1 才需要发,否则省略) 47 | -------------------------------------------------------------------------------- /PROTOCOL_EN.md: -------------------------------------------------------------------------------- 1 | ## GATT Service 2 | 3 | Location Service UUID: 8000DD00-DD00-FFFF-FFFF-FFFFFFFFFFFF 4 | 5 | - Write Characteristic UUID: 0xDD11 6 | - Read Characteristic UUID: 0xDD21 7 | 8 | ## BLE Read Configuration Packet Example 9 | 0610009c 02 00 10 | 11 | |Offset|Content|Remark| 12 | |-|-|-| 13 | |[0:3]|Unknown|| 14 | |[4]|Some sort of flag [**If bit 2 is 1 then timezone offset and DST offset must be provided when writting coordinate data**]|0x02 & 0x02 = 1, Timezone and DST offset data are required| 15 | |[5]|Unknown|| 16 | 17 | ## BLE Write Coordinate Packet Example 18 | 19 | 005d 0802fc 03 0000101010 0bf79e5e 41c385a7 07e40b0504022a 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 01e0 0000 20 | 21 | * All multi-byte data are in **Big Endian**. 22 | 23 | |Offset|Content|Remark| 24 | |-|-|-| 25 | |[0:1]|Payload Length (exclude these two bytes)|0x5D = 93 bytes| 26 | |[2:4]|Fixed Data|0x0802FC| 27 | |[5]|Flag of transmitting timezone offset and DST offset (0x03 for transmit and 0x00 for do not transmit)|0x03 Timezone offset and DST offset required| 28 | |[6:10]|Fixed Data|0x0000101010| 29 | |[11:14]|Latitude (multiplied by 10000000)|0x0BF79E5E = 200777310 / 10000000 = 20.077731| 30 | |[15:18]|Longitude (multiplied by 10000000)|0x41C385A7 = 1103332775 / 10000000 = 110.3332775| 31 | |[19:20]|UTC Year|0x07E4 = 2020| 32 | |[21]|UTC Month|0x0B = 11| 33 | |[22]|UTC Day|0x05 = 5| 34 | |[23]|UTC Hour|0x04 = 4| 35 | |[24]|UTC Minute|0x02 = 2| 36 | |[25]|UTC Second|0x2A = 42| 37 | |[26:90]|Zeros|0x00| 38 | |\*[91:92]|Difference between UTC and current timezone in minutes| 0x01E0 = 480min = 8h (UTC+8)| 39 | |\*[93:94]|Difference for DST in current timezone in minutes|0 (DST is not available in China)| 40 | 41 | (Fields marked by \* is required only when bit 2 of byte 4 of configuration data read is 1, otherwise omitted.) 42 | -------------------------------------------------------------------------------- /src/ILCE7M3ExternalGps.ino: -------------------------------------------------------------------------------- 1 | #define BLE_DEVICE_ADDRESS "48:eb:62:e2:a8:10" // Your camera's bluetooth MAC 2 | #define GPS_MODULE_BAUDRATE 9600 // GPS module baudrate 3 | #define GPS_MODULE_TX_PIN 14 // Connect to GPS module's RX 4 | #define GPS_MODULE_RX_PIN 12 // Connect to GPS module's TX 5 | //#define DEBUG_BT_SERIAL // Uncomment to enable bluetooth serial, comment to enable UART0 (USB on dev board) 6 | 7 | #include "CameraBle.h" 8 | #include "SerialDebug.h" 9 | #include 10 | //#include "BLEScan.h" 11 | 12 | TinyGPSPlus nmea; 13 | TinyGPSCustom isFix(nmea, "GNRMC", 2); 14 | 15 | bool scanning = true; 16 | BLEAdvertisedDevice *deviceFound = NULL; 17 | bool connected = false; 18 | 19 | bool isSendTzDstOffset = false; 20 | unsigned long lastTransmitPacket = 0; 21 | unsigned long lastLatitudeMul = 0, lastLongitudeMul = 0; 22 | unsigned int lastYear = 0; 23 | unsigned char lastMonth = 0, lastDay = 0, lastHour = 0, lastMinute = 0, lastSecond = 0; 24 | 25 | void OnScanDone(bool isSuccess, BLEAdvertisedDevice *device) 26 | { 27 | SerialDebug.print(F("Scan finished. Result=")); 28 | SerialDebug.println(isSuccess); 29 | 30 | deviceFound = device; 31 | scanning = false; 32 | } 33 | 34 | void OnDisconnected() 35 | { 36 | SerialDebug.println(F("Camera disconnected")); 37 | connected = false; 38 | } 39 | 40 | void setup() 41 | { 42 | 43 | #ifdef DEBUG_BT_SERIAL 44 | SerialDebug.begin("ILCE7M3ExternalGps"); 45 | #else 46 | SerialDebug.begin(115200); 47 | #endif 48 | Serial1.begin(GPS_MODULE_BAUDRATE, SERIAL_8N1, GPS_MODULE_RX_PIN, GPS_MODULE_TX_PIN); 49 | 50 | SerialDebug.println(F("Init")); 51 | BLE_Init("ILCE7M3ExternalGps"); 52 | BLE_SetDisconnectedCallback(OnDisconnected); 53 | Serial1.begin(GPS_MODULE_BAUDRATE, SERIAL_8N1, GPS_MODULE_RX_PIN, GPS_MODULE_TX_PIN); 54 | SerialDebug.println(F("Init OK")); 55 | 56 | SerialDebug.println(F("Scanning camera")); 57 | BLE_BeginScanning(BLEAddress(BLE_DEVICE_ADDRESS), OnScanDone); 58 | } 59 | 60 | void loop() 61 | { 62 | if(Serial1.available()) 63 | nmea.encode(Serial1.read()); 64 | 65 | if(!scanning && deviceFound == NULL) 66 | { 67 | SerialDebug.println(F("Scanning camera")); 68 | scanning = true; 69 | BLE_BeginScanning(BLEAddress(BLE_DEVICE_ADDRESS), OnScanDone); 70 | } 71 | 72 | if(deviceFound != NULL && !connected) 73 | { 74 | SerialDebug.println(F("Connecting camera")); 75 | unsigned char connectResult = BLE_ConnectCamera(deviceFound); 76 | switch(connectResult) 77 | { 78 | case BLE_CONNECT_RESULT_SUCCESS: 79 | isSendTzDstOffset = ReadIsSendTzDst(); 80 | SerialDebug.println(F("Connected!")); 81 | SerialDebug.print(F("Need to send timezone and DST offset: ")); 82 | SerialDebug.println(isSendTzDstOffset); 83 | connected = true; 84 | break; 85 | case BLE_CONNECT_RESULT_DEVICE_ERROR: 86 | SerialDebug.println(F("Connect failed: Bluetooth connection problem")); 87 | break; 88 | case BLE_CONNECT_RESULT_CHARACTERISTICS_ERROR: 89 | SerialDebug.println(F("Connect failed: Unable to find services or characteristics")); 90 | break; 91 | case BLE_CONNECT_RESULT_AUTH_ERROR: 92 | SerialDebug.println(F("Connect failed: Unable to finish authentication")); 93 | break; 94 | } 95 | delay(50); 96 | } 97 | 98 | if(isFix.isValid() && isFix.value()[0] == 'A' && nmea.location.isValid() && nmea.date.isValid() && nmea.time.isValid()) 99 | { 100 | double latitude = nmea.location.lat(); 101 | double longitude = nmea.location.lng(); 102 | unsigned long latitudeMul = latitude * 10000000; 103 | unsigned long longitudeMul = longitude * 10000000; 104 | unsigned int year = nmea.date.year(); 105 | unsigned char month = nmea.date.month(); 106 | unsigned char day = nmea.date.day(); 107 | unsigned char hour = nmea.time.hour(); 108 | unsigned char minute = nmea.time.minute(); 109 | unsigned char second = nmea.time.second(); 110 | 111 | if(latitudeMul != lastLatitudeMul || longitudeMul != lastLongitudeMul || year != lastYear || month != lastMonth || day != lastDay || hour != lastHour || minute != lastMinute || second != lastSecond) 112 | { 113 | lastLatitudeMul = latitudeMul; 114 | lastLongitudeMul = longitudeMul; 115 | lastYear = year; 116 | lastMonth = month; 117 | lastDay = day; 118 | lastHour = hour; 119 | lastMinute = minute; 120 | lastSecond = second; 121 | 122 | SerialDebug.print(F("GPS Packet Update: Lat=")); 123 | SerialDebug.print(latitude, 6); 124 | SerialDebug.print(F(" Lon=")); 125 | SerialDebug.print(longitude, 6); 126 | SerialDebug.print(F(" Speed=")); 127 | SerialDebug.print(nmea.speed.kmph(), 2); 128 | 129 | SerialDebug.print(F(" Now=")); 130 | SerialDebug.print(year); 131 | SerialDebug.print(F("-")); 132 | SerialDebug.print(month < 10 ? F("0") : F("")); 133 | SerialDebug.print(month); 134 | SerialDebug.print(F("-")); 135 | SerialDebug.print(day < 10 ? F("0") : F("")); 136 | SerialDebug.print(day); 137 | SerialDebug.print(F(" ")); 138 | SerialDebug.print(hour < 10 ? F("0") : F("")); 139 | SerialDebug.print(hour); 140 | SerialDebug.print(F(":")); 141 | SerialDebug.print(minute < 10 ? F("0") : F("")); 142 | SerialDebug.print(minute); 143 | SerialDebug.print(F(":")); 144 | SerialDebug.print(second < 10 ? F("0") : F("")); 145 | SerialDebug.print(second); 146 | 147 | SerialDebug.println(); 148 | } 149 | 150 | if(connected && millis() - lastTransmitPacket > BLE_LOCATION_PACKET_TRANSMIT_DURATION) 151 | { 152 | WriteLocationPayload(latitudeMul, longitudeMul, year, month, day, hour, minute, second, isSendTzDstOffset); 153 | lastTransmitPacket = millis(); 154 | } 155 | } 156 | 157 | delay(0); 158 | } 159 | -------------------------------------------------------------------------------- /src/CameraBle.h: -------------------------------------------------------------------------------- 1 | #ifndef __CAMERA_BLE_H_ 2 | #define __CAMERA_BLE_H 3 | 4 | #include "SerialDebug.h" 5 | #include "BLEDevice.h" 6 | #include "esp_gap_bt_api.h" 7 | 8 | #define BLE_AUTHENTICATE_TIMEOUT 30000 // How long to wait for bluetooth authentication before try again, no need to modify normally. 9 | #define BLE_LOCATION_PACKET_TRANSMIT_DURATION 1000 // How long to send one packet to camera, no need to modify normally. 10 | 11 | // ********** BLE Device Scanning ********** 12 | static BLEScan *bleScanner; 13 | 14 | static BLEAddress scanTargetAddress("00:00:00:00:00:00"); 15 | static bool isScanning = false; 16 | 17 | void (*scanFinishedCallback)(bool isFound, BLEAdvertisedDevice *device); 18 | // ******************** 19 | 20 | // ********** BLE Connection and Auth ********** 21 | #define BLE_STATE_NOT_CONNECTED 0 22 | #define BLE_STATE_CONNECTING 1 23 | #define BLE_STATE_CONNECT_TIMEOUT 2 24 | #define BLE_STATE_WAITING_CHARACTERISTICS 3 25 | #define BLE_STATE_CHARACTERISTICS_FAILED 4 26 | #define BLE_STATE_WAITING_AUTH 5 27 | #define BLE_STATE_AUTH_FAILED 6 28 | #define BLE_STATE_CONNECTED 7 29 | 30 | #define BLE_CONNECT_RESULT_UNDETERMINED 0 31 | #define BLE_CONNECT_RESULT_SUCCESS 1 32 | #define BLE_CONNECT_RESULT_DEVICE_ERROR 2 33 | #define BLE_CONNECT_RESULT_CHARACTERISTICS_ERROR 3 34 | #define BLE_CONNECT_RESULT_AUTH_ERROR 4 35 | 36 | static const BLEUUID locationServiceUuid("8000dd00-dd00-ffff-ffff-ffffffffffff"); 37 | static const BLEUUID locationCharaReadUuid("0000dd21-0000-1000-8000-00805f9b34fb"); 38 | static const BLEUUID locationCharaWriteUuid("0000dd11-0000-1000-8000-00805f9b34fb"); 39 | 40 | static BLEClient *cameraConnection; 41 | static BLERemoteCharacteristic *locationCharaRead; 42 | static BLERemoteCharacteristic *locationCharaWrite; 43 | 44 | static unsigned char connectState = BLE_STATE_NOT_CONNECTED; 45 | static unsigned char connectResult = BLE_CONNECT_RESULT_UNDETERMINED; 46 | static bool isAuthenticating = false; 47 | 48 | void (*cameraDisconnectedCallback)(void); 49 | // ******************** 50 | 51 | // ********** BLE Transaction ********** 52 | unsigned char sendPayload[] = { 53 | 0x00, 0x5D, // Length 54 | 0x08, 0x02, 0xfc, 0x03, 0x00, 0x00, 0x10, 0x10, 0x10, // Fixed data 55 | 0x00, 0x00, 0x00, 0x00, // Lat 56 | 0x00, 0x00, 0x00, 0x00, // Lon 57 | 0x00, 0x00, // UTC Year 58 | 0x00, // UTC Month 59 | 0x00, // UTC Day 60 | 0x00, // UTC Hour 61 | 0x00, // UTC Minute 62 | 0x00, // UTC Second 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Zeros 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 68 | 0x00, 0x00, // Time zone offset 69 | 0x00, 0x00 // DST offset 70 | }; 71 | 72 | // ********** BLE Device Scanning ********** 73 | 74 | // BLE device timeout handler 75 | static void _OnBleScanComplete(BLEScanResults scanResults) 76 | { 77 | if (isScanning) 78 | isScanning = false; 79 | scanFinishedCallback(false, NULL); 80 | } 81 | 82 | // BLE device found handler 83 | class _BleAdvertisedDeviceHandler : public BLEAdvertisedDeviceCallbacks 84 | { 85 | void onResult(BLEAdvertisedDevice advertisedDevice) 86 | { 87 | if (advertisedDevice.getAddress().equals(scanTargetAddress)) 88 | { 89 | bleScanner->stop(); 90 | scanFinishedCallback(true, new BLEAdvertisedDevice(advertisedDevice)); 91 | } 92 | } 93 | }; 94 | 95 | bool BLE_BeginScanning(BLEAddress targetAddress, void (*onScanningFinished)(bool, BLEAdvertisedDevice*)) 96 | { 97 | if (isScanning || connectState != BLE_STATE_NOT_CONNECTED) 98 | { 99 | SerialDebug.println("[BLEScan] Already scanning or connected to device!"); 100 | return false; 101 | } 102 | scanTargetAddress = targetAddress; 103 | scanFinishedCallback = onScanningFinished; 104 | bleScanner = BLEDevice::getScan(); 105 | bleScanner->setAdvertisedDeviceCallbacks(new _BleAdvertisedDeviceHandler()); 106 | bleScanner->setInterval(1000); 107 | bleScanner->setWindow(500); 108 | bleScanner->setActiveScan(true); 109 | isScanning = true; 110 | bleScanner->start(60, _OnBleScanComplete, false); 111 | return true; 112 | } 113 | 114 | // ******************** 115 | 116 | // ********** BLE Transaction ********** 117 | 118 | unsigned int ReadLocationParam(char **buf) 119 | { 120 | if(locationCharaRead->canRead()) 121 | { 122 | std::string ret = locationCharaRead->readValue(); 123 | if(ret.size() == 0) 124 | return 0; 125 | unsigned int len = ret.size() - 1; 126 | *buf = (char*)malloc(sizeof(char) * len); 127 | memcpy(*buf, ret.data(), len); 128 | return len; 129 | } 130 | else 131 | SerialDebug.println("Cannot read location param"); 132 | return 0; 133 | } 134 | 135 | bool ReadIsSendTzDst() 136 | { 137 | char *buf; 138 | unsigned int readLen = ReadLocationParam(&buf); 139 | bool ret = ((readLen == 6) && ((buf[4] & 0x02) == 0x02)); 140 | free(buf); 141 | return ret; 142 | } 143 | 144 | void WriteLocationPayload(unsigned long latMul, unsigned long lonMul, unsigned int year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second, bool isSendTzDstOffset) 145 | { 146 | // Length 147 | sendPayload[1] = isSendTzDstOffset ? 0x5D : 0x59; 148 | 149 | // Latitude 150 | sendPayload[11] = (latMul & 0xFF000000) >> 24; 151 | sendPayload[12] = (latMul & 0x00FF0000) >> 16; 152 | sendPayload[13] = (latMul & 0x0000FF00) >> 8; 153 | sendPayload[14] = (latMul & 0x000000FF); 154 | 155 | // Longitude 156 | sendPayload[15] = (lonMul & 0xFF000000) >> 24; 157 | sendPayload[16] = (lonMul & 0x00FF0000) >> 16; 158 | sendPayload[17] = (lonMul & 0x0000FF00) >> 8; 159 | sendPayload[18] = (lonMul & 0x000000FF); 160 | 161 | // Time 162 | sendPayload[19] = (year & 0xFF00) >> 8; 163 | sendPayload[20] = (year & 0x00FF); 164 | sendPayload[21] = month; 165 | sendPayload[22] = day; 166 | sendPayload[23] = hour; 167 | sendPayload[24] = minute; 168 | sendPayload[25] = second; 169 | 170 | locationCharaWrite->writeValue(sendPayload, sendPayload[1], true); 171 | } 172 | 173 | // ******************** 174 | 175 | // ********** BLE Connection ********** 176 | 177 | /* 178 | void BLE_DeletePairing() 179 | { 180 | if (esp_ble_remove_bond_device((uint8_t *)cameraMacAddress.getNative()) == ESP_OK) 181 | { 182 | SerialDebug.println(F("Delete pairing status success")); 183 | } 184 | else 185 | { 186 | SerialDebug.println(F("Delete pairing status failed")); 187 | } 188 | } 189 | */ 190 | 191 | // BLE device connected and disconnected callback 192 | class _BleConnectionHandler : public BLEClientCallbacks 193 | { 194 | void onConnect(BLEClient *pclient) 195 | { 196 | 197 | } 198 | 199 | void onDisconnect(BLEClient *pclient) 200 | { 201 | if (connectState == BLE_STATE_CONNECTED) 202 | SerialDebug.println(F("Connection lost")); 203 | connectState = BLE_STATE_NOT_CONNECTED; 204 | cameraDisconnectedCallback(); 205 | } 206 | }; 207 | 208 | // BLE auth callback 209 | class _BleSecurityHandler : public BLESecurityCallbacks 210 | { 211 | 212 | uint32_t onPassKeyRequest() 213 | { 214 | return 0; 215 | } 216 | 217 | void onPassKeyNotify(uint32_t pass_key) 218 | { 219 | } 220 | bool onConfirmPIN(uint32_t pass_key) 221 | { 222 | return true; 223 | } 224 | bool onSecurityRequest() 225 | { 226 | return true; 227 | } 228 | void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl) 229 | { 230 | connectState = auth_cmpl.success ? BLE_STATE_CONNECTED : BLE_STATE_AUTH_FAILED; 231 | } 232 | }; 233 | 234 | void _SetBleSecurity() 235 | { 236 | BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); 237 | BLEDevice::setSecurityCallbacks(new _BleSecurityHandler()); 238 | BLESecurity *bleSecurity = new BLESecurity(); 239 | bleSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND); 240 | bleSecurity->setCapability(ESP_IO_CAP_NONE); 241 | bleSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); 242 | } 243 | 244 | void _ConnectCamera(BLEAdvertisedDevice *device) 245 | { 246 | connectState = BLE_STATE_CONNECTING; 247 | cameraConnection = BLEDevice::createClient(); 248 | cameraConnection->setClientCallbacks(new _BleConnectionHandler()); 249 | cameraConnection->connect(device); 250 | if(cameraConnection->isConnected()) 251 | connectState = BLE_STATE_WAITING_CHARACTERISTICS; 252 | else 253 | connectState = BLE_STATE_CONNECT_TIMEOUT; 254 | } 255 | 256 | void _InitServicesAndCharacteristics() 257 | { 258 | if (connectState != BLE_STATE_WAITING_CHARACTERISTICS) 259 | { 260 | SerialDebug.println(F("[BLEConnect InitServicesAndCharacteristics] Not connected or already done characteristics!")); 261 | return; 262 | } 263 | 264 | // Get location service 265 | BLERemoteService *locationService = cameraConnection->getService(locationServiceUuid); 266 | if (locationService == nullptr) 267 | { 268 | SerialDebug.println(F("ERROR: No specified service")); 269 | connectState = BLE_STATE_CHARACTERISTICS_FAILED; 270 | return; 271 | } 272 | 273 | // Get location read parameter characteristic 274 | locationCharaRead = locationService->getCharacteristic(locationCharaReadUuid); 275 | if (locationCharaRead == nullptr) 276 | { 277 | SerialDebug.println(F("ERROR: No specified characteristic")); 278 | connectState = BLE_STATE_CHARACTERISTICS_FAILED; 279 | return; 280 | } 281 | 282 | // Get location write coordinate characteristic 283 | locationCharaWrite = locationService->getCharacteristic(locationCharaWriteUuid); 284 | if (locationCharaWrite == nullptr) 285 | { 286 | SerialDebug.println(F("ERROR: No specified characteristic")); 287 | connectState = BLE_STATE_CHARACTERISTICS_FAILED; 288 | return; 289 | } 290 | 291 | connectState = BLE_STATE_WAITING_AUTH; 292 | } 293 | 294 | void _DoBleSecurityAttempt() 295 | { 296 | if (connectState != BLE_STATE_WAITING_AUTH) 297 | { 298 | SerialDebug.println(F("[BLEConnect DoBleSecurityAttempt] Not connected or already authed!")); 299 | return; 300 | } 301 | 302 | unsigned long beginTimestamp = millis(); 303 | unsigned long lastPrint = beginTimestamp; 304 | unsigned long now = 0; 305 | char *buf = NULL; 306 | isAuthenticating = true; 307 | while (1) 308 | { 309 | now = millis(); 310 | 311 | if (ReadLocationParam(&buf) > 0) // if something is read then no need to auth 312 | { 313 | isAuthenticating = false; 314 | connectState = BLE_STATE_CONNECTED; 315 | if (buf) 316 | free(buf); 317 | return; 318 | } 319 | 320 | if (connectState == BLE_STATE_CONNECTED) // auth callback returns true 321 | { 322 | isAuthenticating = false; 323 | if (buf) 324 | free(buf); 325 | return; 326 | } 327 | 328 | if (now - lastPrint > 1000) 329 | { 330 | lastPrint = now; 331 | SerialDebug.println(F("Please go to Bluetooth settings and pair the device")); 332 | } 333 | 334 | if(now - beginTimestamp >= BLE_AUTHENTICATE_TIMEOUT) // Timeout 335 | { 336 | connectState = BLE_STATE_AUTH_FAILED; 337 | if (buf) 338 | free(buf); 339 | return; 340 | } 341 | 342 | if (connectState == BLE_STATE_NOT_CONNECTED) // If got kicked 343 | { 344 | if (buf) 345 | free(buf); 346 | return; 347 | } 348 | 349 | delay(50); 350 | } 351 | } 352 | 353 | void BLE_Init(std::string deviceName) 354 | { 355 | BLEDevice::init(deviceName); 356 | _SetBleSecurity(); 357 | } 358 | 359 | void BLE_SetDisconnectedCallback(void (*callback)(void)) 360 | { 361 | cameraDisconnectedCallback = callback; 362 | } 363 | 364 | unsigned char BLE_ConnectCamera(BLEAdvertisedDevice *device) 365 | { 366 | connectResult = BLE_CONNECT_RESULT_UNDETERMINED; 367 | while (connectResult == BLE_CONNECT_RESULT_UNDETERMINED) 368 | { 369 | switch (connectState) 370 | { 371 | case BLE_STATE_NOT_CONNECTED: 372 | if(isAuthenticating) 373 | { 374 | isAuthenticating = false; 375 | connectResult = BLE_CONNECT_RESULT_AUTH_ERROR; 376 | break; 377 | } 378 | SerialDebug.println(F("[BLEConnect ConnectCamera] Connecting to camera...")); 379 | _ConnectCamera(device); 380 | break; 381 | case BLE_STATE_CONNECT_TIMEOUT: 382 | SerialDebug.println(F("[BLEConnect ConnectCamera] Connect Timeout")); 383 | connectState = BLE_STATE_NOT_CONNECTED; 384 | connectResult = BLE_CONNECT_RESULT_DEVICE_ERROR; 385 | break; 386 | case BLE_STATE_WAITING_CHARACTERISTICS: 387 | SerialDebug.println(F("[BLEConnect ConnectCamera] Initializing characteristics...")); 388 | _InitServicesAndCharacteristics(); 389 | break; 390 | case BLE_STATE_CHARACTERISTICS_FAILED: 391 | SerialDebug.println(F("[BLEConnect ConnectCamera] Characteristics FAILED...")); 392 | cameraConnection->disconnect(); 393 | connectResult = BLE_CONNECT_RESULT_CHARACTERISTICS_ERROR; 394 | break; 395 | case BLE_STATE_WAITING_AUTH: 396 | SerialDebug.println(F("[BLEConnect ConnectCamera] Authenticating...")); 397 | _DoBleSecurityAttempt(); 398 | break; 399 | case BLE_STATE_AUTH_FAILED: 400 | SerialDebug.println(F("[BLEConnect ConnectCamera] Authentication FAILED...")); 401 | connectResult = BLE_CONNECT_RESULT_AUTH_ERROR; 402 | break; 403 | case BLE_STATE_CONNECTED: 404 | SerialDebug.println(F("[BLEConnect ConnectCamera] SUCCESSFULLY connected!")); 405 | connectResult = BLE_CONNECT_RESULT_SUCCESS; 406 | break; 407 | } 408 | delay(1); // DoEvents 409 | } 410 | return connectResult; 411 | } 412 | 413 | // ******************** 414 | 415 | #endif 416 | --------------------------------------------------------------------------------