Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esp32: BLE support using Nimble #5171

Merged
merged 4 commits into from Oct 8, 2019

Conversation

jimmo
Copy link
Member

@jimmo jimmo commented Oct 1, 2019

This PR adds BLE support for ESP32, extending on #5051.

Note: This requires building with IDF 4.x. Some thought is required as to how we want to enable this for various boards (i.e. the TINYPICO commit shouldn't be merged).

Some minor refactoring of modbluetooth_nimble.c was required as the IDF version of Nimble doesn't require any supporting port-specific code.

@dpgeorge
Copy link
Member

dpgeorge commented Oct 2, 2019

Great, thanks!

Some thought is required as to how we want to enable this for various boards

I would suggest that BLE be enabled unconditionally for all esp32 boards. It's a useful feature and I think would confuse users if it were missing from some boards and enabled in others.

Of course it should still be possible to disable BLE via some compile-time config settings (eg in .mk or .h board file), so someone who wants to build a custom board without BLE can easily do this.

@jonsmirl
Copy link

jonsmirl commented Oct 2, 2019

I started implementing my code using this branch and discovered that support for encrypted characteristics is missing. In my case I set a password into the BLE device and don't want to send it plaintext.

This should be a matter of passing the right flags down into the BLE stack, right? The native stack will do the encrypt/decrypt.

@jonsmirl
Copy link

jonsmirl commented Oct 2, 2019

How do I encode a 128b service UUID on the advertisement?

=== def adv():
===     bt.advertise(100, adv_encode(0x01, b'\x06') + adv_encode(0x07, b'\x0d\x18\x0d\x18\x0d\x18\x0d\x18\x0d\x18\x0d\x18\x0d\x18\x0d\x18') + adv_encode(0x19, b'\xc1\x03') + adv_encode_name('esp32hr'))
=== 
=== adv()
=== 
GAP procedure initiated: stop advertising.
True
Traceback (most recent call last):
  File "<stdin>", line 35, in <module>
  File "<stdin>", line 33, in adv
OSError: [Errno 5] EIO
>>> 

I also tried this:

adv_encode(0x07, bluetooth.UUID('17b85e2d-b52d-4433-8fca-f90b8a02d017').bytes))

But the bluetooth.UUID class does not implement the bytes member.

Edit: The first failure is because the advertising string is slightly too long. If I make it shorter it will work. The bytes member function would be quite helpful so that I don't have to figure out the correct endian encoding for the byte string.

@MarSoft
Copy link

MarSoft commented Oct 4, 2019

Cannot build this branch for ESP32. (Looks like Travis cannot build it as well.) Am I doing something wrong? I just followed the README.

@MarSoft
Copy link

MarSoft commented Oct 4, 2019

Checked with git bisect; the compilation problem is introduced in 579bc8fb2142be5 . The error message is: nimble.c:31:28: fatal error: esp_nimble_hci.h: No such file or directory.

Found that the problem is because corresponding include directories are added only if CONFIG_BT_NIMBLE_ENABLED is set, but nimble.c is included regardless of that option.

I see now: currently BLE support is only enabled for TINYPICO board, sorry for the noise.
If you want to build for generic non-BLE board: create GENERIC_BLE board based on e.g. GENERIC_SPIRAM and replace sdkconfig.spiram in its mpconfigboard.mk with sdkconfig.ble. Then pass it as a BOARD variable to make.

@jimmo jimmo mentioned this pull request Oct 6, 2019
13 tasks
@hobby16-design
Copy link

Can some helping hand give me a compiled binary please, even of a work-on-progress version? George gave this link https://micropython.org/resources/firmware/esp32-bluetooth.bin in #4589 but it's dead. There is a esp32-bluetooth.bin at the micropython download page but with no info about it.

I am craving to test the ESP32's BLE, but as a C embedded programmer making first steps into the vast & beautiful ESP32 & micropython world, I am at a loss at the install & compile shebang.

@jimmo jimmo force-pushed the common-ble-api-esp32-nimble branch from 54789eb to 4068afc Compare October 7, 2019 23:37
@jimmo
Copy link
Member Author

jimmo commented Oct 7, 2019

I would suggest that BLE be enabled unconditionally for all esp32 boards. It's a useful feature and I think would confuse users if it were missing from some boards and enabled in others.

I've enabled it for GENERIC, GENERIC_SPIRAM and TINYPICO.

But the bluetooth.UUID class does not implement the bytes member.

Yeah good catch. I will add this to the list. #5186

Edit: The first failure is because the advertising string is slightly too long. If I make it shorter it will work. The bytes member function would be quite helpful so that I don't have to figure out the correct endian encoding for the byte string.

Yep, if you want this to work for 128-bit service uuids, you'll need a longer payload, which means active scans (i.e. you need to set the scan response data too). I think this currently works for the advertising role (set resp_data as well as adv_data in bt.advertise()), but I haven't implemented this for the scanning role yet. I believe there's also a way to set partial uuids in the payload, but haven't investigated.

Checked with git bisect; the compilation problem is introduced in 579bc8f . The error message is: nimble.c:31:28: fatal error: esp_nimble_hci.h: No such file or directory.
Found that the problem is because corresponding include directories are added only if CONFIG_BT_NIMBLE_ENABLED is set, but nimble.c is included regardless of that option.

Yup, my mistake. Have fixed that now so that it builds with or without nimble/ble being enabled.

@jimmo jimmo force-pushed the common-ble-api-esp32-nimble branch 3 times, most recently from 0c52cb5 to fef750e Compare October 8, 2019 03:27
@@ -25,13 +25,13 @@
* THE SOFTWARE.
*/

#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These guards usually go after the standard py/ includes, so that they can (in principle) be configured by a header file like mpconfigport.h. Is there a reason to move it up here?

@@ -238,36 +158,7 @@ typedef struct {
/******************************************************************************/
// RUN LOOP
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment header needed now almost all code from this section is gone? Maybe just delete it and leave mp_bluetooth_nimble_ble_state where it is, in this top section.

* THE SOFTWARE.
*/

#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this move down to below the 3 py/ includes?

* THE SOFTWARE.
*/

#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move down?

On other ports (e.g. ESP32) they provide a complete Nimble implementation
(i.e. we don't need to use the code in extmod/nimble). This change
extracts out the bits that we don't need to use in other ports:
 - malloc/free/realloc for Nimble memory.
 - pendsv poll handler
 - depowering the cywbt

Also cleans up the root pointer management.
@jimmo jimmo force-pushed the common-ble-api-esp32-nimble branch from fef750e to cdeed34 Compare October 8, 2019 03:43
@jimmo
Copy link
Member Author

jimmo commented Oct 8, 2019

Thanks, all done.

@jimmo jimmo force-pushed the common-ble-api-esp32-nimble branch from cdeed34 to a1005f2 Compare October 8, 2019 03:50
@jimmo jimmo force-pushed the common-ble-api-esp32-nimble branch from a1005f2 to fa23033 Compare October 8, 2019 03:52
@dpgeorge dpgeorge merged commit fa23033 into micropython:master Oct 8, 2019
@dpgeorge
Copy link
Member

dpgeorge commented Oct 8, 2019

Merged!

@dpgeorge
Copy link
Member

dpgeorge commented Oct 8, 2019

Can some helping hand give me a compiled binary please, even of a work-on-progress version?

The esp32 binaries at https://micropython.org/download/#esp32 now have BLE included.

@hobby16-design
Copy link

The esp32 binaries at https://micropython.org/download/#esp32 now have BLE included.
Wow, you rock dpgeorge! Thank you and thank you.

@hobby16-design
Copy link

hobby16-design commented Oct 8, 2019

Just flashed the above release. There is Jimmo's doc at docs/library/bluetooth.rst but no example (yet), so bad.
I have no luck getting BLE working.
I wrote this

import bluetooth
ble=bluetooth.BLE()
ble.active(True)
ble.gap_advertise(100,'Micropython')
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)

Normally, I should see "Micropython" using a BT scanner. But I don't see it, what's wrong with my lines above? A weird thing is the MAC address changes constantly each time it is read manually in the console using ble.config('mac').
Edit : my tests are on an ESP32 WROOM module

@dpgeorge
Copy link
Member

dpgeorge commented Oct 9, 2019

ble.gap_advertise(100,'Micropython')

You need to pass in an advertising packet, eg `b'\x02\x01\x02\x04\x09MPY'

@hobby16-design
Copy link

Thank you dpgeorge, I see the ESP32 as "MicroPython" on my smartphone now using this (don't know where you got this syntax from nor what the prefix means, but well...):

import bluetooth
ble=bluetooth.BLE()
ble.active(True)
ble.gap_advertise(100, b'\x02\x01\x02\x0C\x09MicroPython')

Then I am stuck from there on because without examples, the doc is like ciphered Chinese to me.
On this new FW, what would be the equivalent of the code below ? (code for the old fw esp32--bluetooth.bin, which works to send and receive in BLE but which always ends up crashing with a "Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)" after several minutes of transmission. Crash is caused by the RX callback while TX is 100% OK).

import bluetooth,time
bt = bluetooth.Bluetooth()
bt.active(True)
bt.advertise(100, "MicroPython") 
tx = bluetooth.Characteristic('00001236-0000-1000-8000-00805F9B34FB', bluetooth.FLAG_READ|bluetooth.FLAG_NOTIFY)
rx = bluetooth.Characteristic('00001235-0000-1000-8000-00805F9B34FB', bluetooth.FLAG_READ|bluetooth.FLAG_WRITE)
s = bt.add_service           ('00001234-0000-1000-8000-00805F9B34FB', [tx, rx])

def callback(char, data): #receive data from smartphone => print it
	print (data)

rx.on_update(callback)

cnt=0
while True:  #send something to smartphone
	cnt=cnt+1
	tx.write('cnt = '+str(cnt))	
	time.sleep(1)

@dpgeorge
Copy link
Member

For a UART service try something like this:

import bluetooth
bt = bluetooth.Bluetooth()
bt.active(1)
def bt_irq(event, data):
    print(event, data)
bt.irq(bt_irq)

def adv_encode_name(name):
    name = bytes(name, 'ascii')
    return bytearray((len(name) + 1, 0x09)) + name

UART_TX = (
    bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'),
    bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
)
UART_RX = (
    bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'),
    bluetooth.FLAG_WRITE,
)
UART_SERVICE= (
    bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E'),
    (UART_TX, UART_RX),
)

bt.gatts_register_services((UART_SERVICE,))
bt.gap_advertise(100, bytearray('\x02\x01\x02') + adv_encode_name('MicroPython'))

@amaza
Copy link

amaza commented Oct 10, 2019 via email

@dpgeorge
Copy link
Member

How can we know the power output of esp32, or change if it'snt the best?

This is not currently exposed. But it could easily be, using the BLE.config() method.

@foxriver76
Copy link

foxriver76 commented Oct 10, 2019

Thanks for the great work. Is it somehow possible to scan for devices like described in #5051 (comment)? Managed it with gap_scan, but where do I get the constants like IRQ_SCAN_RESULT from?

def bt_irq(event, data):
    if event == IRQ_SCAN_RESULT:
        addr_type, addr, connectable, rssi, adv_data = data
        print('Scan result', adv_decode_name(adv_data))
    elif event == IRQ_SCAN_COMPLETE:
        print('Scan complete')

bt.irq(bt_irq, IRQ_ALL)
bt.scan(2000)  # Scan for 2000 ms

@hobby16-design
Copy link

@dpgeorge, code doesn't work. The device is seen by the BLE scan but can't be connected to.
Are you sure you have tested on the right fw? Because the line bt = bluetooth.Bluetooth() is not ok, it should be bt = bluetooth.BLE() on the lastest publised fw.

@hobby16-design
Copy link

where do I get the constants like IRQ_SCAN_RESULT from?

I found doc here : https://github.com/micropython/micropython/pull/5192/files?short_path=5ec29c7#diff-5ec29c7721a8f70cfaf860c248b3d623

@foxriver76
Copy link

@hobby16-design this helps a lot. Thank you

@foxriver76
Copy link

foxriver76 commented Oct 11, 2019

Also getting stuck with the encoding of the adv_data. @jimmo uses adv_decode_name, unfortunately the function is not part of the code snippet.

Edit: After diving into it a little bit I guess the adv_data of my devices just do not make any sense, e. g. getting b'\x02\x01\x1a\x02\n\x0c\x0b\xffL\x00\x10\x06\x11\x1a\x08\x1c\xb5L

@Ubledeli
Copy link

Ubledeli commented Oct 13, 2019

Hi, I have installed the latest firmware but i cannot activate the BLE module.
complete code and output are here:

>>> ble=bluetooth.BLE()
>>> ble.active(True)
I (53720) BTDM_INIT: BT controller compile version [a482cda]
I (54388) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
W (54398) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration

Brownout detector was triggered

ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5068
load:0x40078000,len:10404
load:0x40080400,len:5716
entry 0x400806c0
I (509) cpu_start: Pro cpu up.
I (509) cpu_start: Application information:
I (509) cpu_start: Compile time:     Oct 11 2019 00:36:12
I (513) cpu_start: ELF file SHA256:  0000000000000000...
I (519) cpu_start: ESP-IDF:          v4.0-beta1
I (524) cpu_start: Starting app cpu, entry point is 0x40082cf4
I (516) cpu_start: App cpu up.
I (534) heap_init: Initializing. RAM available for dynamic allocation:
I (541) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (547) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
I (553) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
I (560) heap_init: At 3FFBDB5C len 00000004 (0 KiB): DRAM
I (566) heap_init: At 3FFCC620 len 000139E0 (78 KiB): DRAM
I (572) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (578) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (585) heap_init: At 40099C98 len 00006368 (24 KiB): IRAM
I (591) cpu_start: Pro cpu start user code
I (609) spi_flash: detected chip: generic
I (609) spi_flash: flash io: dio
I (610) cpu_start: Chip Revision: 1
W (611) cpu_start: Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.
I (622) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
MicroPython v1.11-422-g98c2eabaf on 2019-10-11; ESP32 module with ESP32
Type "help()" for more information.

am I missing something, or is there an example of correct code that should run out of the box?

@dpgeorge
Copy link
Member

Brownout detector was triggered

It looks like your esp32 board does not have a stable power supply.

@Ubledeli
Copy link

thank you for your suggestion, I will investigate that further.

@aamacaya
Copy link

I'm having the same problem as @hobby16-design . Im trying to make a bluetooth connection with a cellphone. When I run the code described by @dpgeorge few comments above ( using bt = bluetooth.BLE() instead of bt = bluetooth.Bluetooth()) my esp32 is seen by the cellphone but the cellphone cant make the connection.

Also I have some questions about the library (the documentation is not very usefull).

  1. How do you get de UUID number? this is the identifier of the esp32 where the code is runing or is te identifier of te device I want to connect (in this case the cellphone)?

  2. What is the value_handle and the onn_handleargument in some functions?

@HexVitor
Copy link

@aamacaya try something like this:

# Import of modules and classes
import bluetooth

# Configuration
ble = bluetooth.BLE()
ble.active(True)

# Event Handling
def ble_irq(event, data):
    # print received data
    print(ble.gatts_read(rx))
        
ble.irq(ble_irq)

# GATT Server
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
SERVICES = (UART_SERVICE,)
((tx, rx,), ) = ble.gatts_register_services(SERVICES)

# Advertiser
def adv_encode_name(name):
    name = bytes(name, 'ascii')
    return bytearray((len(name) + 1, 0x09)) + name

ble.gap_advertise(100, bytearray('\x02\x01\x02') + adv_encode_name('ESP32'))

I can connect to ESP32 and send it data from the smartphone (using the Serial Bluetooth Terminal [https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal&hl=pt_BR] on Android), even though they are displayed as b'sent data\r\n'. I also cannot send data to the smartphone through the ESP32 (remembering that this is an initial draft). Hope this helps, greetings from Brazil.

@aamacaya
Copy link

@HexVitor First of all thanks for the help. The code runs with no problems in the ESP32

I still have problems with the pairing of the device. When I go to my smartphone bluetooth settings I can see the 'ESP32' Device. When I select it it tries to make the connection but then it fails.

Does it have something to do with the UUID numbers? Or is it something else? maybe the smartphone?

@jonsmirl
Copy link

I don't believe pairing is implemented yet.

@HexVitor
Copy link

@aamacaya Got the point. Although I can connect through the application, there is no pairing either (odd that there was pairing when I used Arduino IDE). I imagine the pairing function is not yet implemented (I've been researching a lot and haven't seen anything about it). From what I understand about UUIDs, they are essential parts of BLE and identify the services provided by the device to be connected (e.g. battery indicator, external sound player, heart rate sensor ...). A list of some of these services and their UUIDs can be found at this link https://www.bluetooth.com/specifications/gatt/services/.

@sunbeamer
Copy link

It's nice to finally have BLE for mainline Micopython on ESP32.

I did find however, that the garbage collection is deleting something important to do with BLE. This bug can be replicated by using the snippet sample above by @HexVitor and using the following steps:

  1. Establish a BLE connection using something like Serial Bluetooth Terminal on Android
  2. Send a couple of test messages successfully from Serial Bluetooth Terminal
  3. Type gc.collect() at the REPL
  4. Try to send a few more messages and you should eventually see something like the following...
Guru Meditation Error: Core  0 panic'ed (InstrFetchProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x3ffe67b0  PS      : 0x00060530  A0      : 0x80148fdc  A1      : 0x3ffbb4a0  
A2      : 0x3ffc5cbc  A3      : 0x00000010  A4      : 0x00000000  A5      : 0x3ffbb4e0  
A6      : 0x3ffc80ec  A7      : 0x3ffe67b0  A8      : 0x80148fa1  A9      : 0x00000000  
A10     : 0x00000000  A11     : 0x00000010  A12     : 0x3ffbb4e0  A13     : 0x00000002  
A14     : 0x0000cdcd  A15     : 0x00000001  SAR     : 0x00000018  EXCCAUSE: 0x00000014  
EXCVADDR: 0x3ffe67b0  LBEG    : 0x4014d139  LEND    : 0x4014d144  LCOUNT  : 0x00000009  

ELF file SHA256: 0000000000000000000000000000000000000000000000000000000000000000

Backtrace: 0x3ffe67ad:0x3ffbb4a0 |<-CORRUPTED```

@diginfo
Copy link

diginfo commented Oct 17, 2019

I have just received some BLE 5.0 Temp/humidity beacons.

Would it be possible to provide some sample code of how to scan for, connect to and read from a slave device ??

These beacons broadcast their values once a second, this can also be changed by a bluetooth write to the device.

Many Thanks

@HexVitor
Copy link

@sunbeamer This could be caused by the print() function that I put into the ble_irq() interrupt function. I read in the Random Nerd Tutorials that this practice should be avoided (https://randomnerdtutorials.com/micropython-interrupts-esp32-esp8266/).

In our example, the handle_interrupt function simply changes the motion variable to True and saves the interrupt pin. You should keep your handling interrupt functions as short as possible and avoid using the print() function inside. Then, the main code should have all the things we want to happen when the interrupt happens.

Thanks for the feedback!

@sunbeamer
Copy link

sunbeamer commented Oct 17, 2019

@HexVitor I removed the print() statement from the ble_irq() interrupt function and restested, this time just invoking ble.gatts_read(rx) manually after sending a BLE packet and got a similar resulting core dump.

It appears the following will provoke a core dump irrespective of whether the ISR is used or not:

  1. gc.collect()
  2. ble.gatts_read(rx)
  3. The next write to the rx characteristic will cause a core dump

@jimmo
Copy link
Member Author

jimmo commented Oct 18, 2019

I don't believe pairing is implemented yet.

@aamacaya @jonsmirl That's right -- neither pairing or bonding is supported yet. See #5186

Note that you don't need pairing and bonding to connect from a phone. I have a HID keyboard demo that works fine on Android from an ESP32 and PYBD. I'm working on tidying it up to post as an example (continuing on from #5223 )

I did find however, that the garbage collection is deleting something important to do with BLE.

@sunbeamer Thanks for the report. I will attempt to repro and get this fixed ASAP.

This could be caused by the print() function that I put into the ble_irq() interrupt function. I read in the Random Nerd Tutorials that this practice should be avoided.

@HexVitor As the site says, it's good to keep interrupt handlers short, but there's actually nothing wrong with using print. The main thing is that in "hard" handlers, you can't allocate memory, so sometimes that makes it hard to generate a string to print. But in "soft" handlers (which run via micropython.schedule) you can do pretty much anything. All the BLE interrupts, with the exception of _IRQ_READ_REQUEST (only on PYBD, not available on ESP32), are "soft".

Does it have something to do with the UUID numbers?

@aamacaya As @HexVitor has pointed out, these UUIDs are documented at https://www.bluetooth.com/specifications/gatt/services/ and https://www.bluetooth.com/specifications/gatt/characteristics/

These "official" services and characteristics have "short" 16-bit UUIDs. There are vendor-specific ones, which have 128-bit UUIDs (the Nordic UART Service is a good example).

A BLE peripheral device is fundamentally a set of services and their associated characteristics.

(Note this is different to BT Classic, which relies on "profiles" as the way of describing the types of functionality).

Just as a general point about this API though -- it's explicitly designed to be a very low-level BLE API and as such it prioritises access to functionality and minimalism over ease-of-use. Some understanding of the BLE specification is unfortunately required.

As I mentioned above, I am working on example code using this API, but probably more usefully, I plan for there to be higher-level wrappers around specific functionality, so that a lot of these details can be ignored. i.e. common scenarios like UART, writing and accessing various sensor types, beacons, scanners, etc should just be a couple of lines of code.

@dpgeorge
Copy link
Member

It's great to have further discussions about BLE, but they are going to get lost in this merged and closed pull request.

So please use https://forum.micropython.org for discussion and questions about how to use BLE, open new issues for bugs, and add (reasonable) feature requests to #5186

Thanks!

@dpgeorge
Copy link
Member

Thanks for the report. I will attempt to repro and get this fixed ASAP.

Split off into #5226

As I mentioned above, I am working on example code using this API

There are now some BLE examples in examples/bluetooth/

tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Aug 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet