Skip to content
Snippets Groups Projects
main.cpp 5.23 KiB
Newer Older
Marek Ištok's avatar
Marek Ištok committed
#include <main.h>

#include "nvs.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"

#include <string.h>

#include <string>
#include <unordered_set>
#include <algorithm>
Marek Ištok's avatar
Marek Ištok committed

#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG

static const char* TAG = "main";

std::unordered_set<std::string> devices;
uint8_t unique_pings = 0;
uint16_t total_pings = 0;
Marek Ištok's avatar
Marek Ištok committed

static esp_ble_scan_params_t ble_scan_params = {
  .scan_type          = BLE_SCAN_TYPE_ACTIVE,
  .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
  .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
  // Set scan interval & window to 25ms (40 * 0.625)
  .scan_interval      = 0x28,
  .scan_window        = 0x28,
  .scan_duplicate     = BLE_SCAN_DUPLICATE_DISABLE
};

static void esp_gap_cb(
  esp_gap_ble_cb_event_t event,
  esp_ble_gap_cb_param_t *param
);

void app_main(void) {
  // Initialize NVS.
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
  }
  ESP_ERROR_CHECK( ret );

  ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  ret = esp_bt_controller_init(&bt_cfg);
  if (ret) {
    ESP_LOGE(TAG, "%s initialize controller failed: %s\n",
      __func__, esp_err_to_name(ret));
    return;
  }

  ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
  if (ret) {
    ESP_LOGE(TAG, "%s enable controller failed: %s\n",
      __func__, esp_err_to_name(ret));
    return;
  }

  ret = esp_bluedroid_init();
  if (ret) {
    ESP_LOGE(TAG, "%s init bluetooth failed: %s\n",
      __func__, esp_err_to_name(ret));
    return;
  }

  ret = esp_bluedroid_enable();
  if (ret) {
    ESP_LOGE(TAG, "%s enable bluetooth failed: %s\n",
      __func__, esp_err_to_name(ret));
    return;
  }

  //register the  callback function to the gap module
  ret = esp_ble_gap_register_callback(esp_gap_cb);
  if (ret){
    ESP_LOGE(TAG, "%s gap register failed, error code = %x\n", __func__, ret);
    return;
  }

  // Set wakeup interval of 4s
  esp_sleep_enable_timer_wakeup(4 * 1e6);

  while (true) {
     ret = esp_ble_gap_set_scan_params(&ble_scan_params);
    if (ret){
      ESP_LOGE(TAG, "set scan params error, error code = %x", ret);
    }

    unique_pings = 0;
    total_pings = 0;
Marek Ištok's avatar
Marek Ištok committed
    devices.clear();
    // Set scan duration to 30s, we can control it with the delay below
    esp_ble_gap_start_scanning(30);

    vTaskDelay(pdMS_TO_TICKS(2000));
    ESP_ERROR_CHECK(esp_ble_gap_stop_scanning());

    ESP_LOGI(TAG, "[%s]: Unique devices captured: %u", __func__, unique_pings);
    ESP_LOGI(TAG, "[%s]: Total pings captured: %u", __func__, total_pings);

    vTaskDelay(2);
Marek Ištok's avatar
Marek Ištok committed
    ESP_LOGI(TAG, "[%s]: Slep", __func__);
    esp_light_sleep_start();
    ESP_LOGI(TAG, "[%s]: Wakey", __func__);
  }
}

static void esp_gap_cb(
  esp_gap_ble_cb_event_t event,
  esp_ble_gap_cb_param_t *param
) {
  uint8_t *adv_name = NULL;
  uint8_t adv_name_len = 0;
  switch (event) {
    case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
      //scan start complete event to indicate scan start successfully or failed
      if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
        ESP_LOGE(TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
        break;
      }
      ESP_LOGI(TAG, "scan start success");

      break;
    case ESP_GAP_BLE_SCAN_RESULT_EVT: {
      esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
      switch (scan_result->scan_rst.search_evt) {
      case ESP_GAP_SEARCH_INQ_RES_EVT: {
        char mac[18];
        auto addr = scan_result->scan_rst.bda;

        snprintf(mac, 18, "%.2x %.2x %.2x %.2x %.2x %.2x",
          addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);

        adv_name = esp_ble_resolve_adv_data(
          scan_result->scan_rst.ble_adv,
          ESP_BLE_AD_TYPE_NAME_CMPL,
          &adv_name_len
        );

        if (adv_name_len > 0 && strncmp(
            (char*) adv_name, "INFOTECH", std::min(adv_name_len, (uint8_t) 8)
          ) == 0
        ) {
          if (devices.find(mac) == devices.end()) {
            devices.insert(mac);
            unique_pings += 1;

            ESP_LOGI(TAG, "%s (%ddBm, %.*s)", 
              mac, scan_result->scan_rst.rssi, adv_name_len, adv_name); 
          }

          // Also count duplicates here
          total_pings += 1;
Marek Ištok's avatar
Marek Ištok committed
          ESP_LOGD(TAG, "%s", mac);
        }

        break;
      }
      case ESP_GAP_SEARCH_INQ_CMPL_EVT:
        break;
      default:
        break;
      }
      break;
    }

    case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
      if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
        ESP_LOGE(TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
        break;
      }
      ESP_LOGI(TAG, "stop scan successfully");
      break;

    case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
      if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
        ESP_LOGE(TAG, "adv stop failed, error status = %x", param->adv_stop_cmpl.status);
        break;
      }
      ESP_LOGI(TAG, "stop adv successfully");
      break;
    default:
      break;
    }
}