AboutServicesProjectsBlog
Projects
Hanging Plotter
First Steps - Pinning an idea down and checking assumptions
Post Print Iterations
ESP32 development in NixOS using VSCode
Spinning a Stepper
Android development on NixOS
Connecting an ESP32 to android with bluetooth
Using an ESP32 as a logic analyzer
Using an Arduino as a logic analyzer
Driving steppers with the RMT module
Using Nix to write rust on the esp32
Using a smooth stepper driver on the esp32 in rust
Translating an esp32+esp-idf bluetooth example to rust
Musings on packaging build system via splitting independent libraries

Connecting an ESP32 to android with bluetooth

6th article in Hanging Plotter
SoftwareNixOSAndroidBluetoothFlutter
2020-3-20

Communicating between a Flutter app on Android and an ESP32 under ESP-IDF

Bluetooth Low Energy overview

If you're interested in working with BLE first read this oreilly online chapter

Yea, it's long, you'll be tempted to skip it. I sure did. Once you get stuck go back and actually read it

At a high level BLE is composed of several layers:

  • Device - A piece of hardware you connect to
  • Service - A logicical grouping of behavior or information on the device
  • Characteristic - A specific part of the service
  • Attribute - The actual concrete value

There exists a structured description of various characteristics that allow your device to behave predictably, for example if your device has a battery level you can expose it in a way that cause phones to display it next to the device.

Flutter BLE

The first library under consideration is flutter blue

Running the "Packages get" in android studio doesn't work because flutter tries to use its sdk directory as a tmp.

pubspec.yaml

...
dependencies:
    ...
    flutter_blue:

So we just run it in bash in the shell:

$ flutter pub get
$ flutter run
/home/username/projects/hanging-plotter/flutter/plotter_control/android/app/src/debug/AndroidManifest.xml Error:
	uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:flutter_blue]

Quick fix on the build gradle to correct the minimum sdk version

./android/app/build.gradle

android{
    ...
    defaultConfig {
        ...
        minSdkVersion 19
    }
}

Copying main.dart and widgets.dart from the example project and rerunning...

E/flutter ( 5174): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(bluetooth_unavailable, the device does not have bluetooth, null)

right.

Installing on a device...

hexadecimal bluetooth device ids on an android screen
Woah. There it is, real hardware interaction

ESP-IDF BLE

Handily for us espressif has a gatt server walkthrough

First we enable the bluetooth stack in the handy menuconfig wrapper (shift+ctrl+p > ESP-IDF: Launch gui configuration tool)

There was an error finding cmake due to all of the nix files moving around after version upgrades, deleting the ./build directory and running build cleaned it up

Here is the esp-idf vscode plugins menuconfig GUI

a gui menu showing esp-idf configuration options
Not much different from the terminal, much more discoverable than looking up all of the options

Copying the example files into the esp32 project has a core panic:

0x4012d0d2: __assert_func at /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libc/stdlib/assert.c:58
0x40125745: s_prepare_reserved_regions at /nix/store/p6mcp8kcs20x7d64p9408d7nh3qk7i13-esp-idf/components/soc/src/memory_layout_utils.c:91 (discriminator 1)
0x401257c9: soc_get_available_memory_regions at /nix/store/p6mcp8kcs20x7d64p9408d7nh3qk7i13-esp-idf/components/soc/src/memory_layout_utils.c:114
0x400d416d: heap_caps_init at /nix/store/p6mcp8kcs20x7d64p9408d7nh3qk7i13-esp-idf/components/heap/heap_caps_init.c:67
0x40081491: call_start_cpu0 at /nix/store/p6mcp8kcs20x7d64p9408d7nh3qk7i13-esp-idf/components/esp32/cpu_start.c:266

Which points towards an issue with allocation. It has been merged in 4.2-dev, time to upgrade! Note: I had to modify the sha256 of the fetchFromGithub and fetchurl in order for nix to accept the version changes

$ idf.py build && idf.py flash && idf.py monitor
I (1279) GATTS_DEMO: REGISTER_APP_EVT, status 0, app_id 0
I (1369) GATTS_DEMO: CREATE_SERVICE_EVT, status 0,  service_handle 40
I (1389) GATTS_DEMO: SERVICE_START_EVT, status 0, service_handle 40
I (1389) GATTS_DEMO: ADD_CHAR_EVT, status 0,  attr_handle 42, service_handle 40
I (1394) GATTS_DEMO: the gatts demo char length = 3
I (1399) GATTS_DEMO: prf_char[0] =11
I (1404) GATTS_DEMO: prf_char[1] =22
I (1404) GATTS_DEMO: prf_char[2] =33
I (1409) GATTS_DEMO: REGISTER_APP_EVT, status 0, app_id 1
I (1419) GATTS_DEMO: ADD_DESCR_EVT, status 0, attr_handle 43, service_handle 40
I (1424) GATTS_DEMO: CREATE_SERVICE_EVT, status 0,  service_handle 44
I (1434) GATTS_DEMO: SERVICE_START_EVT, status 0, service_handle 44
I (1439) GATTS_DEMO: ADD_CHAR_EVT, status 0,  attr_handle 46, service_handle 44
I (1449) GATTS_DEMO: ADD_DESCR_EVT, status 0, attr_handle 47, service_handle 44

the gatts demo connected on android
Zuh!

Two quick tweaks to finish this off. First I broke the bluetooth code into a separate file, but was having trouble including it.

this stack overflow post mentioned that you need extern C to include c in cpp files:

main.cpp:

...
extern "C" {
#include "bluetooth.h"
}

void app_main() {
    bluetooth_init()
    ...
}

Since the bluetooth stack is configured to run on core 0 I have the stepper loop bound to core 1 using xTaskCreatePinnedToCore

    xTaskCreatePinnedToCore(&bounce, "bounce", 2048,NULL,5,NULL, 1);

Now the stepper is happily spinning away while the bluetooth stack remains responsive. Next up: controlling the stepper via an app

state of codebase as of this post

PreviousNext
Featured Projects
GeneratorHandwheel Repair
Company Info
About UsContactAffiliate DisclosurePrivacy Policy
Specific Solutions LLC
Portland, OR