Remove legacy nrf-sdk code/b-parasite
This commit is contained in:
parent
192cca127c
commit
3bf90451db
20 changed files with 0 additions and 13757 deletions
1
code/b-parasite/.gitignore
vendored
1
code/b-parasite/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
_build
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
# Supported platforms:
|
||||
# * E73_2G4M08S1C (nRF52840, default)
|
||||
# * E73_2G4M08S1E (nRF52833)
|
||||
# note: the missing whitespace after the = is on purpose here
|
||||
PLATFORM ?=E73_2G4M08S1C
|
||||
|
||||
ifeq ($(PLATFORM),E73_2G4M08S1E)
|
||||
SRC_FILES := \
|
||||
$(SDK_ROOT)/modules/nrfx/mdk/gcc_startup_nrf52833.S \
|
||||
$(SDK_ROOT)/modules/nrfx/mdk/system_nrf52833.c
|
||||
TARGETS := nrf52833_xxaa
|
||||
CFLAGS += -DNRF52833_XXAA
|
||||
ASMFLAGS += -DNRF52833_XXAA
|
||||
LINKER_SCRIPT := b_parasite_gcc_nrf52833.ld
|
||||
HEAP_SIZE := 2048
|
||||
STACK_SIZE := 2048
|
||||
else ifeq ($(PLATFORM),E73_2G4M08S1C)
|
||||
SRC_FILES := \
|
||||
$(SDK_ROOT)/modules/nrfx/mdk/gcc_startup_nrf52840.S \
|
||||
$(SDK_ROOT)/modules/nrfx/mdk/system_nrf52840.c
|
||||
TARGETS := nrf52840_xxaa
|
||||
CFLAGS += -DNRF52840_XXAA
|
||||
ASMFLAGS += -DNRF52840_XXAA
|
||||
LINKER_SCRIPT := b_parasite_gcc_nrf52840.ld
|
||||
HEAP_SIZE := 8192
|
||||
STACK_SIZE := 8192
|
||||
endif
|
||||
|
||||
|
||||
PROJECT_NAME := ble_app_beacon_pca10056_s140
|
||||
OUTPUT_DIRECTORY := _build
|
||||
|
||||
# Set SDK_ROOT via env vars.
|
||||
# SDK_ROOT := ../../../.././..
|
||||
PROJ_DIR := ./src
|
||||
|
||||
# Source files common to all targets
|
||||
SRC_FILES += \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_backend_rtt.c \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_backend_serial.c \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_backend_uart.c \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_default_backends.c \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_frontend.c \
|
||||
$(SDK_ROOT)/components/libraries/log/src/nrf_log_str_formatter.c \
|
||||
$(SDK_ROOT)/components/libraries/button/app_button.c \
|
||||
$(SDK_ROOT)/components/libraries/util/app_error.c \
|
||||
$(SDK_ROOT)/components/libraries/util/app_error_handler_gcc.c \
|
||||
$(SDK_ROOT)/components/libraries/util/app_error_weak.c \
|
||||
$(SDK_ROOT)/components/libraries/scheduler/app_scheduler.c \
|
||||
$(SDK_ROOT)/components/libraries/timer/app_timer2.c \
|
||||
$(SDK_ROOT)/components/libraries/util/app_util_platform.c \
|
||||
$(SDK_ROOT)/components/libraries/timer/drv_rtc.c \
|
||||
$(SDK_ROOT)/components/libraries/hardfault/hardfault_implementation.c \
|
||||
$(SDK_ROOT)/components/libraries/util/nrf_assert.c \
|
||||
$(SDK_ROOT)/components/libraries/atomic_fifo/nrf_atfifo.c \
|
||||
$(SDK_ROOT)/components/libraries/atomic/nrf_atomic.c \
|
||||
$(SDK_ROOT)/components/libraries/balloc/nrf_balloc.c \
|
||||
$(SDK_ROOT)/external/fprintf/nrf_fprintf.c \
|
||||
$(SDK_ROOT)/external/fprintf/nrf_fprintf_format.c \
|
||||
$(SDK_ROOT)/components/libraries/memobj/nrf_memobj.c \
|
||||
$(SDK_ROOT)/components/libraries/pwr_mgmt/nrf_pwr_mgmt.c \
|
||||
$(SDK_ROOT)/components/libraries/ringbuf/nrf_ringbuf.c \
|
||||
$(SDK_ROOT)/components/libraries/experimental_section_vars/nrf_section_iter.c \
|
||||
$(SDK_ROOT)/components/libraries/sortlist/nrf_sortlist.c \
|
||||
$(SDK_ROOT)/components/libraries/strerror/nrf_strerror.c \
|
||||
$(SDK_ROOT)/integration/nrfx/legacy/nrf_drv_clock.c \
|
||||
$(SDK_ROOT)/integration/nrfx/legacy/nrf_drv_twi.c \
|
||||
$(SDK_ROOT)/modules/nrfx/soc/nrfx_atomic.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_clock.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_gpiote.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_rtc.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_saadc.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_twi.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/prs/nrfx_prs.c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_pwm.c \
|
||||
$(PROJ_DIR)/main.c \
|
||||
$(SDK_ROOT)/external/segger_rtt/SEGGER_RTT.c \
|
||||
$(SDK_ROOT)/external/segger_rtt/SEGGER_RTT_Syscalls_GCC.c \
|
||||
$(SDK_ROOT)/external/segger_rtt/SEGGER_RTT_printf.c \
|
||||
$(SDK_ROOT)/components/ble/common/ble_advdata.c \
|
||||
$(SDK_ROOT)/components/ble/common/ble_srv_common.c \
|
||||
$(SDK_ROOT)/external/utf_converter/utf.c \
|
||||
$(SDK_ROOT)/components/softdevice/common/nrf_sdh.c \
|
||||
$(SDK_ROOT)/components/softdevice/common/nrf_sdh_ble.c \
|
||||
$(SDK_ROOT)/components/softdevice/common/nrf_sdh_soc.c \
|
||||
$(PROJ_DIR)/prst/adc.c \
|
||||
$(PROJ_DIR)/prst/ble.c \
|
||||
$(PROJ_DIR)/prst/pwm.c \
|
||||
$(PROJ_DIR)/prst/rtc.c \
|
||||
$(PROJ_DIR)/prst/shtc3.c \
|
||||
|
||||
# Include folders common to all targets
|
||||
INC_FOLDERS += \
|
||||
$(SDK_ROOT)/components/nfc/ndef/generic/message \
|
||||
$(SDK_ROOT)/components/nfc/t2t_lib \
|
||||
$(SDK_ROOT)/components/nfc/t4t_parser/hl_detection_procedure \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_ancs_c \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_ias_c \
|
||||
$(SDK_ROOT)/components/libraries/pwm \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/cdc/acm \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/hid/generic \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/msc \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/hid \
|
||||
$(SDK_ROOT)/modules/nrfx/hal \
|
||||
$(SDK_ROOT)/components/nfc/ndef/conn_hand_parser/le_oob_rec_parser \
|
||||
$(SDK_ROOT)/components/libraries/log \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_gls \
|
||||
$(SDK_ROOT)/components/libraries/fstorage \
|
||||
$(SDK_ROOT)/components/nfc/ndef/text \
|
||||
$(SDK_ROOT)/components/libraries/mutex \
|
||||
$(SDK_ROOT)/components/libraries/gpiote \
|
||||
$(SDK_ROOT)/components/libraries/bootloader/ble_dfu \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/common \
|
||||
$(SDK_ROOT)/components/nfc/ndef/generic/record \
|
||||
$(SDK_ROOT)/components/ble/ble_advertising \
|
||||
$(SDK_ROOT)/external/utf_converter \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_bas_c \
|
||||
$(SDK_ROOT)/modules/nrfx/drivers/include \
|
||||
$(SDK_ROOT)/components/libraries/experimental_task_manager \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_hrs_c \
|
||||
$(SDK_ROOT)/components/softdevice/s140/headers/nrf52 \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/le_oob_rec \
|
||||
$(SDK_ROOT)/components/libraries/queue \
|
||||
$(SDK_ROOT)/components/libraries/pwr_mgmt \
|
||||
$(SDK_ROOT)/components/ble/ble_dtm \
|
||||
$(SDK_ROOT)/components/toolchain/cmsis/include \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_rscs_c \
|
||||
$(SDK_ROOT)/components/ble/common \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_lls \
|
||||
$(SDK_ROOT)/components/nfc/platform \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/ac_rec \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_bas \
|
||||
$(SDK_ROOT)/components/libraries/mpu \
|
||||
$(SDK_ROOT)/components/libraries/experimental_section_vars \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_ans_c \
|
||||
$(SDK_ROOT)/components/libraries/slip \
|
||||
$(SDK_ROOT)/components/libraries/delay \
|
||||
$(SDK_ROOT)/components/libraries/csense_drv \
|
||||
$(SDK_ROOT)/components/libraries/memobj \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_nus_c \
|
||||
$(SDK_ROOT)/components/softdevice/common \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_ias \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/hid/mouse \
|
||||
$(SDK_ROOT)/components/libraries/low_power_pwm \
|
||||
$(SDK_ROOT)/components/nfc/ndef/conn_hand_parser/ble_oob_advdata_parser \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_dfu \
|
||||
$(SDK_ROOT)/external/fprintf \
|
||||
$(SDK_ROOT)/components/libraries/svc \
|
||||
$(SDK_ROOT)/components/libraries/atomic \
|
||||
$(SDK_ROOT)/components \
|
||||
$(SDK_ROOT)/components/libraries/scheduler \
|
||||
$(SDK_ROOT)/components/libraries/cli \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_lbs \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_hts \
|
||||
$(SDK_ROOT)/components/libraries/crc16 \
|
||||
$(SDK_ROOT)/components/nfc/t4t_parser/apdu \
|
||||
$(SDK_ROOT)/components/libraries/util \
|
||||
./config \
|
||||
$(PROJ_DIR) \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/cdc \
|
||||
$(SDK_ROOT)/components/libraries/csense \
|
||||
$(SDK_ROOT)/components/libraries/balloc \
|
||||
$(SDK_ROOT)/components/libraries/ecc \
|
||||
$(SDK_ROOT)/components/libraries/hardfault \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_cscs \
|
||||
$(SDK_ROOT)/components/libraries/hci \
|
||||
$(SDK_ROOT)/components/libraries/timer \
|
||||
$(SDK_ROOT)/components/softdevice/s140/headers \
|
||||
$(SDK_ROOT)/integration/nrfx \
|
||||
$(SDK_ROOT)/components/nfc/t4t_parser/tlv \
|
||||
$(SDK_ROOT)/components/libraries/sortlist \
|
||||
$(SDK_ROOT)/components/libraries/spi_mngr \
|
||||
$(SDK_ROOT)/components/libraries/led_softblink \
|
||||
$(SDK_ROOT)/components/nfc/ndef/conn_hand_parser \
|
||||
$(SDK_ROOT)/components/libraries/sdcard \
|
||||
$(SDK_ROOT)/components/nfc/ndef/parser/record \
|
||||
$(SDK_ROOT)/modules/nrfx/mdk \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_cts_c \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_nus \
|
||||
$(SDK_ROOT)/components/libraries/twi_mngr \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_hids \
|
||||
$(SDK_ROOT)/components/libraries/strerror \
|
||||
$(SDK_ROOT)/components/libraries/crc32 \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/ble_oob_advdata \
|
||||
$(SDK_ROOT)/components/nfc/t2t_parser \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/ble_pair_msg \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/audio \
|
||||
$(SDK_ROOT)/components/nfc/t4t_lib \
|
||||
$(SDK_ROOT)/components/ble/peer_manager \
|
||||
$(SDK_ROOT)/components/libraries/mem_manager \
|
||||
$(SDK_ROOT)/components/libraries/ringbuf \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_tps \
|
||||
$(SDK_ROOT)/components/nfc/ndef/parser/message \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_dis \
|
||||
$(SDK_ROOT)/components/nfc/ndef/uri \
|
||||
$(SDK_ROOT)/components/nfc/t4t_parser/cc_file \
|
||||
$(SDK_ROOT)/components/ble/nrf_ble_qwr \
|
||||
$(SDK_ROOT)/components/libraries/gfx \
|
||||
$(SDK_ROOT)/components/libraries/button \
|
||||
$(SDK_ROOT)/modules/nrfx \
|
||||
$(SDK_ROOT)/components/libraries/twi_sensor \
|
||||
$(SDK_ROOT)/integration/nrfx/legacy \
|
||||
$(SDK_ROOT)/components/libraries/usbd/class/hid/kbd \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/ep_oob_rec \
|
||||
$(SDK_ROOT)/external/segger_rtt \
|
||||
$(SDK_ROOT)/components/libraries/atomic_fifo \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_lbs_c \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/ble_pair_lib \
|
||||
$(SDK_ROOT)/components/libraries/crypto \
|
||||
$(SDK_ROOT)/components/ble/ble_racp \
|
||||
$(SDK_ROOT)/components/libraries/fds \
|
||||
$(SDK_ROOT)/components/nfc/ndef/launchapp \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_hrs \
|
||||
$(SDK_ROOT)/components/ble/ble_services/ble_rscs \
|
||||
$(SDK_ROOT)/components/nfc/ndef/connection_handover/hs_rec \
|
||||
$(SDK_ROOT)/components/libraries/usbd \
|
||||
$(SDK_ROOT)/components/nfc/ndef/conn_hand_parser/ac_rec_parser \
|
||||
$(SDK_ROOT)/components/libraries/stack_guard \
|
||||
$(SDK_ROOT)/components/libraries/log/src \
|
||||
|
||||
# Libraries common to all targets
|
||||
LIB_FILES += \
|
||||
|
||||
# Optimization flags
|
||||
OPT = -O3 -g3
|
||||
# Uncomment the line below to enable link time optimization
|
||||
#OPT += -flto
|
||||
|
||||
# C flags common to all targets
|
||||
CFLAGS += $(OPT)
|
||||
CFLAGS += -DAPP_TIMER_V2
|
||||
CFLAGS += -DAPP_TIMER_V2_RTC1_ENABLED
|
||||
CFLAGS += -DCONFIG_GPIO_AS_PINRESET
|
||||
CFLAGS += -DFLOAT_ABI_HARD
|
||||
CFLAGS += -DNRF_SD_BLE_API_VERSION=7
|
||||
CFLAGS += -DS140
|
||||
CFLAGS += -DSOFTDEVICE_PRESENT
|
||||
CFLAGS += -DDEBUG
|
||||
# Setting -DDEBUG prints info via JLkinkRTTLogger, but hides the stack trace
|
||||
# when debugging with VSCode's Cortex Debug extension.
|
||||
# CFLAGS += -DDEBUG
|
||||
CFLAGS += -mcpu=cortex-m4
|
||||
CFLAGS += -mthumb -mabi=aapcs
|
||||
CFLAGS += -Wall -Werror -Wno-maybe-uninitialized
|
||||
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
||||
# keep every function in a separate section, this allows linker to discard unused ones
|
||||
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
|
||||
CFLAGS += -fno-builtin -fshort-enums
|
||||
|
||||
# C++ flags common to all targets
|
||||
CXXFLAGS += $(OPT)
|
||||
# Assembler flags common to all targets
|
||||
ASMFLAGS += -g3
|
||||
ASMFLAGS += -mcpu=cortex-m4
|
||||
ASMFLAGS += -mthumb -mabi=aapcs
|
||||
ASMFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
||||
ASMFLAGS += -DAPP_TIMER_V2
|
||||
ASMFLAGS += -DAPP_TIMER_V2_RTC1_ENABLED
|
||||
ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
|
||||
ASMFLAGS += -DFLOAT_ABI_HARD
|
||||
ASMFLAGS += -DNRF_SD_BLE_API_VERSION=7
|
||||
ASMFLAGS += -DS140
|
||||
ASMFLAGS += -DSOFTDEVICE_PRESENT
|
||||
|
||||
# Linker flags
|
||||
LDFLAGS += $(OPT)
|
||||
LDFLAGS += -mthumb -mabi=aapcs -L$(SDK_ROOT)/modules/nrfx/mdk -T$(LINKER_SCRIPT)
|
||||
LDFLAGS += -mcpu=cortex-m4
|
||||
LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
||||
# let linker dump unused sections
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
# use newlib in nano version
|
||||
LDFLAGS += --specs=nano.specs
|
||||
|
||||
$(TARGETS): CFLAGS += -D__HEAP_SIZE=$(HEAP_SIZE)
|
||||
$(TARGETS): CFLAGS += -D__STACK_SIZE=$(STACK_SIZE)
|
||||
$(TARGETS): ASMFLAGS += -D__HEAP_SIZE=$(HEAP_SIZE)
|
||||
$(TARGETS): ASMFLAGS += -D__STACK_SIZE=$(STACK_SIZE)
|
||||
|
||||
# Add standard libraries at the very end of the linker input, after all objects
|
||||
# that may need symbols provided by these libraries.
|
||||
LIB_FILES += -lc -lnosys -lm
|
||||
|
||||
|
||||
.PHONY: default help
|
||||
|
||||
# Default target - first one defined
|
||||
default: $(TARGETS)
|
||||
|
||||
# Print all targets that can be built
|
||||
help:
|
||||
@echo following targets are available:
|
||||
@echo $(TARGETS)
|
||||
@echo flash_softdevice
|
||||
@echo sdk_config - starting external tool for editing sdk_config.h
|
||||
@echo flash - flashing binary
|
||||
|
||||
TEMPLATE_PATH := $(SDK_ROOT)/components/toolchain/gcc
|
||||
|
||||
|
||||
include $(TEMPLATE_PATH)/Makefile.common
|
||||
|
||||
$(foreach target, $(TARGETS), $(call define_target, $(target)))
|
||||
|
||||
.PHONY: flash flash_softdevice erase
|
||||
|
||||
# Flash the program
|
||||
flash: default
|
||||
@echo Flashing: $(OUTPUT_DIRECTORY)/$(TARGETS).hex
|
||||
nrfjprog -f nrf52 --program $(OUTPUT_DIRECTORY)/$(TARGETS).hex --sectorerase
|
||||
nrfjprog -f nrf52 --reset
|
||||
|
||||
# Flash softdevice
|
||||
flash_softdevice:
|
||||
@echo Flashing: s140_nrf52_7.2.0_softdevice.hex
|
||||
nrfjprog -f nrf52 --program $(SDK_ROOT)/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --sectorerase
|
||||
nrfjprog -f nrf52 --reset
|
||||
|
||||
erase:
|
||||
nrfjprog -f nrf52 --eraseall
|
||||
|
||||
SDK_CONFIG_FILE := ../config/sdk_config.h
|
||||
CMSIS_CONFIG_TOOL := $(SDK_ROOT)/external_tools/cmsisconfig/CMSIS_Configuration_Wizard.jar
|
||||
sdk_config:
|
||||
java -jar $(CMSIS_CONFIG_TOOL) $(SDK_CONFIG_FILE)
|
||||
|
||||
.PHONY: flash_loop
|
||||
flash_loop:
|
||||
while [ 1 ]; do make flash && break; done
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
find src -iname *.h -o -iname *.c | xargs clang-format -n -Werror
|
||||
|
||||
.PHONY: fix
|
||||
lint-fix:
|
||||
find src -iname *.h -o -iname *.c | xargs clang-format -i
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
# Overview
|
||||
|
||||
This is the b-parasite firmware based on Nordic's [nRF5 SDK](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fstruct_sdk%2Fstruct%2Fsdk_nrf5_latest.html&cp=7_1).
|
||||
|
||||
It uses Nordic's SoftDevice, which should additionally be flashed to the chip before running our firmware.
|
||||
|
||||
I use a [JLink probe](https://www.segger.com/products/debug-probes/j-link/) for flashing and debugging.
|
||||
|
||||
# Configuration
|
||||
The b-parasite specific configuration, such as active/sleep time and transmitting power are defined in [config/prst_config.h](./config/prst_config.h).
|
||||
|
||||
# Flashing SoftDevice and Firmware
|
||||
```bash
|
||||
# Flash softdevice
|
||||
$ SDK_ROOT=~/dev/nrf52/sdk/nRF5_SDK_17.0.2_d674dde make flash_softdevice
|
||||
# Compile and flash our firmware
|
||||
$ SDK_ROOT=~/dev/nrf52/sdk/nRF5_SDK_17.0.2_d674dde make flash
|
||||
```
|
||||
|
||||
# Debugging
|
||||
Calls to `NRF_LOG` will be readable on the console using `JLinkRTTLogger`. This is the handy one-liner I use for pulling log messages:
|
||||
|
||||
```bash
|
||||
$ echo "\n\n\n\n0\n/dev/stdout" | JLinkRTTLogger | sed 's/^.*app: //'
|
||||
```
|
||||
|
||||
# Bluetooth Low Energy Advertisement Data Encoding
|
||||
Sensor data is encoded in the BLE advertisement packet as Service Data for the [Environmental Sensing Service profile](https://www.bluetooth.com/specifications/assigned-numbers/environmental-sensing-service-characteristics/) (UUID 0x181a).
|
||||
|
||||
Sensor data is encoded in unsigned 16 bits (2 bytes), and whenever multiple
|
||||
bytes are used to represent a single value, the encoding is big-endian.
|
||||
|
||||
| Byte index | Description |
|
||||
|------------|-------------------------------------------------------------------|
|
||||
| 0 | Protocol version (4 bits) + reserved (3 bits) + `has_lux`* (1 bit)|
|
||||
| 1 | Reserved (4 bits) + increasing, wrap-around counter (4 bits) |
|
||||
| 2-3 | Battery voltage in millivolts |
|
||||
| 4-5 | Temp in 1000 * Celsius (protocol v1) or 100 * Celsius (v2) |
|
||||
| 6-7 | Relative air humidity, scaled from 0 (0%) to 0xffff (100%) |
|
||||
| 8-9 | Soil moisture, scaled from from 0 (0%) to 0xffff (100%) |
|
||||
| 10-15 | b-parasite's own MAC address |
|
||||
| 16-17* | Ambient light in lux |
|
||||
|
||||
\* If the `has_lux` bit is set, bytes 16-17 shall contain the ambient light in lux.
|
||||
If the `has_lux` bit is not set, bytes 16-17 may not exist or may contain
|
||||
meaningless data. The reasons for this behavior are:
|
||||
1. b-parasite version 1.0.x has no light sensor and its advertisement data may
|
||||
have only 16 bytes if its using an older firmware. In this case, `has_lux` shall
|
||||
never be set;
|
||||
2. b-parasite version 1.1.x has space for an optional LDR. Users can configure
|
||||
whether or not they have added the LDR by setting the `PRST_HAS_LDR` to 1 in
|
||||
prst_config.h.
|
||||
|
||||
# Supported Modules
|
||||
|
||||
This code supports two E73 modules:
|
||||
* E73-2G4M08S1C (nRF52840, default)
|
||||
* E73-2G4M08S1E (nRF52833)
|
||||
|
||||
To choose for which one you want to compile, just pass PLATFORM as an env variable to make, and set it to the platform you want to use. For example, to compile for E73-2G4M08S1E:
|
||||
|
||||
|
||||
```bash
|
||||
SDK_ROOT=<...> PLATFORM=E73_2G4M08S1E make
|
||||
```
|
||||
|
||||
and vice-versa for E73-2G4M08S1C, although that platform will be chosen as default anyways:
|
||||
|
||||
|
||||
```bash
|
||||
SDK_ROOT=<...> PLATFORM=E73_2G4M08S1C make
|
||||
```
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
/* Linker script to configure memory regions. */
|
||||
|
||||
SEARCH_DIR(.)
|
||||
GROUP(-lgcc -lc -lnosys)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0x59000
|
||||
RAM (rwx) : ORIGIN = 0x20002300, LENGTH = 0x1dd00
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = ALIGN(4);
|
||||
.mem_section_dummy_ram :
|
||||
{
|
||||
}
|
||||
.cli_sorted_cmd_ptrs :
|
||||
{
|
||||
PROVIDE(__start_cli_sorted_cmd_ptrs = .);
|
||||
KEEP(*(.cli_sorted_cmd_ptrs))
|
||||
PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
|
||||
} > RAM
|
||||
.fs_data :
|
||||
{
|
||||
PROVIDE(__start_fs_data = .);
|
||||
KEEP(*(.fs_data))
|
||||
PROVIDE(__stop_fs_data = .);
|
||||
} > RAM
|
||||
.log_dynamic_data :
|
||||
{
|
||||
PROVIDE(__start_log_dynamic_data = .);
|
||||
KEEP(*(SORT(.log_dynamic_data*)))
|
||||
PROVIDE(__stop_log_dynamic_data = .);
|
||||
} > RAM
|
||||
.log_filter_data :
|
||||
{
|
||||
PROVIDE(__start_log_filter_data = .);
|
||||
KEEP(*(SORT(.log_filter_data*)))
|
||||
PROVIDE(__stop_log_filter_data = .);
|
||||
} > RAM
|
||||
|
||||
} INSERT AFTER .data;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.mem_section_dummy_rom :
|
||||
{
|
||||
}
|
||||
.sdh_ble_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_ble_observers = .);
|
||||
KEEP(*(SORT(.sdh_ble_observers*)))
|
||||
PROVIDE(__stop_sdh_ble_observers = .);
|
||||
} > FLASH
|
||||
.sdh_soc_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_soc_observers = .);
|
||||
KEEP(*(SORT(.sdh_soc_observers*)))
|
||||
PROVIDE(__stop_sdh_soc_observers = .);
|
||||
} > FLASH
|
||||
.sdh_req_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_req_observers = .);
|
||||
KEEP(*(SORT(.sdh_req_observers*)))
|
||||
PROVIDE(__stop_sdh_req_observers = .);
|
||||
} > FLASH
|
||||
.sdh_state_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_state_observers = .);
|
||||
KEEP(*(SORT(.sdh_state_observers*)))
|
||||
PROVIDE(__stop_sdh_state_observers = .);
|
||||
} > FLASH
|
||||
.sdh_stack_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_stack_observers = .);
|
||||
KEEP(*(SORT(.sdh_stack_observers*)))
|
||||
PROVIDE(__stop_sdh_stack_observers = .);
|
||||
} > FLASH
|
||||
.nrf_queue :
|
||||
{
|
||||
PROVIDE(__start_nrf_queue = .);
|
||||
KEEP(*(.nrf_queue))
|
||||
PROVIDE(__stop_nrf_queue = .);
|
||||
} > FLASH
|
||||
.nrf_balloc :
|
||||
{
|
||||
PROVIDE(__start_nrf_balloc = .);
|
||||
KEEP(*(.nrf_balloc))
|
||||
PROVIDE(__stop_nrf_balloc = .);
|
||||
} > FLASH
|
||||
.cli_command :
|
||||
{
|
||||
PROVIDE(__start_cli_command = .);
|
||||
KEEP(*(.cli_command))
|
||||
PROVIDE(__stop_cli_command = .);
|
||||
} > FLASH
|
||||
.crypto_data :
|
||||
{
|
||||
PROVIDE(__start_crypto_data = .);
|
||||
KEEP(*(SORT(.crypto_data*)))
|
||||
PROVIDE(__stop_crypto_data = .);
|
||||
} > FLASH
|
||||
.pwr_mgmt_data :
|
||||
{
|
||||
PROVIDE(__start_pwr_mgmt_data = .);
|
||||
KEEP(*(SORT(.pwr_mgmt_data*)))
|
||||
PROVIDE(__stop_pwr_mgmt_data = .);
|
||||
} > FLASH
|
||||
.log_const_data :
|
||||
{
|
||||
PROVIDE(__start_log_const_data = .);
|
||||
KEEP(*(SORT(.log_const_data*)))
|
||||
PROVIDE(__stop_log_const_data = .);
|
||||
} > FLASH
|
||||
.log_backends :
|
||||
{
|
||||
PROVIDE(__start_log_backends = .);
|
||||
KEEP(*(SORT(.log_backends*)))
|
||||
PROVIDE(__stop_log_backends = .);
|
||||
} > FLASH
|
||||
|
||||
} INSERT AFTER .text
|
||||
|
||||
|
||||
INCLUDE "nrf_common.ld"
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
/* Linker script to configure memory regions. */
|
||||
|
||||
SEARCH_DIR(.)
|
||||
GROUP(-lgcc -lc -lnosys)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xd9000
|
||||
RAM (rwx) : ORIGIN = 0x20002300, LENGTH = 0x3dd00
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = ALIGN(4);
|
||||
.mem_section_dummy_ram :
|
||||
{
|
||||
}
|
||||
.cli_sorted_cmd_ptrs :
|
||||
{
|
||||
PROVIDE(__start_cli_sorted_cmd_ptrs = .);
|
||||
KEEP(*(.cli_sorted_cmd_ptrs))
|
||||
PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
|
||||
} > RAM
|
||||
.fs_data :
|
||||
{
|
||||
PROVIDE(__start_fs_data = .);
|
||||
KEEP(*(.fs_data))
|
||||
PROVIDE(__stop_fs_data = .);
|
||||
} > RAM
|
||||
.log_dynamic_data :
|
||||
{
|
||||
PROVIDE(__start_log_dynamic_data = .);
|
||||
KEEP(*(SORT(.log_dynamic_data*)))
|
||||
PROVIDE(__stop_log_dynamic_data = .);
|
||||
} > RAM
|
||||
.log_filter_data :
|
||||
{
|
||||
PROVIDE(__start_log_filter_data = .);
|
||||
KEEP(*(SORT(.log_filter_data*)))
|
||||
PROVIDE(__stop_log_filter_data = .);
|
||||
} > RAM
|
||||
|
||||
} INSERT AFTER .data;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.mem_section_dummy_rom :
|
||||
{
|
||||
}
|
||||
.sdh_soc_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_soc_observers = .);
|
||||
KEEP(*(SORT(.sdh_soc_observers*)))
|
||||
PROVIDE(__stop_sdh_soc_observers = .);
|
||||
} > FLASH
|
||||
.sdh_ble_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_ble_observers = .);
|
||||
KEEP(*(SORT(.sdh_ble_observers*)))
|
||||
PROVIDE(__stop_sdh_ble_observers = .);
|
||||
} > FLASH
|
||||
.pwr_mgmt_data :
|
||||
{
|
||||
PROVIDE(__start_pwr_mgmt_data = .);
|
||||
KEEP(*(SORT(.pwr_mgmt_data*)))
|
||||
PROVIDE(__stop_pwr_mgmt_data = .);
|
||||
} > FLASH
|
||||
.sdh_req_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_req_observers = .);
|
||||
KEEP(*(SORT(.sdh_req_observers*)))
|
||||
PROVIDE(__stop_sdh_req_observers = .);
|
||||
} > FLASH
|
||||
.sdh_state_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_state_observers = .);
|
||||
KEEP(*(SORT(.sdh_state_observers*)))
|
||||
PROVIDE(__stop_sdh_state_observers = .);
|
||||
} > FLASH
|
||||
.sdh_stack_observers :
|
||||
{
|
||||
PROVIDE(__start_sdh_stack_observers = .);
|
||||
KEEP(*(SORT(.sdh_stack_observers*)))
|
||||
PROVIDE(__stop_sdh_stack_observers = .);
|
||||
} > FLASH
|
||||
.nrf_queue :
|
||||
{
|
||||
PROVIDE(__start_nrf_queue = .);
|
||||
KEEP(*(.nrf_queue))
|
||||
PROVIDE(__stop_nrf_queue = .);
|
||||
} > FLASH
|
||||
.nrf_balloc :
|
||||
{
|
||||
PROVIDE(__start_nrf_balloc = .);
|
||||
KEEP(*(.nrf_balloc))
|
||||
PROVIDE(__stop_nrf_balloc = .);
|
||||
} > FLASH
|
||||
.cli_command :
|
||||
{
|
||||
PROVIDE(__start_cli_command = .);
|
||||
KEEP(*(.cli_command))
|
||||
PROVIDE(__stop_cli_command = .);
|
||||
} > FLASH
|
||||
.crypto_data :
|
||||
{
|
||||
PROVIDE(__start_crypto_data = .);
|
||||
KEEP(*(SORT(.crypto_data*)))
|
||||
PROVIDE(__stop_crypto_data = .);
|
||||
} > FLASH
|
||||
.log_const_data :
|
||||
{
|
||||
PROVIDE(__start_log_const_data = .);
|
||||
KEEP(*(SORT(.log_const_data*)))
|
||||
PROVIDE(__stop_log_const_data = .);
|
||||
} > FLASH
|
||||
.log_backends :
|
||||
{
|
||||
PROVIDE(__start_log_backends = .);
|
||||
KEEP(*(SORT(.log_backends*)))
|
||||
PROVIDE(__stop_log_backends = .);
|
||||
} > FLASH
|
||||
|
||||
} INSERT AFTER .text
|
||||
|
||||
|
||||
INCLUDE "nrf_common.ld"
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
#ifndef _PRST_CONFIG_H_
|
||||
#define _PRST_CONFIG_H_
|
||||
|
||||
#include "nrf_gpio.h"
|
||||
// Some configurations are version-specific. Uncomment the line corresponding
|
||||
// the the version you're programming. The version can be found on the
|
||||
// b-parasite board.
|
||||
// #define PRST_VERSION_1_0_X
|
||||
// #define PRST_VERSION_1_1_X
|
||||
#define PRST_VERSION_1_2_X
|
||||
|
||||
// Built-in LED.
|
||||
// Wether or not to turn the LED on/off during the wake-up cycle. Impacts
|
||||
// battery life.
|
||||
#define PRST_BLINK_LED 0
|
||||
#define PRST_LED_PIN NRF_GPIO_PIN_MAP(0, 28)
|
||||
|
||||
// Deep sleep.
|
||||
#define PRST_DEEP_SLEEP_IN_SECONDS 300
|
||||
|
||||
// Analog to digital converter (ADC).
|
||||
// Prints out ADC debug info, such as the values read for battery and soil
|
||||
// moisture.
|
||||
#define PRST_ADC_BATT_DEBUG 0
|
||||
#define PRST_ADC_SOIL_DEBUG 0
|
||||
|
||||
// BLE.
|
||||
// Prints out BLE debug info, such as the final encoded advertisement packet.
|
||||
#define PRST_BLE_DEBUG 0
|
||||
|
||||
// Supported BLE protocols.
|
||||
// Default, custom BLE protocol.
|
||||
#define PRST_BLE_PROTOCOL_BPARASITE_V2 0x01
|
||||
// BTHome BLE protocol - https://bthome.io.
|
||||
#define PRST_BLE_PROTOCOL_BTHOME 0x02
|
||||
|
||||
// Chosen BLE protocol.
|
||||
#define PRST_BLE_PROTOCOL PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
|
||||
// There are two options for configuring the MAC address of b-parasites:
|
||||
// 1. Comment out the PRST_BLE_MAC_ADDR to use a random static MAC address that
|
||||
// is preprogrammed in each nRF52 chip.
|
||||
// 2. Manually specify the MAC address you want below. In this scenario, the
|
||||
// following constraints must be met to ensure valid random static MAC
|
||||
// addresses:
|
||||
// a. Two most significant bits are set to 1;
|
||||
// b. The remaining bits should not _all_ be set to 0;
|
||||
// c. The remaining bits should not _all_ be set to 1;
|
||||
#define PRST_BLE_MAC_ADDR "f0:ca:f0:ca:01:01"
|
||||
|
||||
#define PRST_BLE_ADV_NAME "prst"
|
||||
// Total time spend advertising.
|
||||
#define PRST_BLE_ADV_TIME_IN_S 1
|
||||
// Interval between advertising packets.
|
||||
// From the specs, this value has to be greater or equal 20ms.
|
||||
#define PRST_BLE_ADV_INTERVAL_IN_MS 30
|
||||
// Possible values are ..., -8, -4, 0, 4, 8.
|
||||
#define PRST_BLE_ADV_TX_POWER 8
|
||||
// Experimental support for "long range" BLE, introduced in Bluetooth 5. It uses
|
||||
// a different type of physical layer - the Coded PHY. Receivers should also
|
||||
// scan using Coded PHY in order to find this device when operating in this
|
||||
// mode.
|
||||
#define PRST_BLE_EXPERIMENTAL_LONG_RANGE 0
|
||||
|
||||
// PWM.
|
||||
#define PRST_PWM_PIN NRF_GPIO_PIN_MAP(0, 5)
|
||||
|
||||
#ifdef NRF52833_XXAA
|
||||
#define PRST_FAST_DISCH_PIN NRF_GPIO_PIN_MAP(0, 25)
|
||||
#else
|
||||
#define PRST_FAST_DISCH_PIN NRF_GPIO_PIN_MAP(1, 10)
|
||||
#endif
|
||||
|
||||
// SHT3C temp/humidity sensor.
|
||||
#define PRST_SHT3C_DEBUG 0
|
||||
|
||||
// Version-specific configuration.
|
||||
#if defined(PRST_VERSION_1_1_X)
|
||||
// The photoresistor (LDR) is optional in this revision. If set to 1, the LDR's
|
||||
// ADC channel will be sampled and its data will be encoded in the BLE
|
||||
// advertisement packet.
|
||||
#define PRST_HAS_LDR 1
|
||||
|
||||
// Light sensor pins.
|
||||
#define PRST_PHOTO_V_PIN NRF_GPIO_PIN_MAP(0, 29)
|
||||
#define PRST_PHOTO_OUT_PIN NRF_GPIO_PIN_MAP(0, 2)
|
||||
|
||||
// Whether to produce debug messages for the LDR
|
||||
#define PRST_ADC_PHOTO_DEBUG 0
|
||||
|
||||
#elif defined(PRST_VERSION_1_2_X)
|
||||
|
||||
#define PRST_HAS_PHOTOTRANSISTOR 1
|
||||
|
||||
#define PRST_PHOTO_V_PIN NRF_GPIO_PIN_MAP(0, 29)
|
||||
#define PRST_PHOTO_OUT_PIN NRF_GPIO_PIN_MAP(0, 2)
|
||||
|
||||
#define PRST_ADC_PHOTO_DEBUG 0
|
||||
|
||||
#endif // End of version-specific configuration.
|
||||
|
||||
#endif // _PRST_CONFIG_H_
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,144 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nrf_delay.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
#include "nrf_pwr_mgmt.h"
|
||||
#include "prst/adc.h"
|
||||
#include "prst/ble.h"
|
||||
#include "prst/data.h"
|
||||
#include "prst/pwm.h"
|
||||
#include "prst/rtc.h"
|
||||
#include "prst/shtc3.h"
|
||||
#include "prst_config.h"
|
||||
|
||||
// A small wrap-around counter for deduplicating BLE packets on the receiver.
|
||||
static uint8_t run_counter = 0;
|
||||
|
||||
typedef enum {
|
||||
SLEEPING,
|
||||
ADVERTISING,
|
||||
} State;
|
||||
|
||||
static State state = SLEEPING;
|
||||
|
||||
static void log_init(void) {
|
||||
APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
|
||||
NRF_LOG_DEFAULT_BACKENDS_INIT();
|
||||
NRF_LOG_INFO("Log inited.");
|
||||
}
|
||||
|
||||
static void gpio_init(void) {
|
||||
nrf_gpio_cfg_output(PRST_LED_PIN);
|
||||
nrf_gpio_cfg_output(PRST_FAST_DISCH_PIN);
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
nrf_gpio_cfg_output(PRST_PHOTO_V_PIN);
|
||||
#endif
|
||||
NRF_LOG_INFO("GPIO pins inited.");
|
||||
}
|
||||
|
||||
static void power_management_init(void) {
|
||||
APP_ERROR_CHECK(nrf_pwr_mgmt_init());
|
||||
NRF_LOG_INFO("GPIO pins inited.");
|
||||
}
|
||||
|
||||
// This FPU exception mask trick is recommended for avoiding unwanted
|
||||
// interupts from the floating point unit. This would be pretty bad,
|
||||
// since it would wake us up from deep sleep for nothing.
|
||||
#define FPU_EXCEPTION_MASK 0x0000009F
|
||||
static void power_manage(void) {
|
||||
__set_FPSCR(__get_FPSCR() & ~(FPU_EXCEPTION_MASK));
|
||||
(void)__get_FPSCR();
|
||||
NVIC_ClearPendingIRQ(FPU_IRQn);
|
||||
nrf_pwr_mgmt_run();
|
||||
}
|
||||
|
||||
// This is the RTC callback in which we do all of our work as quickly as
|
||||
// possible:
|
||||
// - Measure the soil moisture;
|
||||
// - Measure the air temperature and humidity;
|
||||
// - Encode the measurements into the BLE advertisement packet;
|
||||
// - Turn on BLE advertising for a while;
|
||||
// - Turn everything off and return back to sleep.
|
||||
static void rtc_callback() {
|
||||
#if PRST_BLINK_LED
|
||||
nrf_gpio_pin_set(PRST_LED_PIN);
|
||||
#endif
|
||||
|
||||
if (state == SLEEPING) {
|
||||
prst_shtc3_read_t temp_humi = prst_shtc3_read();
|
||||
nrf_gpio_pin_set(PRST_FAST_DISCH_PIN);
|
||||
prst_pwm_init();
|
||||
prst_pwm_start();
|
||||
prst_adc_batt_read_t batt_read = prst_adc_batt_read();
|
||||
prst_adc_soil_moisture_t soil_read = prst_adc_soil_read(batt_read.voltage);
|
||||
prst_pwm_stop();
|
||||
nrf_gpio_pin_clear(PRST_FAST_DISCH_PIN);
|
||||
|
||||
uint16_t lux = 0;
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
nrf_gpio_pin_set(PRST_PHOTO_V_PIN);
|
||||
nrf_delay_ms(50);
|
||||
prst_adc_photo_sensor_t photo_read = prst_adc_photo_read(batt_read.voltage);
|
||||
lux = photo_read.brightness;
|
||||
nrf_gpio_pin_clear(PRST_PHOTO_V_PIN);
|
||||
#endif
|
||||
|
||||
prst_sensor_data_t sensors = {
|
||||
.batt_mv = batt_read.millivolts,
|
||||
.temp_c = temp_humi.temp_celsius,
|
||||
.humi = temp_humi.humidity,
|
||||
.soil_moisture = soil_read.relative,
|
||||
.lux = lux,
|
||||
.run_counter = run_counter,
|
||||
};
|
||||
|
||||
prst_ble_update_adv_data(&sensors);
|
||||
|
||||
state = ADVERTISING;
|
||||
prst_adv_start();
|
||||
prst_rtc_set_timer(PRST_BLE_ADV_TIME_IN_S);
|
||||
run_counter++;
|
||||
} else if (state == ADVERTISING) {
|
||||
prst_adv_stop();
|
||||
state = SLEEPING;
|
||||
prst_rtc_set_timer(PRST_DEEP_SLEEP_IN_SECONDS);
|
||||
}
|
||||
#if PRST_BLINK_LED
|
||||
nrf_gpio_pin_clear(PRST_LED_PIN);
|
||||
#endif
|
||||
|
||||
NRF_LOG_FLUSH();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
log_init();
|
||||
gpio_init();
|
||||
power_management_init();
|
||||
prst_ble_init();
|
||||
prst_adc_init();
|
||||
prst_shtc3_init();
|
||||
|
||||
// Quick LED flash.
|
||||
nrf_gpio_pin_set(PRST_LED_PIN);
|
||||
nrf_delay_ms(200);
|
||||
nrf_gpio_pin_clear(PRST_LED_PIN);
|
||||
|
||||
// Set up RTC. It will call our custom callback at a regular interval, defined
|
||||
// by PRST_DEEP_SLEEP_IN_SECONDS.
|
||||
prst_rtc_set_callback(rtc_callback);
|
||||
prst_rtc_init();
|
||||
|
||||
// In addition to scheduling it, let's immediatelly call it - it makes
|
||||
// debugging less tedious.
|
||||
rtc_callback();
|
||||
|
||||
// Here we go into a low energy mode. The datasheet calls this mode "System
|
||||
// ON", and in my tests it consumes around 2.7uA.
|
||||
for (;;) {
|
||||
power_manage();
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
BasedOnStyle: Google
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
#include "prst/adc.h"
|
||||
|
||||
#include <app_error.h>
|
||||
#include <math.h>
|
||||
#include <nrf_drv_saadc.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_saadc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
#define PRST_ADC_RESOLUTION 10
|
||||
|
||||
#define PRST_ADC_BATT_INPUT NRF_SAADC_INPUT_VDD
|
||||
#define PRST_ADC_BATT_CHANNEL 0
|
||||
|
||||
#define PRST_ADC_SOIL_INPUT NRF_SAADC_INPUT_AIN1
|
||||
#define PRST_ADC_SOIL_CHANNEL 1
|
||||
|
||||
#define PRST_ADC_PHOTO_INPUT NRF_SAADC_INPUT_AIN0
|
||||
#define PRST_ADC_PHOTO_CHANNEL 2
|
||||
|
||||
static nrf_saadc_value_t sample_adc_channel(uint8_t channel) {
|
||||
nrf_saadc_value_t result;
|
||||
// *WARNING* this function is blocking, which is ot ideal but okay, but it
|
||||
// *does not work* when oversampling is set! I had to manually disable
|
||||
// SAADC_CONFIG_OVERSAMPLE in sdk_config.h.
|
||||
APP_ERROR_CHECK(nrf_drv_saadc_sample_convert(channel, &result));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Caps the argument to the [0.0, 1.0] range.
|
||||
static inline double cap_percentage(double value) {
|
||||
return value > 1.0 ? 1.0 : (value < 0.0 ? 0.0 : value);
|
||||
}
|
||||
|
||||
// Unused, since we'll call the SAADC synchronously for now.
|
||||
void saadc_callback(nrf_drv_saadc_evt_t const* p_event) {
|
||||
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) {
|
||||
ret_code_t err_code;
|
||||
uint16_t size = p_event->data.done.size;
|
||||
|
||||
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, size);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
int i;
|
||||
NRF_LOG_INFO("[adc] ADC event!");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
NRF_LOG_INFO("[adc] %d", p_event->data.done.p_buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void prst_adc_init() {
|
||||
nrf_saadc_channel_config_t batt_channel_config =
|
||||
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PRST_ADC_BATT_INPUT);
|
||||
|
||||
APP_ERROR_CHECK(nrf_drv_saadc_init(NULL, saadc_callback));
|
||||
|
||||
APP_ERROR_CHECK(
|
||||
nrf_drv_saadc_channel_init(PRST_ADC_BATT_CHANNEL, &batt_channel_config));
|
||||
|
||||
nrf_saadc_channel_config_t soil_channel_config =
|
||||
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PRST_ADC_SOIL_INPUT);
|
||||
soil_channel_config.reference = NRF_SAADC_REFERENCE_VDD4;
|
||||
APP_ERROR_CHECK(
|
||||
nrf_drv_saadc_channel_init(PRST_ADC_SOIL_CHANNEL, &soil_channel_config));
|
||||
|
||||
nrf_saadc_channel_config_t photo_channel_config =
|
||||
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PRST_ADC_PHOTO_INPUT);
|
||||
APP_ERROR_CHECK(nrf_drv_saadc_channel_init(PRST_ADC_PHOTO_CHANNEL,
|
||||
&photo_channel_config));
|
||||
}
|
||||
|
||||
prst_adc_batt_read_t prst_adc_batt_read() {
|
||||
nrf_saadc_value_t result = sample_adc_channel(PRST_ADC_BATT_CHANNEL);
|
||||
prst_adc_batt_read_t ret;
|
||||
ret.raw = (uint16_t)result;
|
||||
ret.voltage = (3.6 * result) / (1 << PRST_ADC_RESOLUTION);
|
||||
ret.millivolts = ret.voltage * 1000;
|
||||
#if PRST_ADC_BATT_DEBUG
|
||||
NRF_LOG_INFO(
|
||||
"[adc] Read battery voltage: %d (raw); %d mV; " NRF_LOG_FLOAT_MARKER " V",
|
||||
ret.raw, ret.millivolts, NRF_LOG_FLOAT(ret.voltage));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If you got this far and really want to see how the sausage is made,
|
||||
// this function estimates the soil moisture percent based on the raw
|
||||
// ADC value as returned from the saadc. It assumes 10 bits resolution.
|
||||
// Ideally, we're taking the ADC sample relative to the VDD voltage, so
|
||||
// this input value should be stable across the range of input voltages.
|
||||
// In practice, when varying the input voltage, this value is drifting
|
||||
// enough to be annoying. To account for this drift, I collected ADC readings
|
||||
// while varying the input voltage from 2V to 3V (CR2032 voltage range) and
|
||||
// fitted two second degree polynomials over them - one for the sensor
|
||||
// out in the air (representing a dry soil) and one while holding the
|
||||
// sensor in my hand (representing a wet soil).
|
||||
// This raw data is available at the data/ dir at the root of this repository.
|
||||
static inline double get_soil_moisture_percent(
|
||||
double battery_voltage, nrf_saadc_value_t raw_adc_output) {
|
||||
const double x = battery_voltage;
|
||||
const double dry = -12.9 * x * x + 111 * x + 228;
|
||||
const double wet = -5.71 * x * x + 60.2 * x + 126;
|
||||
#if PRST_ADC_SOIL_DEBUG
|
||||
NRF_LOG_INFO("[adc] batt: " NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(x));
|
||||
NRF_LOG_INFO("[adc] dry: " NRF_LOG_FLOAT_MARKER " wet: " NRF_LOG_FLOAT_MARKER,
|
||||
NRF_LOG_FLOAT(dry), NRF_LOG_FLOAT(wet));
|
||||
#endif
|
||||
return (raw_adc_output - dry) / (wet - dry);
|
||||
}
|
||||
|
||||
prst_adc_soil_moisture_t prst_adc_soil_read(double battery_voltage) {
|
||||
nrf_saadc_value_t raw_adc_output = sample_adc_channel(PRST_ADC_SOIL_CHANNEL);
|
||||
const double percentage =
|
||||
get_soil_moisture_percent(battery_voltage, raw_adc_output);
|
||||
prst_adc_soil_moisture_t ret;
|
||||
ret.raw = raw_adc_output;
|
||||
ret.percentage = percentage;
|
||||
ret.relative = cap_percentage(percentage) * UINT16_MAX;
|
||||
#if PRST_ADC_SOIL_DEBUG
|
||||
NRF_LOG_INFO("[adc] Read soil moisture: %d (raw); " NRF_LOG_FLOAT_MARKER
|
||||
" %% (percentage); %u (relative)",
|
||||
ret.raw, NRF_LOG_FLOAT(percentage * 100), ret.relative);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
prst_adc_photo_sensor_t prst_adc_photo_read(double battery_voltage) {
|
||||
nrf_saadc_value_t raw_photo_output =
|
||||
MAX(0, sample_adc_channel(PRST_ADC_PHOTO_CHANNEL));
|
||||
prst_adc_photo_sensor_t ret;
|
||||
ret.raw = raw_photo_output;
|
||||
ret.voltage = (3.6 * raw_photo_output) / (1 << PRST_ADC_RESOLUTION);
|
||||
|
||||
#if PRST_HAS_LDR
|
||||
// The photo resistor forms a voltage divider with a 10 kOhm resistor.
|
||||
// The voltage here is measured in the middle of the voltage divider.
|
||||
// Vcc ---- (R_photo) ---|--- (10k) ---- GND
|
||||
// Vout
|
||||
// So we can estimate R_photo = R * (Vcc - Vout) / Vout
|
||||
const float photo_resistance =
|
||||
1e4f * (battery_voltage - ret.voltage) / ret.voltage;
|
||||
|
||||
// The relationship between the LDR resistance and the lux level is
|
||||
// logarithmic. We need to solve a logarithmic equation to find the lux
|
||||
// level, given the LDR resistance we just measured.
|
||||
// These values work for the GL5528 LDR and were borrowed from
|
||||
// https://github.com/QuentinCG/Arduino-Light-Dependent-Resistor-Library.
|
||||
const float mult_value = 32017200.0f;
|
||||
const float pow_value = 1.5832f;
|
||||
ret.brightness =
|
||||
MAX(0, MIN(mult_value / powf(photo_resistance, pow_value), UINT16_MAX));
|
||||
|
||||
#elif PRST_HAS_PHOTOTRANSISTOR
|
||||
// The ALS-PT19 phototransistor is a device in which the current flow between
|
||||
// its two terminals is controlled by how much light there is in the ambient.
|
||||
// We measure that current by calculating the voltage across a resistor that
|
||||
// is connected in series with the phototransistor.
|
||||
const float phototransistor_resistor = 470.0f;
|
||||
const float current_sun = 3.59e-3f;
|
||||
// Assuming 10000 lux for the saturation test. Calibration with a proper light
|
||||
// meter would be better.
|
||||
const float lux_sun = 10000.0f;
|
||||
const float current = ret.voltage / phototransistor_resistor;
|
||||
ret.brightness = MAX(0, MIN(lux_sun * current / current_sun, UINT16_MAX));
|
||||
|
||||
#if PRST_ADC_PHOTO_DEBUG
|
||||
NRF_LOG_INFO("[adc] Phototransistor current: " NRF_LOG_FLOAT_MARKER " uA",
|
||||
NRF_LOG_FLOAT(1000000 * current));
|
||||
#endif // PRST_ADC_PHOTO_DEBUG
|
||||
#endif // PRST_HAS_PHOTOTRANSISTOR
|
||||
|
||||
#if PRST_ADC_PHOTO_DEBUG
|
||||
NRF_LOG_INFO("[adc] Read brightness level: " NRF_LOG_FLOAT_MARKER
|
||||
" mV %d (raw); %d (lux)",
|
||||
NRF_LOG_FLOAT(1000 * ret.voltage), ret.raw, ret.brightness);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef _PRST_ADC_H_
|
||||
#define _PRST_ADC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct prst_adc_batt_val {
|
||||
int16_t raw;
|
||||
uint16_t millivolts;
|
||||
double voltage;
|
||||
} prst_adc_batt_read_t;
|
||||
|
||||
typedef struct prst_adc_soil_moisture {
|
||||
int16_t raw;
|
||||
// A value from 0 (completely dry) to 2^10 (completely wet).
|
||||
uint16_t relative;
|
||||
double percentage;
|
||||
} prst_adc_soil_moisture_t;
|
||||
|
||||
typedef struct prst_adc_photo_sensor {
|
||||
int16_t raw;
|
||||
double voltage;
|
||||
// Value in lux.
|
||||
uint16_t brightness;
|
||||
} prst_adc_photo_sensor_t;
|
||||
|
||||
void prst_adc_init();
|
||||
|
||||
prst_adc_batt_read_t prst_adc_batt_read();
|
||||
|
||||
prst_adc_soil_moisture_t prst_adc_soil_read(double battery_voltage);
|
||||
|
||||
prst_adc_photo_sensor_t prst_adc_photo_read(double battery_voltage);
|
||||
|
||||
#endif // _PRST_ADC_H_
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
#include "prst/ble.h"
|
||||
|
||||
#include <ble_advdata.h>
|
||||
#include <ble_gap.h>
|
||||
#include <nordic_common.h>
|
||||
#include <nrf_delay.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_sdh.h>
|
||||
#include <nrf_sdh_ble.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
// The connection to configure. We only have the one.
|
||||
#define PRST_CONN_CFG_TAG 1
|
||||
|
||||
#define NON_CONNECTABLE_ADV_INTERVAL \
|
||||
MSEC_TO_UNITS(PRST_BLE_ADV_INTERVAL_IN_MS, UNIT_0_625_MS)
|
||||
|
||||
// Sensor data payload that will go into the advertisement message.
|
||||
// We have a maximum of 20 bytes to play with here.
|
||||
// Sensor data is encoded in unsigned 16 bits (2 bytes), and whenever multiple
|
||||
// bytes are used to represent a single value, the encoding is big-endian:
|
||||
/*
|
||||
| Byte index | Description |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
| 0 | Protocol version (4 bits) + reserved (3 bits) + has_lux* (1 bit)|
|
||||
| 1 | Reserved (4 bits) + increasing, wrap-around counter (4 bits) |
|
||||
| 2-3 | Battery voltage in millivolts |
|
||||
| 4-5 | Temp in 1000 * Celsius (protocol v1) or 100 * Celsius (v2) |
|
||||
| 6-7 | Relative air humidity, scaled from 0 (0%) to 0xffff (100%) |
|
||||
| 8-9 | Soil moisture, scaled from from 0 (0%) to 0xffff (100%) |
|
||||
| 10-15 | b-parasite's own MAC address |
|
||||
| 16-17* | Ambient light in lux |
|
||||
|
||||
* If the has_lux bit is set, bytes 16-17 shall contain the ambient light in lux.
|
||||
If the has_lux bit is not set, bytes 16-17 may not exist or may contain
|
||||
meaningless data. The reasons for this behavior are:
|
||||
1. b-parasite version 1.0.0 has no light sensor and its advertisement data may
|
||||
have only 16 bytes if its using an older firmware. In this case, has_lux shall
|
||||
never be set;
|
||||
2. b-parasite version 1.1.0 has space for an optional LDR. Users can configure
|
||||
whether or not they have added the LDR by setting the PRST_HAS_LDR to 1 in
|
||||
prst_config.h.
|
||||
*/
|
||||
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
#define SERVICE_UUID 0x181a
|
||||
#define SERVICE_DATA_LEN 18
|
||||
#elif PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
#define SERVICE_UUID 0x181c
|
||||
#define SERVICE_DATA_LEN 16
|
||||
#else
|
||||
#error "PRST_BLE_PROTOCOL is not properly configured"
|
||||
#endif
|
||||
|
||||
static uint8_t service_data[SERVICE_DATA_LEN];
|
||||
|
||||
// Stores the encoded advertisement data. As per BLE spec, 31 bytes max.
|
||||
static uint8_t encoded_adv_data_[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
|
||||
|
||||
// Structure holding high level advertisement data and contains a pointer to
|
||||
// the actual encoded advertised bytes.
|
||||
static ble_gap_adv_data_t gap_adv_data_ = {
|
||||
.adv_data = {.p_data = encoded_adv_data_,
|
||||
.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX},
|
||||
.scan_rsp_data = {.p_data = NULL, .len = 0}};
|
||||
|
||||
// We'll put our sensor data inside an advertisement service.
|
||||
static ble_advdata_service_data_t advdata_service_data_ = {
|
||||
.service_uuid = SERVICE_UUID,
|
||||
.data = {
|
||||
.p_data = service_data,
|
||||
.size = SERVICE_DATA_LEN,
|
||||
}};
|
||||
|
||||
// Holds the service data to be broadcasted. The contents of this struct
|
||||
// will be encoded into gap_adv_data.
|
||||
// Warning: do not update this while advertising.
|
||||
static ble_advdata_t adv_data_ = {
|
||||
.name_type = BLE_ADVDATA_FULL_NAME,
|
||||
#if PRST_BLE_EXPERIMENTAL_LONG_RANGE
|
||||
.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE,
|
||||
#else
|
||||
.flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED,
|
||||
#endif
|
||||
.p_service_data_array = &advdata_service_data_,
|
||||
.service_data_count = 1,
|
||||
};
|
||||
|
||||
// NRF supports multiple advertisement sets. This initialization is a request
|
||||
// for configuring a new one.
|
||||
static uint8_t adv_handle_ = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
|
||||
|
||||
// Advertisement parameters.
|
||||
static ble_gap_adv_params_t adv_params_;
|
||||
|
||||
// Stores the MAC address & type.
|
||||
static ble_gap_addr_t gap_addr_ = {.addr_type =
|
||||
BLE_GAP_ADDR_TYPE_RANDOM_STATIC};
|
||||
|
||||
static void init_advertisement_data() {
|
||||
// We'll just broadcast our data, so we disallow connections and scan
|
||||
// requests.
|
||||
#if PRST_BLE_EXPERIMENTAL_LONG_RANGE
|
||||
adv_params_.properties.type =
|
||||
BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
|
||||
adv_params_.primary_phy = BLE_GAP_PHY_CODED;
|
||||
adv_params_.secondary_phy = BLE_GAP_PHY_CODED;
|
||||
#else
|
||||
adv_params_.properties.type =
|
||||
BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED;
|
||||
#endif
|
||||
|
||||
adv_params_.p_peer_addr = NULL;
|
||||
adv_params_.filter_policy = BLE_GAP_ADV_FP_ANY;
|
||||
adv_params_.interval = NON_CONNECTABLE_ADV_INTERVAL;
|
||||
adv_params_.duration = 0; // Never time out.
|
||||
|
||||
ble_gap_conn_sec_mode_t sec_mode;
|
||||
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
|
||||
sd_ble_gap_device_name_set(&sec_mode, (const uint8_t*)PRST_BLE_ADV_NAME,
|
||||
strlen(PRST_BLE_ADV_NAME));
|
||||
|
||||
uint32_t err_code =
|
||||
sd_ble_gap_adv_set_configure(&adv_handle_, &gap_adv_data_, &adv_params_);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
}
|
||||
|
||||
void prst_ble_init() {
|
||||
uint32_t err_code;
|
||||
|
||||
// Enable SoftDevice request.
|
||||
err_code = nrf_sdh_enable_request();
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Set the default config and get the starting RAM address.
|
||||
uint32_t ram_start = 0;
|
||||
err_code = nrf_sdh_ble_default_cfg_set(PRST_CONN_CFG_TAG, &ram_start);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Enable SoftDevice.
|
||||
err_code = nrf_sdh_ble_enable(&ram_start);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
#ifdef PRST_BLE_MAC_ADDR
|
||||
// Parses configured MAC address from PRST_BLE_MAC_ADDR.
|
||||
int mac_bytes[6];
|
||||
sscanf(PRST_BLE_MAC_ADDR, "%x:%x:%x:%x:%x:%x", &mac_bytes[0], &mac_bytes[1],
|
||||
&mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
gap_addr_.addr[5 - i] = (uint8_t)mac_bytes[i];
|
||||
}
|
||||
APP_ERROR_CHECK(sd_ble_gap_addr_set(&gap_addr_));
|
||||
#endif
|
||||
|
||||
APP_ERROR_CHECK(sd_ble_gap_addr_get(&gap_addr_));
|
||||
NRF_LOG_INFO("[ble] MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
gap_addr_.addr[5], gap_addr_.addr[4], gap_addr_.addr[3],
|
||||
gap_addr_.addr[2], gap_addr_.addr[1], gap_addr_.addr[0]);
|
||||
|
||||
init_advertisement_data();
|
||||
}
|
||||
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
static void set_service_data_bparasite_protocol(
|
||||
const prst_sensor_data_t* sensors) {
|
||||
// Four bits for the protocol version.
|
||||
service_data[0] |= (2 << 4) & 0xf0;
|
||||
|
||||
// Bit 0 of byte 0 specifies whether or not ambient light data exists in the
|
||||
// payload.
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
service_data[0] |= 1;
|
||||
#endif
|
||||
|
||||
// 4 bits for a small wrap-around counter for deduplicating messages on the
|
||||
// receiver.
|
||||
service_data[1] = sensors->run_counter & 0x0f;
|
||||
|
||||
service_data[2] = sensors->batt_mv >> 8;
|
||||
service_data[3] = sensors->batt_mv & 0xff;
|
||||
|
||||
int16_t temp_centicelsius = 100 * sensors->temp_c;
|
||||
service_data[4] = temp_centicelsius >> 8;
|
||||
service_data[5] = temp_centicelsius & 0xff;
|
||||
|
||||
service_data[6] = sensors->humi >> 8;
|
||||
service_data[7] = sensors->humi & 0xff;
|
||||
|
||||
service_data[8] = sensors->soil_moisture >> 8;
|
||||
service_data[9] = sensors->soil_moisture & 0xff;
|
||||
|
||||
// Bytes 10-15 (inclusive) contain the whole MAC address in big-endian.
|
||||
for (int i = 0; i < 6; i++) {
|
||||
service_data[10 + i] = gap_addr_.addr[5 - i];
|
||||
}
|
||||
|
||||
#if PRST_HAS_LDR || PRST_HAS_PHOTOTRANSISTOR
|
||||
service_data[16] = sensors->lux >> 8;
|
||||
service_data[17] = sensors->lux & 0xff;
|
||||
#endif
|
||||
}
|
||||
#endif // PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
static void set_service_data_bthome_protocol(
|
||||
const prst_sensor_data_t* sensors) {
|
||||
// See values in https://bthome.io/.
|
||||
|
||||
// 1. Soil moisture.
|
||||
// uint16_t.
|
||||
service_data[0] = (0b000 << 5) | 3;
|
||||
// Type of measurement - Moisture.
|
||||
service_data[1] = 0x14;
|
||||
// Value. Factor of 0.01, so we need to multiply our the value in 100% by
|
||||
// 1/0.01 = 100.
|
||||
uint16_t soil_val = (10000 * sensors->soil_moisture) / UINT16_MAX;
|
||||
service_data[2] = soil_val & 0xff;
|
||||
service_data[3] = soil_val >> 8;
|
||||
|
||||
// 2. Temp.
|
||||
// int16_t.
|
||||
service_data[4] = (0b001 << 5) | 3;
|
||||
// Type of measurement - temperature.
|
||||
service_data[5] = 0x02;
|
||||
// Value. Factor 0.01.
|
||||
int16_t temp_val = 100 * sensors->temp_c;
|
||||
service_data[6] = temp_val & 0xff;
|
||||
service_data[7] = temp_val >> 8;
|
||||
|
||||
// 3. Humidity
|
||||
// uint16_t.
|
||||
service_data[8] = (0b000 << 5) | 3;
|
||||
// Type - humidity.
|
||||
service_data[9] = 0x03;
|
||||
// Value. Factor 0.01, over 100%.
|
||||
uint16_t humi_val = (10000 * sensors->humi) / UINT16_MAX;
|
||||
service_data[10] = humi_val & 0xff;
|
||||
service_data[11] = humi_val >> 8;
|
||||
|
||||
// 4. Battery voltage.
|
||||
// uint16_t.
|
||||
service_data[12] = (0b000 << 5) | 3;
|
||||
// Type - voltage.
|
||||
service_data[13] = 0x0c;
|
||||
// Value. Factor of 0.001.
|
||||
uint16_t batt_val = sensors->batt_mv;
|
||||
service_data[14] = batt_val & 0xff;
|
||||
service_data[15] = batt_val >> 8;
|
||||
}
|
||||
#endif // PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
|
||||
void prst_ble_update_adv_data(const prst_sensor_data_t* sensors) {
|
||||
#if PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BPARASITE_V2
|
||||
set_service_data_bparasite_protocol(sensors);
|
||||
#elif PRST_BLE_PROTOCOL == PRST_BLE_PROTOCOL_BTHOME
|
||||
set_service_data_bthome_protocol(sensors);
|
||||
#endif
|
||||
|
||||
// Encodes adv_data_ into .gap_adv_data_.
|
||||
uint32_t err_code = ble_advdata_encode(
|
||||
&adv_data_, gap_adv_data_.adv_data.p_data, &gap_adv_data_.adv_data.len);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
#if PRST_BLE_DEBUG
|
||||
NRF_LOG_INFO("[ble] Encoded BLE adv packet:");
|
||||
for (int i = 0; i < sizeof(encoded_adv_data_); i++) {
|
||||
NRF_LOG_INFO("[ble] byte %02d: 0x%02x", i, encoded_adv_data_[i]);
|
||||
nrf_delay_ms(50);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void prst_adv_start() {
|
||||
APP_ERROR_CHECK(sd_ble_gap_adv_start(adv_handle_, PRST_CONN_CFG_TAG));
|
||||
APP_ERROR_CHECK(sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV,
|
||||
adv_handle_, PRST_BLE_ADV_TX_POWER));
|
||||
#if PRST_BLE_DEBUG
|
||||
NRF_LOG_INFO("[ble] Advertising started.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void prst_adv_stop() {
|
||||
ret_code_t err_code;
|
||||
err_code = sd_ble_gap_adv_stop(adv_handle_);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
#if PRST_BLE_DEBUG
|
||||
NRF_LOG_INFO("[ble] Advertising stopped.\n");
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef _PRST_BLE_H_
|
||||
#define _PRST_BLE_H_
|
||||
|
||||
#include <app_error.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prst/data.h"
|
||||
|
||||
// Initializes SoftDevice.
|
||||
void prst_ble_init();
|
||||
|
||||
void prst_adv_start();
|
||||
|
||||
void prst_adv_stop();
|
||||
|
||||
void prst_ble_update_adv_data(const prst_sensor_data_t* sensors);
|
||||
|
||||
#endif // _PRST_BLE_H_
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef _PRST_DATA_H_
|
||||
#define _PRST_DATA_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t batt_mv;
|
||||
float temp_c;
|
||||
uint16_t humi;
|
||||
uint16_t soil_moisture;
|
||||
uint16_t lux;
|
||||
uint8_t run_counter;
|
||||
} prst_sensor_data_t;
|
||||
|
||||
#endif // _PRST_DATA_H_
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#include "prst/pwm.h"
|
||||
|
||||
#include <app_error.h>
|
||||
#include <nordic_common.h>
|
||||
#include <nrf_drv_pwm.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_pwm.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
// Each step in the counter will take 1/16e6 s.
|
||||
#define PRST_PWM_BASE_FREQ NRF_PWM_CLK_16MHz
|
||||
// We will count up to 16. It will take 1us at 16MHz.
|
||||
// With the NRF_PWM_MODE_UP_AND_DOWN count mode, we assume 1us is half the
|
||||
// output PWM period (total 2us => 500MHz frequency). We set a duty cycle of
|
||||
// 50% below with PRST_PWM_FLIP_AT_COUNT to be half the max count.
|
||||
#define PRST_PWM_MAX_COUNT 16
|
||||
// We will toggle the PWM output when we reach this count.
|
||||
// #define PRST_PWM_FLIP_AT_COUNT PRST_PWM_MAX_COUNT / 2
|
||||
#define PRST_PWM_FLIP_AT_COUNT 8
|
||||
|
||||
static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
|
||||
|
||||
static nrf_pwm_values_common_t seq_values_[] = {PRST_PWM_FLIP_AT_COUNT};
|
||||
|
||||
static const nrf_pwm_sequence_t seq_ = {
|
||||
.values.p_common = seq_values_,
|
||||
.length = NRF_PWM_VALUES_LENGTH(seq_values_),
|
||||
.repeats = 0,
|
||||
.end_delay = 0};
|
||||
|
||||
void prst_pwm_init() {
|
||||
// We set the PWM pin as output so we can control its state after the PWM is
|
||||
// stopped. Without this, I'm seeing the PWM pin remaining high after stopped.
|
||||
nrf_gpio_pin_dir_set(PRST_PWM_PIN, NRF_GPIO_PIN_DIR_OUTPUT);
|
||||
|
||||
nrf_drv_pwm_config_t const config0 = {
|
||||
// We have to specify the state of the 4 channels. We only care about the
|
||||
// first one, so we set all others to not used.
|
||||
.output_pins =
|
||||
{
|
||||
PRST_PWM_PIN | NRF_DRV_PWM_PIN_INVERTED,
|
||||
NRF_DRV_PWM_PIN_NOT_USED,
|
||||
NRF_DRV_PWM_PIN_NOT_USED,
|
||||
NRF_DRV_PWM_PIN_NOT_USED,
|
||||
},
|
||||
.irq_priority = APP_IRQ_PRIORITY_LOWEST,
|
||||
// This is the hal PRESCALER
|
||||
.base_clock = NRF_PWM_CLK_16MHz,
|
||||
.count_mode = NRF_PWM_MODE_UP_AND_DOWN,
|
||||
// This is the hal COUNTERTOP.
|
||||
.top_value = PRST_PWM_MAX_COUNT,
|
||||
.load_mode = NRF_PWM_LOAD_COMMON,
|
||||
.step_mode = NRF_PWM_STEP_AUTO};
|
||||
APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
|
||||
}
|
||||
|
||||
void prst_pwm_start() {
|
||||
// Loop until stopped.
|
||||
APP_ERROR_CHECK(
|
||||
nrf_drv_pwm_simple_playback(&m_pwm0, &seq_, 1, NRF_DRV_PWM_FLAG_LOOP));
|
||||
}
|
||||
|
||||
void prst_pwm_stop() {
|
||||
nrf_drv_pwm_stop(&m_pwm0, /*wait_until_stopped=*/true);
|
||||
nrf_drv_pwm_uninit(&m_pwm0);
|
||||
nrf_gpio_pin_clear(PRST_PWM_PIN);
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef _PRST_PWM_H_
|
||||
#define _PRST_PWM_H_
|
||||
|
||||
void prst_pwm_init();
|
||||
|
||||
void prst_pwm_start();
|
||||
|
||||
void prst_pwm_stop();
|
||||
|
||||
#endif // _PRST_PWM_H_
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#include "prst/rtc.h"
|
||||
|
||||
#include <nrf_drv_rtc.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_log_ctrl.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
// RTC0 is used by softdevice, so we need to pick another instance.
|
||||
static const nrf_drv_rtc_t rtc_ = NRF_DRV_RTC_INSTANCE(2);
|
||||
static prst_rtc_callback_t callback_handler_ = NULL;
|
||||
|
||||
static void rtc_callback(nrf_drv_rtc_int_type_t int_type) {
|
||||
if (int_type == NRF_DRV_RTC_INT_COMPARE2) {
|
||||
if (callback_handler_ != NULL) {
|
||||
callback_handler_();
|
||||
}
|
||||
// Reset RTC2 counter.
|
||||
nrf_drv_rtc_counter_clear(&rtc_);
|
||||
// We need to re-enable the RTC2 interrupt after rest.
|
||||
nrf_drv_rtc_int_enable(&rtc_, NRF_RTC_INT_COMPARE2_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
void prst_rtc_set_callback(prst_rtc_callback_t cb) { callback_handler_ = cb; }
|
||||
|
||||
void prst_rtc_init() {
|
||||
uint32_t err_code;
|
||||
nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
|
||||
config.prescaler = 4095;
|
||||
err_code = nrf_drv_rtc_init(&rtc_, &config, rtc_callback);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
// Disable events we're not interested in so they don't trigger interrupts.
|
||||
nrf_drv_rtc_tick_disable(&rtc_);
|
||||
nrf_drv_rtc_overflow_disable(&rtc_);
|
||||
}
|
||||
|
||||
void prst_rtc_set_timer(uint16_t seconds) {
|
||||
// Make sure we're counting from 0.
|
||||
nrf_drv_rtc_counter_clear(&rtc_);
|
||||
|
||||
// Set compare channel to trigger interrupt after specified time.
|
||||
APP_ERROR_CHECK(nrf_drv_rtc_cc_set(&rtc_, 2, seconds * 8, true));
|
||||
|
||||
// Power on RTC instance.
|
||||
nrf_drv_rtc_enable(&rtc_);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _PRST_RTC_H_
|
||||
#define _PRST_RTC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*prst_rtc_callback_t)(void);
|
||||
|
||||
void prst_rtc_set_callback(prst_rtc_callback_t cb);
|
||||
|
||||
void prst_rtc_init();
|
||||
|
||||
void prst_rtc_set_timer(uint16_t seconds);
|
||||
|
||||
#endif // _PRST_RTC_H_
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#include "prst/shtc3.h"
|
||||
|
||||
#include <app_error.h>
|
||||
#include <nrf_delay.h>
|
||||
#include <nrf_drv_twi.h>
|
||||
#include <nrf_log.h>
|
||||
#include <nrf_log_ctrl.h>
|
||||
|
||||
#include "prst_config.h"
|
||||
|
||||
static const nrf_drv_twi_t twi_ = NRF_DRV_TWI_INSTANCE(0);
|
||||
static nrf_drv_twi_config_t twi_config_ = NRF_DRV_TWI_DEFAULT_CONFIG;
|
||||
|
||||
static uint8_t buff[6];
|
||||
|
||||
static void write_cmd(uint16_t command) {
|
||||
uint8_t cmd[2];
|
||||
cmd[0] = command >> 8;
|
||||
cmd[1] = command & 0xff;
|
||||
APP_ERROR_CHECK(nrf_drv_twi_tx(&twi_, PRST_SHTC3_ADDR, cmd, 2,
|
||||
/*no_stop=*/false));
|
||||
}
|
||||
|
||||
void prst_shtc3_init() {
|
||||
twi_config_.scl = PRST_SHT3C_SCL_PIN;
|
||||
twi_config_.sda = PRST_SHT3C_SDA_PIN;
|
||||
twi_config_.frequency = NRF_TWI_FREQ_100K;
|
||||
}
|
||||
|
||||
prst_shtc3_read_t prst_shtc3_read() {
|
||||
APP_ERROR_CHECK(nrf_drv_twi_init(&twi_, &twi_config_, NULL, NULL));
|
||||
nrf_drv_twi_enable(&twi_);
|
||||
|
||||
// Wake the sensor up.
|
||||
write_cmd(PRST_SHTC3_CMD_WAKEUP);
|
||||
nrf_delay_ms(1);
|
||||
|
||||
// Request measurement.
|
||||
write_cmd(PRST_SHTC3_CMD_MEASURE_TFIRST_NORMAL);
|
||||
|
||||
// Reading in normal (not low power) mode can take up to 12.1 ms, according to
|
||||
// the datasheet.
|
||||
nrf_delay_ms(15);
|
||||
|
||||
// Read temp and humidity.
|
||||
while (nrf_drv_twi_rx(&twi_, PRST_SHTC3_ADDR, buff, 6) != 0) {
|
||||
nrf_delay_ms(10);
|
||||
}
|
||||
// Put the sensor in sleep mode.
|
||||
write_cmd(PRST_SHTC3_CMD_SLEEP);
|
||||
|
||||
// Uninit i2c.
|
||||
nrf_drv_twi_uninit(&twi_);
|
||||
|
||||
// TODO(rbaron): verify the CRC of the measurements. The function is described
|
||||
// in the datasheet.
|
||||
|
||||
float temp_c = -45 + 175 * ((float)((buff[0] << 8) | buff[1])) / (1 << 16);
|
||||
uint16_t humi = (buff[3] << 8) | buff[4];
|
||||
|
||||
prst_shtc3_read_t ret = {.temp_celsius = temp_c, .humidity = humi};
|
||||
|
||||
#if PRST_SHT3C_DEBUG
|
||||
NRF_LOG_INFO("[sht3c] Read temp: " NRF_LOG_FLOAT_MARKER " oC",
|
||||
NRF_LOG_FLOAT((float)ret.temp_celsius));
|
||||
NRF_LOG_INFO("[sht3c] Read humi: " NRF_LOG_FLOAT_MARKER " %%",
|
||||
NRF_LOG_FLOAT(100.0 * ret.humidity / 0xffff));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef _PRST_SHT3C_H_
|
||||
#define _PRST_SHT3C_H_
|
||||
|
||||
#include <nrf_gpio.h>
|
||||
|
||||
#define PRST_SHT3C_SDA_PIN NRF_GPIO_PIN_MAP(0, 24)
|
||||
#define PRST_SHT3C_SCL_PIN NRF_GPIO_PIN_MAP(0, 13)
|
||||
|
||||
// Values from the SHTC3 datasheet.
|
||||
#define PRST_SHTC3_ADDR 0x70
|
||||
#define PRST_SHTC3_CMD_SLEEP 0xb098
|
||||
#define PRST_SHTC3_CMD_WAKEUP 0x3517
|
||||
#define PRST_SHTC3_CMD_MEASURE_TFIRST_LOW_POWER 0x609c
|
||||
#define PRST_SHTC3_CMD_MEASURE_TFIRST_NORMAL 0x7866
|
||||
|
||||
typedef struct prst_shtc3_values {
|
||||
// Temperature in degrees Celsius.
|
||||
float temp_celsius;
|
||||
// Relative humidity, from 0 to 2^16.
|
||||
uint16_t humidity;
|
||||
} prst_shtc3_read_t;
|
||||
|
||||
void prst_shtc3_init();
|
||||
prst_shtc3_read_t prst_shtc3_read();
|
||||
|
||||
#endif // _PRST_SHT3C_H_
|
||||
Loading…
Add table
Reference in a new issue