Compare commits
69 commits
code-of-co
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5214f904f1 | ||
|
|
20693143ae | ||
|
|
2e5f89b228 | ||
|
|
2dc7144de1 | ||
|
|
5f671b0170 | ||
|
|
21dd14d7f3 | ||
|
|
f8c28cebd6 | ||
|
|
8ef2b5b748 | ||
|
|
4e0f3911bd | ||
|
|
20d98d02a0 | ||
|
|
ccdbaaf142 | ||
|
|
57cf5aa0e5 | ||
|
|
e7e4b77eef | ||
|
|
dc02480da9 | ||
|
|
4796bfab5f | ||
|
|
e62521d2ae | ||
|
|
16c4d23c47 | ||
|
|
15920b1ae4 | ||
|
|
d26eab5825 | ||
|
|
c7aaf5b388 | ||
|
|
905978e8c9 | ||
|
|
4c0fe9b4c6 | ||
|
|
dd373ea235 | ||
|
|
25a5941777 | ||
|
|
37ea3a1062 | ||
|
|
d3ddd089bd | ||
|
|
28c2809b04 | ||
|
|
ad3cd4194f | ||
|
|
171a1eb4a0 | ||
|
|
5199ceaa50 | ||
|
|
7de5115705 | ||
|
|
d5ed701c45 | ||
|
|
141071a414 | ||
|
|
35618227d5 | ||
|
|
77c204397e | ||
|
|
5d2b648b22 | ||
|
|
da1642514a | ||
|
|
85ca1a67bc | ||
|
|
e68c113513 | ||
|
|
e0481994b2 | ||
|
|
9ea5c7b4d0 | ||
|
|
1a5acd02a5 | ||
|
|
8fb45f7165 | ||
|
|
9fdd15626a | ||
|
|
c70eb600a3 | ||
|
|
95ec660cb6 | ||
|
|
d84a6422fe | ||
|
|
8c21fe73d5 | ||
|
|
0a73159ce9 | ||
|
|
105016e24c | ||
|
|
bc3d834b20 | ||
|
|
37aff683ad | ||
|
|
c86f04e406 | ||
|
|
7f42dd0c00 | ||
|
|
46feb542cc | ||
|
|
62a99cc716 | ||
|
|
90f99bd5b0 | ||
|
|
5882312a77 | ||
|
|
a4a02257f9 | ||
|
|
f9f122b818 | ||
|
|
d5891f4a6f | ||
|
|
56c5fa7ba0 | ||
|
|
f6b4600044 | ||
|
|
afa53f0e94 | ||
|
|
426195184d | ||
|
|
930239e385 | ||
|
|
015ce94bbd | ||
|
|
987c4f52c0 | ||
|
|
509350457f |
47 changed files with 578 additions and 285 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "nrf-connect:v2.2",
|
||||
"image": "nordicplayground/nrfconnect-sdk:v2.2-branch",
|
||||
"name": "nrf-connect:v2.4",
|
||||
"image": "nordicplayground/nrfconnect-sdk:v2.5-branch",
|
||||
"features": {
|
||||
},
|
||||
"customizations": {
|
||||
|
|
|
|||
5
.github/actions/build/Dockerfile
vendored
5
.github/actions/build/Dockerfile
vendored
|
|
@ -1,5 +0,0 @@
|
|||
FROM nordicplayground/nrfconnect-sdk:v2.2-branch
|
||||
|
||||
COPY build.sh /build.sh
|
||||
|
||||
ENTRYPOINT ["/build.sh"]
|
||||
38
.github/actions/build/action.yml
vendored
38
.github/actions/build/action.yml
vendored
|
|
@ -1,27 +1,27 @@
|
|||
name: 'Build'
|
||||
description: 'Builds a nrf-connect sample for b-parasite'
|
||||
name: "Build"
|
||||
description: "Builds a nrf-connect sample for b-parasite"
|
||||
inputs:
|
||||
sample-dir:
|
||||
description: 'Sample directory to build'
|
||||
description: "Sample directory to build"
|
||||
required: true
|
||||
board:
|
||||
description: 'Board definition to use'
|
||||
description: "Board definition to use"
|
||||
default: bparasite_nrf52840
|
||||
revision:
|
||||
description: 'Board revision use'
|
||||
default: '1.2.0'
|
||||
description: "Board revision use"
|
||||
default: "2.0.0"
|
||||
cmake-extra:
|
||||
description: 'Extra CMake arguments'
|
||||
default: ''
|
||||
output-bin:
|
||||
description: 'Name of the .hex output'
|
||||
required: true
|
||||
description: "Extra CMake arguments"
|
||||
default: ""
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
args:
|
||||
- ${{ inputs.sample-dir }}
|
||||
- ${{ inputs.board }}
|
||||
- ${{ inputs.revision }}
|
||||
- ${{ inputs.cmake-extra }}
|
||||
- ${{ inputs.output-bin }}
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
docker run --rm -v ${GITHUB_WORKSPACE}:/repo \
|
||||
nordicplayground/nrfconnect-sdk:v2.5-branch \
|
||||
west build \
|
||||
--build-dir /repo/${{ inputs.sample-dir }}/build \
|
||||
--pristine \
|
||||
--board ${{ inputs.board }}@${{ inputs.revision }} \
|
||||
/repo/${{ inputs.sample-dir }} -- ${{ inputs.cmake-extra }}
|
||||
shell: bash
|
||||
|
|
|
|||
21
.github/actions/build/build.sh
vendored
21
.github/actions/build/build.sh
vendored
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
SAMPLE_DIR=$1
|
||||
BOARD=$2
|
||||
REVISION=$3
|
||||
CMAKE_EXTRA=$4
|
||||
OUTPUT_BIN=$5
|
||||
|
||||
TODAY=$(date +'%Y-%m-%d')
|
||||
|
||||
# Replaces occurrences of "__TODAY__" with $TODAY in $CMAKE_EXTRA.
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA/__TODAY__/"$TODAY"}"
|
||||
|
||||
cd "${GITHUB_WORKSPACE}/${SAMPLE_DIR}"
|
||||
|
||||
echo $CMAKE_EXTRA
|
||||
|
||||
west build --build-dir ./build --pristine --board "${BOARD}@${REVISION}" -- $CMAKE_EXTRA
|
||||
|
||||
mv build/zephyr/zephyr.hex build/zephyr/"${OUTPUT_BIN}"
|
||||
33
.github/actions/build_and_upload/action.yml
vendored
33
.github/actions/build_and_upload/action.yml
vendored
|
|
@ -1,33 +0,0 @@
|
|||
name: 'Build and upload artifact'
|
||||
description: 'Builds a nrf-connect sample for b-parasite'
|
||||
inputs:
|
||||
sample-dir:
|
||||
description: 'Sample directory to build'
|
||||
required: true
|
||||
board:
|
||||
description: 'Board definition to use'
|
||||
required: true
|
||||
revision:
|
||||
description: 'Board revision use'
|
||||
default: '1.2.0'
|
||||
cmake-extra:
|
||||
description: 'Extra CMake arguments'
|
||||
default: ''
|
||||
output-bin:
|
||||
description: 'Name of the .hex output'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/actions/build
|
||||
with:
|
||||
sample-dir: ${{ inputs.sample-dir }}
|
||||
board: ${{ inputs.board }}
|
||||
revision: ${{ inputs.revision }}
|
||||
cmake-extra: ${{ inputs.cmake-extra }}
|
||||
output-bin: ${{ inputs.output-bin }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sample-binaries
|
||||
path: ${{ inputs.sample-dir }}/build/zephyr/${{ inputs.output-bin }}
|
||||
18
.github/workflows/b-parasite.yml
vendored
18
.github/workflows/b-parasite.yml
vendored
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
- name: Check clang-format
|
||||
uses: jidicula/clang-format-action@v4.9.0
|
||||
with:
|
||||
check-path: 'code/nrf-connect'
|
||||
check-path: "code/nrf-connect"
|
||||
exclude-regex: '\/build\/'
|
||||
|
||||
build-blinky:
|
||||
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
- lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build blinky
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
|
|
@ -43,7 +43,7 @@ jobs:
|
|||
- lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build input
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
|
|
@ -59,7 +59,7 @@ jobs:
|
|||
- lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build soil_read_loop
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
|
|
@ -79,14 +79,14 @@ jobs:
|
|||
- lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build
|
||||
uses: ./.github/actions/build_and_upload
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
sample-dir: code/nrf-connect/samples/ble
|
||||
board: bparasite_${{ matrix.soc }}
|
||||
revision: ${{ matrix.revision }}
|
||||
cmake-extra: -DCONFIG_PRST_BLE_ENCODING_BTHOME_V2=y -DCONFIG_PRST_SLEEP_DURATION_SEC=1 -DCONFIG_PRSTLIB_LOG_LEVEL_DBG=y
|
||||
cmake-extra: -DCONFIG_PRST_BLE_ENCODING_BTHOME_V2=y -DCONFIG_PRST_SLEEP_DURATION_MSEC=1000 -DCONFIG_PRSTLIB_LOG_LEVEL_DBG=y
|
||||
output-bin: ble_${{ matrix.soc }}_${{ matrix.revision }}_debug.hex
|
||||
|
||||
build-zigbee:
|
||||
|
|
@ -100,9 +100,9 @@ jobs:
|
|||
- lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Build
|
||||
uses: ./.github/actions/build_and_upload
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
sample-dir: code/nrf-connect/samples/zigbee
|
||||
board: bparasite_${{ matrix.soc }}
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -10,7 +10,7 @@ b-parasite is an open source soil moisture and ambient temperature/humidity/ligh
|
|||
# Features
|
||||
* Capacitive Soil moisture sensor - see [this blog post](https://rbaron.net/blog/2021/04/05/How-capacitive-soil-moisture-sensors-work.html), [this Twitter thread](https://twitter.com/rbaron_/status/1367182806368071685), and [this post](https://wemakethings.net/2012/09/26/capacitance_measurement/) for nice resources on how they work
|
||||
* Air temperature and humidity sensor using a [Sensirion's SHTC3](https://www.sensirion.com/en/environmental-sensors/humidity-sensors/digital-humidity-sensor-shtc3-our-new-standard-for-consumer-electronics/)
|
||||
* Light sensor using an [ALS-PT19](https://everlighteurope.com/ambient-light-sensors/7/ALSPT19315CL177TR8.html) phototransistor
|
||||
* Light sensor using an [ALS-PT19](https://en.everlight.com/wp-content/plugins/ItemRelationship/product_files/pdf/ALS-PT19-315C-L177-TR8_V8.pdf) phototransistor
|
||||
* Powered by a common CR2032 coin cell, potentially for over two years
|
||||
* Support for [nRF52840](https://www.nordicsemi.com/products/nrf52840) and [nRF52833](https://www.nordicsemi.com/products/nrf52833) modules
|
||||
* Open hardware and open source design
|
||||
|
|
@ -20,7 +20,7 @@ This repository also hosts a few different firmware samples for b-parasite.
|
|||
|
||||
|Sample|Description|Extra Documentation|
|
||||
|---|---|---|
|
||||
|[samples/ble](./code/nrf-connect/samples/ble)|This is the most battle-tested and useful firmware. It periodically reads all sensors and broadcast them via Bluetooth Low Energy (BLE). It works with [Home Assistant](https://www.home-assistant.io/) out of the box. |[Docs](./code/nrf-connect/samples/ble/README.md)|
|
||||
|[samples/ble](./code/nrf-connect/samples/ble)|This is the most battle-tested and useful firmware. It periodically reads all sensors and broadcast them via Bluetooth Low Energy (BLE). It works with [Home Assistant](https://www.home-assistant.io/) + [BTHome](https://bthome.io/) out of the box. |[Docs](./code/nrf-connect/samples/ble/README.md)|
|
||||
|[samples/zigbee](./code/nrf-connect/samples/zigbee)| An experimental/educational/exploratory basic Zigbee sample built on [nRF Connect + ZBOSS](https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/ug_zigbee.html). It integrates with [Home Assistant](https://www.home-assistant.io/) via [ZHA](https://www.home-assistant.io/integrations/zha) or [Zigbee2MQTT](https://www.zigbee2mqtt.io/). |[Docs](./code/nrf-connect/samples/zigbee/README.md)|
|
||||
|[samples/blinky](./code/nrf-connect/samples/blinky)| The classic "Hello, world" |-|
|
||||
|[samples/soil_read_loop](./code/nrf-connect/samples/soil_read_loop)| Reads the soil moisture sensor on a loop. Useful for experimenting and calibrating the sensor. |-|
|
||||
|
|
@ -49,6 +49,12 @@ We have three different 3D-printable cases:
|
|||
1. Original snap-on case - [case/Top.stl](./case/Top.stl), [case/Bottom.stl](./case/Bottom.stl)
|
||||
2. High airflow - [case/b_parasite_case_high_airflow.stl](./case/b_parasite_case_high_airflow.stl)
|
||||
3. Mushroom-style - available on [Printables](https://www.printables.com/model/456571-mushroomcap-for-b-parasite-soil-moisture-sensor)
|
||||
4. b-parasite Hat - available on [Printables](https://www.printables.com/model/901220-waterproof-case-for-b-parasite-soil-moisture-air-s)
|
||||
|
||||
# Accessories
|
||||
|
||||
Designs and hardware to help you, when building your own:
|
||||
1. Desk holder for b-parasites [Printables](https://www.printables.com/de/model/566974-b-parasite-holder)
|
||||
|
||||
# License
|
||||
The hardware and associated design files are released under the [Creative Commons CC BY-SA 4.0 license](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -8,6 +8,10 @@ config BOARD_REVISION
|
|||
string "Board revision."
|
||||
default "1.0.0"
|
||||
|
||||
config BOARD_REVISION_CODE
|
||||
int "Board revision code. An integer representation of the board revision."
|
||||
default 1
|
||||
|
||||
config BT_CTLR
|
||||
default BT
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
&uicr {
|
||||
gpio-as-nreset;
|
||||
};
|
||||
|
||||
&gpiote {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
@ -135,7 +139,6 @@
|
|||
|
||||
|
||||
&flash0 {
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
|
|
@ -143,33 +146,23 @@
|
|||
|
||||
boot_partition: partition@0 {
|
||||
label = "mcuboot";
|
||||
reg = <0x00000000 0x0000C000>;
|
||||
reg = <0x000000000 0xC000>;
|
||||
};
|
||||
slot0_partition: partition@c000 {
|
||||
label = "image-0";
|
||||
reg = <0x0000C000 0x00067000>;
|
||||
reg = <0x0000C000 0x32000>;
|
||||
};
|
||||
slot1_partition: partition@73000 {
|
||||
slot1_partition: partition@3e000 {
|
||||
label = "image-1";
|
||||
reg = <0x00073000 0x00067000>;
|
||||
reg = <0x0003E000 0x32000>;
|
||||
};
|
||||
scratch_partition: partition@da000 {
|
||||
scratch_partition: partition@70000 {
|
||||
label = "image-scratch";
|
||||
reg = <0x000da000 0x0001e000>;
|
||||
reg = <0x00070000 0xA000>;
|
||||
};
|
||||
|
||||
/*
|
||||
* The flash starting at 0x000f8000 and ending at
|
||||
* 0x000fffff is reserved for use by the application.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Storage partition will be used by FCB/LittleFS/NVS
|
||||
* if enabled.
|
||||
*/
|
||||
storage_partition: partition@f8000 {
|
||||
storage_partition: partition@7a000 {
|
||||
label = "storage";
|
||||
reg = <0x000f8000 0x00008000>;
|
||||
reg = <0x0007A000 0x00006000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="1.1.0"
|
||||
CONFIG_BOARD_REVISION_CODE=2
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="1.2.0"
|
||||
CONFIG_BOARD_REVISION_CODE=3
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="2.0.0"
|
||||
CONFIG_BOARD_REVISION_CODE=4
|
||||
|
|
|
|||
|
|
@ -16,6 +16,4 @@ CONFIG_GPIO=y
|
|||
CONFIG_CONSOLE=y
|
||||
CONFIG_RTT_CONSOLE=y
|
||||
|
||||
CONFIG_GPIO_AS_PINRESET=y
|
||||
|
||||
CONFIG_PINCTRL=y
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ config BOARD_REVISION
|
|||
string "Board revision."
|
||||
default "1.0.0"
|
||||
|
||||
config BOARD_REVISION_CODE
|
||||
int "Board revision code. An integer representation of the board revision."
|
||||
default 1
|
||||
|
||||
config BT_CTLR
|
||||
default BT
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
&uicr {
|
||||
gpio-as-nreset;
|
||||
};
|
||||
|
||||
&gpiote {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="1.1.0"
|
||||
CONFIG_BOARD_REVISION_CODE=2
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="1.2.0"
|
||||
CONFIG_BOARD_REVISION_CODE=3
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
CONFIG_BOARD_REVISION="2.0.0"
|
||||
CONFIG_BOARD_REVISION_CODE=4
|
||||
|
|
|
|||
|
|
@ -16,6 +16,4 @@ CONFIG_GPIO=y
|
|||
CONFIG_CONSOLE=y
|
||||
CONFIG_RTT_CONSOLE=y
|
||||
|
||||
CONFIG_GPIO_AS_PINRESET=y
|
||||
|
||||
CONFIG_PINCTRL=y
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ static int read_adc_spec(const struct adc_dt_spec* spec, prst_adc_read_t* out) {
|
|||
|
||||
int32_t val_mv = buf;
|
||||
RET_IF_ERR(adc_raw_to_millivolts_dt(spec, &val_mv));
|
||||
val_mv = MAX(0, val_mv);
|
||||
|
||||
out->raw = buf;
|
||||
out->millivolts = val_mv;
|
||||
|
|
|
|||
|
|
@ -16,10 +16,9 @@ int prst_sensors_read_all(prst_sensors_t *sensors) {
|
|||
|
||||
LOG_DBG("Batt: %d mV (%.2f%%)", sensors->batt.adc_read.millivolts,
|
||||
100 * sensors->batt.percentage);
|
||||
LOG_DBG("Soil: %.0f %% (%d mV)", 100 * sensors->soil.percentage,
|
||||
sensors->soil.adc_read.millivolts);
|
||||
LOG_DBG("Soil: %.0f %%", 100 * sensors->soil.percentage);
|
||||
LOG_DBG("Photo: %u lx (%d mV)", sensors->photo.brightness,
|
||||
sensors->soil.adc_read.millivolts);
|
||||
sensors->photo.adc_read.millivolts);
|
||||
LOG_DBG("Temp: %f oC", sensors->shtc3.temp_c);
|
||||
LOG_DBG("Humi: %.0f %%", 100 * sensors->shtc3.rel_humi);
|
||||
LOG_DBG("--------------------------------------------------");
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@ int prst_shtc3_read(prst_shtc3_read_t *out) {
|
|||
|
||||
// Reading in normal (not low power) mode can take up to 12.1 ms, according to
|
||||
// the datasheet.
|
||||
k_msleep(15);
|
||||
k_msleep(20);
|
||||
|
||||
while (i2c_read_dt(&shtc3, buff, 6) != 0) {
|
||||
k_msleep(10);
|
||||
}
|
||||
// Read response.
|
||||
RET_IF_ERR(i2c_read_dt(&shtc3, buff, 6));
|
||||
|
||||
// Put the sensor in sleep mode.
|
||||
RET_IF_ERR(write_cmd(PRST_SHTC3_CMD_SLEEP));
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
source "Kconfig.zephyr"
|
||||
rsource "../../prstlib/Kconfig"
|
||||
|
||||
config PRST_SLEEP_DURATION_SEC
|
||||
int "Sleep duration in seconds"
|
||||
default 600
|
||||
config PRST_SLEEP_DURATION_MSEC
|
||||
int "Sleep duration in milliseconds"
|
||||
default 600000
|
||||
|
||||
config PRST_BLE_ADV_DURATION_SEC
|
||||
int "Advertising duration in seconds"
|
||||
default 1
|
||||
config PRST_BLE_ADV_DURATION_MSEC
|
||||
int "Advertising duration in milliseconds"
|
||||
default 1000
|
||||
|
||||
config PRST_BLE_MIN_ADV_INTERVAL
|
||||
int "Minimum advertising interval in milliseconds"
|
||||
|
|
@ -20,7 +20,7 @@ config PRST_BLE_MAX_ADV_INTERVAL
|
|||
|
||||
choice PRST_BLE_ENCODING
|
||||
prompt "b-parasite BLE encoding"
|
||||
default PRST_BLE_ENCODING_BPARASITE_V2
|
||||
default PRST_BLE_ENCODING_BTHOME_V2
|
||||
|
||||
config PRST_BLE_ENCODING_BPARASITE_V2
|
||||
bool "Uses the custom b-parasite protocol v2 for encoding advertising packets"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Bluetooth Low Energy (BLE)
|
||||
In this saple, b-parasite sensors are periodically read and broadcast using Bluetooth Low Energy (BLE) dvertising packets.
|
||||
In this sample, b-parasite sensors are periodically read and broadcast using Bluetooth Low Energy (BLE) dvertising packets.
|
||||
|
||||
## Configuration
|
||||
Available configurations and their default values are in [`Kconfig`](./Kconfig). They are set in [`prj.conf`](./prj.conf). Here are some notable examples.
|
||||
|
|
@ -8,7 +8,7 @@ Available configurations and their default values are in [`Kconfig`](./Kconfig).
|
|||
To save energy, the board spends most of the time in a "deep sleep" state, in which most peripherals and radio are completely turned off. The period of sleep is controlled by the `PRST_SLEEP_DURATION_SEC` config.
|
||||
|
||||
### Advertising Duration
|
||||
When it wakes up, the sample reads all sensors and keep broadcasting advertising packets for `PRST_BLE_ADV_DURATION_SEC` before going back to sleep.
|
||||
When it wakes up, the sample reads all sensors and keep broadcasting advertising packets for `PRST_BLE_ADV_DURATION_MSEC` before going back to sleep.
|
||||
|
||||
### Advertising Packet Encoding
|
||||
There are different ways to encode the sensor data in a BLE advertising packet.
|
||||
|
|
@ -22,11 +22,10 @@ This is what a typical deployment with BTHome looks like:
|
|||

|
||||
|
||||
There are two versions of BTHome encodings supported by this sample:
|
||||
* `PRST_BLE_ENCODING_BTHOME_V2=y` (**default**) uses the [BTHome V2](https://bthome.io/format/), supported by Home Assistant since version `2022.12`
|
||||
* `PRST_BLE_ENCODING_BTHOME_V1=y` uses the [legacy BTHome V1](https://bthome.io/v1/), which was briefly in use
|
||||
* `PRST_BLE_ENCODING_BTHOME_V2=y` uses the [BTHome V2](https://bthome.io/format/), which is not yet (as of early Dec/2022) in the stable Home Assistant release. This will soon become the default.
|
||||
|
||||
#### b-parasite Encoding
|
||||
`PRST_BLE_ENCODING_BPARASITE_V2=y` selects the "legacy" encoding, used historically inn this project. This is the encoding that the [`b_parasite`](https://esphome.io/components/sensor/b_parasite.html) ESPHome component understands.
|
||||
`PRST_BLE_ENCODING_BPARASITE_V2=y` selects the legacy encoding, used historically in this project. This is the encoding that the [`b_parasite`](https://esphome.io/components/sensor/b_parasite.html) ESPHome component understands.
|
||||
|
||||
With this encoding and a ESPHome + `b_parasite` component, this is an usual deployment topology:
|
||||
|
||||
|
|
@ -53,4 +52,4 @@ If for example we lower the connection interval to the SDK defaults (`[100, 150]
|
|||
|
||||

|
||||
|
||||
With a `200 mAh` CR2032 battery, we can use [this spreadsheet](https://docs.google.com/spreadsheets/d/157JQiX20bGkTrlbvWbWRrs_WViL3MgVZffSCWRR7uAI/edit#gid=0) to estimate the battery life to over two years. Note that this is a simplified model and results in practice may vary.
|
||||
With a `200 mAh` CR2032 battery, we can use [this spreadsheet](https://docs.google.com/spreadsheets/d/157JQiX20bGkTrlbvWbWRrs_WViL3MgVZffSCWRR7uAI/edit#gid=0) to estimate the battery life to over two years. Note that this is a simplified model and results in practice may vary.
|
||||
|
|
|
|||
|
|
@ -11,17 +11,17 @@ CONFIG_BT_DEVICE_NAME="prst"
|
|||
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
|
||||
|
||||
CONFIG_SERIAL=n
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
|
||||
|
||||
CONFIG_ASSERT=y
|
||||
|
||||
# Application config - see all options in Kconfig.
|
||||
# CONFIG_PRST_BLE_ENCODING_BTHOME_V2=y
|
||||
# CONFIG_PRST_SLEEP_DURATION_SEC=1
|
||||
# CONFIG_PRST_SLEEP_DURATION_MSEC=1000
|
||||
|
||||
# prstlib config - ser all options in prstlib/Kconfig.
|
||||
# CONFIG_PRSTLIB_LOG_LEVEL_DBG=y
|
||||
|
|
|
|||
|
|
@ -104,33 +104,36 @@ int prst_ble_encode_service_data(const prst_sensors_t* sensors,
|
|||
out[4] = temp_val & 0xff;
|
||||
out[5] = temp_val >> 8;
|
||||
// Humidity.
|
||||
out[6] = 0x03;
|
||||
// Value. Factor 0.01, over 100%.
|
||||
uint16_t humi_val = 10000 * sensors->shtc3.rel_humi;
|
||||
out[7] = humi_val & 0xff;
|
||||
out[8] = humi_val >> 8;
|
||||
out[6] = 0x2E;
|
||||
// Value. Factor 1 over 100%.
|
||||
uint8_t humi_val = 100 * sensors->shtc3.rel_humi + 0.5f;
|
||||
out[7] = humi_val;
|
||||
// Illuminance.
|
||||
out[9] = 0x05;
|
||||
out[8] = 0x05;
|
||||
// Value. Factor of 0.01.
|
||||
uint32_t lux_val = sensors->photo.brightness * 100;
|
||||
out[10] = lux_val & 0xff;
|
||||
out[11] = (lux_val >> 8) & 0xff;
|
||||
out[12] = (lux_val >> 16) & 0xff;
|
||||
out[9] = lux_val & 0xff;
|
||||
out[10] = (lux_val >> 8) & 0xff;
|
||||
out[11] = (lux_val >> 16) & 0xff;
|
||||
// Battery voltage.
|
||||
out[13] = 0x0c;
|
||||
out[12] = 0x0c;
|
||||
// Value. Factor of 0.001.
|
||||
uint16_t batt_val = sensors->batt.adc_read.millivolts;
|
||||
out[14] = batt_val & 0xff;
|
||||
out[15] = batt_val >> 8;
|
||||
out[13] = batt_val & 0xff;
|
||||
out[14] = batt_val >> 8;
|
||||
// Soil moisture.
|
||||
out[16] = 0x14;
|
||||
// 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.percentage;
|
||||
out[17] = soil_val & 0xff;
|
||||
out[18] = soil_val >> 8;
|
||||
out[15] = 0x2F;
|
||||
// Factor of 1 over 100%
|
||||
uint8_t soil_val = 100 * sensors->soil.percentage + 0.5f;
|
||||
out[16] = soil_val;
|
||||
// Battery percentage.
|
||||
out[17] = 0x01;
|
||||
// Value. Factor 1 over 100%
|
||||
uint8_t batt_percentage_val = 100 * sensors->batt.percentage + 0.5f;
|
||||
out[18] = batt_percentage_val;
|
||||
|
||||
#endif // Encoding protocols
|
||||
|
||||
LOG_HEXDUMP_DBG(out, out_len, "Encoded BLE adv: ");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,25 +14,29 @@
|
|||
|
||||
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
|
||||
|
||||
int main(void) {
|
||||
static int prst_init() {
|
||||
RET_IF_ERR(prst_adc_init());
|
||||
RET_IF_ERR(prst_led_init());
|
||||
RET_IF_ERR(prst_button_init());
|
||||
RET_IF_ERR(prst_ble_init());
|
||||
return 0;
|
||||
}
|
||||
|
||||
RET_IF_ERR(prst_led_flash(2));
|
||||
static int prst_loop(prst_sensors_t *sensors) {
|
||||
RET_IF_ERR(prst_sensors_read_all(sensors));
|
||||
RET_IF_ERR(prst_ble_adv_set_data(sensors));
|
||||
RET_IF_ERR(prst_ble_adv_start());
|
||||
k_msleep(CONFIG_PRST_BLE_ADV_DURATION_MSEC);
|
||||
RET_IF_ERR(prst_ble_adv_stop());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
__ASSERT(!prst_init(), "Error in prst_init()");
|
||||
prst_led_flash(2);
|
||||
prst_sensors_t sensors;
|
||||
while (true) {
|
||||
RET_IF_ERR(prst_sensors_read_all(&sensors));
|
||||
|
||||
RET_IF_ERR(prst_ble_adv_set_data(&sensors));
|
||||
RET_IF_ERR(prst_ble_adv_start());
|
||||
|
||||
k_sleep(K_SECONDS(CONFIG_PRST_BLE_ADV_DURATION_SEC));
|
||||
|
||||
RET_IF_ERR(prst_ble_adv_stop());
|
||||
|
||||
k_sleep(K_SECONDS(CONFIG_PRST_SLEEP_DURATION_SEC));
|
||||
__ASSERT(!prst_loop(&sensors), "Error in prst_loop()");
|
||||
k_msleep(CONFIG_PRST_SLEEP_DURATION_MSEC);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ CONFIG_GPIO=y
|
|||
CONFIG_CBPRINTF_FP_SUPPORT=y
|
||||
|
||||
CONFIG_SERIAL=n
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,4 @@ CONFIG_PWM_LOG_LEVEL_DBG=y
|
|||
CONFIG_CBPRINTF_FP_SUPPORT=y
|
||||
CONFIG_ADC=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
|
|
|
|||
|
|
@ -12,11 +12,14 @@ include_directories(src)
|
|||
|
||||
target_sources(app PRIVATE
|
||||
src/main.c
|
||||
src/debug_counters.c
|
||||
src/double_reset_detector.c
|
||||
src/factory_reset.c
|
||||
src/flash_fs.c
|
||||
src/prst_zb_attrs.c
|
||||
src/prst_zb_soil_moisture_defs.c
|
||||
src/restart_handler.c
|
||||
src/watchdog.c
|
||||
)
|
||||
|
||||
add_subdirectory(../../prstlib prstlib)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ config PRST_ZB_SLEEP_DURATION_SEC
|
|||
|
||||
config PRST_ZB_PARENT_POLL_INTERVAL_SEC
|
||||
int "Interval for when b-parasite polls its parent for data in seconds."
|
||||
default 60
|
||||
default 10
|
||||
|
||||
config PRST_ZB_BUILD_DATE
|
||||
string "Zigbee basic cluster build date attribute. Max 16 bytes."
|
||||
|
|
@ -19,11 +19,11 @@ config PRST_ZB_MODEL_ID
|
|||
|
||||
config PRST_ZB_HARDWARE_VERSION
|
||||
int "Zigbee basic cluster hardware version attribute. 1 byte."
|
||||
default 2
|
||||
default BOARD_REVISION_CODE
|
||||
|
||||
choice PRST_ZB_FACTORY_RESET_METHOD
|
||||
bool "Factory reset method"
|
||||
default PRST_ZB_FACTORY_RESET_VIA_DOUBLE_RESET
|
||||
default PRST_ZB_FACTORY_RESET_VIA_SW1
|
||||
|
||||
config PRST_ZB_FACTORY_RESET_VIA_DOUBLE_RESET
|
||||
bool "Double resetting factory resets the device."
|
||||
|
|
@ -31,6 +31,12 @@ config PRST_ZB_FACTORY_RESET_VIA_DOUBLE_RESET
|
|||
config PRST_ZB_FACTORY_RESET_VIA_RESET_PIN
|
||||
bool "Resetting via the reset pin will factory reset the device. Power cycling through battery replacement will not."
|
||||
|
||||
config PRST_ZB_FACTORY_RESET_VIA_SW1
|
||||
bool "Resetting while pressing and holding SW1 for 5 seconds will factory reset the device. Only available on v2.0.0+ hardware revisions."
|
||||
|
||||
config PRST_ZB_FACTORY_RESET_DISABLED
|
||||
bool "No factory reset procedure."
|
||||
|
||||
endchoice # PRST_ZB_FACTORY_RESET_METHOD
|
||||
|
||||
config PRST_ZB_RESTART_WATCHDOG_TIMEOUT_SEC
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ CONFIG_I2C=y
|
|||
CONFIG_ADC=y
|
||||
CONFIG_GPIO=y
|
||||
|
||||
CONFIG_PM=y
|
||||
CONFIG_PM_DEVICE=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
|
||||
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
|
||||
|
|
@ -36,8 +36,17 @@ CONFIG_NET_IPV6_RA_RDNSS=n
|
|||
CONFIG_NET_IP_ADDR_CHECK=n
|
||||
CONFIG_NET_UDP=n
|
||||
|
||||
##
|
||||
## ZigBee Channel Selection
|
||||
##
|
||||
# Get Zigbee to scan every channel.
|
||||
CONFIG_ZIGBEE_CHANNEL_SELECTION_MODE_MULTI=y
|
||||
# By default only scans channel 11 (ZigBee2MQTT default) and 15 (ZHA default).
|
||||
# Comment to scan all channels - this will make pairing consume more energy.
|
||||
# CONFIG_ZIGBEE_CHANNEL_MASK=0x8800
|
||||
|
||||
# Uncomment to set a specific channel - this will make pairing more energy efficient.
|
||||
# CONFIG_ZIGBEE_CHANNEL=11
|
||||
|
||||
# Enable API for powering down unused RAM parts.
|
||||
# https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.7.1/nrf/ug_zigbee_configuring.html#power-saving-during-sleep
|
||||
|
|
@ -49,4 +58,15 @@ CONFIG_FLASH=y
|
|||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FILE_SYSTEM=y
|
||||
CONFIG_FILE_SYSTEM_LITTLEFS=y
|
||||
CONFIG_FILE_SYSTEM_LITTLEFS=y
|
||||
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_HWINFO=y
|
||||
CONFIG_ASSERT=y
|
||||
|
||||
# Uncomment for debug log level.
|
||||
# CONFIG_LOG_DEFAULT_LEVEL=4
|
||||
|
||||
# Factory reset method selection. Only hardware revision 2.0.0+ has button SW1. Earlier
|
||||
# revisions must select a different method. See Kconfig for options.
|
||||
# CONFIG_PRST_ZB_FACTORY_RESET_VIA_SW1=y
|
||||
|
|
|
|||
106
code/nrf-connect/samples/zigbee/src/debug_counters.c
Normal file
106
code/nrf-connect/samples/zigbee/src/debug_counters.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "debug_counters.h"
|
||||
|
||||
#include <prstlib/macros.h>
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(debug_counters, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
static const char kDebugCountersDir[] = "/lfs/debug_counters";
|
||||
|
||||
#define PRST_MAX_COUNTER_NAME_LENGTH 64
|
||||
#define PRST_MAX_FILE_NAME_LENGTH (sizeof(kDebugCountersDir) + 1 + PRST_MAX_COUNTER_NAME_LENGTH)
|
||||
|
||||
static int mk_filename(const char* counter_name, char* buff, size_t buff_size) {
|
||||
RET_CHECK(strlen(counter_name) <= PRST_MAX_COUNTER_NAME_LENGTH, "Counter name too long");
|
||||
strcpy(buff, kDebugCountersDir);
|
||||
strcat(buff, "/");
|
||||
strcat(buff, counter_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_counter_file(struct fs_file_t* file, prst_debug_counter_t* value) {
|
||||
int n_read = fs_read(file, value, sizeof(prst_debug_counter_t));
|
||||
if (n_read != sizeof(prst_debug_counter_t)) {
|
||||
LOG_WRN("fs_read returned %d, expected %d, assuming first access", n_read, sizeof(prst_debug_counter_t));
|
||||
*value = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prst_debug_counters_init() {
|
||||
struct fs_dirent entry;
|
||||
int err = fs_stat(kDebugCountersDir, &entry);
|
||||
if (err == 0) {
|
||||
LOG_DBG("Directory %s already exists", kDebugCountersDir);
|
||||
return 0;
|
||||
} else if (err == -ENOENT) {
|
||||
LOG_DBG("Creating directory %s", kDebugCountersDir);
|
||||
return fs_mkdir(kDebugCountersDir);
|
||||
}
|
||||
LOG_ERR("Unexpected error in fs_stat for %s: %d", kDebugCountersDir, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
int prst_debug_counters_increment(const char* counter_name) {
|
||||
char filename[PRST_MAX_FILE_NAME_LENGTH];
|
||||
RET_IF_ERR(mk_filename(counter_name, filename, sizeof(filename)));
|
||||
|
||||
LOG_DBG("Incrementing counter %s", filename);
|
||||
|
||||
// Open the file.
|
||||
struct fs_file_t file;
|
||||
fs_file_t_init(&file);
|
||||
RET_IF_ERR(fs_open(&file, filename, FS_O_CREATE | FS_O_RDWR));
|
||||
// Read the current value.
|
||||
prst_debug_counter_t value;
|
||||
RET_IF_ERR(read_counter_file(&file, &value));
|
||||
// Increment the value.
|
||||
value++;
|
||||
// Write back to file.
|
||||
RET_CHECK(fs_seek(&file, 0, SEEK_SET) == 0, "Unable to seek");
|
||||
ssize_t written = fs_write(&file, &value, sizeof(value));
|
||||
if (written != sizeof(value)) {
|
||||
LOG_ERR("fs_write returned %d, expected %d", written, sizeof(value));
|
||||
}
|
||||
RET_IF_ERR(fs_sync(&file));
|
||||
return fs_close(&file);
|
||||
}
|
||||
|
||||
int prst_debug_counters_get(const char* counter_name, prst_debug_counter_t* value) {
|
||||
char filename[PRST_MAX_FILE_NAME_LENGTH];
|
||||
RET_IF_ERR(mk_filename(counter_name, filename, sizeof(filename)));
|
||||
|
||||
LOG_DBG("Getting counter %s", filename);
|
||||
|
||||
// Open the file.
|
||||
struct fs_file_t file;
|
||||
fs_file_t_init(&file);
|
||||
RET_IF_ERR(fs_open(&file, filename, FS_O_CREATE | FS_O_READ));
|
||||
// Read the current value.
|
||||
RET_IF_ERR(read_counter_file(&file, value));
|
||||
return fs_close(&file);
|
||||
}
|
||||
|
||||
int prst_debug_counters_get_all(prst_debug_counters_callback_t callback) {
|
||||
LOG_DBG("Getting all counters from %s", kDebugCountersDir);
|
||||
|
||||
struct fs_dir_t dirp;
|
||||
fs_dir_t_init(&dirp);
|
||||
static struct fs_dirent entry;
|
||||
RET_IF_ERR(fs_opendir(&dirp, kDebugCountersDir));
|
||||
prst_debug_counter_t value;
|
||||
for (;;) {
|
||||
RET_IF_ERR(fs_readdir(&dirp, &entry));
|
||||
// End of directory;
|
||||
if (entry.name[0] == 0) {
|
||||
break;
|
||||
}
|
||||
LOG_DBG("Found %s", entry.name);
|
||||
prst_debug_counters_get(entry.name, &value);
|
||||
callback(entry.name, value);
|
||||
}
|
||||
return fs_closedir(&dirp);
|
||||
}
|
||||
18
code/nrf-connect/samples/zigbee/src/debug_counters.h
Normal file
18
code/nrf-connect/samples/zigbee/src/debug_counters.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _PRST_DEBUG_COUNTERS_H_
|
||||
#define _PRST_DEBUG_COUNTERS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint32_t prst_debug_counter_t;
|
||||
|
||||
typedef void (*prst_debug_counters_callback_t)(const char* counter_name, prst_debug_counter_t value);
|
||||
|
||||
int prst_debug_counters_init();
|
||||
|
||||
int prst_debug_counters_increment(const char* counter_name);
|
||||
|
||||
int prst_debug_counters_get(const char* counter_name, prst_debug_counter_t* value);
|
||||
|
||||
int prst_debug_counters_get_all(prst_debug_counters_callback_t callback);
|
||||
|
||||
#endif // _PRST_DEBUG_COUNTERS_H_
|
||||
|
|
@ -7,17 +7,10 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "debug_counters.h"
|
||||
|
||||
LOG_MODULE_REGISTER(double_reset_detector, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
|
||||
|
||||
static struct fs_mount_t lfs_storage_mnt = {
|
||||
.type = FS_LITTLEFS,
|
||||
.fs_data = &storage,
|
||||
.storage_dev = (void *)FLASH_AREA_ID(storage),
|
||||
.mnt_point = "/lfs",
|
||||
};
|
||||
|
||||
static const char *flag_filename = "/lfs/reset_flag";
|
||||
|
||||
static const char flag_prefix[] = "prst-rst-count";
|
||||
|
|
@ -38,12 +31,6 @@ void erase_flag_callback(struct k_work *work) {
|
|||
K_WORK_DELAYABLE_DEFINE(erase_flag_work, erase_flag_callback);
|
||||
|
||||
int prst_detect_double_reset(prst_double_reset_callback_t on_double_reset) {
|
||||
// TODO: if booting for the first time after a full flash erase, fs_mount will
|
||||
// complain (via a LOG_ERR) and then automatically format the flash. It all works,
|
||||
// but avoiding a scary red message would be ideal. Maybe somehow check if it's
|
||||
// formatted before mounting?
|
||||
RET_IF_ERR(fs_mount(&lfs_storage_mnt));
|
||||
|
||||
fs_file_t_init(&flag_file);
|
||||
|
||||
RET_IF_ERR(fs_open(&flag_file, flag_filename, FS_O_CREATE | FS_O_RDWR));
|
||||
|
|
@ -55,6 +42,7 @@ int prst_detect_double_reset(prst_double_reset_callback_t on_double_reset) {
|
|||
if (strcmp(buff, flag_prefix) == 0) {
|
||||
RET_IF_ERR(fs_close(&flag_file));
|
||||
RET_IF_ERR(erase_flag());
|
||||
prst_debug_counters_increment("double_reset");
|
||||
return on_double_reset();
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +52,7 @@ int prst_detect_double_reset(prst_double_reset_callback_t on_double_reset) {
|
|||
// Write the flag and erase it after some time.
|
||||
ssize_t written = fs_write(&flag_file, flag_prefix, sizeof(flag_prefix));
|
||||
if (written != sizeof(flag_prefix)) {
|
||||
LOG_ERR("s_write returned %d, expected %d", written, sizeof(flag_prefix));
|
||||
LOG_ERR("fs_write returned %d, expected %d", written, sizeof(flag_prefix));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "factory_reset.h"
|
||||
|
||||
#include <hal/nrf_power.h>
|
||||
#include <prstlib/button.h>
|
||||
#include <prstlib/led.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
|
|
@ -10,8 +11,8 @@
|
|||
LOG_MODULE_REGISTER(factory_reset, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
static int factory_reset() {
|
||||
// TODO: consider zb_bdb_reset_via_local_action(/*param=*/0);
|
||||
zigbee_erase_persistent_storage(/*erase=*/true);
|
||||
LOG_WRN("Factory resetting device");
|
||||
zb_bdb_reset_via_local_action(/*param=*/0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -37,10 +38,38 @@ static int factory_reset_if_reset_via_reset_pin() {
|
|||
}
|
||||
#endif // CONFIG_PRST_ZB_FACTORY_RESET_VIA_RESET_PIN
|
||||
|
||||
#if CONFIG_PRST_ZB_FACTORY_RESET_VIA_SW1
|
||||
static void timer_do_reset(zb_uint8_t unused_param) {
|
||||
LOG_WRN("SW1 button was pressed for 5 seconds, factory resetting device");
|
||||
prst_led_flash(/*times=*/5);
|
||||
factory_reset();
|
||||
}
|
||||
|
||||
static void sw1_factory_reset_check_timer_cb(struct k_timer *timer_id) {
|
||||
if (!prst_button_poll(PRST_BUTTON_SW1)) {
|
||||
LOG_DBG("SW1 button was released, will not factory reset device");
|
||||
return;
|
||||
}
|
||||
ZB_SCHEDULE_APP_CALLBACK(timer_do_reset, /*param=*/0);
|
||||
}
|
||||
|
||||
K_TIMER_DEFINE(sw1_factory_reset_check_timer, sw1_factory_reset_check_timer_cb, NULL);
|
||||
#endif
|
||||
|
||||
int prst_zb_factory_reset_check() {
|
||||
#if CONFIG_PRST_ZB_FACTORY_RESET_VIA_DOUBLE_RESET
|
||||
return prst_detect_double_reset(double_reset_handler);
|
||||
#elif CONFIG_PRST_ZB_FACTORY_RESET_VIA_RESET_PIN
|
||||
return factory_reset_if_reset_via_reset_pin();
|
||||
#elif CONFIG_PRST_ZB_FACTORY_RESET_VIA_SW1
|
||||
if (prst_button_poll(PRST_BUTTON_SW1)) {
|
||||
LOG_DBG("SW1 pressed. Scheduling timer");
|
||||
k_timer_start(&sw1_factory_reset_check_timer, K_SECONDS(5), K_NO_WAIT);
|
||||
}
|
||||
return 0;
|
||||
#elif CONFIG_PRST_ZB_FACTORY_RESET_DISABLED
|
||||
return 0;
|
||||
#else
|
||||
#error "No factory reset method selected -- explicitly select CONFIG_PRST_ZB_FACTORY_RESET_DISABLED=y to disable it"
|
||||
#endif // CONFIG_PRST_ZB_FACTORY_RESET_VIA_RESET_PIN
|
||||
}
|
||||
26
code/nrf-connect/samples/zigbee/src/flash_fs.c
Normal file
26
code/nrf-connect/samples/zigbee/src/flash_fs.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "flash_fs.h"
|
||||
|
||||
#include <prstlib/macros.h>
|
||||
#include <zephyr/fs/fs.h>
|
||||
#include <zephyr/fs/littlefs.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(flash_fs, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
|
||||
|
||||
static struct fs_mount_t lfs_storage_mnt = {
|
||||
.type = FS_LITTLEFS,
|
||||
.fs_data = &storage,
|
||||
.storage_dev = (void *)FIXED_PARTITION_ID(storage_partition),
|
||||
.mnt_point = "/lfs",
|
||||
};
|
||||
|
||||
int prst_flash_fs_init() {
|
||||
// TODO: if booting for the first time after a full flash erase, fs_mount will
|
||||
// complain (via a LOG_ERR) and then automatically format the flash. It all works,
|
||||
// but avoiding a scary red message would be ideal. Maybe somehow check if it's
|
||||
// formatted before mounting?
|
||||
RET_IF_ERR(fs_mount(&lfs_storage_mnt));
|
||||
return 0;
|
||||
}
|
||||
9
code/nrf-connect/samples/zigbee/src/flash_fs.h
Normal file
9
code/nrf-connect/samples/zigbee/src/flash_fs.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _PRST_FLASH_FS_H_
|
||||
#define _PRST_FLASH_FS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// Initializes and mounts littlefs.
|
||||
int prst_flash_fs_init();
|
||||
|
||||
#endif // _PRST_FLASH_FS_H_
|
||||
|
|
@ -10,16 +10,20 @@
|
|||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
#include <zcl/zb_zcl_power_config.h>
|
||||
#include <zephyr/drivers/hwinfo.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
#include <zigbee/zigbee_error_handler.h>
|
||||
|
||||
#include "debug_counters.h"
|
||||
#include "factory_reset.h"
|
||||
#include "flash_fs.h"
|
||||
#include "prst_zb_attrs.h"
|
||||
#include "prst_zb_endpoint_defs.h"
|
||||
#include "prst_zb_soil_moisture_defs.h"
|
||||
#include "restart_handler.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
LOG_MODULE_REGISTER(app, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
|
|
@ -120,84 +124,28 @@ void identify_cb(zb_bufid_t bufid) {
|
|||
prst_led_flash(15);
|
||||
}
|
||||
|
||||
void zboss_signal_handler(zb_bufid_t bufid) {
|
||||
// See zigbee_default_signal_handler() for all available signals.
|
||||
zb_zdo_app_signal_hdr_t *sig_hndler = NULL;
|
||||
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, /*sg_p=*/&sig_hndler);
|
||||
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
|
||||
switch (sig) {
|
||||
case ZB_BDB_SIGNAL_STEERING: // New network.
|
||||
case ZB_BDB_SIGNAL_DEVICE_REBOOT: { // Previously joined network.
|
||||
LOG_DBG("Steering complete. Status: %d", status);
|
||||
if (status == RET_OK) {
|
||||
LOG_DBG("Steering successful. Status: %d", status);
|
||||
prst_led_flash(/*times=*/3);
|
||||
k_timer_stop(&led_flashing_timer);
|
||||
prst_restart_watchdog_stop();
|
||||
prst_led_off();
|
||||
} else {
|
||||
LOG_DBG("Steering failed. Status: %d", status);
|
||||
prst_led_flash(7);
|
||||
prst_restart_watchdog_start();
|
||||
k_timer_stop(&led_flashing_timer); // Power saving
|
||||
prst_led_off();
|
||||
}
|
||||
}
|
||||
case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
|
||||
joining_signal_received = true;
|
||||
break;
|
||||
case ZB_ZDO_SIGNAL_LEAVE:
|
||||
if (status == RET_OK) {
|
||||
k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1));
|
||||
zb_zdo_signal_leave_params_t *leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_leave_params_t);
|
||||
LOG_INF("Network left (leave type: %d)", leave_params->leave_type);
|
||||
|
||||
/* Set joining_signal_received to false so broken rejoin procedure can be detected correctly. */
|
||||
if (leave_params->leave_type == ZB_NWK_LEAVE_TYPE_REJOIN) {
|
||||
joining_signal_received = false;
|
||||
}
|
||||
}
|
||||
case ZB_ZDO_SIGNAL_SKIP_STARTUP: {
|
||||
stack_initialised = true;
|
||||
LOG_DBG("Started zigbee stack and waiting for connection to network.");
|
||||
k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1));
|
||||
break;
|
||||
}
|
||||
case ZB_NLME_STATUS_INDICATION: {
|
||||
zb_zdo_signal_nlme_status_indication_params_t *nlme_status_ind =
|
||||
ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_nlme_status_indication_params_t);
|
||||
if (nlme_status_ind->nlme_status.status == ZB_NWK_COMMAND_STATUS_PARENT_LINK_FAILURE) {
|
||||
/* Check for broken rejoin procedure and restart the device to recover.
|
||||
This implements Nordic's suggested workaround for errata KRKNWK-12017, which effects
|
||||
the recent nRF Connect SDK (v1.8.0 - v2.3.0 at time of writing).
|
||||
For details see: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/known_issues.html?v=v2-3-0
|
||||
*/
|
||||
if (stack_initialised && !joining_signal_received) {
|
||||
zb_reset(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
|
||||
if (bufid) {
|
||||
zb_buf_free(bufid);
|
||||
}
|
||||
}
|
||||
|
||||
void update_sensors_cb(zb_uint8_t arg) {
|
||||
LOG_INF("Updating sensors");
|
||||
LOG_DBG("Updating sensors");
|
||||
|
||||
ZB_SCHEDULE_APP_ALARM(update_sensors_cb,
|
||||
/*param=*/0,
|
||||
ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_SLEEP_DURATION_SEC);
|
||||
|
||||
if (prst_sensors_read_all(&sensors)) {
|
||||
LOG_ERR("Unable to read sensors");
|
||||
return;
|
||||
// Reschedule the same callback.
|
||||
zb_ret_t ret = ZB_SCHEDULE_APP_ALARM(
|
||||
update_sensors_cb,
|
||||
/*param=*/0,
|
||||
ZB_MILLISECONDS_TO_BEACON_INTERVAL(1000 * CONFIG_PRST_ZB_SLEEP_DURATION_SEC));
|
||||
if (ret != RET_OK) {
|
||||
prst_debug_counters_increment("sens_cb_schedule_err");
|
||||
__ASSERT(false, "Unable to schedule sensor update callback");
|
||||
}
|
||||
|
||||
__ASSERT(!prst_watchdog_feed(), "Failed to feed watchdog");
|
||||
|
||||
prst_debug_counters_increment("sensors_read_before");
|
||||
if (prst_sensors_read_all(&sensors)) {
|
||||
prst_debug_counters_increment("sensors_read_error");
|
||||
__ASSERT(false, "Unable to read sensors");
|
||||
}
|
||||
prst_debug_counters_increment("sensors_read_after");
|
||||
|
||||
// Battery voltage in units of 100 mV.
|
||||
uint8_t batt_voltage = sensors.batt.adc_read.millivolts / 100;
|
||||
prst_zb_set_attr_value(ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
|
||||
|
|
@ -235,30 +183,149 @@ void update_sensors_cb(zb_uint8_t arg) {
|
|||
&log_lux);
|
||||
}
|
||||
|
||||
void zboss_signal_handler(zb_bufid_t bufid) {
|
||||
// See zigbee_default_signal_handler() for all available signals.
|
||||
zb_zdo_app_signal_hdr_t *sig_hndler = NULL;
|
||||
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, /*sg_p=*/&sig_hndler);
|
||||
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
|
||||
switch (sig) {
|
||||
case ZB_BDB_SIGNAL_STEERING: // New network.
|
||||
case ZB_BDB_SIGNAL_DEVICE_REBOOT: { // Previously joined network.
|
||||
LOG_DBG("Steering complete. Status: %d", status);
|
||||
if (status == RET_OK) {
|
||||
LOG_DBG("Steering successful. Status: %d", status);
|
||||
k_timer_stop(&led_flashing_timer);
|
||||
prst_led_off();
|
||||
prst_restart_watchdog_stop();
|
||||
// Update the long polling parent interval - needs to be done after joining.
|
||||
zb_zdo_pim_set_long_poll_interval(1000 * CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC);
|
||||
} else {
|
||||
LOG_DBG("Steering failed. Status: %d", status);
|
||||
prst_restart_watchdog_start();
|
||||
// Power saving.
|
||||
k_timer_stop(&led_flashing_timer);
|
||||
prst_led_off();
|
||||
}
|
||||
joining_signal_received = true;
|
||||
break;
|
||||
}
|
||||
case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
|
||||
joining_signal_received = true;
|
||||
break;
|
||||
case ZB_ZDO_SIGNAL_LEAVE:
|
||||
if (status == RET_OK) {
|
||||
k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1));
|
||||
zb_zdo_signal_leave_params_t *leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_leave_params_t);
|
||||
LOG_DBG("Network left (leave type: %d)", leave_params->leave_type);
|
||||
|
||||
/* Set joining_signal_received to false so broken rejoin procedure can be detected correctly. */
|
||||
if (leave_params->leave_type == ZB_NWK_LEAVE_TYPE_REJOIN) {
|
||||
joining_signal_received = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZB_ZDO_SIGNAL_SKIP_STARTUP: {
|
||||
stack_initialised = true;
|
||||
LOG_DBG("Started zigbee stack and waiting for connection to network.");
|
||||
k_timer_start(&led_flashing_timer, K_NO_WAIT, K_SECONDS(1));
|
||||
|
||||
// Kick off main sensor update task.
|
||||
ZB_ERROR_CHECK(ZB_SCHEDULE_APP_ALARM(update_sensors_cb,
|
||||
/*param=*/0,
|
||||
ZB_MILLISECONDS_TO_BEACON_INTERVAL(1000)));
|
||||
__ASSERT_NO_MSG(!prst_watchdog_start());
|
||||
break;
|
||||
}
|
||||
case ZB_NLME_STATUS_INDICATION: {
|
||||
zb_zdo_signal_nlme_status_indication_params_t *nlme_status_ind =
|
||||
ZB_ZDO_SIGNAL_GET_PARAMS(sig_hndler, zb_zdo_signal_nlme_status_indication_params_t);
|
||||
if (nlme_status_ind->nlme_status.status == ZB_NWK_COMMAND_STATUS_PARENT_LINK_FAILURE) {
|
||||
/* Check for broken rejoin procedure and restart the device to recover.
|
||||
This implements Nordic's suggested workaround for errata KRKNWK-12017, which effects
|
||||
the recent nRF Connect SDK (v1.8.0 - v2.3.0 at time of writing).
|
||||
For details see: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/known_issues.html?v=v2-3-0
|
||||
*/
|
||||
if (stack_initialised && !joining_signal_received) {
|
||||
zb_reset(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
|
||||
if (bufid) {
|
||||
zb_buf_free(bufid);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_counter(const char *counter_name, prst_debug_counter_t value) {
|
||||
LOG_INF("- %s: %d", counter_name, value);
|
||||
}
|
||||
|
||||
int log_reset_reason_counter() {
|
||||
uint32_t cause;
|
||||
const char *reset_counter_str = "reset_cause_unknown";
|
||||
RET_IF_ERR(hwinfo_get_reset_cause(&cause));
|
||||
RET_IF_ERR(hwinfo_clear_reset_cause());
|
||||
if (cause & RESET_PIN) {
|
||||
reset_counter_str = "reset_cause_pin";
|
||||
} else if (cause & RESET_SOFTWARE) {
|
||||
// Includes fatal errors from __ASSERT, ZB_ERROR_CHECK and friends.
|
||||
reset_counter_str = "reset_cause_software";
|
||||
} else if (cause & RESET_BROWNOUT) {
|
||||
reset_counter_str = "reset_cause_brownout";
|
||||
} else if (cause & RESET_POR) {
|
||||
reset_counter_str = "reset_cause_power_on";
|
||||
} else if (cause & RESET_WATCHDOG) {
|
||||
reset_counter_str = "reset_cause_watchdog";
|
||||
} else if (cause & RESET_DEBUG) {
|
||||
reset_counter_str = "reset_cause_debug";
|
||||
} else if (cause & RESET_LOW_POWER_WAKE) {
|
||||
reset_counter_str = "reset_cause_low_power";
|
||||
} else if (cause & RESET_CPU_LOCKUP) {
|
||||
reset_counter_str = "reset_cause_cpu_lockup";
|
||||
} else if (cause & RESET_HARDWARE) {
|
||||
reset_counter_str = "reset_cause_hardware";
|
||||
} else if (cause & RESET_USER) {
|
||||
reset_counter_str = "reset_cause_user";
|
||||
}
|
||||
return prst_debug_counters_increment(reset_counter_str);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
RET_IF_ERR(prst_adc_init());
|
||||
RET_IF_ERR(prst_led_init());
|
||||
RET_IF_ERR(prst_button_init());
|
||||
RET_IF_ERR(prst_flash_fs_init());
|
||||
RET_IF_ERR(prst_debug_counters_init());
|
||||
|
||||
RET_IF_ERR(prst_zb_factory_reset_check());
|
||||
// Initialize sensors - quickly put them into low power mode.
|
||||
__ASSERT_NO_MSG(!prst_sensors_read_all(&sensors));
|
||||
|
||||
prst_debug_counters_increment("boot");
|
||||
|
||||
log_reset_reason_counter();
|
||||
|
||||
LOG_INF("Dumping debug counters:");
|
||||
prst_debug_counters_get_all(dump_counter);
|
||||
|
||||
__ASSERT_NO_MSG(!prst_zb_factory_reset_check());
|
||||
|
||||
prst_zb_attrs_init(&dev_ctx);
|
||||
|
||||
ZB_AF_REGISTER_DEVICE_CTX(&app_template_ctx);
|
||||
|
||||
update_sensors_cb(/*arg=*/0);
|
||||
|
||||
zb_zdo_pim_set_long_poll_interval(
|
||||
ZB_TIME_ONE_SECOND * CONFIG_PRST_ZB_PARENT_POLL_INTERVAL_SEC);
|
||||
power_down_unused_ram();
|
||||
|
||||
RET_IF_ERR(prst_led_flash(2));
|
||||
prst_led_flash(2);
|
||||
k_msleep(100);
|
||||
|
||||
ZB_AF_SET_IDENTIFY_NOTIFICATION_HANDLER(PRST_ZIGBEE_ENDPOINT, identify_cb);
|
||||
|
||||
zigbee_enable();
|
||||
zigbee_configure_sleepy_behavior(/*enable=*/true);
|
||||
power_down_unused_ram();
|
||||
zigbee_enable();
|
||||
|
||||
prst_debug_counters_increment("main_finish");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,25 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
|
||||
#include "debug_counters.h"
|
||||
|
||||
LOG_MODULE_REGISTER(restart_handler, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
static void restart_network_steering_cb(struct k_timer *timer) {
|
||||
LOG_DBG("Restart handler expired. Restarting network steering.");
|
||||
void callback_work_handler(struct k_work *work) {
|
||||
LOG_INF("Running restart callback_work_handler.");
|
||||
prst_debug_counters_increment("steering_watchdog_restart");
|
||||
// If the device is not commissioned, the rejoin procedure is started.
|
||||
user_input_indicate();
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(callback_work, callback_work_handler);
|
||||
|
||||
// Runs in an ISR context. We offload the actual work to a workqueue.
|
||||
static void restart_network_steering_cb(struct k_timer *timer) {
|
||||
LOG_INF("Triggered restart_network_steering_cb. Offloading work.");
|
||||
k_work_submit(&callback_work);
|
||||
}
|
||||
|
||||
K_TIMER_DEFINE(restart_timer, restart_network_steering_cb, NULL);
|
||||
|
||||
void prst_restart_watchdog_start() {
|
||||
|
|
|
|||
47
code/nrf-connect/samples/zigbee/src/watchdog.c
Normal file
47
code/nrf-connect/samples/zigbee/src/watchdog.c
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#include "watchdog.h"
|
||||
|
||||
#include <prstlib/macros.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/watchdog.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#define PRST_ZB_WATCHDOG_TIMEOUT_SEC (2 * CONFIG_PRST_ZB_SLEEP_DURATION_SEC)
|
||||
|
||||
LOG_MODULE_REGISTER(watchdog, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
typedef struct {
|
||||
const struct device *const wdt;
|
||||
int wtd_channel_id;
|
||||
} wtd_data_t;
|
||||
|
||||
static wtd_data_t wtd_data = {
|
||||
.wdt = DEVICE_DT_GET(DT_NODELABEL(wdt)),
|
||||
};
|
||||
|
||||
int prst_watchdog_start() {
|
||||
static const struct wdt_timeout_cfg wdt_settings = {
|
||||
.window = {
|
||||
.min = 0,
|
||||
.max = PRST_ZB_WATCHDOG_TIMEOUT_SEC * MSEC_PER_SEC,
|
||||
},
|
||||
// NULL callback means use the default, which is the system reset.
|
||||
.callback = NULL,
|
||||
.flags = WDT_FLAG_RESET_SOC};
|
||||
|
||||
RET_IF_ERR(!device_is_ready(wtd_data.wdt));
|
||||
|
||||
// Install timeout.
|
||||
wtd_data.wtd_channel_id = wdt_install_timeout(wtd_data.wdt, &wdt_settings);
|
||||
RET_CHECK(wtd_data.wtd_channel_id >= 0, "Failed to install watchdog timeout.");
|
||||
|
||||
// Start watchdog.
|
||||
RET_IF_ERR(wdt_setup(wtd_data.wdt, WDT_OPT_PAUSE_HALTED_BY_DBG));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prst_watchdog_feed() {
|
||||
RET_IF_ERR(wdt_feed(wtd_data.wdt, wtd_data.wtd_channel_id));
|
||||
return 0;
|
||||
}
|
||||
8
code/nrf-connect/samples/zigbee/src/watchdog.h
Normal file
8
code/nrf-connect/samples/zigbee/src/watchdog.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _PRST_ZB_WATCHDOG_H_
|
||||
#define _PRST_ZB_WATCHDOG_H_
|
||||
|
||||
int prst_watchdog_start();
|
||||
|
||||
int prst_watchdog_feed();
|
||||
|
||||
#endif // _PRST_ZB_WATCHDOG_H_
|
||||
|
|
@ -3,7 +3,7 @@ Comment,Designator,Footprint,LCSC
|
|||
"1n","C1","Capacitor_SMD:C_0402_1005Metric","C1523"
|
||||
"100n","C2","Capacitor_SMD:C_0402_1005Metric","C1525"
|
||||
"12p","C3,C4","Capacitor_SMD:C_0402_1005Metric","C1547"
|
||||
"LL4148","D1","Diode_SMD:D_MiniMELF","C9808"
|
||||
"LL4148","D1","Diode_SMD:D_MiniMELF","C3011166"
|
||||
"LED","D2","LED_SMD:LED_0603_1608Metric","C2286"
|
||||
"MMBT3906","Q1","Package_TO_SOT_SMD:SOT-23","C2910191"
|
||||
"Q_Photo_NPN","Q4","snapeda:TR8","C146233"
|
||||
|
|
|
|||
|
|
|
@ -1027,7 +1027,7 @@
|
|||
(at 66.742 55.536 180)
|
||||
(descr "Diode Mini-MELF")
|
||||
(tags "Diode Mini-MELF")
|
||||
(property "LCSC" "C9808")
|
||||
(property "LCSC" "C3011166")
|
||||
(property "Sheetfile" "parasite.kicad_sch")
|
||||
(property "Sheetname" "")
|
||||
(property "ki_description" "100V 0.15A standard switching diode, MiniMELF")
|
||||
|
|
|
|||
|
|
@ -1963,10 +1963,10 @@
|
|||
(property "Footprint" "Diode_SMD:D_MiniMELF" (at 63.5 111.125 0)
|
||||
(effects (font (size 1.27 1.27)) hide)
|
||||
)
|
||||
(property "Datasheet" "http://www.vishay.com/docs/85557/ll4148.pdf" (at 63.5 115.57 0)
|
||||
(property "Datasheet" "https://datasheet.lcsc.com/lcsc/2205131645_JUXING-LL4148_C3011166.pdf" (at 63.5 115.57 0)
|
||||
(effects (font (size 1.27 1.27)) hide)
|
||||
)
|
||||
(property "LCSC" "C9808" (at 63.5 115.57 0)
|
||||
(property "LCSC" "C3011166" (at 63.5 115.57 0)
|
||||
(effects (font (size 1.27 1.27)) hide)
|
||||
)
|
||||
(pin "1" (uuid b7ede69c-719d-4a3e-977e-6b4e4c5e39dd))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue