This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Binary file not shown.
Binary file not shown.
8,678 changes: 0 additions & 8,678 deletions ports/nrf/bluetooth/s132_nrf52_5.0.0/s132_nrf52_5.0.0_softdevice.hex

This file was deleted.

114 changes: 0 additions & 114 deletions ports/nrf/board_busses.c

This file was deleted.

192 changes: 0 additions & 192 deletions ports/nrf/boards/feather_nrf52832/README.md

This file was deleted.

44 changes: 0 additions & 44 deletions ports/nrf/boards/feather_nrf52832/custom_nrf52832_dfu_app_2.0.1.ld

This file was deleted.

44 changes: 0 additions & 44 deletions ports/nrf/boards/feather_nrf52832/custom_nrf52832_dfu_app_5.0.0.ld

This file was deleted.

26 changes: 0 additions & 26 deletions ports/nrf/boards/feather_nrf52832/examples/ble_scan.py

This file was deleted.

12 changes: 0 additions & 12 deletions ports/nrf/boards/feather_nrf52832/examples/blinky.py

This file was deleted.

20 changes: 0 additions & 20 deletions ports/nrf/boards/feather_nrf52832/examples/i2c_scan.py

This file was deleted.

25 changes: 0 additions & 25 deletions ports/nrf/boards/feather_nrf52832/examples/pulseio.py

This file was deleted.

13 changes: 0 additions & 13 deletions ports/nrf/boards/feather_nrf52832/mpconfigboard.mk

This file was deleted.

47 changes: 0 additions & 47 deletions ports/nrf/boards/feather_nrf52832/pins.c

This file was deleted.

70 changes: 38 additions & 32 deletions ports/nrf/boards/feather_nrf52840_express/pins.c
Original file line number Diff line number Diff line change
@@ -1,49 +1,55 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_04) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_30) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_28) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) },
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_04) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_30) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_28) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) },

{ MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) },
{ MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) },

{ MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_P0_29) },
{ MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_P0_29) },

{ MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P1_02) },
{ MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P1_02) },

{ MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) },
{ MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) },
{ MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) },

{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_08) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_07) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_26) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_27) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P1_09) },
{ MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_08) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_07) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_26) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_27) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P1_09) },

{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P0_16) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P0_16) },

{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_14) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_15) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_14) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_13) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_15) },

{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_25) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_24) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_25) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_24) },

{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_11) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_12) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_11) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_12) },

{ MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_RED_LED), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P1_10) },
{ MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_RED_LED), MP_ROM_PTR(&pin_P1_15) },
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P1_15) },

{ MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P1_10) },

{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
};

MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
2 changes: 1 addition & 1 deletion ports/nrf/boards/makerdiary_nrf52840_mdk/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_AIN0), MP_ROM_PTR(&pin_P0_02) },
Expand Down
96 changes: 96 additions & 0 deletions ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# MakerDiary NRF52840 MDK USB Dongle

Refer to [The makerdiary Github repo](https://github.com/makerdiary/nrf52840-mdk-usb-dongle)
or [The nrf52840-mdk-usb-dongle wiki](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
for more details about the device.

This is pretty much just the nRF52840 with a useful number of pins exposed for
your pleasure along with one RGB LED and an onboard antenna in a USB stick form
factor with room for headers on the sides.

Note that all three LEDs on this device are wired through sinks, not sources,
so flip your boolean expectations when dealing with `DigitalInOut` or `PWMOut`
on this device --
`led.value = True` or `led.duty_cycle = 0xffff` turns the LED off!

The onboard button is hard wired to the Reset pin so you cannot use it yourself.

## Installing CircuitPython submodules

Before you can build, you will need to run the following commands once, which
will install the submodules that are part of the CircuitPython ecosystem, and
build the `mpy-cross` tool:

```
$ cd circuitpython
$ git submodule update --init
$ make -C mpy-cross
```

## Note about bootloaders

While most Adafruit devices come with (or can easily be flashed with) an
Adafruit-provided bootloader (supporting niceties like UF2 flashing), this
board comes with one that supports DFU via nrfutil. If you ever need to
restore the DFU bootloader via a SWD debugger, use
[the nRF52 open bootloader hex file](https://github.com/makerdiary/nrf52840-mdk-usb-dongle/tree/master/firmware/open_bootloader).

## Building and Flashing CircuitPython

```
$ cd ports/nrf
```

### Build CircuitPython for the MDK USB Dongle

```
make BOARD=makerdiary_nrf52840_mdk_usb_dongle SD=s140 V=1 -j4 hex
```

This should produce a `build-makerdiary_nrf52840_mdk_usb_dongle-s140/firmware.hex` file.

### Install nrfutil

You'll need to have [nrfutil](https://pypi.org/project/nrfutil/) installed as
appropriate for your system.
As of 2019-01, _nrfutil still requires Python 2.7_... ugh!

### Flash the nRF52 Radio Soft Device

Build a DFU package from the softdevice hex file and flash it:

```sh
nrfutil pkg generate --hw-version 52 --sd-req 0x00 --sd-id 0xAE --softdevice bluetooth/s140_nrf52_6.1.0/s140_nrf52_6.1.0_softdevice.hex dfu_sd140-6.1.0.zip
nrfutil dfu usb-serial -pkg dfu_sd140-6.1.0.zip -p /dev/tty.usbmodemABRACADBRA # likely /dev/ttyACM0 on Linux
```

Note that the `--sd=id 0xAE` comes from the Nordic nRF52 manual for SoftDevice
6.1.0. When the SoftDevice is changed, read the Nordic manual to find the
correct value and use it on all of the `nrfutil pkg generate` commands.

`/dev/tty.usbmodem*` is a macOS name. On Linux it'll likely be `/dev/ttyACM*`. On Windows probably a COM port.

### Flash CircuitPython

Build a DFU package from the hex application file and flash it:

```
nrfutil pkg generate --sd-req 0xAE --application build-makerdiary_nrf52840_mdk_usb_dongle-s140/firmware.hex --hw-version 52 --application-version 1 dfu_circuitpython.zip
nrfutil dfu usb-serial -pkg dfu_circuitpython.zip -p /dev/tty.usbmodemABRACADBRA
```

I'm not sure if `--application-version 1` is actually meaningful or required.

After this, your device should be up and running CircuitPython. When it
resets, you'll see the CIRCUITPY USB filesystem and a new console usb modem
serial port show up.

```
Adafruit CircuitPython 4.0.0-alpha.5-139-g10ceb6716 on 2019-01-14; MakerDiary nRF52840 MDK USB Dongle with nRF52840
>>>
```

### TODO items

* Update the Makefile to do the above DFU .zip building and nrfutil flashing.
* Create a UF2 bootloader for this. It is already a USB stick form factor, it deserves to behave like one.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@
* THE SOFTWARE.
*/

#include <string.h>
#include <stdbool.h>

#include "nrf.h"

#include "boards/board.h"

void board_init(void) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Glenn Ruben Bakke
* Copyright (c) 2016 Glenn Ruben Bakke
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -24,24 +25,25 @@
* THE SOFTWARE.
*/

#define MICROPY_HW_BOARD_NAME "Bluefruit nRF52 Feather"
#define MICROPY_HW_MCU_NAME "nRF52832"
#define MICROPY_PY_SYS_PLATFORM "nRF52"
#include "nrfx/hal/nrf_gpio.h"

#define MICROPY_HW_LED_STATUS (&pin_P0_17)
#define MAKERDIARY_NRF52840_MDK_DONGLE

#define MICROPY_HW_UART_RX NRF_GPIO_PIN_MAP(0, 8)
#define MICROPY_HW_UART_TX NRF_GPIO_PIN_MAP(0, 6)
#define MICROPY_HW_BOARD_NAME "MakerDiary nRF52840 MDK USB Dongle"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "MakerDiary52840MDKDongle"

#define PORT_HEAP_SIZE (32 * 1024)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500

#define DEFAULT_I2C_BUS_SCL (&pin_P0_26)
#define DEFAULT_I2C_BUS_SDA (&pin_P0_25)
// If you change this, then make sure to update the linker scripts as well to
// make sure you don't overwrite code
#define PORT_HEAP_SIZE (128 * 1024)
// TODO #define CIRCUITPY_INTERNAL_NVM_SIZE 8192

#define DEFAULT_SPI_BUS_SCK (&pin_P0_12)
#define DEFAULT_SPI_BUS_MOSI (&pin_P0_13)
#define DEFAULT_SPI_BUS_MISO (&pin_P0_14)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

#define DEFAULT_UART_BUS_RX (&pin_P0_08)
#define DEFAULT_UART_BUS_TX (&pin_P0_06)
#define BOARD_HAS_CRYSTAL 1 // according to the schematic we do

// See https://github.com/adafruit/circuitpython/issues/1300, circuitpython
// doesn't yet support NFC so just force those pins to be GPIO.
#define CONFIG_NFCT_PINS_AS_GPIOS
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
USB_VID = 0x239A
USB_PID = 0x802A
USB_PRODUCT = "nRF52840-MDK-Dongle"
USB_MANUFACTURER = "makerdiary"

MCU_SERIES = m4
MCU_VARIANT = nrf52
MCU_SUB_VARIANT = nrf52840
MCU_CHIP = nrf52840
SD ?= s140
SOFTDEV_VERSION ?= 6.1.0

BOOT_SETTING_ADDR = 0xFF000
BOOT_FILE = boards/$(BOARD)/bootloader/$(SOFTDEV_VERSION)/$(BOARD)_bootloader_$(SOFTDEV_VERSION)_s140

ifeq ($(SD),)
LD_FILE = boards/nrf52840_1M_256k.ld
else
LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld
endif

NRF_DEFINES += -DNRF52840_XXAA -DNRF52840
41 changes: 41 additions & 0 deletions ports/nrf/boards/makerdiary_nrf52840_mdk_usb_dongle/pins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "shared-bindings/board/__init__.h"

#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_AIN0), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_AIN1), MP_ROM_PTR(&pin_P0_03) },
{ MP_ROM_QSTR(MP_QSTR_AIN2), MP_ROM_PTR(&pin_P0_04) },
{ MP_ROM_QSTR(MP_QSTR_AIN3), MP_ROM_PTR(&pin_P0_05) },

{ MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_04) }, // User must connect manually.
{ MP_ROM_QSTR(MP_QSTR_VDIV), MP_ROM_PTR(&pin_P0_05) }, // User must connect manually.

// Not defining the NFC names until CircuitPython supports NFC.
// { MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) },
// { MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) },

{ MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_P0_02) },
{ MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_P0_03) },
{ MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_P0_04) },
{ MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_P0_05) },
{ MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_P0_06) },
{ MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_P0_07) },
{ MP_ROM_QSTR(MP_QSTR_P8), MP_ROM_PTR(&pin_P0_08) },
{ MP_ROM_QSTR(MP_QSTR_P9), MP_ROM_PTR(&pin_P0_09) },
{ MP_ROM_QSTR(MP_QSTR_P10), MP_ROM_PTR(&pin_P0_10) },
{ MP_ROM_QSTR(MP_QSTR_P18), MP_ROM_PTR(&pin_P0_18) }, // !Reset button.
{ MP_ROM_QSTR(MP_QSTR_P19), MP_ROM_PTR(&pin_P0_19) },
{ MP_ROM_QSTR(MP_QSTR_P22), MP_ROM_PTR(&pin_P0_22) }, // green led, low is on.
{ MP_ROM_QSTR(MP_QSTR_P23), MP_ROM_PTR(&pin_P0_23) }, // red led, low is on.
{ MP_ROM_QSTR(MP_QSTR_P24), MP_ROM_PTR(&pin_P0_24) }, // blue led, low is on.

{ MP_ROM_QSTR(MP_QSTR_LED_RED), MP_ROM_PTR(&pin_P0_23) }, // Low is on.
{ MP_ROM_QSTR(MP_QSTR_LED_GREEN), MP_ROM_PTR(&pin_P0_22) }, // Low is on.
{ MP_ROM_QSTR(MP_QSTR_LED_BLUE), MP_ROM_PTR(&pin_P0_24) }, // Low is on.

// BUT this is the RESET pin so we can't really use it.
{ MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_P0_18) }, // Low is pressed.
};

MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
28 changes: 0 additions & 28 deletions ports/nrf/boards/nrf52832_512k_64k.ld

This file was deleted.

28 changes: 0 additions & 28 deletions ports/nrf/boards/nrf52832_512k_64k_s132_2.0.1.ld

This file was deleted.

28 changes: 0 additions & 28 deletions ports/nrf/boards/nrf52832_512k_64k_s132_5.0.0.ld

This file was deleted.

2 changes: 1 addition & 1 deletion ports/nrf/boards/particle_argon/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ endif

NRF_DEFINES += -DNRF52840_XXAA -DNRF52840

SPI_FLASH_FILESYSTEM = 1
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICE_COUNT = 1
EXTERNAL_FLASH_DEVICES = "MX25L3233F"
2 changes: 1 addition & 1 deletion ports/nrf/boards/particle_argon/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_03) },
Expand Down
2 changes: 1 addition & 1 deletion ports/nrf/boards/particle_boron/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_03) },
Expand Down
2 changes: 1 addition & 1 deletion ports/nrf/boards/particle_xenon/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_03) },
Expand Down
15 changes: 0 additions & 15 deletions ports/nrf/boards/pca10040/mpconfigboard.mk

This file was deleted.

44 changes: 0 additions & 44 deletions ports/nrf/boards/pca10040/pins.c

This file was deleted.

2 changes: 1 addition & 1 deletion ports/nrf/boards/pca10056/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_P0_00), MP_ROM_PTR(&pin_P0_00) },
Expand Down
2 changes: 1 addition & 1 deletion ports/nrf/boards/pca10059/pins.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "shared-bindings/board/__init__.h"

#include "board_busses.h"
#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_P0_02), MP_ROM_PTR(&pin_P0_02) },
Expand Down
48 changes: 48 additions & 0 deletions ports/nrf/boards/sparkfun_nrf52840_mini/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# SparkFun Pro nRF52840 Mini Breakout

The [SparkFun Pro nRF52840 Mini](https://www.sparkfun.com/products/15025) small breakout board for Raytac's MDBT50Q-P1M module, which features an nRF52840. It breaks out as many pins as it can in an Arduino Pro Mini footprint. Also included on the board are a qwiic (I<sup>2</sup>C) connector, LiPo battery charger, and on/off switch.

Note: the SparkFun Pro nRF52840 Mini Breakout does not include a QSPI external flash. Any Python code will need to be stored on the internal flash filesystem.

## CircuitPython Pin Defs

CircuitPython pin definitions try to follow those of the [Arduino Pro Mini](https://www.sparkfun.com/products/11113), which the footprint is based on.

This can be somewhat confusing, especially around the analog pins. Here's a quick pin-map:

<table>
<tr><th>Board pin label</th><th>Digital Pin Reference</th><th>Additional Pin Capabilities</th><th>Pin/Port Reference</th></tr>
<tr><td>17</td><td>D1</td><td>TX</td><td>P0_17</td></tr>
<tr><td>15</td><td>D0</td><td>RX</td><td>P0_15</td></tr>
<tr><td>8</td><td></td><td>SDA</td><td>P0_08</td></tr>
<tr><td>11</td><td></td><td>SCL</td><td>P0_11</td></tr>
<tr><td>19</td><td>D3</td><td></td><td>P0_19</td></tr>
<tr><td>20</td><td>D4</td><td></td><td>P0_20</td></tr>
<tr><td>21</td><td>D5</td><td></td><td>P0_21</td></tr>
<tr><td>22</td><td>D6</td><td></td><td>P0_22</td></tr>
<tr><td>23</td><td>D7</td><td></td><td>P0_23</td></tr>
<tr><td>9</td><td>D8</td><td></td><td>P0_09</td></tr>
<tr><td>10</td><td>D9</td><td></td><td>P0_10</td></tr>
<tr><td>2</td><td>D10</td><td>A0</td><td>P0_02</td></tr>
<tr><td>3</td><td>D11</td><td>MOSI, A1</td><td>P0_03</td></tr>
<tr><td>31</td><td>D12</td><td>MISO, A7</td><td>P0_31</td></tr>
<tr><td>30</td><td>D13</td><td>SCK, A6</td><td>P0_31</td></tr>
<tr><td>29</td><td></td><td>A5</td><td>P0_29</td></tr>
<tr><td>28</td><td></td><td>A4</td><td>P0_28</td></tr>
<tr><td>5</td><td></td><td>A3</td><td>P0_05</td></tr>
<tr><td>4</td><td></td><td>A2</td><td>P0_04</td></tr>
</table>

If a pin isn't defined as D0, D1, etc., standard port/pin references should work -- e.g. `P0_17` is pin 17, `P0_02` is pin 2, etc.

## Bootloader Notes

The nRF52840 Mini ships with a slightly modified (i.e pin defs and USB defs) version of the Adafruit nRF52 bootloader, which supports UF2 and CDC bootloading.

## Hardware Reference

The nRF52840 Mini hardware layout is open source:

* [Schematic](https://cdn.sparkfun.com/assets/learn_tutorials/8/2/0/nrf52840-breakout-mdbt50q-v10.pdf)
* [Eagle Files](https://cdn.sparkfun.com/assets/learn_tutorials/8/2/0/nrf52840-breakout-mdbt50q-v10.zip)
* [Hookup Guide](https://learn.sparkfun.com/tutorials/sparkfun-pro-nrf52840-mini-hookup-guide)
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -24,7 +24,15 @@
* THE SOFTWARE.
*/

#include "nrfx.h"
#include "boards/board.h"

void board_init(void) {
}

bool board_requests_safe_mode(void) {
return false;
}

void reset_board(void) {

void nrf_peripherals_power_init(void) {
}
68 changes: 68 additions & 0 deletions ports/nrf/boards/sparkfun_nrf52840_mini/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "nrfx/hal/nrf_gpio.h"

#define MICROPY_HW_BOARD_NAME "SparkFun Pro nRF52840 Mini"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_PY_SYS_PLATFORM "SFE_NRF52840_Mini"

#define PORT_HEAP_SIZE (128 * 1024)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500

#define DEFAULT_I2C_BUS_SCL (&pin_P0_11)
#define DEFAULT_I2C_BUS_SDA (&pin_P0_08)

#define DEFAULT_SPI_BUS_SCK (&pin_P0_30)
#define DEFAULT_SPI_BUS_MOSI (&pin_P0_03)
#define DEFAULT_SPI_BUS_MISO (&pin_P0_31)

#define DEFAULT_UART_BUS_RX (&pin_P0_15)
#define DEFAULT_UART_BUS_TX (&pin_P0_17)

/* Note: Flash chip is not provided on SparkFun nRF52840 Mini.
* Leaving this as a reminder for future/similar versions of the board. */
// Flash operation mode is determined by MICROPY_QSPI_DATAn pin configuration.
// A pin config is valid if it is defined and its value is not 0xFF.
// Quad mode: If all DATA0 --> DATA3 are valid
// Dual mode: If DATA0 and DATA1 are valid while either DATA2 and/or DATA3 are invalid
// Single mode: If only DATA0 is valid
/*#ifdef QSPI_FLASH_FILESYSTEM
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 20)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 21)
#define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(0, 22)
#define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 23)
#define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 19)
#define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(0, 17)
#endif
#ifdef SPI_FLASH_FILESYSTEM
#define SPI_FLASH_MOSI_PIN &pin_P0_20
#define SPI_FLASH_MISO_PIN &pin_P0_21
#define SPI_FLASH_SCK_PIN &pin_P0_19
#define SPI_FLASH_CS_PIN &pin_P0_17
#endif*/

25 changes: 25 additions & 0 deletions ports/nrf/boards/sparkfun_nrf52840_mini/mpconfigboard.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
USB_VID = 0x1B4F
USB_PID = 0x5289
USB_PRODUCT = "SFE_nRF52840_Mini"
USB_MANUFACTURER = "SparkFun Electronics"

MCU_SERIES = m4
MCU_VARIANT = nrf52
MCU_SUB_VARIANT = nrf52840
MCU_CHIP = nrf52840
SD ?= s140
SOFTDEV_VERSION ?= 6.1.0

BOOT_SETTING_ADDR = 0xFF000

ifeq ($(SD),)
LD_FILE = boards/nrf52840_1M_256k.ld
else
LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld
endif

NRF_DEFINES += -DNRF52840_XXAA -DNRF52840

QSPI_FLASH_FILESYSTEM = 0
EXTERNAL_FLASH_DEVICE_COUNT = 0
EXTERNAL_FLASH_DEVICES =
55 changes: 55 additions & 0 deletions ports/nrf/boards/sparkfun_nrf52840_mini/pins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "shared-bindings/board/__init__.h"

#include "supervisor/shared/board_busses.h"

STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P1_15) }, // D1/TX
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_17) }, // D0/RX
// D2 on qwiic gap
{ MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P0_19) }, // D3
{ MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P0_20) }, // D4
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P0_21) }, // D5
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_22) }, // D6
{ MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P0_23) }, // D7
{ MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P0_09) }, // D8
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_10) }, // D9

{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_02) }, // D10
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_03) }, // D11
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_31) }, // D12
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P0_30) }, // D13
{ MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_P0_29) }, // D14
{ MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_P0_28) }, // D15
{ MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_P0_05) }, // D16
{ MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_P0_04) }, // D17

{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_02) }, // A0
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_03) }, // A1
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_04) }, // A2
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_05) }, // A3
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_28) }, // A4
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_29) }, // A5
{ MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) }, // A6
{ MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_P0_31) }, // A7

{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_08) }, // 8 - SDA
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_11) }, // 11 - SCL

{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_31) }, // 31 - MISO
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_03) }, // 3 - MOSI
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_30) }, // 30 - SCK

{ MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_P0_07) }, // 7 - Blue LED

{ MP_ROM_QSTR(MP_QSTR_BUTTON1), MP_ROM_PTR(&pin_P0_13) }, // 13 - Button

{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_15) }, // 15 - UART RX
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_17) }, // 17 - UART TX

{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_QWIIC), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
};

MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);
35 changes: 9 additions & 26 deletions ports/nrf/common-hal/bleio/Adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,22 @@
#include "nrfx_power.h"
#include "nrf_nvic.h"
#include "nrf_sdm.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "shared-bindings/bleio/Adapter.h"

STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AssertionError,
translate("Soft device assert, id: 0x%08lX, pc: 0x%08lX"), id, pc));
mp_raise_msg_varg(&mp_type_AssertionError,
translate("Soft device assert, id: 0x%08lX, pc: 0x%08lX"), id, pc);
}

STATIC uint32_t ble_stack_enable(void) {
nrf_clock_lf_cfg_t clock_config = {
.source = NRF_CLOCK_LF_SRC_XTAL,
#if (BLE_API_VERSION == 4)
.accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM
#else
.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM
#endif
};

#if (BLUETOOTH_SD == 140)
// The SD takes over the POWER IRQ and will fail if the IRQ is already in use
nrfx_power_uninit();
#endif

uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler);
if (err_code != NRF_SUCCESS)
Expand All @@ -64,17 +58,10 @@ STATIC uint32_t ble_stack_enable(void) {
if (err_code != NRF_SUCCESS)
return err_code;

uint32_t app_ram_start;
#if (BLE_API_VERSION == 2)
ble_enable_params_t ble_enable_params = {
.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT,
.gap_enable_params.central_conn_count = 1,
.gap_enable_params.periph_conn_count = 1,
};
// Start with no event handlers, etc.
ble_drv_reset();

app_ram_start = 0x200039c0;
err_code = sd_ble_enable(&ble_enable_params, &app_ram_start);
#else
uint32_t app_ram_start;
app_ram_start = 0x20004000;

ble_cfg_t ble_conf;
Expand All @@ -100,7 +87,6 @@ STATIC uint32_t ble_stack_enable(void) {
return err_code;

err_code = sd_ble_enable(&app_ram_start);
#endif

return err_code;
}
Expand All @@ -121,8 +107,7 @@ void common_hal_bleio_adapter_set_enabled(bool enabled) {
}

if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to change softdevice state, error: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to change softdevice state"));
}
}

Expand All @@ -131,8 +116,7 @@ bool common_hal_bleio_adapter_get_enabled(void) {

const uint32_t err_code = sd_softdevice_is_enabled(&is_enabled);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to get softdevice state, error: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to get softdevice state"));
}

return is_enabled;
Expand All @@ -151,8 +135,7 @@ void common_hal_bleio_adapter_get_address(bleio_address_obj_t *address) {
#endif

if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to get local address, error: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to get local address"));
}

address->type = local_address.addr_type;
Expand Down
98 changes: 98 additions & 0 deletions ports/nrf/common-hal/bleio/Broadcaster.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <string.h>

#include "ble.h"
#include "ble_drv.h"
#include "ble_hci.h"
#include "nrf_soc.h"
#include "py/runtime.h"

#include "common-hal/bleio/Broadcaster.h"
#include "shared-bindings/bleio/Adapter.h"
#include "shared-bindings/bleio/Broadcaster.h"

static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;

void common_hal_bleio_broadcaster_construct(bleio_broadcaster_obj_t *self, mp_float_t interval) {
common_hal_bleio_adapter_set_enabled(true); // TODO -- Do this somewhere else maybe bleio __init__
const mp_float_t min = BLE_GAP_ADV_INTERVAL_MIN * ADV_INTERVAL_UNIT_FLOAT_SECS;
const mp_float_t max = BLE_GAP_ADV_INTERVAL_MAX * ADV_INTERVAL_UNIT_FLOAT_SECS;

if (interval < min || interval > max) {
// Would like to print range using the constants above, but vargs would convert to double.
mp_raise_ValueError(translate("interval not in range 0.0020 to 10.24"));
}
self->interval = interval;
}


void common_hal_bleio_broadcaster_start_advertising(bleio_broadcaster_obj_t *self, mp_buffer_info_t *data) {
uint32_t err_code;

if (data->len >= BLE_GAP_ADV_SET_DATA_SIZE_MAX) {
mp_raise_ValueError(translate("Data too large for advertisement packet"));
}
memcpy(self->adv_data, data->buf, data->len);

ble_gap_adv_params_t m_adv_params = {
.interval = (uint32_t) (self->interval / ADV_INTERVAL_UNIT_FLOAT_SECS),
.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED,
.duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED,
.filter_policy = BLE_GAP_ADV_FP_ANY,
.primary_phy = BLE_GAP_PHY_1MBPS,
};

common_hal_bleio_broadcaster_stop_advertising(self);

const ble_gap_adv_data_t ble_gap_adv_data = {
.adv_data.p_data = self->adv_data,
.adv_data.len = data->len,
};

err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &ble_gap_adv_data, &m_adv_params);
if (err_code == NRF_SUCCESS) {
err_code = sd_ble_gap_adv_start(m_adv_handle, BLE_CONN_CFG_TAG_CUSTOM);
}

if (err_code != NRF_SUCCESS) {
mp_raise_OSError_msg_varg(translate("Failed to start advertising, err 0x%04x"), err_code);
}
}

void common_hal_bleio_broadcaster_stop_advertising(bleio_broadcaster_obj_t *self) {

if (m_adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) {
return;
}

const uint32_t err_code = sd_ble_gap_adv_stop(m_adv_handle);

if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) {
mp_raise_OSError_msg_varg(translate("Failed to stop advertising, err 0x%04x"), err_code);
}
}
47 changes: 47 additions & 0 deletions ports/nrf/common-hal/bleio/Broadcaster.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Artur Pacholec
* Copyright (c) 2018 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H
#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H

#include "ble.h"

#include "shared-module/bleio/__init__.h"
#include "shared-module/bleio/Address.h"

typedef struct {
mp_obj_base_t base;
// In seconds.
mp_float_t interval;
// The advertising data buffer is held by us, not by the SD, so we must
// maintain it and not change it. If we need to change its contents during advertising,
// there are tricks to get the SD to notice (see DevZone - TBS).
uint8_t adv_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX];

} bleio_broadcaster_obj_t;

#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_BROADCASTER_H
222 changes: 159 additions & 63 deletions ports/nrf/common-hal/bleio/Characteristic.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,71 @@
#include "ble_drv.h"
#include "ble_gatts.h"
#include "nrf_soc.h"
#include "py/nlr.h"

#include "py/runtime.h"
#include "common-hal/bleio/__init__.h"
#include "common-hal/bleio/Characteristic.h"
#include "shared-module/bleio/Characteristic.h"

static volatile bleio_characteristic_obj_t *m_read_characteristic;
static volatile uint8_t m_tx_in_progress;
static nrf_mutex_t *m_write_mutex;
STATIC volatile bleio_characteristic_obj_t *m_read_characteristic;
STATIC volatile uint8_t m_tx_in_progress;
// Serialize gattc writes that send a response. This might be done per object?
STATIC nrf_mutex_t *m_write_mutex;

STATIC uint16_t get_cccd(bleio_characteristic_obj_t *characteristic) {
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
uint16_t cccd;
ble_gatts_value_t value = {
.p_value = (uint8_t*) &cccd,
.len = 2,
};

const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, characteristic->cccd_handle, &value);


if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) {
// CCCD is not set, so say that neither Notify nor Indicate is enabled.
cccd = 0;
} else if (err_code != NRF_SUCCESS) {
mp_raise_OSError_msg_varg(translate("Failed to read CCCD value, err 0x%04x"), err_code);
}

return cccd;
}

STATIC void gatts_read(bleio_characteristic_obj_t *characteristic) {
// This might be BLE_CONN_HANDLE_INVALID if we're not conected, but that's OK, because
// we can still read and write the local value.
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);

mp_buffer_info_t bufinfo;
ble_gatts_value_t gatts_value = {
.p_value = NULL,
.len = 0,
};

// Read once to find out what size buffer we need, then read again to fill buffer.

uint32_t err_code = sd_ble_gatts_value_get(conn_handle, characteristic->handle, &gatts_value);
if (err_code == NRF_SUCCESS) {
characteristic->value_data = mp_obj_new_bytearray_of_zeros(gatts_value.len);
mp_get_buffer_raise(characteristic->value_data, &bufinfo, MP_BUFFER_WRITE);
gatts_value.p_value = bufinfo.buf;

// Read again, with the correct size of buffer.
err_code = sd_ble_gatts_value_get(conn_handle, characteristic->handle, &gatts_value);
}

if (err_code != NRF_SUCCESS) {
mp_raise_OSError_msg_varg(translate("Failed to read gatts value, err 0x%04x"), err_code);
}
}


STATIC void gatts_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) {
bleio_device_obj_t *device = characteristic->service->device;
const uint16_t conn_handle = device->conn_handle;
// This might be BLE_CONN_HANDLE_INVALID if we're not conected, but that's OK, because
// we can still read and write the local value.
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);

ble_gatts_value_t gatts_value = {
.p_value = bufinfo->buf,
Expand All @@ -48,18 +103,17 @@ STATIC void gatts_write(bleio_characteristic_obj_t *characteristic, mp_buffer_in

const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, characteristic->handle, &gatts_value);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to write gatts value, status: 0x%08lX"), err_code));
mp_raise_OSError_msg_varg(translate("Failed to write gatts value, err 0x%04x"), err_code);
}
}

STATIC void gatts_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) {
bleio_device_obj_t *device = characteristic->service->device;
STATIC void gatts_notify_indicate(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo, uint16_t hvx_type) {
uint16_t hvx_len = bufinfo->len;

ble_gatts_hvx_params_t hvx_params = {
.handle = characteristic->handle,
.type = BLE_GATT_HVX_NOTIFICATION,
.type = hvx_type,
.offset = 0,
.p_len = &hvx_len,
.p_data = bufinfo->buf,
};
Expand All @@ -70,27 +124,27 @@ STATIC void gatts_notify(bleio_characteristic_obj_t *characteristic, mp_buffer_i
#endif
}

const uint32_t err_code = sd_ble_gatts_hvx(device->conn_handle, &hvx_params);
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
m_tx_in_progress++;
const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to notify attribute value, status: 0x%08lX"), err_code));
m_tx_in_progress--;
mp_raise_OSError_msg_varg(translate("Failed to notify or indicate attribute value, err %0x04x"), err_code);
}

m_tx_in_progress += 1;
}

STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) {
bleio_service_obj_t *service = characteristic->service;
bleio_device_obj_t *device = service->device;
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);

m_read_characteristic = characteristic;

const uint32_t err_code = sd_ble_gattc_read(device->conn_handle, characteristic->handle, 0);
const uint32_t err_code = sd_ble_gattc_read(conn_handle, characteristic->handle, 0);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to read attribute value, status: 0x%08lX"), err_code));
mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err %0x04x"), err_code);
}

//
while (m_read_characteristic != NULL) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
Expand All @@ -99,7 +153,7 @@ STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) {
}

STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) {
bleio_device_obj_t *device = characteristic->service->device;
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
uint32_t err_code;

ble_gattc_write_params_t write_params = {
Expand All @@ -110,20 +164,18 @@ STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_in
.len = bufinfo->len,
};

if (characteristic->props.write_wo_resp) {
if (characteristic->props.write_no_response) {
write_params.write_op = BLE_GATT_OP_WRITE_CMD;

err_code = sd_mutex_acquire(m_write_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to acquire mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg_varg(translate("Failed to acquire mutex, err 0x%04x"), err_code);
}
}

err_code = sd_ble_gattc_write(device->conn_handle, &write_params);
err_code = sd_ble_gattc_write(conn_handle, &write_params);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to write attribute value, status: 0x%08lX"), err_code));
mp_raise_OSError_msg_varg(translate("Failed to write attribute value, err 0x%04x"), err_code);
}

while (sd_mutex_acquire(m_write_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) {
Expand All @@ -134,58 +186,102 @@ STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_in

err_code = sd_mutex_release(m_write_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to release mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg_varg(translate("Failed to release mutex, err 0x%04x"), err_code);
}
}

STATIC void on_ble_evt(ble_evt_t *ble_evt, void *param) {
STATIC void characteristic_on_ble_evt(ble_evt_t *ble_evt, void *param) {
switch (ble_evt->header.evt_id) {
#if (BLE_API_VERSION == 4)
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
m_tx_in_progress -= ble_evt->evt.gatts_evt.params.hvn_tx_complete.count;
break;
#else
case BLE_EVT_TX_COMPLETE:
m_tx_in_progress -= ble_evt->evt.common_evt.params.tx_complete.count;
break;
#endif

case BLE_GATTC_EVT_READ_RSP:
{
ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp;
m_read_characteristic->value_data = mp_obj_new_bytearray(response->len, response->data);
m_read_characteristic = NULL;
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
{
uint8_t count = ble_evt->evt.gatts_evt.params.hvn_tx_complete.count;
// Don't underflow the count.
if (count >= m_tx_in_progress) {
m_tx_in_progress = 0;
} else {
m_tx_in_progress -= count;
}
break;
}

case BLE_GATTC_EVT_WRITE_RSP:
sd_mutex_release(m_write_mutex);
// m_write_done = true;
break;
case BLE_GATTC_EVT_READ_RSP:
{
ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp;
m_read_characteristic->value_data = mp_obj_new_bytearray(response->len, response->data);
// Flag to busy-wait loop that we've read the characteristic.
m_read_characteristic = NULL;
break;
}

case BLE_GATTC_EVT_WRITE_RSP:
// Someone else can write now.
sd_mutex_release(m_write_mutex);
break;

// For debugging.
default:
// mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id);
break;
}

}

void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self) {
ble_drv_add_event_handler(on_ble_evt, NULL);
void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props) {
self->service = NULL;
self->uuid = uuid;
self->value_data = NULL;
self->props = props;
self->handle = BLE_GATT_HANDLE_INVALID;

ble_drv_add_event_handler(characteristic_on_ble_evt, self);

}

void common_hal_bleio_characteristic_read_value(bleio_characteristic_obj_t *self) {
gattc_read(self);
void common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) {
switch (common_hal_bleio_device_get_gatt_role(self->service->device)) {
case GATT_ROLE_CLIENT:
gattc_read(self);
break;

case GATT_ROLE_SERVER:
gatts_read(self);
break;

default:
mp_raise_RuntimeError(translate("bad GATT role"));
break;
}
}

void common_hal_bleio_characteristic_write_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
const bleio_device_obj_t *device = self->service->device;
void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
bool sent = false;
uint16_t cccd = 0;

if (device->is_peripheral) {
// TODO: Add indications
if (self->props.notify) {
gatts_notify(self, bufinfo);
} else {
switch (common_hal_bleio_device_get_gatt_role(self->service->device)) {
case GATT_ROLE_SERVER:
if (self->props.notify || self->props.indicate) {
cccd = get_cccd(self);
}
// It's possible that both notify and indicate are set.
if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) {
gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION);
sent = true;
}
if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) {
gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION);
sent = true;
}
if (!sent) {
gatts_write(self, bufinfo);
}
} else {
break;

case GATT_ROLE_CLIENT:
gattc_write(self, bufinfo);
}
break;

default:
mp_raise_RuntimeError(translate("bad GATT role"));
break;
}
}
46 changes: 46 additions & 0 deletions ports/nrf/common-hal/bleio/Characteristic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Artur Pacholec
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTIC_H
#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTIC_H

#include "shared-module/bleio/Characteristic.h"
#include "shared-module/bleio/Service.h"
#include "common-hal/bleio/UUID.h"

typedef struct {
mp_obj_base_t base;
bleio_service_obj_t *service;
bleio_uuid_obj_t *uuid;
mp_obj_t value_data;
uint16_t handle;
bleio_characteristic_properties_t props;
uint16_t user_desc_handle;
uint16_t cccd_handle;
uint16_t sccd_handle;
} bleio_characteristic_obj_t;

#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTIC_H
135 changes: 135 additions & 0 deletions ports/nrf/common-hal/bleio/CharacteristicBuffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <string.h>
#include <stdio.h>

#include "ble_drv.h"
#include "ble_gatts.h"
#include "sd_mutex.h"

#include "lib/utils/interrupt_char.h"
#include "py/runtime.h"
#include "py/stream.h"

#include "tick.h"

#include "common-hal/bleio/__init__.h"
#include "common-hal/bleio/CharacteristicBuffer.h"

STATIC void characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) {
bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *) param;
switch (ble_evt->header.evt_id) {
case BLE_GATTS_EVT_WRITE: {
ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write;
// Event handle must match the handle for my characteristic.
if (evt_write->handle == self->characteristic->handle) {
// Push all the data onto the ring buffer, but wait for any reads to finish.
sd_mutex_acquire_wait_no_vm(&self->ringbuf_mutex);
for (size_t i = 0; i < evt_write->len; i++) {
ringbuf_put(&self->ringbuf, evt_write->data[i]);
}
// Don't check for errors: we're in an event handler.
sd_mutex_release(&self->ringbuf_mutex);
break;
}
}
}

}

// Assumes that timeout and buffer_size have been validated before call.
void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self,
bleio_characteristic_obj_t *characteristic,
mp_float_t timeout,
size_t buffer_size) {

self->characteristic = characteristic;
self->timeout_ms = timeout * 1000;
// This is a macro.
// true means long-lived, so it won't be moved.
ringbuf_alloc(&self->ringbuf, buffer_size, true);
sd_mutex_new(&self->ringbuf_mutex);

ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self);

}

int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) {
uint64_t start_ticks = ticks_ms;

// Wait for all bytes received or timeout
while ( (ringbuf_count(&self->ringbuf) < len) && (ticks_ms - start_ticks < self->timeout_ms) ) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP ;
// Allow user to break out of a timeout with a KeyboardInterrupt.
if ( mp_hal_is_interrupted() ) {
return 0;
}
#endif
}

// Copy received data. Lock out writes while copying.
sd_mutex_acquire_wait(&self->ringbuf_mutex);

size_t rx_bytes = MIN(ringbuf_count(&self->ringbuf), len);
for ( size_t i = 0; i < rx_bytes; i++ ) {
data[i] = ringbuf_get(&self->ringbuf);
}

// Writes now OK.
sd_mutex_release_check(&self->ringbuf_mutex);

return rx_bytes;
}

uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) {
return ringbuf_count(&self->ringbuf);
}

void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) {
// prevent conflict with uart irq
sd_mutex_acquire_wait(&self->ringbuf_mutex);
ringbuf_clear(&self->ringbuf);
sd_mutex_release_check(&self->ringbuf_mutex);
}

bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) {
return self->characteristic == NULL;
}

void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) {
if (!common_hal_bleio_characteristic_buffer_deinited(self)) {
ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self);
}
}

bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) {
return self->characteristic != NULL &&
self->characteristic->service != NULL &&
self->characteristic->service->device != NULL &&
common_hal_bleio_device_get_conn_handle(self->characteristic->service->device) != BLE_CONN_HANDLE_INVALID;
}
44 changes: 44 additions & 0 deletions ports/nrf/common-hal/bleio/CharacteristicBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Artur Pacholec
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H
#define MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H

#include "nrf_soc.h"

#include "py/ringbuf.h"
#include "shared-bindings/bleio/Characteristic.h"

typedef struct {
mp_obj_base_t base;
bleio_characteristic_obj_t *characteristic;
uint32_t timeout_ms;
// Ring buffer storing consecutive incoming values.
ringbuf_t ringbuf;
nrf_mutex_t ringbuf_mutex;
} bleio_characteristic_buffer_obj_t;

#endif // MICROPY_INCLUDED_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H
11 changes: 4 additions & 7 deletions ports/nrf/common-hal/bleio/Descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,17 @@
*/

#include "common-hal/bleio/Descriptor.h"
#include "shared-bindings/bleio/UUID.h"

void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid) {
// TODO: set handle ???
self->uuid = uuid;
}

void common_hal_bleio_descriptor_print(bleio_descriptor_obj_t *self, const mp_print_t *print) {
mp_printf(print, "Descriptor(uuid: 0x" HEX2_FMT HEX2_FMT ")",
self->uuid->value[1], self->uuid->value[0]);
}

mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self) {
return self->handle;
}

mp_int_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) {
return self->uuid->value[0] | (self->uuid->value[1] << 8);
mp_obj_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) {
return MP_OBJ_FROM_PTR(self->uuid);
}
94 changes: 34 additions & 60 deletions ports/nrf/common-hal/bleio/Device.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connecta
#define ADD_FIELD(field, len) \
do { \
if (byte_pos + (len) > BLE_GAP_ADV_MAX_SIZE) { \
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, \
translate("Can not fit data into the advertisment packet"))); \
mp_raise_ValueError(translate("Data too large for the advertisement packet")); \
} \
adv_data[byte_pos] = (field); \
byte_pos += (len); \
Expand Down Expand Up @@ -110,8 +109,7 @@ STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connecta
ADD_FIELD(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE, BLE_AD_TYPE_FLAGS_DATA_SIZE);
} else {
if (byte_pos + raw_data->len > BLE_GAP_ADV_MAX_SIZE) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Can not fit data into the advertisment packet")));
mp_raise_ValueError(translate("Data too large for the advertisement packet"));
}

memcpy(&adv_data[byte_pos], raw_data->buf, raw_data->len);
Expand All @@ -130,12 +128,13 @@ STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connecta
continue;
}

if (service->uuid->type == UUID_TYPE_16BIT) {
switch (common_hal_bleio_uuid_get_size(service->uuid)) {
case 16:
has_16bit_services = true;
}

if (service->uuid->type == UUID_TYPE_128BIT) {
break;
case 128:
has_128bit_services = true;
break;
}
}

Expand All @@ -152,13 +151,12 @@ STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connecta
const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]);
uint8_t encoded_size = 0;

if ((service->uuid->type != UUID_TYPE_16BIT) || service->is_secondary) {
if (common_hal_bleio_uuid_get_size(service->uuid) != 16 || service->is_secondary) {
continue;
}

ble_uuid_t uuid;
uuid.type = BLE_UUID_TYPE_BLE;
uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8);
bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid);

err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]);
if (err_code != NRF_SUCCESS) {
Expand All @@ -185,13 +183,12 @@ STATIC uint32_t set_advertisement_data(bleio_device_obj_t *device, bool connecta
const bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[i]);
uint8_t encoded_size = 0;

if ((service->uuid->type != UUID_TYPE_128BIT) || service->is_secondary) {
if (common_hal_bleio_uuid_get_size(service->uuid) != 16 || service->is_secondary) {
continue;
}

ble_uuid_t uuid;
uuid.type = service->uuid->uuid_vs_idx;
uuid.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8);
bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid);

err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]);
if (err_code != NRF_SUCCESS) {
Expand Down Expand Up @@ -262,16 +259,16 @@ STATIC bool discover_services(bleio_device_obj_t *device, uint16_t start_handle)

uint32_t err_code = sd_ble_gattc_primary_services_discover(device->conn_handle, start_handle, NULL);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to discover serivices, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to discover services"));
}

// Serialize discovery.
err_code = sd_mutex_acquire(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to acquire mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to acquire mutex"));
}

// Wait for someone else to release m_discovery_mutex.
while (sd_mutex_acquire(m_discovery_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) {
#ifdef MICROPY_VM_HOOK_LOOP
MICROPY_VM_HOOK_LOOP
Expand All @@ -280,8 +277,7 @@ STATIC bool discover_services(bleio_device_obj_t *device, uint16_t start_handle)

err_code = sd_mutex_release(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to release mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to release mutex"));
}

return m_discovery_successful;
Expand All @@ -303,8 +299,7 @@ STATIC bool discover_characteristics(bleio_device_obj_t *device, bleio_service_o

err_code = sd_mutex_acquire(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to acquire mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to acquire mutex"));
}

while (sd_mutex_acquire(m_discovery_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) {
Expand All @@ -315,16 +310,15 @@ STATIC bool discover_characteristics(bleio_device_obj_t *device, bleio_service_o

err_code = sd_mutex_release(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to release mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to release mutex"));
}

return m_discovery_successful;
}

STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_device_obj_t *device) {
for (size_t i = 0; i < response->count; ++i) {
const ble_gattc_service_t *gattc_service = &response->services[i];
ble_gattc_service_t *gattc_service = &response->services[i];

bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
service->base.type = &bleio_service_type;
Expand All @@ -335,10 +329,7 @@ STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *res
service->handle = gattc_service->handle_range.start_handle;

bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
uuid->base.type = &bleio_uuid_type;
uuid->type = (gattc_service->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT;
uuid->value[0] = gattc_service->uuid.uuid & 0xFF;
uuid->value[1] = gattc_service->uuid.uuid >> 8;
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid);
service->uuid = uuid;

mp_obj_list_append(device->service_list, service);
Expand All @@ -350,31 +341,28 @@ STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *res

const uint32_t err_code = sd_mutex_release(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to release mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to release mutex"));
}
}

STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_device_obj_t *device) {
for (size_t i = 0; i < response->count; ++i) {
const ble_gattc_char_t *gattc_char = &response->chars[i];
ble_gattc_char_t *gattc_char = &response->chars[i];

bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
characteristic->base.type = &bleio_characteristic_type;

bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
uuid->base.type = &bleio_uuid_type;
uuid->type = (gattc_char->uuid.type == BLE_UUID_TYPE_BLE) ? UUID_TYPE_16BIT : UUID_TYPE_128BIT;
uuid->value[0] = gattc_char->uuid.uuid & 0xFF;
uuid->value[1] = gattc_char->uuid.uuid >> 8;
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid);
characteristic->uuid = uuid;

characteristic->props.broadcast = gattc_char->char_props.broadcast;
characteristic->props.indicate = gattc_char->char_props.indicate;
characteristic->props.notify = gattc_char->char_props.notify;
characteristic->props.read = gattc_char->char_props.read;
characteristic->props.write = gattc_char->char_props.write;
characteristic->props.write_wo_resp = gattc_char->char_props.write_wo_resp;
characteristic->props.write_no_response = gattc_char->char_props.write_wo_resp;
characteristic->handle = gattc_char->handle_value;
characteristic->service = m_char_discovery_service;

Expand All @@ -387,8 +375,7 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio

const uint32_t err_code = sd_mutex_release(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to release mutex, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to release mutex"));
}
}

Expand All @@ -399,8 +386,7 @@ STATIC void on_adv_report(ble_gap_evt_adv_report_t *report, bleio_device_obj_t *
#if (BLUETOOTH_SD == 140)
err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to continue scanning, status: 0x%0xlX"), err_code));
mp_raise_OSError_msg(translate("Failed to continue scanning"));
}
#endif
return;
Expand Down Expand Up @@ -432,8 +418,7 @@ STATIC void on_adv_report(ble_gap_evt_adv_report_t *report, bleio_device_obj_t *
#endif

if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to connect, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to connect:"));
}
}

Expand Down Expand Up @@ -491,14 +476,8 @@ STATIC void on_ble_evt(ble_evt_t *ble_evt, void *device_in) {
}

void common_hal_bleio_device_add_service(bleio_device_obj_t *device, bleio_service_obj_t *service) {
ble_uuid_t uuid = {
.type = BLE_UUID_TYPE_BLE,
.uuid = service->uuid->value[0] | (service->uuid->value[1] << 8)
};

if (service->uuid->type == UUID_TYPE_128BIT) {
uuid.type = service->uuid->uuid_vs_idx;
}
ble_uuid_t uuid;
bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid);

uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY;
if (service->is_secondary) {
Expand All @@ -509,8 +488,7 @@ void common_hal_bleio_device_add_service(bleio_device_obj_t *device, bleio_servi

const uint32_t err_code = sd_ble_gatts_service_add(service_type, &uuid, &service->handle);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to add service, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to add service"));
}

const mp_obj_list_t *char_list = MP_OBJ_TO_PTR(service->char_list);
Expand All @@ -527,8 +505,7 @@ void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bool

const uint32_t err_code = set_advertisement_data(device, connectable, raw_data);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to start advertisment, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to start advertising"));
}
}

Expand All @@ -545,8 +522,7 @@ void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device) {
#endif

if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to stop advertisment, status: 0x%08lX"), err_code));
mp_raise_OSError_msg(translate("Failed to stop advertising"));
}
}

Expand All @@ -571,8 +547,7 @@ void common_hal_bleio_device_connect(bleio_device_obj_t *device) {
#endif

if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to start scanning, status: 0x%0xlX"), err_code));
mp_raise_OSError_msg(translate("Failed to start scanning"));
}

while (device->conn_handle == BLE_CONN_HANDLE_INVALID) {
Expand All @@ -588,8 +563,7 @@ void common_hal_bleio_device_connect(bleio_device_obj_t *device) {

err_code = sd_mutex_new(m_discovery_mutex);
if (err_code != NRF_SUCCESS) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
translate("Failed to create mutex, status: 0x%0xlX"), err_code));
mp_raise_OSError_msg(translate("Failed to create mutex"));
}
}

Expand Down
Loading