esp32 arduino ble 有时扫描结果不完全的解决方案

问题描述:

用esp32 做扫描应用时发现一个bug

本来想用esp32做ble扫描我的小米手环3广播信号,,实际操作时发现一个bug

在回调函数中的扫描总是扫描不到设备名????

翻阅源码后发现

具体在下面这个ble库里

#include <BLEScan.h>

 

 

 

在如图所示位置加入代码即可解决问题。。。

 

/*
 * BLEScan.cpp
 *
 *  Created on: Jul 1, 2017
 *      Author: kolban
 */
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)


#include <esp_err.h>

#include <map>

#include "BLEAdvertisedDevice.h"
#include "BLEScan.h"
#include "BLEUtils.h"
#include "GeneralUtils.h"
#include "esp32-hal-log.h"

/**
 * Constructor
 */
BLEScan::BLEScan() {
	m_scan_params.scan_type          = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan.
	m_scan_params.own_addr_type      = BLE_ADDR_TYPE_PUBLIC;
	m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
	m_pAdvertisedDeviceCallbacks     = nullptr;
	m_stopped                        = true;
	m_wantDuplicates                 = false;
	setInterval(100);
	setWindow(100);
} // BLEScan


/**
 * @brief Handle GAP events related to scans.
 * @param [in] event The event type for this event.
 * @param [in] param Parameter data for this event.
 */
void BLEScan::handleGAPEvent(
	esp_gap_ble_cb_event_t  event,
	esp_ble_gap_cb_param_t* param) {
  //char* zhoufeng_pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
//	printf("\n\n(event(%d):event2(%d):p>>(%s)\r\n)",event,param->scan_rst.search_evt,zhoufeng_pHex);//还有信息
	switch(event) {

		// ---------------------------
		// scan_rst:
		// esp_gap_search_evt_t search_evt
		// esp_bd_addr_t bda
		// esp_bt_dev_type_t dev_type
		// esp_ble_addr_type_t ble_addr_type
		// esp_ble_evt_type_t ble_evt_type
		// int rssi
		// uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX]
		// int flag
		// int num_resps
		// uint8_t adv_data_len
		// uint8_t scan_rsp_len
		case ESP_GAP_BLE_SCAN_RESULT_EVT: {
				
			switch(param->scan_rst.search_evt) {
				//
				// ESP_GAP_SEARCH_INQ_CMPL_EVT
				//
				// Event that indicates that the duration allowed for the search has completed or that we have been
				// asked to stop.
				case ESP_GAP_SEARCH_INQ_CMPL_EVT: {
					log_w("ESP_GAP_SEARCH_INQ_CMPL_EVT");
					m_stopped = true;
					m_semaphoreScanEnd.give();
					if (m_scanCompleteCB != nullptr) {
						m_scanCompleteCB(m_scanResults);
					}
					break;
				} // ESP_GAP_SEARCH_INQ_CMPL_EVT

				//
				// ESP_GAP_SEARCH_INQ_RES_EVT
				//
				// Result that has arrived back from a Scan inquiry.
				case ESP_GAP_SEARCH_INQ_RES_EVT: {
					if (m_stopped) { // If we are not scanning, nothing to do with the extra results.
						break;
					}
							
// Examine our list of previously scanned addresses and, if we found this one already,
// ignore it.
					BLEAddress advertisedAddress(param->scan_rst.bda);
					bool found = false;
					printf("advertisedAddress.toString() (%s)\r\n",advertisedAddress.toString().c_str());
					if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) {
						found = true;

						auto advertisedDevicemap = m_scanResults.m_vectorAdvertisedDevices.find(advertisedAddress.toString());
						BLEAdvertisedDevice* advertisedDevice=advertisedDevicemap->second;
						advertisedDevice->setAddress(advertisedAddress);
						advertisedDevice->setRSSI(param->scan_rst.rssi);
						advertisedDevice->setAdFlag(param->scan_rst.flag);
						advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
						advertisedDevice->setScan(this);
						advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);
						printf("found = true;\r\n");
					}
					
					if (found && !m_wantDuplicates) {  // If we found a previous entry AND we don't want duplicates, then we are done.
						log_d("Ignoring %s, already seen it.", advertisedAddress.toString().c_str());
						vTaskDelay(1);  // <--- allow to switch task in case we scan infinity and dont have new devices to report, or we are blocked here
						break;
					}

					// We now construct a model of the advertised device that we have just found for the first
					// time.
					// ESP_LOG_BUFFER_HEXDUMP((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len, ESP_LOG_DEBUG);
					// log_w("bytes length: %d + %d, addr type: %d", param->scan_rst.adv_data_len, param->scan_rst.scan_rsp_len, param->scan_rst.ble_addr_type);
					BLEAdvertisedDevice *advertisedDevice = new BLEAdvertisedDevice();
					printf("newp->%p\r\n",advertisedDevice);
					advertisedDevice->setAddress(advertisedAddress);
					advertisedDevice->setRSSI(param->scan_rst.rssi);
					advertisedDevice->setAdFlag(param->scan_rst.flag);
					advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
					advertisedDevice->setScan(this);
					advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);

					if (!found) {   // If we have previously seen this device, don't record it again.
					printf("insertp->%p\r\n",advertisedDevice);
						m_scanResults.m_vectorAdvertisedDevices.insert(std::pair<std::string, BLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice));
					}

					if (m_pAdvertisedDeviceCallbacks) {
						m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
					}
					
					if(found){
						printf("delp->%p\r\n",advertisedDevice);
						delete advertisedDevice;
					}
						
						

					break;
				} // ESP_GAP_SEARCH_INQ_RES_EVT

				default: {
					break;
				}
			} // switch - search_evt


			break;
		} // ESP_GAP_BLE_SCAN_RESULT_EVT

		default: {
			break;
		} // default
	} // End switch
} // gapEventHandler


/**
 * @brief Should we perform an active or passive scan?
 * The default is a passive scan.  An active scan means that we will wish a scan response.
 * @param [in] active If true, we perform an active scan otherwise a passive scan.
 * @return N/A.
 */
void BLEScan::setActiveScan(bool active) {
	if (active) {
		m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE;
	} else {
		m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE;
	}
} // setActiveScan


/**
 * @brief Set the call backs to be invoked.
 * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
 * @param [in] wantDuplicates  True if we wish to be called back with duplicates.  Default is false.
 */
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) {
	m_wantDuplicates = wantDuplicates;
	m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
} // setAdvertisedDeviceCallbacks


/**
 * @brief Set the interval to scan.
 * @param [in] The interval in msecs.
 */
void BLEScan::setInterval(uint16_t intervalMSecs) {
	m_scan_params.scan_interval = intervalMSecs / 0.625;
} // setInterval


/**
 * @brief Set the window to actively scan.
 * @param [in] windowMSecs How long to actively scan.
 */
void BLEScan::setWindow(uint16_t windowMSecs) {
	m_scan_params.scan_window = windowMSecs / 0.625;
} // setWindow


/**
 * @brief Start scanning.
 * @param [in] duration The duration in seconds for which to scan.
 * @param [in] scanCompleteCB A function to be called when scanning has completed.
 * @param [in] are we continue scan (true) or we want to clear stored devices (false)
 * @return True if scan started or false if there was an error.
 */
bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue) {
	log_v(">> start(duration=%d)", duration);

	m_semaphoreScanEnd.take(std::string("start"));
	m_scanCompleteCB = scanCompleteCB;                  // Save the callback to be invoked when the scan completes.

	//  if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals
	//  then we should not clear map or we will connect the same device few times
	if(!is_continue) {  
		for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
			delete _dev.second;
		}
		m_scanResults.m_vectorAdvertisedDevices.clear();
	}

	esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params);

	if (errRc != ESP_OK) {
		log_e("esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
		m_semaphoreScanEnd.give();
		return false;
	}

	errRc = ::esp_ble_gap_start_scanning(duration);

	if (errRc != ESP_OK) {
		log_e("esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
		m_semaphoreScanEnd.give();
		return false;
	}

	m_stopped = false;

	log_v("<< start()");
	return true;
} // start


/**
 * @brief Start scanning and block until scanning has been completed.
 * @param [in] duration The duration in seconds for which to scan.
 * @return The BLEScanResults.
 */
BLEScanResults BLEScan::start(uint32_t duration, bool is_continue) {
	if(start(duration, nullptr, is_continue)) {
		m_semaphoreScanEnd.wait("start");   // Wait for the semaphore to release.
	}
	return m_scanResults;
} // start


/**
 * @brief Stop an in progress scan.
 * @return N/A.
 */
void BLEScan::stop() {
	log_v(">> stop()");

	esp_err_t errRc = ::esp_ble_gap_stop_scanning();

	m_stopped = true;
	m_semaphoreScanEnd.give();

	if (errRc != ESP_OK) {
		log_e("esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc));
		return;
	}

	log_v("<< stop()");
} // stop

// delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address
void BLEScan::erase(BLEAddress address) {
	log_i("erase device: %s", address.toString().c_str());
	BLEAdvertisedDevice *advertisedDevice = m_scanResults.m_vectorAdvertisedDevices.find(address.toString())->second;
	m_scanResults.m_vectorAdvertisedDevices.erase(address.toString());
	delete advertisedDevice;
}


/**
 * @brief Dump the scan results to the log.
 */
void BLEScanResults::dump() {
	log_v(">> Dump scan results:");
	for (int i=0; i<getCount(); i++) {
		log_d("- %s", getDevice(i).toString().c_str());
	}
} // dump


/**
 * @brief Return the count of devices found in the last scan.
 * @return The number of devices found in the last scan.
 */
int BLEScanResults::getCount() {
	return m_vectorAdvertisedDevices.size();
} // getCount


/**
 * @brief Return the specified device at the given index.
 * The index should be between 0 and getCount()-1.
 * @param [in] i The index of the device.
 * @return The device at the specified index.
 */
BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) {
	uint32_t x = 0;
	BLEAdvertisedDevice dev = *m_vectorAdvertisedDevices.begin()->second;
	for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) {
		dev = *it->second;
		if (x==i)	break;
		x++;
	}
	return dev;
}

BLEScanResults BLEScan::getResults() {
	return m_scanResults;
}

void BLEScan::clearResults() {
	for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){
		delete _dev.second;
	}
	m_scanResults.m_vectorAdvertisedDevices.clear();
}

#endif /* CONFIG_BT_ENABLED */

更改的代码如下::

 

问题的原因是因为接收到的小米手环广播被拆分成两的字段

前面的信息段和后面的数据段

 

5701009941c3cdde08ecaa1fbb56f9ebb119cf02c5e53967bab2(数据段)

 

用map里的数据把应该有的数据添加到设备对象里就可以了!!!!!

 

 

/home/zhou/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src/BLEScan.cpp

//在这个文件里



						auto advertisedDevicemap = m_scanResults.m_vectorAdvertisedDevices.find(advertisedAddress.toString());
						BLEAdvertisedDevice* advertisedDevice=advertisedDevicemap->second;
						advertisedDevice->setAddress(advertisedAddress);
						advertisedDevice->setRSSI(param->scan_rst.rssi);
						advertisedDevice->setAdFlag(param->scan_rst.flag);
						advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
						advertisedDevice->setScan(this);
						advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);
						printf("found = true;\r\n");

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Arduino ESP32是一种开源硬件平台,可以通过编程和连接各种外部设备来创建各种项目。ESP32是ESP系列的微控制器模块,具有强大的处理能力和低功耗特性。 BLE(蓝牙低功耗)是一种无线通信技术,可用于设备之间的短距离通信。通过使用ESP32BLE库,我们可以实现BLE广播和扫描的功能。 要同时进行BLE广播和扫描,我们可以使用两个不同的ESP32设备,一个作为广播者,另一个作为扫描者。 作为广播者,我们可以使用ESP32BLE广播库来设置广播数据包。我们可以在广播数据包中包含任何想要传输的信息,比如设备名称、传感器数据等。然后,我们可以使用BLE广播库中的函数将广播数据包发送到周围的设备。 作为扫描者,我们可以使用ESP32BLE扫描库来搜索附近的BLE设备。我们可以设置扫描持续时间和扫描类型,并在找到设备时执行特定的动作。我们可以使用BLE扫描库中的回调函数获取扫描结果,并进行相应的处理。 在两个ESP32设备之间实现BLE广播和扫描可以通过建立连接来进一步交互和传输数据。广播者可以在广播数据包中包含用于建立连接的信息,而扫描者可以在找到广播者时尝试建立连接,并通过BLE通信协议进行数据传输。 通过在Arduino IDE中编写适当的代码,我们可以将ESP32配置为同时进行BLE广播和扫描,从而实现设备之间的无线通信。这样,我们可以开发各种基于ESP32的项目,如智能家居系统、传感器网络等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值