├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
└── app
├── CMakeLists.txt
├── Kconfig.hypnos
├── boards
└── arm
│ ├── ds_d6
│ ├── Kconfig
│ ├── Kconfig.board
│ ├── Kconfig.defconfig
│ ├── board.cmake
│ ├── doc
│ │ └── index.rst
│ ├── ds_d6.dts
│ ├── ds_d6.yaml
│ └── ds_d6_defconfig
│ ├── p8
│ ├── Kconfig
│ ├── Kconfig.board
│ ├── Kconfig.defconfig
│ ├── board.cmake
│ ├── doc
│ │ └── index.rst
│ ├── p8.dts
│ ├── p8.yaml
│ └── p8_defconfig
│ └── pinetime
│ ├── Kconfig
│ ├── Kconfig.board
│ ├── Kconfig.defconfig
│ ├── board.cmake
│ ├── doc
│ └── index.rst
│ ├── pinetime.dts
│ ├── pinetime.yaml
│ └── pinetime_defconfig
├── drivers
├── Kconfig
└── sensor
│ ├── CMakeLists.txt
│ ├── Kconfig
│ ├── bma421
│ ├── CMakeLists.txt
│ ├── Kconfig
│ ├── bma421.c
│ ├── bma421.h
│ ├── bma421_trigger.c
│ └── bma421_trigger.c-todo
│ ├── cst816s
│ ├── CMakeLists.txt
│ ├── Kconfig
│ ├── cst816s.c
│ ├── cst816s.h
│ └── cst816s_trigger.c
│ └── hrs3300
│ ├── CMakeLists.txt
│ ├── Kconfig
│ ├── hrs3300.c
│ └── hrs3300.h
├── dts
└── bindings
│ └── sensor
│ ├── bosch,bma421-i2c.yaml
│ ├── hx,hrs3300.yaml
│ └── hynitron,cst816s.yaml
├── hypnos
├── CMakeLists.txt
├── config
│ ├── bootloader.conf
│ ├── logging_rtt.conf
│ └── prj.conf
├── hypnos-photo.png
├── include
│ ├── backlight.h
│ ├── battery.h
│ ├── bt.h
│ ├── clock.h
│ ├── cts_sync.h
│ ├── display.h
│ ├── event_handler.h
│ ├── gfx.h
│ ├── gui.h
│ ├── log.h
│ └── version.h
├── src
│ ├── backlight.c
│ ├── battery.c
│ ├── bt.c
│ ├── clock.c
│ ├── cts_sync.c
│ ├── display.c
│ ├── event_handler.c
│ ├── fonts
│ │ └── rubik
│ │ │ ├── OFL.txt
│ │ │ └── Rubik-Regular.ttf
│ ├── gfx.c
│ ├── gui.c
│ ├── log.c
│ ├── main.c
│ ├── rubik_regular_34.c
│ └── rubik_regular_68.c
└── watch_photo.jpg
├── include
├── battery.h
└── drivers
│ └── sensor
│ └── cst816s.h
├── pkglist
├── subsys
├── CMakeLists.txt
├── Kconfig
└── battery
│ ├── CMakeLists.txt
│ ├── Kconfig
│ └── battery.c
├── west.yml
└── zephyr
└── module.yml
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2020 ZMK Firmware Contributors
2 | # Copyright (c) 2020 Endian Technologies AB
3 |
4 | # SPDX-License-Identifier: MIT
5 |
6 | name: Build and upload Hypnos
7 |
8 | # When to run this Workflow
9 | on:
10 |
11 | # Run this Workflow when files are pushed to this Branch
12 | push:
13 | branches: [ master ]
14 |
15 | # Also run this Workflow when a Pull Request is created or updated in this Branch
16 | pull_request:
17 | branches: [ master ]
18 |
19 | # Steps to run for the Workflow
20 | jobs:
21 | build:
22 | strategy:
23 | matrix:
24 | device: [pinetime, p8]
25 | runs-on: ubuntu-latest
26 | name: Build and upload
27 | steps:
28 | # To use this repository's private action,
29 | # you must check out the repository
30 | # Fetch tags and print them as well as the short commit hash
31 | - name: Checkout
32 | uses: actions/checkout@v2
33 | with:
34 | fetch-depth: 0
35 | - name: Cache west modules
36 | uses: actions/cache@v2
37 | env:
38 | cache-name: cache-zephyr-modules
39 | with:
40 | path: |
41 | modules/
42 | tools/
43 | zephyr/
44 | bootloader/
45 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('app/west.yml') }}
46 | restore-keys: |
47 | ${{ runner.os }}-build-${{ env.cache-name }}-
48 | ${{ runner.os }}-build-
49 | ${{ runner.os }}-
50 | - name: West Init
51 | uses: 'docker://zmkfirmware/zephyr-west-action-arm:latest'
52 | id: west-init
53 | with:
54 | args: 'init "-l app/'
55 | - name: West Update
56 | uses: 'docker://zmkfirmware/zephyr-west-action-arm:latest'
57 | id: west-update
58 | with:
59 | args: 'update'
60 | - name: West Config Zephyr Base
61 | uses: 'docker://zmkfirmware/zephyr-west-action-arm:latest'
62 | id: west-config
63 | with:
64 | args: 'config "--global zephyr.base-prefer configfile"'
65 | - name: West Zephyr Export
66 | uses: 'docker://zmkfirmware/zephyr-west-action-arm:latest'
67 | id: west-zephyr-export
68 | with:
69 | args: 'zephyr-export'
70 | - name: West Build ${{ matrix.device }}
71 | uses: 'docker://zmkfirmware/zephyr-west-action-arm:latest'
72 | id: west-build
73 | with:
74 | args: 'build "-p -b ${{ matrix.device }} app/hypnos"'
75 | - name: Install adafruit-nrfutil
76 | run: |
77 | pip3 install --user wheel
78 | pip3 install --user setuptools
79 | pip3 install --user adafruit-nrfutil
80 | - name: Install imgtool dependencies
81 | run: pip3 install --user -r bootloader/mcuboot/scripts/requirements.txt
82 | - name: Create mcuboot app image for lupyuen's custom PineTime bootloader # Use mcuboot v1.6.0-rc2 referenced by west.yml
83 | run: |
84 | bootloader/mcuboot/scripts/imgtool.py create --align 4 --version 1.0.0 --header-size 512 --slot-size 475136 build/zephyr/zephyr.bin hypnos-mcuboot-app-img.bin
85 | bootloader/mcuboot/scripts/imgtool.py verify hypnos-mcuboot-app-img.bin
86 | - name: Create DFU package
87 | run: |
88 | ~/.local/bin/adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application hypnos-mcuboot-app-img.bin hypnos-mcuboot-app-dfu.zip
89 | # Unzip the package because Upload Artifact will zip up the files
90 | unzip hypnos-mcuboot-app-dfu.zip -d hypnos-mcuboot-app-dfu
91 | - name: Get firmware version from git
92 | id: vars
93 | shell: bash
94 | run:
95 | echo "::set-output name=fw_ver::$(git describe --tags --dirty)"
96 | # Upload zephyr firmware build
97 | - name: Upload firmware build
98 | uses: actions/upload-artifact@v2
99 | with:
100 | # Append firmware version to file name
101 | name: ${{ matrix.device }}-hypnos-${{ steps.vars.outputs.fw_ver }}
102 | path: |
103 | build/zephyr/zephyr.*
104 | # Upload DFU package
105 | - name: Upload DFU package
106 | uses: actions/upload-artifact@v2
107 | with:
108 | # Append firmware version to file name
109 | name: ${{ matrix.device }}-hypnos-${{ steps.vars.outputs.fw_ver }}-mcuboot-app-dfu
110 | path: hypnos-mcuboot-app-dfu/*
111 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.west
2 | /bootloader
3 | /modules
4 | /tools
5 | /zephyr
6 | /app/build
7 | /build
8 | /images
9 | GPATH
10 | GRTAGS
11 | GTAGS
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2020 Endian Technologies AB
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | ifneq ($(BOARD),p8)
6 | BOARD := $(shell cat build/zephyr/.config 2>/dev/null | grep CONFIG_BOARD= \
7 | | cut -d'"' -f 2 2>/dev/null)
8 | ifndef BOARD
9 | BOARD := pinetime
10 | endif
11 | endif
12 |
13 | ifneq ($(BOOTLOADER),n)
14 | BOOTLOADER := $(shell cat build/zephyr/.config 2>/dev/null \
15 | | grep BOOTLOADER_MCUBOOT \
16 | | cut -d'=' -f 2 | tr -cd '[ny]\n')
17 | endif
18 |
19 | BUILD := build/zephyr/zephyr.bin
20 | VERSION := $(shell git describe --tags --dirty)
21 | IMGDIR := images
22 | IMAGE := $(IMGDIR)/$(BOARD)-hypnos-$(VERSION)-mcuboot-app-img.bin
23 | PACKAGE := $(IMGDIR)/$(BOARD)-hypnos-$(VERSION)-mcuboot-app-dfu.zip
24 |
25 | .PHONY: build clean help tools
26 |
27 | ifneq ($(BOOTLOADER),n)
28 | dfu: $(BUILD) $(IMAGE) $(PACKAGE)
29 | image: $(BUILD) $(IMAGE)
30 |
31 | $(IMAGE): $(BUILD) | $(IMGDIR)
32 | @echo "Creating an MCUBoot app image"
33 | bootloader/mcuboot/scripts/imgtool.py create --align 4 --version 1.0.0 \
34 | --header-size 512 --slot-size 475136 $(BUILD) $(IMAGE)
35 | endif
36 | build:
37 | west build -p -b $(BOARD) app/hypnos
38 |
39 | help:
40 | @echo "Build and flash the Hypnos application firmware as well as"
41 | @echo "images and DFU packages for devices running Lup Yuen Lee's"
42 | @echo "custom MCUBoot bootloader\n"
43 | @echo "Usage:"
44 | @echo " make [OPTION]... [TARGET]\n"
45 | @echo "Options:"
46 | @echo " BOARD=p8 build for p8 instead of pinetime"
47 | @echo " BOOTLOADER=n disable bootloader support"
48 | @echo " LOGGING=y enable RTT logging"
49 | @echo "Targets:"
50 | @echo " build build application firmware"
51 | @echo " clean remove the build directory"
52 | @echo " dfu build a Device Firmare Upgrade package"
53 | @echo " flash flash the most recent app image or firmware build over SWD"
54 | @echo " help show this message and exit"
55 | @echo " image build an MCUBoot app image"
56 | @echo " print print variables and file paths for debugging this Makefile"
57 | @echo " tools install tools for creating images and DFU packages"
58 |
59 | tools:
60 | @echo "Installing tools for creating app images and DFU packages"
61 | pip3 install --user setuptools
62 | pip3 install --user -r bootloader/mcuboot/scripts/requirements.txt
63 | pip3 install --user pyocd
64 | @echo "Done"
65 |
66 | $(IMGDIR):
67 | mkdir $(IMGDIR)
68 |
69 | $(BUILD):
70 | west build -p auto -b $(BOARD) app/hypnos
71 |
72 | $(PACKAGE): $(IMAGE)
73 | @echo "Creating a Device Firmware Update package"
74 | adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application $(IMAGE) \
75 | $(PACKAGE)
76 |
77 | ifneq ($(BOOTLOADER),n)
78 | flash: $(BUILD) $(IMAGE)
79 | @echo "Flashing the last modified Hypnos image after the bootloader"
80 | pyocd flash -e sector -a 0x8000 -t nrf52 $(shell ls -t images/*.bin | head -1)
81 | else
82 | flash: $(BUILD)
83 | @echo "Flashing Hypnos firmware without bootloader support"
84 | west flash
85 | endif
86 |
87 | clean:
88 | rm -rf build/
89 |
90 | print:
91 | @echo "Board: $(BOARD)"
92 | @echo "Bootloader: $(BOOTLOADER)"
93 | @echo "Version: $(VERSION)"
94 | @echo "Build: $(BUILD)"
95 | @echo "Image: $(IMAGE)"
96 | @echo "Package: $(PACKAGE)"
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hypnos
2 |
3 | This is a [Zephyr](https://www.zephyrproject.org/)-based firmware for the
4 | [PineTime](https://www.pine64.org/pinetime/) and P8 smartwatches.
5 |
6 |
7 |
8 | > **Hypnos**, son of Night and Darkness
9 | > He is said to be a calm and gentle god, as he helps humans in need and, due to their sleep, owns
10 | > half of their lives.[1](https://en.wikipedia.org/wiki/Hypnos)
11 |
12 | ## Features and roadmap
13 |
14 | - [x] 100 % Free Software
15 | - [x] Battery life: about one week
16 | - [x] Battery status: get state of charge and whether it's charging
17 | - [x] Clock: accurately increment current time
18 | - [x] Time and date synchronization with Bluetooth-connected device
19 | - [x] Touch sensor: tap to light up the display, swipe to display version information
20 | - [x] LVGL graphics: show time, date, battery and Bluetooth status
21 | - [x] Support for the PineTime bootloader
22 | - [x] Over-the-air firmware updates (SMP over BLE)
23 | - [x] Optional debug output via JLink RTT
24 | - [ ] Show notifications from Bluetooth-connected device
25 | - [ ] Set alarm
26 | - [ ] Wrist vibration
27 | - [ ] Quick glance via lift-to-wake
28 |
29 | ## Developer getting started guide
30 |
31 | This document assumes that you run a GNU/Linux or Mac operating system.
32 |
33 | ### Set up the development environment
34 |
35 | Follow Zephyr's [Getting Started
36 | Guide](https://docs.zephyrproject.org/latest/getting_started/index.html) up to
37 | step 3.2 "Get the Zephyr source code". Here you should run the commands below
38 | instead of the ones in the guide:
39 |
40 | ```
41 | $ git clone https://github.com/endian-albin/pinetime-hypnos
42 | $ cd pinetime-hypnos
43 | $ west init -l app/
44 | $ west update
45 | ```
46 |
47 | Then complete the remaining steps under section 3 and 4. Finally, run `make
48 | tools`.
49 |
50 | ### Build and flash Hypnos
51 |
52 | Run `make` to build everything with the defaults or `make help` to view all the
53 | options and targets.
54 |
55 | Then connect your in-circuit programmer and run `make flash`. To install
56 | without a programmer, see Firmware updates below.
57 |
58 | ### Build and flash the bootloader
59 |
60 | To install or upgrade the bootloader, follow Lup Yuen's [build
61 | instructions](https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot#build-and-flash-mcuboot-bootloader)
62 | or [fetch the prebuilt
63 | binary](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v5.0.4).
64 |
65 | Then flash it to the beginning of the internal memory:
66 | ```
67 | pyocd flash -e sector -t nrf52 bootloader-image.bin
68 | ```
69 |
70 | ## Firmware updates
71 |
72 | ### SMP over Bluetooth LE
73 |
74 | Hypnos supports firmware image management over the Simple Management Protocol.
75 |
76 | To make use of this feature, get the
77 | [mcumgr](https://github.com/apache/mynewt-mcumgr#command-line-tool) command-line
78 | tool. Then run the commands below to list, upload, test and confirm firmware
79 | images over BLE:
80 |
81 | ```
82 | # mcumgr --conntype="ble" --connstring ctlr_name=hci0,peer_name='Hypnos' image list
83 | # mcumgr --conntype="ble" --connstring ctlr_name=hci0,peer_name='Hypnos' image upload hypnos-mcuboot-app-img.bin
84 | # mcumgr --conntype="ble" --connstring ctlr_name=hci0,peer_name='Hypnos' image test
85 | # mcumgr --conntype="ble" --connstring ctlr_name=hci0,peer_name='Hypnos' reset
86 | # mcumgr --conntype="ble" --connstring ctlr_name=hci0,peer_name='Hypnos' image confirm
87 | ```
88 |
89 | If you are unhappy with the new image, simply run the `reset` command again
90 | instead of `image confirm` to revert to the old one. If the image has already
91 | been confirmed but you still want to revert, simply run the commands above but
92 | skip the upload step or perform a manual rollback (see below). [See this
93 | document for more
94 | information](https://docs.zephyrproject.org/latest/samples/subsys/mgmt/mcumgr/smp_svr/README.html).
95 |
96 | ### DFU over Bluetooth LE
97 |
98 | To install Hypnos over the air from
99 | [InfiniTime](https://github.com/JF002/Pinetime), run `make dfu` to create a
100 | (Nordic) DFU package and upload it using
101 | [ota-dfu.py](https://github.com/JF002/Pinetime/tree/master/bootloader/ota-dfu-python)
102 | or nRF Connect.
103 |
104 | ### Manual rollback
105 |
106 | Version 5 of Lup Yuen's bootloader allows you to revert to the old firmware
107 | image by holding the button during boot.
108 |
109 | ## Copying
110 |
111 | This software may be used under the terms of the Apache License 2.0, unless
112 | explicitly stated otherwise.
113 |
114 | The documentation contained in this README and on the wiki are under the CC
115 | BY-SA 4.0 license.
116 |
--------------------------------------------------------------------------------
/app/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(PINETIME_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE PATH "Hypnos root directory")
2 |
3 | zephyr_include_directories(include)
4 |
5 | add_subdirectory(drivers/sensor)
6 | add_subdirectory(subsys)
7 |
--------------------------------------------------------------------------------
/app/Kconfig.hypnos:
--------------------------------------------------------------------------------
1 | menu "Hypnos"
2 |
3 | rsource "drivers/sensor/Kconfig"
4 | rsource "subsys/Kconfig"
5 |
6 | endmenu
7 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/Kconfig:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_DS_D6
7 |
8 | config BOARD_ENABLE_DCDC
9 | bool "Enable DCDC mode"
10 | select SOC_DCDC_NRF52X
11 | default y
12 |
13 | endif # BOARD_DS_D6
14 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/Kconfig.board:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | config BOARD_DS_D6
7 | bool "DS-D6"
8 | depends on SOC_NRF52832_QFAA
9 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/Kconfig.defconfig:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_DS_D6
7 |
8 | config BOARD
9 | default "ds_d6"
10 |
11 | if I2C
12 |
13 | config I2C_0
14 | default y
15 |
16 | endif # I2C
17 |
18 | if PWM
19 |
20 | config PWM_0
21 | default y
22 |
23 | endif # PWM
24 |
25 | config BT_CTLR
26 | default BT
27 |
28 | endif # BOARD_DS_D6
29 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/board.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | board_runner_args(pyocd "--target=nrf52")
4 | include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
5 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. _nrf52832_mdk:
2 |
3 | ds-d6
4 | #################
5 |
6 | Overview
7 | ********
8 |
9 | The ds_d6 board is a smart watch, produced by Desay.
10 |
11 | It is cheap and hackable.
12 |
13 | Over the air device firmware update is possible.
14 |
15 | which means you can flash firmware without opening the watch
16 |
17 |
18 |
19 | See `ds_d6 website`_ for more information about the development
20 | board and `nRF52832 website`_ for the official reference on the IC itself.
21 |
22 | References
23 | **********
24 | .. target-notes::
25 |
26 | .. _nRF52832 website: https://www.nordicsemi.com/Products/Low-power-short-range-wireless/nRF52832
27 | .. _ds-d6 website: https://gitter.im/nRF51822-Arduino-Mbed-smart-watch/Lobby
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/ds_d6.dts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Zelin
3 | * Copyright (c) 2018 makerdiary.com.
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | /dts-v1/;
9 | #include
10 |
11 | / {
12 | model = "Desay D6 smart watch";
13 | compatible = "ds-d6", "nordic,nrf52832-qfaa",
14 | "nordic,nrf52832";
15 |
16 | chosen {
17 | zephyr,console = &uart0;
18 | zephyr,shell-uart = &uart0;
19 | zephyr,uart-mcumgr = &uart0;
20 | zephyr,bt-mon-uart = &uart0;
21 | zephyr,bt-c2h-uart = &uart0;
22 | zephyr,sram = &sram0;
23 | zephyr,flash = &flash0;
24 | zephyr,code-partition = &slot0_partition;
25 | };
26 |
27 | leds {
28 | compatible = "gpio-leds";
29 | led0_green: led_0 {
30 | gpios = <&gpio0 26 GPIO_INT_ACTIVE_LOW>;
31 | label = "Green LED 0";
32 | };
33 | led1_red: led_1 {
34 | gpios = <&gpio0 23 GPIO_INT_ACTIVE_LOW>;
35 | label = "Red LED 1";
36 | };
37 | led2_blue: led_2 {
38 | gpios = <&gpio0 24 GPIO_INT_ACTIVE_LOW>;
39 | label = "Blue LED 1";
40 | };
41 | };
42 |
43 | buttons {
44 | compatible = "gpio-keys";
45 | button0: button_0 {
46 | gpios = <&gpio0 18 GPIO_PUD_PULL_UP>;
47 | label = "Push button switch 0";
48 | };
49 | };
50 |
51 | /* These aliases are provided for compatibility with samples */
52 | aliases {
53 | sw0 = &button0;
54 | led0 = &led0_green;
55 | led1 = &led1_red;
56 | led2 = &led2_blue;
57 | led0-green = &led0_green;
58 | led1-red = &led1_red;
59 | led2-blue = &led2_blue;
60 | };
61 |
62 | };
63 |
64 | &gpiote {
65 | status = "okay";
66 | };
67 |
68 | &gpio0 {
69 | status = "okay";
70 | };
71 |
72 | &uart0 {
73 | status = "okay";
74 | compatible = "nordic,nrf-uart";
75 | current-speed = <115200>;
76 | tx-pin = <23>;
77 | rx-pin = <22>;
78 | /* rts-pin = <-1>;
79 | cts-pin = <-1>;*/
80 | };
81 |
82 | &i2c0 {
83 | compatible = "nordic,nrf-twi";
84 | status = "okay";
85 | sda-pin = <8>;
86 | scl-pin = <7>;
87 | };
88 |
89 | &i2c1 {
90 | compatible = "nordic,nrf-twi";
91 | status = "okay";
92 | sda-pin = <14>;
93 | scl-pin = <13>;
94 | };
95 |
96 | &pwm0 {
97 | status = "okay";
98 | ch0-pin = <22>;
99 | ch0-inverted;
100 | };
101 |
102 | &flash0 {
103 | /*
104 | * For more information, see:
105 | * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions
106 | */
107 | partitions {
108 | compatible = "fixed-partitions";
109 | #address-cells = <1>;
110 | #size-cells = <1>;
111 |
112 | boot_partition: partition@0 {
113 | label = "mcuboot";
114 | reg = <0x00000000 0xc000>;
115 | };
116 | slot0_partition: partition@c000 {
117 | label = "image-0";
118 | reg = <0x0000C000 0x32000>;
119 | };
120 | slot1_partition: partition@3e000 {
121 | label = "image-1";
122 | reg = <0x0003E000 0x32000>;
123 | };
124 | scratch_partition: partition@70000 {
125 | label = "image-scratch";
126 | reg = <0x00070000 0xa000>;
127 | };
128 | storage_partition: partition@7a000 {
129 | label = "storage";
130 | reg = <0x0007a000 0x00006000>;
131 | };
132 | };
133 | };
134 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/ds_d6.yaml:
--------------------------------------------------------------------------------
1 | identifier: ds_d6
2 | name: DS-D6
3 | type: mcu
4 | arch: arm
5 | toolchain:
6 | - zephyr
7 | - gnuarmemb
8 | - xtools
9 | ram: 64
10 | flash: 512
11 | supported:
12 | - pwm
13 |
--------------------------------------------------------------------------------
/app/boards/arm/ds_d6/ds_d6_defconfig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | CONFIG_ARM=y
4 | CONFIG_SOC_FAMILY_NRF=y
5 | CONFIG_SOC_SERIES_NRF52X=y
6 | CONFIG_SOC_NRF52832_QFAA=y
7 | CONFIG_BOARD_DS_D6=y
8 |
9 | # Enable MPU
10 | CONFIG_ARM_MPU=y
11 |
12 | # enable GPIO
13 | CONFIG_GPIO=y
14 |
15 | # enable uart driver
16 | CONFIG_SERIAL=y
17 | CONFIG_UART_0_NRF_UART=y
18 |
19 | # enable console
20 | CONFIG_CONSOLE=y
21 | CONFIG_UART_CONSOLE=y
22 |
23 | # additional board options
24 | CONFIG_GPIO_AS_PINRESET=y
25 |
26 | # bluetooth no external crystal
27 | CONFIG_CLOCK_CONTROL_NRF=y
28 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
29 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_20PPM=y
30 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/Kconfig:
--------------------------------------------------------------------------------
1 | # P8 smartwatch configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_P8
7 |
8 | config BOARD_ENABLE_DCDC
9 | bool "Enable DCDC mode"
10 | select SOC_DCDC_NRF52X
11 | default y
12 |
13 | endif # BOARD_P8
14 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/Kconfig.board:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | config BOARD_P8
7 | bool "p8"
8 | depends on SOC_NRF52832_QFAA
9 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/Kconfig.defconfig:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_P8
7 |
8 | config BOARD
9 | default "p8"
10 |
11 | if I2C
12 |
13 | config I2C_1
14 | default y
15 |
16 | endif # I2C
17 |
18 | if SPI
19 |
20 | config SPI_0
21 | default y
22 |
23 | endif # SPI
24 |
25 | config BT_CTLR
26 | default BT
27 |
28 | endif # P8
29 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/board.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | board_runner_args(pyocd "--target=nrf52" "--frequency=4000000")
4 | board_runner_args(nrfjprog "--nrf-family=NRF52")
5 | board_runner_args(jlink "--device=nrf52" "--speed=4000")
6 | include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
7 | include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
8 | include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
9 | #include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
10 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. _p8:
2 |
3 | p8
4 | ########
5 |
6 | Overview
7 | ********
8 |
9 | P8 is a smartwatch similar to the PineTime. It comes with a proprietary
10 | bootloader which must be removed for Hypnos to be installed. This
11 | requires access to the SWD pins, i.e. the sealed casing must be opened.
12 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/p8.dts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Zelin
3 | * Copyright (c) 2018 makerdiary.com.
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | /dts-v1/;
9 | #include
10 |
11 | / {
12 | model = "p8 smartwatch";
13 | compatible = "nrf52832";
14 |
15 | chosen {
16 | zephyr,sram = &sram0;
17 | zephyr,console = &uart0;
18 | // zephyr,shell-uart = &uart0;
19 | //zephyr,uart-mcumgr = &uart0;
20 | //zephyr,bt-mon-uart = &uart0;
21 | //zephyr,bt-c2h-uart = &uart0;
22 | zephyr,flash = &flash0;
23 | //zephyr,flash = &mx25r64;
24 | zephyr,code-partition = &slot0_partition;
25 | };
26 |
27 | leds {
28 | compatible = "gpio-leds";
29 | led0_green: led_0 {
30 | gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
31 | label = "Background LED 0";
32 | };
33 | led1_red: led_1 {
34 | gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
35 | label = "Background LED 1";
36 | };
37 | led2_blue: led_2 {
38 | gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
39 | label = "Background LED 2";
40 | };
41 | };
42 |
43 | buttons {
44 | compatible = "gpio-keys";
45 | button0: button_0 {
46 | gpios = <&gpio0 17 0>;
47 | label = "Push button switch 0";
48 | };
49 | };
50 |
51 | /* These aliases are provided for compatibility with samples */
52 | aliases {
53 | sw0 = &button0;
54 | led0 = &led0_green;
55 | led1 = &led1_red;
56 | led2 = &led2_blue;
57 | led0-green = &led0_green;
58 | led1-red = &led1_red;
59 | led2-blue = &led2_blue;
60 | };
61 | };
62 |
63 | &gpiote {
64 | status = "okay";
65 | };
66 |
67 | &gpio0 {
68 | status = "okay";
69 | };
70 |
71 | &i2c1 {
72 | compatible = "nordic,nrf-twi";
73 | status = "okay";
74 | sda-pin = <6>;
75 | scl-pin = <7>;
76 | clock-frequency = <100000>;
77 | bma421@18 {
78 | compatible = "bosch,bma421";
79 | reg=<0x18>;
80 | label="BMA421";
81 | int1-gpios = <&gpio0 8 0>;
82 | };
83 | hrs3300@44 {
84 | compatible = "hx,hrs3300";
85 | reg = <0x44>;
86 | label = "HRS3300";
87 | };
88 | cst816s@15 {
89 | compatible = "hynitron,cst816s";
90 | label = "CST816S";
91 | reg = <0x15>;
92 | int1-gpios = <&gpio0 28 0>;
93 | reset-gpios = <&gpio0 10 0>;
94 | };
95 | };
96 |
97 | &spi0 {
98 | compatible = "nordic,nrf-spi";
99 | status = "okay";
100 | sck-pin = <2>;
101 | mosi-pin = <3>;
102 | miso-pin = <4>;
103 | cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>,<&gpio0 5 GPIO_ACTIVE_LOW>;
104 | st7789v@0 {
105 | compatible = "sitronix,st7789v";
106 | label = "DISPLAY";
107 | spi-max-frequency = <8000000>;
108 | reg = <0>;
109 | cmd-data-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
110 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
111 | width = <240>;
112 | height = <240>;
113 | x-offset = <0>;
114 | y-offset = <0>;
115 | vcom = <0x19>;
116 | gctrl = <0x35>;
117 | vrhs = <0x12>;
118 | vdvs = <0x20>;
119 | mdac = <0x00>;
120 | gamma = <0x01>;
121 | colmod = <0x05>;
122 | lcm = <0x2c>;
123 | porch-param = [0c 0c 00 33 33];
124 | cmd2en-param = [5a 69 02 01];
125 | pwctrl1-param = [a4 a1];
126 | pvgam-param = [D0 04 0D 11 13 2B 3F 54 4C 18 0D 0B 1F 23];
127 | nvgam-param = [D0 04 0C 11 13 2C 3F 44 51 2F 1F 1F 20 23];
128 | ram-param = [00 F0];
129 | rgb-param = [CD 08 14];
130 | };
131 |
132 | flash1: mx25r6435f@1 {
133 | compatible = "jedec,spi-nor";
134 | reg = <1>;
135 | spi-max-frequency = <1000000>;
136 | label = "MX25R64";
137 | jedec-id = [20 40 16];
138 | size = <67108864>;
139 | has-be32k;
140 | };
141 | };
142 |
143 | &flash0 {
144 | /*
145 | * For more information, see:
146 | * https://docs.zephyrproject.org/latest/guides/dts/legacy-macros.html#legacy-flash-partitions
147 | */
148 | partitions {
149 | compatible = "fixed-partitions";
150 | #address-cells = <1>;
151 | #size-cells = <1>;
152 |
153 | boot_partition: partition@0 {
154 | label = "mcuboot";
155 | reg = <0x00000000 0x8000>;
156 | };
157 | slot0_partition: partition@8000 {
158 | label = "image-0";
159 | reg = <0x00008000 0x74000>;
160 | };
161 | scratch_partition: partition@7c000 {
162 | label = "image-scratch";
163 | reg = <0x0007c000 0xa000>;
164 | };
165 | };
166 | };
167 |
168 | &flash1 {
169 | /*
170 | * For more information, see:
171 | * https://docs.zephyrproject.org/latest/guides/dts/legacy-macros.html#legacy-flash-partitions
172 | */
173 | partitions {
174 | compatible = "fixed-partitions";
175 | #address-cells = <1>;
176 | #size-cells = <1>;
177 |
178 | slot1_partition: partition@40000 {
179 | label = "image-1";
180 | reg = <0x00040000 0x74000>;
181 | };
182 | storage_partition: partition@b4000 {
183 | label = "storage";
184 | reg = <0x000b4000 0x0034c000>;
185 | };
186 | };
187 | };
188 |
189 | &adc {
190 | status = "okay";
191 | };
192 |
193 | &uart0 {
194 | status = "disabled";
195 | };
196 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/p8.yaml:
--------------------------------------------------------------------------------
1 | identifier: p8
2 | name: P8
3 | type: mcu
4 | arch: arm
5 | toolchain:
6 | - zephyr
7 | - gnuarmemb
8 | - xtools
9 | ram: 64
10 | flash: 512
11 | supported:
12 | - pwm
13 | - spi
14 | - i2c
15 | - gpio
16 |
--------------------------------------------------------------------------------
/app/boards/arm/p8/p8_defconfig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | #CONFIG_ARM=y
4 | #CONFIG_SOC_FAMILY_NRF=y
5 | CONFIG_SOC_SERIES_NRF52X=y
6 | CONFIG_SOC_NRF52832_QFAA=y
7 | CONFIG_BOARD_P8=y
8 |
9 | # Enable MPU
10 | CONFIG_ARM_MPU=y
11 |
12 | # enable GPIO
13 | CONFIG_GPIO=y
14 |
15 | # enable uart driver
16 | #CONFIG_SERIAL=y
17 | #CONFIG_UART_0_NRF_UART=y
18 |
19 | # enable console
20 | #CONFIG_CONSOLE=y
21 | #CONFIG_UART_CONSOLE=y
22 |
23 | # additional board options
24 | CONFIG_GPIO_AS_PINRESET=y
25 |
26 |
27 | #CONFIG_CLOCK_CONTROL_NRF=y
28 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH=y
29 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_20PPM=y
30 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_250PPM=y
31 | #
32 | CONFIG_CLOCK_CONTROL_NRF=y
33 | # CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC is not set
34 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
35 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH is not set
36 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING is not set
37 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING is not set
38 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y
39 |
40 | #CONFIG_SPI=y
41 | #CONFIG_DISPLAY=y
42 | #CONFIG_ST7789V=y
43 | #CONFIG_ST7789V_RGB565=y
44 | #CONFIG_ADXL362=y
45 |
46 |
47 | #CONFIG_LVGL=y
48 | #CONFIG_LVGL_BITS_PER_PIXEL=16
49 | #CONFIG_LVGL_HOR_RES=240
50 | #CONFIG_LVGL_VER_RES=240
51 | #CONFIG_LVGL_DISPLAY_DEV_NAME="DISPLAY"
52 | #CONFIG_NRFX_TWI=y
53 | # CONFIG_NRFX_TWI0 is not set
54 | #
55 | #
56 | #
57 | CONFIG_I2C=y
58 | CONFIG_I2C_1=y
59 | CONFIG_I2C_INIT_PRIORITY=60
60 | #CONFIG_SENSOR=y
61 | #CONFIG_SENSOR_INIT_PRIORITY=90
62 | #
63 | #
64 | #CONFIG_BMA421=y
65 | #CONFIG_ADXL372=y
66 | #CONFIG_ADXL372_I2C=y
67 | #CONFIG_ADXL362_ACCEL_RANGE_RUNTIME=y
68 | ## CONFIG_ADXL362_ACCEL_RANGE_2G is not set
69 | ## # CONFIG_ADXL362_ACCEL_RANGE_4G is not set
70 | ## # CONFIG_ADXL362_ACCEL_RANGE_8G is not set
71 | #CONFIG_ADXL362_ACCEL_ODR_RUNTIME=y
72 | ## # CONFIG_ADXL362_ACCEL_ODR_12_5 is not set
73 | ## # CONFIG_ADXL362_ACCEL_ODR_25 is not set
74 | ## # CONFIG_ADXL362_ACCEL_ODR_50 is not set
75 | ## # CONFIG_ADXL362_ACCEL_ODR_100 is not set
76 | ## # CONFIG_ADXL362_ACCEL_ODR_200 is not set
77 | ## # CONFIG_ADXL362_ACCEL_ODR_400 is not set
78 | ## # CONFIG_ADXL362_TRIGGER_NONE is not set
79 | ## CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD=y
80 | ## # CONFIG_ADXL362_TRIGGER_OWN_THREAD is not set
81 | #CONFIG_ADXL362_TRIGGER=y
82 | #CONFIG_ADXL362_ACTIVITY_THRESHOLD=1000
83 | #CONFIG_ADXL362_INACTIVITY_THRESHOLD=100
84 | #CONFIG_ADXL362_INTERRUPT_MODE=1
85 | #CONFIG_ADXL362_ABS_REF_MODE=1
86 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/Kconfig:
--------------------------------------------------------------------------------
1 | # PINETIME smartwatch configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_PINETIME
7 |
8 | config BOARD_ENABLE_DCDC
9 | bool "Enable DCDC mode"
10 | select SOC_DCDC_NRF52X
11 | default y
12 |
13 | endif # BOARD_PINETIME
14 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/Kconfig.board:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | config BOARD_PINETIME
7 | bool "pinetime"
8 | depends on SOC_NRF52832_QFAA
9 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/Kconfig.defconfig:
--------------------------------------------------------------------------------
1 | # nRF52832-MDK board configuration
2 |
3 | # Copyright (c) 2018 makerdiary.com.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | if BOARD_PINETIME
7 |
8 | config BOARD
9 | default "pinetime"
10 |
11 | if I2C
12 |
13 | config I2C_1
14 | default y
15 |
16 | endif # I2C
17 |
18 | if SPI
19 |
20 | config SPI_0
21 | default y
22 |
23 | endif # SPI
24 |
25 | config BT_CTLR
26 | default BT
27 |
28 | endif # PINETIME
29 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/board.cmake:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | board_runner_args(pyocd "--target=nrf52" "--frequency=4000000")
4 | board_runner_args(nrfjprog "--nrf-family=NRF52")
5 | board_runner_args(jlink "--device=nrf52" "--speed=4000")
6 | include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
7 | include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
8 | include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
9 | #include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
10 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. _pinetime:
2 |
3 | pinetime
4 | ########
5 |
6 | Overview
7 | ********
8 |
9 | PineTime is an nRF52832-based smartwatch that is shipped with free bootloader
10 | and application firmware. The PineTime contains, among other things, a battery,
11 | touch screen, vibrator, heart-rate sensor, an accelerometer and Bluetooth LE.
12 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/pinetime.dts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Zelin
3 | * Copyright (c) 2018 makerdiary.com.
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | /dts-v1/;
9 | #include
10 |
11 | / {
12 | model = "pinetime smartwatch";
13 | compatible = "nrf52832";
14 |
15 | chosen {
16 | zephyr,sram = &sram0;
17 | zephyr,console = &uart0;
18 | // zephyr,shell-uart = &uart0;
19 | //zephyr,uart-mcumgr = &uart0;
20 | //zephyr,bt-mon-uart = &uart0;
21 | //zephyr,bt-c2h-uart = &uart0;
22 | zephyr,flash = &flash0;
23 | //zephyr,flash = &mx25r64;
24 | zephyr,code-partition = &slot0_partition;
25 | };
26 |
27 | leds {
28 | compatible = "gpio-leds";
29 | led0_green: led_0 {
30 | gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
31 | label = "Background LED 0";
32 | };
33 | led1_red: led_1 {
34 | gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
35 | label = "Background LED 1";
36 | };
37 | led2_blue: led_2 {
38 | gpios = <&gpio0 23 GPIO_ACTIVE_LOW>;
39 | label = "Background LED 2";
40 | };
41 | };
42 |
43 | buttons {
44 | compatible = "gpio-keys";
45 | button0: button_0 {
46 | gpios = <&gpio0 13 0>;
47 | label = "Push button switch 0";
48 | };
49 | };
50 |
51 | /* These aliases are provided for compatibility with samples */
52 | aliases {
53 | sw0 = &button0;
54 | led0 = &led0_green;
55 | led1 = &led1_red;
56 | led2 = &led2_blue;
57 | led0-green = &led0_green;
58 | led1-red = &led1_red;
59 | led2-blue = &led2_blue;
60 | };
61 | };
62 |
63 | &gpiote {
64 | status = "okay";
65 | };
66 |
67 | &gpio0 {
68 | status = "okay";
69 | };
70 |
71 | &i2c1 {
72 | compatible = "nordic,nrf-twi";
73 | status = "okay";
74 | sda-pin = <6>;
75 | scl-pin = <7>;
76 | clock-frequency = <100000>;
77 | bma421@18 {
78 | compatible = "bosch,bma421";
79 | reg=<0x18>;
80 | label="BMA421";
81 | int1-gpios = <&gpio0 8 0>;
82 | };
83 | hrs3300@44 {
84 | compatible = "hx,hrs3300";
85 | reg = <0x44>;
86 | label = "HRS3300";
87 | };
88 | cst816s@15 {
89 | compatible = "hynitron,cst816s";
90 | label = "CST816S";
91 | reg = <0x15>;
92 | int1-gpios = <&gpio0 28 0>;
93 | reset-gpios = <&gpio0 10 0>;
94 | };
95 | };
96 |
97 | &spi0 {
98 | compatible = "nordic,nrf-spi";
99 | status = "okay";
100 | sck-pin = <2>;
101 | mosi-pin = <3>;
102 | miso-pin = <4>;
103 | cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>,<&gpio0 5 GPIO_ACTIVE_LOW>;
104 | st7789v@0 {
105 | compatible = "sitronix,st7789v";
106 | label = "DISPLAY";
107 | spi-max-frequency = <8000000>;
108 | reg = <0>;
109 | cmd-data-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
110 | reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
111 | width = <240>;
112 | height = <240>;
113 | x-offset = <0>;
114 | y-offset = <0>;
115 | vcom = <0x19>;
116 | gctrl = <0x35>;
117 | vrhs = <0x12>;
118 | vdvs = <0x20>;
119 | mdac = <0x00>;
120 | gamma = <0x01>;
121 | colmod = <0x05>;
122 | lcm = <0x2c>;
123 | porch-param = [0c 0c 00 33 33];
124 | cmd2en-param = [5a 69 02 01];
125 | pwctrl1-param = [a4 a1];
126 | pvgam-param = [D0 04 0D 11 13 2B 3F 54 4C 18 0D 0B 1F 23];
127 | nvgam-param = [D0 04 0C 11 13 2C 3F 44 51 2F 1F 1F 20 23];
128 | ram-param = [00 F0];
129 | rgb-param = [CD 08 14];
130 | };
131 |
132 | flash1: mx25r6435f@1 {
133 | compatible = "jedec,spi-nor";
134 | reg = <1>;
135 | spi-max-frequency = <1000000>;
136 | label = "MX25R64";
137 | jedec-id = [0b 40 16];
138 | size = <67108864>;
139 | has-be32k;
140 | };
141 | };
142 |
143 | &flash0 {
144 | /*
145 | * For more information, see:
146 | * https://docs.zephyrproject.org/latest/guides/dts/legacy-macros.html#legacy-flash-partitions
147 | */
148 | partitions {
149 | compatible = "fixed-partitions";
150 | #address-cells = <1>;
151 | #size-cells = <1>;
152 |
153 | boot_partition: partition@0 {
154 | label = "mcuboot";
155 | reg = <0x00000000 0x8000>;
156 | };
157 | slot0_partition: partition@8000 {
158 | label = "image-0";
159 | reg = <0x00008000 0x74000>;
160 | };
161 | scratch_partition: partition@7c000 {
162 | label = "image-scratch";
163 | reg = <0x0007c000 0xa000>;
164 | };
165 | };
166 | };
167 |
168 | &flash1 {
169 | /*
170 | * For more information, see:
171 | * https://docs.zephyrproject.org/latest/guides/dts/legacy-macros.html#legacy-flash-partitions
172 | */
173 | partitions {
174 | compatible = "fixed-partitions";
175 | #address-cells = <1>;
176 | #size-cells = <1>;
177 |
178 | slot1_partition: partition@40000 {
179 | label = "image-1";
180 | reg = <0x00040000 0x74000>;
181 | };
182 | storage_partition: partition@b4000 {
183 | label = "storage";
184 | reg = <0x000b4000 0x0034c000>;
185 | };
186 | };
187 | };
188 |
189 | &adc {
190 | status = "okay";
191 | };
192 |
193 | &uart0 {
194 | status = "disabled";
195 | };
196 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/pinetime.yaml:
--------------------------------------------------------------------------------
1 | identifier: pinetime
2 | name: PINETIME
3 | type: mcu
4 | arch: arm
5 | toolchain:
6 | - zephyr
7 | - gnuarmemb
8 | - xtools
9 | ram: 64
10 | flash: 512
11 | supported:
12 | - pwm
13 | - spi
14 | - i2c
15 | - gpio
16 |
--------------------------------------------------------------------------------
/app/boards/arm/pinetime/pinetime_defconfig:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | #CONFIG_ARM=y
4 | #CONFIG_SOC_FAMILY_NRF=y
5 | CONFIG_SOC_SERIES_NRF52X=y
6 | CONFIG_SOC_NRF52832_QFAA=y
7 | CONFIG_BOARD_PINETIME=y
8 |
9 | # Enable MPU
10 | CONFIG_ARM_MPU=y
11 |
12 | # enable GPIO
13 | CONFIG_GPIO=y
14 |
15 | # enable uart driver
16 | #CONFIG_SERIAL=y
17 | #CONFIG_UART_0_NRF_UART=y
18 |
19 | # enable console
20 | #CONFIG_CONSOLE=y
21 | #CONFIG_UART_CONSOLE=y
22 |
23 | # additional board options
24 | CONFIG_GPIO_AS_PINRESET=y
25 |
26 |
27 | #CONFIG_CLOCK_CONTROL_NRF=y
28 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH=y
29 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_20PPM=y
30 | #CONFIG_CLOCK_CONTROL_NRF_K32SRC_250PPM=y
31 | #
32 | CONFIG_CLOCK_CONTROL_NRF=y
33 | # CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC is not set
34 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
35 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH is not set
36 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING is not set
37 | # # CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING is not set
38 | CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y
39 |
40 | #CONFIG_SPI=y
41 | #CONFIG_DISPLAY=y
42 | #CONFIG_ST7789V=y
43 | #CONFIG_ST7789V_RGB565=y
44 | #CONFIG_ADXL362=y
45 |
46 |
47 | #CONFIG_LVGL=y
48 | #CONFIG_LVGL_BITS_PER_PIXEL=16
49 | #CONFIG_LVGL_HOR_RES=240
50 | #CONFIG_LVGL_VER_RES=240
51 | #CONFIG_LVGL_DISPLAY_DEV_NAME="DISPLAY"
52 | #CONFIG_NRFX_TWI=y
53 | # CONFIG_NRFX_TWI0 is not set
54 | #
55 | #
56 | #
57 | CONFIG_I2C=y
58 | CONFIG_I2C_1=y
59 | CONFIG_I2C_INIT_PRIORITY=60
60 | #CONFIG_SENSOR=y
61 | #CONFIG_SENSOR_INIT_PRIORITY=90
62 | #
63 | #
64 | #CONFIG_BMA421=y
65 | #CONFIG_ADXL372=y
66 | #CONFIG_ADXL372_I2C=y
67 | #CONFIG_ADXL362_ACCEL_RANGE_RUNTIME=y
68 | ## CONFIG_ADXL362_ACCEL_RANGE_2G is not set
69 | ## # CONFIG_ADXL362_ACCEL_RANGE_4G is not set
70 | ## # CONFIG_ADXL362_ACCEL_RANGE_8G is not set
71 | #CONFIG_ADXL362_ACCEL_ODR_RUNTIME=y
72 | ## # CONFIG_ADXL362_ACCEL_ODR_12_5 is not set
73 | ## # CONFIG_ADXL362_ACCEL_ODR_25 is not set
74 | ## # CONFIG_ADXL362_ACCEL_ODR_50 is not set
75 | ## # CONFIG_ADXL362_ACCEL_ODR_100 is not set
76 | ## # CONFIG_ADXL362_ACCEL_ODR_200 is not set
77 | ## # CONFIG_ADXL362_ACCEL_ODR_400 is not set
78 | ## # CONFIG_ADXL362_TRIGGER_NONE is not set
79 | ## CONFIG_ADXL362_TRIGGER_GLOBAL_THREAD=y
80 | ## # CONFIG_ADXL362_TRIGGER_OWN_THREAD is not set
81 | #CONFIG_ADXL362_TRIGGER=y
82 | #CONFIG_ADXL362_ACTIVITY_THRESHOLD=1000
83 | #CONFIG_ADXL362_INACTIVITY_THRESHOLD=100
84 | #CONFIG_ADXL362_INTERRUPT_MODE=1
85 | #CONFIG_ADXL362_ABS_REF_MODE=1
86 |
--------------------------------------------------------------------------------
/app/drivers/Kconfig:
--------------------------------------------------------------------------------
1 | # drivers configuration options
2 |
3 | # Copyright (c) 2015 Intel Corporation
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | menu "Device Drivers"
7 |
8 |
9 | source "drivers/sensor/Kconfig"
10 |
11 |
12 | endmenu
13 |
--------------------------------------------------------------------------------
/app/drivers/sensor/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | add_subdirectory_ifdef(CONFIG_BMA421 bma421)
4 | add_subdirectory_ifdef(CONFIG_HRS3300 hrs3300)
5 | add_subdirectory_ifdef(CONFIG_CST816S cst816s)
6 |
7 |
--------------------------------------------------------------------------------
/app/drivers/sensor/Kconfig:
--------------------------------------------------------------------------------
1 | # Sensor configuration options
2 |
3 | # Copyright (c) 2016 Intel Corporation
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | menu "Sensor drivers"
8 |
9 |
10 | rsource "bma421/Kconfig"
11 |
12 | rsource "hrs3300/Kconfig"
13 |
14 | rsource "cst816s/Kconfig"
15 |
16 | endmenu
17 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | zephyr_library()
4 |
5 | zephyr_library_sources_ifdef(CONFIG_BMA421 bma421.c)
6 | zephyr_library_sources_ifdef(CONFIG_BMA421_TRIGGER bma421_trigger.c)
7 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/Kconfig:
--------------------------------------------------------------------------------
1 | # BMA421 Three Axis Accelerometer configuration options
2 |
3 | # Copyright (c) 2016 Intel Corporation
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 | menuconfig BMA421
7 | bool "BMA421 Three Axis Accelerometer Family"
8 | depends on I2C
9 | help
10 | Enable driver for BMA421 I2C-based triaxial accelerometer sensor
11 | family.
12 |
13 | if BMA421
14 |
15 | choice
16 | prompt "Chip type"
17 | default BMA421_CHIP_BMA421
18 | help
19 | Choose desired chip type from the BMA421 family.
20 |
21 | config BMA421_CHIP_BMA421
22 | bool "BMA421"
23 | help
24 | Choose this option to enable the BMA421 chip.
25 |
26 | endchoice
27 |
28 | config BMA421_NAME
29 | string "Driver name"
30 | default "BMA421" if BMA421_CHIP_BMA421
31 | help
32 | Device name with which the sensor is identified.
33 |
34 | config BMA421_I2C_ADDR
35 | hex "BMA421 I2C address"
36 | default 0x18 if BMA421_CHIP_BMA421
37 | help
38 | I2C address of the BMA421 sensor.
39 |
40 | 0x10: Use if the SDO pin is pulled to GND.
41 | 0x10: Use if the SDO pin is pulled to VDDIO.
42 | 0x18: Use if the SDO pin is pulled to GND.
43 | 0x19: Use if the SDO pin is pulled to VDDIO.
44 |
45 | config BMA421_I2C_MASTER_DEV_NAME
46 | string "I2C master device name"
47 | default "I2C_1"
48 | help
49 | Specify the device name of the I2C master device to which chip is
50 | connected.
51 |
52 | choice
53 | prompt "Trigger mode"
54 | default BMA421_TRIGGER_GLOBAL_THREAD
55 | help
56 | Specify the type of triggering to be used by the driver.
57 |
58 | config BMA421_TRIGGER_NONE
59 | bool "No trigger"
60 |
61 | config BMA421_TRIGGER_GLOBAL_THREAD
62 | bool "Use global thread"
63 | depends on GPIO
64 | select BMA421_TRIGGER
65 |
66 | config BMA421_TRIGGER_OWN_THREAD
67 | bool "Use own thread"
68 | depends on GPIO
69 | select BMA421_TRIGGER
70 |
71 | endchoice
72 |
73 | config BMA421_TRIGGER
74 | bool
75 |
76 | config BMA421_GPIO_DEV_NAME
77 | string "GPIO device"
78 | default "GPIO_0"
79 | depends on BMA421_TRIGGER
80 | help
81 | The device name of the GPIO device to which the chip's interrupt pins
82 | are connected.
83 |
84 | config BMA421_GPIO_PIN_NUM
85 | int "Interrupt GPIO pin number"
86 | default 8
87 | depends on BMA421_TRIGGER
88 | help
89 | The number of the GPIO on which the interrupt signal from the chip
90 | will be received.
91 |
92 | config BMA421_THREAD_PRIORITY
93 | int "Thread priority"
94 | depends on BMA421_TRIGGER_OWN_THREAD
95 | default 10
96 | help
97 | Priority of thread used by the driver to handle interrupts.
98 |
99 | config BMA421_THREAD_STACK_SIZE
100 | int "Thread stack size"
101 | depends on BMA421_TRIGGER_OWN_THREAD
102 | default 1024
103 | help
104 | Stack size of thread used by the driver to handle interrupts.
105 |
106 | choice
107 | prompt "Acceleration measurement range"
108 | default BMA421_ACC_RANGE_2G
109 | help
110 | Measurement range for acceleration values.
111 |
112 | config BMA421_ACC_RANGE_2G
113 | bool "+/-2g"
114 |
115 | config BMA421_ACC_RANGE_4G
116 | bool "+/-4g"
117 |
118 | config BMA421_ACC_RANGE_8G
119 | bool "+/-8g"
120 |
121 | config BMA421_ACC_RANGE_16G
122 | bool "+/-16g"
123 |
124 | endchoice
125 |
126 | choice
127 | prompt "Acceleration data filter bandwidth"
128 | default BMA421_ACC_ODR_7
129 | help
130 | Bandwidth of filtered acceleration data.
131 |
132 | config BMA421_ACC_ODR_1
133 | bool "7.81Hz"
134 |
135 | config BMA421_ACC_ODR_2
136 | bool "15.63HZ"
137 |
138 | config BMA421_ACC_ODR_3
139 | bool "31.25Hz"
140 |
141 | config BMA421_ACC_ODR_4
142 | bool "62.5Hz"
143 |
144 | config BMA421_ACC_ODR_5
145 | bool "125Hz"
146 |
147 | config BMA421_ACC_ODR_6
148 | bool "250HZ"
149 |
150 | config BMA421_ACC_ODR_7
151 | bool "500Hz"
152 |
153 | config BMA421_ACC_ODR_8
154 | bool "1000Hz"
155 |
156 | config BMA421_ACC_ODR_9
157 | bool "2000Hz"
158 |
159 | config BMA421_ACC_ODR_10
160 | bool "4000Hz"
161 |
162 | config BMA421_ACC_ODR_11
163 | bool "8000Hz"
164 |
165 | config BMA421_ACC_ODR_12
166 | bool "16000Hz"
167 |
168 | config BMA421_PMU_ODR_13
169 | bool "unfiltered"
170 |
171 | endchoice
172 |
173 | endif # BMA421
174 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/bma421.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "bma421.h"
13 |
14 | #define MY_REGISTER1 (*(volatile uint8_t*)0x2000F005)
15 | #define MY_REGISTER2 (*(volatile uint8_t*)0x2000F006)
16 | #define MY_REGISTER3 (*(volatile uint8_t*)0x2000F007)
17 | #define MY_REGISTER4 (*(volatile uint8_t*)0x2000F008)
18 | #define MY_REGISTER5 (*(volatile uint8_t*)0x2000F009)
19 | #define MY_REGISTER6 (*(volatile uint8_t*)0x2000F00A)
20 |
21 |
22 | //#define BMA421_CMD_ADDR UINT8_C(0X7E)
23 |
24 | LOG_MODULE_REGISTER(BMA421, CONFIG_SENSOR_LOG_LEVEL);
25 |
26 |
27 |
28 | static void i2c_delay(unsigned int cycles_to_wait)
29 | {
30 | u32_t start = k_cycle_get_32();
31 |
32 | /* Wait until the given number of cycles have passed */
33 | while (k_cycle_get_32() - start < cycles_to_wait) {
34 | }
35 | }
36 |
37 |
38 |
39 |
40 |
41 | static int bma421_sample_fetch(struct device *dev, enum sensor_channel chan)
42 | {
43 | struct bma421_data *drv_data = dev->driver_data;
44 | u8_t buf[6];
45 | u8_t lsb;
46 | u8_t id = 0U;
47 | i2c_delay(1000);
48 |
49 | __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
50 |
51 | /*
52 | * since all accel data register addresses are consecutive,
53 | * a burst read can be used to read all the samples
54 | */
55 | if (i2c_burst_read(drv_data->i2c, BMA421_I2C_ADDRESS,
56 | BMA421_REG_ACCEL_X_LSB, buf, 6) < 0) {
57 | LOG_DBG("Could not read accel axis data");
58 | return -EIO;
59 | }
60 |
61 | lsb = (buf[0] & BMA421_ACCEL_LSB_MASK) >> BMA421_ACCEL_LSB_SHIFT;
62 | drv_data->x_sample = (((s8_t)buf[1]) << BMA421_ACCEL_LSB_BITS) | lsb;
63 |
64 | lsb = (buf[2] & BMA421_ACCEL_LSB_MASK) >> BMA421_ACCEL_LSB_SHIFT;
65 | drv_data->y_sample = (((s8_t)buf[3]) << BMA421_ACCEL_LSB_BITS) | lsb;
66 |
67 | lsb = (buf[4] & BMA421_ACCEL_LSB_MASK) >> BMA421_ACCEL_LSB_SHIFT;
68 | drv_data->z_sample = (((s8_t)buf[5]) << BMA421_ACCEL_LSB_BITS) | lsb;
69 |
70 | if (i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
71 | BMA421_REG_TEMP,
72 | (u8_t *)&drv_data->temp_sample) < 0) {
73 | LOG_DBG("Could not read temperature data");
74 | return -EIO;
75 | }
76 | return 0;
77 | }
78 |
79 | static void bma421_channel_accel_convert(struct sensor_value *val,
80 | s64_t raw_val)
81 | {
82 | /*
83 | * accel_val = (sample * BMA280_PMU_FULL_RAGE) /
84 | * (2^data_width * 10^6)
85 | */
86 | raw_val = (raw_val * BMA421_ACC_FULL_RANGE) /
87 | (1 << (8 + BMA421_ACCEL_LSB_BITS));
88 | val->val1 = raw_val / 1000000;
89 | val->val2 = raw_val % 1000000;
90 |
91 | /* normalize val to make sure val->val2 is positive */
92 | if (val->val2 < 0) {
93 | val->val1 -= 1;
94 | val->val2 += 1000000;
95 | }
96 | }
97 |
98 | static void bma421_channel_value_add(struct sensor_value *val)
99 | {
100 | val->val1 = 32; //todo -- here values can be read from REG 0x1E step counter
101 | val->val2 = 88;
102 | }
103 |
104 | static int bma421_channel_get(struct device *dev,
105 | enum sensor_channel chan,
106 | struct sensor_value *val)
107 | {
108 | struct bma421_data *drv_data = dev->driver_data;
109 |
110 | /*
111 | * See datasheet "Sensor data" section for
112 | * more details on processing sample data.
113 | */
114 | if (chan == SENSOR_CHAN_ACCEL_X) {
115 | bma421_channel_accel_convert(val, drv_data->x_sample);
116 | } else if (chan == SENSOR_CHAN_ACCEL_Y) {
117 | bma421_channel_accel_convert(val, drv_data->y_sample);
118 | } else if (chan == SENSOR_CHAN_ACCEL_Z) {
119 | bma421_channel_accel_convert(val, drv_data->z_sample);
120 | } else if (chan == SENSOR_CHAN_ACCEL_XYZ) {
121 | bma421_channel_accel_convert(val, drv_data->x_sample);
122 | bma421_channel_accel_convert(val + 1, drv_data->y_sample);
123 | bma421_channel_accel_convert(val + 2, drv_data->z_sample);
124 | bma421_channel_value_add(val + 3); //todo check how extra data can be passed
125 | } else if (chan == SENSOR_CHAN_DIE_TEMP) {
126 | /* temperature_val = 23 + sample / 2 */
127 | val->val1 = (drv_data->temp_sample >> 1) + 23;
128 | val->val2 = 500000 * (drv_data->temp_sample & 1);
129 | return 0;
130 | } else {
131 | return -ENOTSUP;
132 | }
133 |
134 | return 0;
135 | }
136 |
137 | static const struct sensor_driver_api bma421_driver_api = {
138 | #if CONFIG_BMA421_TRIGGER
139 | .attr_set = bma421_attr_set,
140 | .trigger_set = bma421_trigger_set,
141 | #endif
142 | .sample_fetch = bma421_sample_fetch,
143 | .channel_get = bma421_channel_get,
144 | };
145 |
146 |
147 |
148 |
149 |
150 | int bma421_init(struct device *dev)
151 | {
152 | struct bma421_data *drv_data = dev->driver_data;
153 | u8_t id = 0U;
154 | drv_data->i2c = device_get_binding(CONFIG_BMA421_I2C_MASTER_DEV_NAME);
155 | if (drv_data->i2c == NULL) {
156 | LOG_DBG("Could not get pointer to %s device",
157 | CONFIG_BMA421_I2C_MASTER_DEV_NAME);
158 | return -EINVAL;
159 | }
160 |
161 | /* read device ID */
162 | if (i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
163 | BMA421_REG_CHIP_ID, &id) < 0) {
164 | LOG_DBG("Could not read chip id");
165 | return -EIO;
166 | }
167 |
168 | if (id != BMA421_CHIP_ID) {
169 | LOG_DBG("Unexpected chip id (%x)", id);
170 | return -EIO;
171 | }
172 |
173 |
174 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_CMD, BMA421_CMD_SOFT_RESET_MASK, BMA421_CMD_SOFT_RESET) < 0) { //soft reset
175 | // MY_REGISTER5=0x33;
176 | }
177 | //todo clean up debug registers
178 |
179 | i2c_delay(100);
180 |
181 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_ACC_CONF, 0x80, 0x80) < 0) { //acc performance 1
182 | // MY_REGISTER4=0x33;
183 | }
184 |
185 | //todo create names for hardcoded stuff, review masks - should cover multiple bits...
186 | i2c_delay(100);
187 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_PWR_CTRL , 0x04, 0x04) < 0) { //enable accelerometer
188 | // MY_REGISTER5=0x33;
189 | }
190 | i2c_delay(100);
191 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_PWR_CONF , 0x03, 0x00) < 0) { //disable powersave for testing (todo powersave)
192 | // MY_REGISTER5=0x33;
193 | }
194 | i2c_delay(100);
195 | if (i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS, 0x40, &id) < 0) {
196 | //could not read 0x40
197 | // MY_REGISTER3=0xFF;
198 | }
199 | MY_REGISTER3=id; // read statement to check if update took place -- useless afterwards todo delete
200 | /* set g-range */
201 | i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,BMA421_REG_ACC_RANGE, &id);
202 | id=id & 0xFC; // bit 1 and 0 of 0x41 are set to 0
203 | id=id | BMA421_ACC_RANGE; //this is set with a variable from Kconfig
204 |
205 |
206 | //todo use update_byte instead of write_byte
207 | if (i2c_reg_write_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
208 | BMA421_REG_ACC_RANGE, id) < 0) {
209 | MY_REGISTER5=0xCC;
210 | LOG_DBG("Could not set data g-range");
211 | return -EIO;
212 | }
213 | else
214 | MY_REGISTER5=id; //todo remove
215 |
216 | i2c_delay(100);
217 | i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,BMA421_REG_ACC_CONF, &id);
218 | id=id & 0xF0; //bit 3,2,1,0 are set to 0
219 | id=id | BMA421_ACC_ODR;
220 | if (i2c_reg_write_byte(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_ACC_CONF, id) < 0) {
221 | MY_REGISTER6=0xCC;
222 | }
223 | else
224 | MY_REGISTER6=id; //todo remove
225 |
226 | #ifdef CONFIG_BMA421_TRIGGER
227 | if (bma421_init_interrupt(dev) < 0) {
228 | LOG_DBG("Could not initialize interrupts");
229 | return -EIO;
230 | }
231 | #endif
232 |
233 | return 0;
234 | }
235 |
236 | struct bma421_data bma421_driver;
237 |
238 | DEVICE_AND_API_INIT(bma421, CONFIG_BMA421_NAME, bma421_init, &bma421_driver,
239 | NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
240 | &bma421_driver_api);
241 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/bma421.h:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef ZEPHYR_DRIVERS_SENSOR_BMA421_BMA421_H_
8 | #define ZEPHYR_DRIVERS_SENSOR_BMA421_BMA421_H_
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #define BMA421_I2C_ADDRESS CONFIG_BMA421_I2C_ADDR
16 |
17 | #define BMA421_REG_CHIP_ID 0x00
18 | #if CONFIG_BMA421_CHIP_BMA421
19 | #define BMA421_CHIP_ID 0x11
20 | #endif
21 |
22 | #define BMA421_REG_ACC_CONF 0x40 //set the output data rate, bandwidth and read mode
23 | #define BMA421_REG_ACC_RANGE 0x41 //set the output data rate, bandwidth and read mode
24 | #define BMA421_REG_PWR_CONF 0x7C //power mode configuration
25 | #define BMA421_REG_PWR_CTRL 0x7D //sensor enable
26 | #define BMA421_REG_CMD 0x7E //command register
27 | #define BMA421_REG_FEATURE 0x5E //feature register
28 | #define BMA421_REG_INT_LATCH 0x55
29 | #define BMA421_INT_MODE_LATCH 0x01 //permanent latched
30 | #define BMA421_REG_INT1_MAP 0x56
31 | #define BMA421_INT_MAP_MOTION 0x40 //bit 6 for any motion
32 | #define BMA421_REG_INT_STATUS_0 0x1C //interrupt feature status
33 |
34 | //#define BMA421_FEATURE_SIZE UINT8_C(64)
35 | #define BMA421_FEATURE_SIZE 64
36 |
37 | #define BMA421_CMD_SOFT_RESET 0xB6
38 | #define BMA421_CMD_SOFT_RESET_MASK 0xB6
39 | #define BMA421_ACC_PERF_MODE 0x80 //continues filter function
40 |
41 | //#define BMA421_REG_PMU_BW 0x10
42 | #if CONFIG_BMA421_ACC_ODR_1
43 | #define BMA421_ACC_ODR 0x01
44 | #elif CONFIG_BMA421_ACC_ODR_2
45 | #define BMA421_ACC_ODR 0x02
46 | #elif CONFIG_BMA421_ACC_ODR_3
47 | #define BMA421_ACC_ODR 0x03
48 | #elif CONFIG_BMA421_ACC_ODR_4
49 | #define BMA421_ACC_ODR 0x04
50 | #elif CONFIG_BMA421_ACC_ODR_5
51 | #define BMA421_ACC_ODR 0x05
52 | #elif CONFIG_BMA421_ACC_ODR_6
53 | #define BMA421_ACC_ODR 0x06
54 | #elif CONFIG_BMA421_ACC_ODR_7
55 | #define BMA421_ACC_ODR 0x07
56 | #elif CONFIG_BMA421_ACC_ODR_8
57 | #define BMA421_ACC_ODR 0x08
58 | #elif CONFIG_BMA421_ACC_ODR_9
59 | #define BMA421_ACC_ODR 0x09
60 | #elif CONFIG_BMA421_ACC_ODR_10
61 | #define BMA421_ACC_ODR 0x0a
62 | #elif CONFIG_BMA421_ACC_ODR_11
63 | #define BMA421_ACC_ODR 0x0b
64 | #elif CONFIG_BMA421_ACC_ODR_12
65 | #define BMA421_ACC_ODR 0x0c
66 | #elif CONFIG_BMA421_ACC_ODR_13
67 | #define BMA421_ACC_ODR 0x00
68 | #endif
69 |
70 |
71 |
72 |
73 | #if CONFIG_BMA421_ACC_RANGE_2G
74 | #define BMA421_ACC_RANGE 0x00
75 | #define BMA421_ACC_FULL_RANGE (4 * SENSOR_G)
76 | #elif CONFIG_BMA421_ACC_RANGE_4G
77 | #define BMA421_ACC_RANGE 0x01
78 | #define BMA421_ACC_FULL_RANGE (8 * SENSOR_G)
79 | #elif CONFIG_BMA421_ACC_RANGE_8G
80 | #define BMA421_ACC_RANGE 0x02
81 | #define BMA421_ACC_FULL_RANGE (16 * SENSOR_G)
82 | #elif CONFIG_BMA421_ACC_RANGE_16G
83 | #define BMA421_ACC_RANGE 0x03
84 | #define BMA421_ACC_FULL_RANGE (32 * SENSOR_G)
85 | #endif
86 |
87 | #define BMA421_REG_TEMP 0x08
88 | #define BMA421_REG_ACCEL_X_LSB 0x12
89 | #define BMA421_REG_ACCEL_Y_LSB 0x14
90 | #define BMA421_REG_ACCEL_Z_LSB 0x16
91 |
92 | #if CONFIG_BMA421_CHIP_BMA421
93 | #define BMA421_ACCEL_LSB_BITS 6
94 | #define BMA421_ACCEL_LSB_SHIFT 2
95 | #endif
96 | #define BMA421_ACCEL_LSB_MASK \
97 | (BIT_MASK(BMA421_ACCEL_LSB_BITS) << BMA421_ACCEL_LSB_SHIFT)
98 |
99 | #define BMA421_REG_ACCEL_X_MSB 0x3
100 | #define BMA421_REG_ACCEL_Y_MSB 0x5
101 | #define BMA421_REG_ACCEL_Z_MSB 0x7
102 |
103 | #define BMA421_THREAD_PRIORITY 10
104 | #define BMA421_THREAD_STACKSIZE_UNIT 1024
105 |
106 | struct bma421_data {
107 | struct device *i2c;
108 | s16_t x_sample;
109 | s16_t y_sample;
110 | s16_t z_sample;
111 | s8_t temp_sample;
112 |
113 | #ifdef CONFIG_BMA421_TRIGGER
114 | struct device *gpio;
115 | struct gpio_callback gpio_cb;
116 |
117 | struct sensor_trigger data_ready_trigger;
118 | sensor_trigger_handler_t data_ready_handler;
119 |
120 | struct sensor_trigger any_motion_trigger;
121 | sensor_trigger_handler_t any_motion_handler;
122 |
123 | #if defined(CONFIG_BMA421_TRIGGER_OWN_THREAD)
124 | K_THREAD_STACK_MEMBER(thread_stack, CONFIG_BMA421_THREAD_STACK_SIZE);
125 | struct k_thread thread;
126 | struct k_sem gpio_sem;
127 | #elif defined(CONFIG_BMA421_TRIGGER_GLOBAL_THREAD)
128 | struct k_work work;
129 | struct device *dev;
130 | #endif
131 |
132 | #endif /* CONFIG_BMA421_TRIGGER */
133 | };
134 |
135 | #ifdef CONFIG_BMA421_TRIGGER
136 | int bma421_trigger_set(struct device *dev,
137 | const struct sensor_trigger *trig,
138 | sensor_trigger_handler_t handler);
139 |
140 | int bma421_attr_set(struct device *dev,
141 | enum sensor_channel chan,
142 | enum sensor_attribute attr,
143 | const struct sensor_value *val);
144 |
145 | int bma421_init_interrupt(struct device *dev);
146 | #endif
147 |
148 | #endif /* ZEPHYR_DRIVERS_SENSOR_BMA421_BMA421_H_ */
149 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/bma421_trigger.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Intel Corporation
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "bma421.h"
14 |
15 | #include
16 | LOG_MODULE_DECLARE(BMA421, CONFIG_SENSOR_LOG_LEVEL);
17 |
18 | int bma421_attr_set(struct device *dev,
19 | enum sensor_channel chan,
20 | enum sensor_attribute attr,
21 | const struct sensor_value *val)
22 | {
23 | struct bma421_data *drv_data = dev->driver_data;
24 | u64_t slope_th;
25 | u8_t buf[BMA421_FEATURE_SIZE];
26 | //default anymotion is selected
27 | //todo set any parameter eg stepcounter, tap double tap, wrist tilt etc
28 | // if (i2c_burst_read(drv_data->i2c, BMA421_I2C_ADDRESS, BMA421_REG_FEATURE, buf, BMA421_FEATURE_SIZE) < 0) {}
29 |
30 | if (chan != SENSOR_CHAN_ACCEL_XYZ) {
31 | return -ENOTSUP;
32 | }
33 | //0x5E features register burst read
34 | /* if (attr == SENSOR_ATTR_SLOPE_TH) {
35 | }
36 | } else if (attr == SENSOR_ATTR_SLOPE_DUR) {
37 | }
38 | } else {
39 | return -ENOTSUP;
40 | }
41 | */
42 | return 0;
43 | }
44 |
45 | static void bma421_gpio_callback(struct device *dev,
46 | struct gpio_callback *cb, u32_t pins)
47 | {
48 | struct bma421_data *drv_data =
49 | CONTAINER_OF(cb, struct bma421_data, gpio_cb);
50 |
51 | ARG_UNUSED(pins);
52 |
53 | gpio_pin_disable_callback(dev, CONFIG_BMA421_GPIO_PIN_NUM);
54 |
55 | #if defined(CONFIG_BMA421_TRIGGER_OWN_THREAD)
56 | k_sem_give(&drv_data->gpio_sem);
57 | #elif defined(CONFIG_BMA421_TRIGGER_GLOBAL_THREAD)
58 | k_work_submit(&drv_data->work);
59 | #endif
60 | }
61 |
62 | static void bma421_thread_cb(void *arg)
63 | {
64 | struct device *dev = arg;
65 | struct bma421_data *drv_data = dev->driver_data;
66 | u8_t status = 0U;
67 | int err = 0;
68 |
69 | /* check for data ready */
70 | /* err = i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
71 | BMA421_REG_INT_STATUS_1, &status);
72 | if (status & BMA421_BIT_DATA_INT_STATUS &&
73 | drv_data->data_ready_handler != NULL &&
74 | err == 0) {
75 | drv_data->data_ready_handler(dev,
76 | &drv_data->data_ready_trigger);
77 | }
78 | */
79 | /* check for any motion */
80 | err = i2c_reg_read_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
81 | BMA421_REG_INT_STATUS_0, &status);
82 | if (status &&
83 | drv_data->any_motion_handler != NULL &&
84 | err == 0) {
85 | drv_data->any_motion_handler(dev,
86 | &drv_data->data_ready_trigger);
87 |
88 | /* clear latched interrupt -- according this is already done by reading the register*/
89 | /* err = i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
90 | BMA421_REG_INT_RST_LATCH,
91 | BMA421_BIT_INT_LATCH_RESET,
92 | BMA421_BIT_INT_LATCH_RESET);
93 |
94 | if (err < 0) {
95 | LOG_DBG("Could not update clear the interrupt");
96 | return;
97 | }*/
98 | }
99 |
100 | gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA421_GPIO_PIN_NUM);
101 | }
102 |
103 | #ifdef CONFIG_BMA421_TRIGGER_OWN_THREAD
104 | static void bma421_thread(int dev_ptr, int unused)
105 | {
106 | struct device *dev = INT_TO_POINTER(dev_ptr);
107 | struct bma421_data *drv_data = dev->driver_data;
108 |
109 | ARG_UNUSED(unused);
110 |
111 | while (1) {
112 | k_sem_take(&drv_data->gpio_sem, K_FOREVER);
113 | bma421_thread_cb(dev);
114 | }
115 | }
116 | #endif
117 |
118 | #ifdef CONFIG_BMA421_TRIGGER_GLOBAL_THREAD
119 | static void bma421_work_cb(struct k_work *work)
120 | {
121 | struct bma421_data *drv_data =
122 | CONTAINER_OF(work, struct bma421_data, work);
123 |
124 | bma421_thread_cb(drv_data->dev);
125 | }
126 | #endif
127 |
128 | int bma421_trigger_set(struct device *dev,
129 | const struct sensor_trigger *trig,
130 | sensor_trigger_handler_t handler)
131 | {
132 | struct bma421_data *drv_data = dev->driver_data;
133 |
134 | if (trig->type == SENSOR_TRIG_DATA_READY) {
135 | /* disable data ready interrupt while changing trigger params */
136 | /* if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
137 | BMA421_REG_INT_EN_1,
138 | BMA421_BIT_DATA_EN, 0) < 0) {
139 | LOG_DBG("Could not disable data ready interrupt");
140 | return -EIO;
141 | }
142 |
143 | drv_data->data_ready_handler = handler;
144 | if (handler == NULL) {
145 | return 0;
146 | }
147 | drv_data->data_ready_trigger = *trig;
148 | */
149 | /* enable data ready interrupt */
150 | /* if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
151 | BMA421_REG_INT_EN_1,
152 | BMA421_BIT_DATA_EN,
153 | BMA421_BIT_DATA_EN) < 0) {
154 | LOG_DBG("Could not enable data ready interrupt");
155 | return -EIO;
156 | }*/
157 | } else if (trig->type == SENSOR_TRIG_DELTA) {
158 | /* disable any-motion interrupt while changing trigger params */
159 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
160 | BMA421_REG_INT1_MAP,
161 | BMA421_INT_MAP_MOTION, 0) < 0) {
162 | LOG_DBG("Could not disable data ready interrupt");
163 | return -EIO;
164 | }
165 |
166 | drv_data->any_motion_handler = handler;
167 | if (handler == NULL) {
168 | return 0;
169 | }
170 | drv_data->any_motion_trigger = *trig;
171 |
172 | /* enable any-motion interrupt */
173 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
174 | BMA421_REG_INT1_MAP,
175 | BMA421_INT_MAP_MOTION,
176 | BMA421_INT_MAP_MOTION) < 0) {
177 | LOG_DBG("Could not enable data ready interrupt");
178 | return -EIO;
179 | }
180 | } else {
181 | return -ENOTSUP;
182 | }
183 |
184 | return 0;
185 | }
186 |
187 | int bma421_init_interrupt(struct device *dev)
188 | {
189 | struct bma421_data *drv_data = dev->driver_data;
190 |
191 | /* set latched interrupts */
192 | if (i2c_reg_write_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
193 | BMA421_REG_INT_LATCH,
194 | BMA421_INT_MODE_LATCH) < 0) {
195 | LOG_DBG("Could not set latched interrupts");
196 | return -EIO;
197 | }
198 |
199 | /* setup data ready gpio interrupt */
200 | /* drv_data->gpio = device_get_binding(CONFIG_BMA421_GPIO_DEV_NAME);
201 | if (drv_data->gpio == NULL) {
202 | LOG_DBG("Cannot get pointer to %s device",
203 | CONFIG_BMA421_GPIO_DEV_NAME);
204 | return -EINVAL;
205 | }
206 |
207 | gpio_pin_configure(drv_data->gpio, CONFIG_BMA421_GPIO_PIN_NUM,
208 | GPIO_DIR_IN | GPIO_INT | GPIO_INT_LEVEL |
209 | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
210 |
211 | gpio_init_callback(&drv_data->gpio_cb,
212 | bma421_gpio_callback,
213 | BIT(CONFIG_BMA421_GPIO_PIN_NUM));
214 |
215 | if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
216 | LOG_DBG("Could not set gpio callback");
217 | return -EIO;
218 | }
219 | */
220 | /* map data ready interrupt to INT1 */
221 | /* if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
222 | BMA421_REG_INT_MAP_1,
223 | BMA421_INT_MAP_1_BIT_DATA,
224 | BMA421_INT_MAP_1_BIT_DATA) < 0) {
225 | LOG_DBG("Could not map data ready interrupt pin");
226 | return -EIO;
227 | }
228 | */
229 | /* map any-motion interrupt to INT1 */
230 | if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
231 | BMA421_REG_INT1_MAP,
232 | BMA421_INT_MAP_MOTION,
233 | BMA421_INT_MAP_MOTION) < 0) {
234 | LOG_DBG("Could not map any-motion interrupt pin");
235 | return -EIO;
236 | }
237 |
238 | /* if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
239 | BMA421_REG_INT1_MAP,
240 | BMA421_BIT_DATA_EN, 0) < 0) {
241 | LOG_DBG("Could not disable data ready interrupt");
242 | return -EIO;
243 | }
244 | */
245 | /* disable any-motion interrupt */
246 | /* if (i2c_reg_update_byte(drv_data->i2c, BMA421_I2C_ADDRESS,
247 | BMA421_REG_INT_EN_0,
248 | BMA421_SLOPE_EN_XYZ, 0) < 0) {
249 | LOG_DBG("Could not disable data ready interrupt");
250 | return -EIO;
251 | }
252 | */
253 | #if defined(CONFIG_BMA421_TRIGGER_OWN_THREAD)
254 | k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
255 |
256 | k_thread_create(&drv_data->thread, drv_data->thread_stack,
257 | CONFIG_BMA421_THREAD_STACK_SIZE,
258 | (k_thread_entry_t)bma421_thread, dev,
259 | 0, NULL, K_PRIO_COOP(CONFIG_BMA421_THREAD_PRIORITY),
260 | 0, K_NO_WAIT);
261 | #elif defined(CONFIG_BMA421_TRIGGER_GLOBAL_THREAD)
262 | drv_data->work.handler = bma421_work_cb;
263 | drv_data->dev = dev;
264 | #endif
265 |
266 | gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA421_GPIO_PIN_NUM);
267 |
268 | return 0;
269 | }
270 |
--------------------------------------------------------------------------------
/app/drivers/sensor/bma421/bma421_trigger.c-todo:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Intel Corporation
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "bma421.h"
14 |
15 | #include
16 | LOG_MODULE_DECLARE(BMA280, CONFIG_SENSOR_LOG_LEVEL);
17 |
18 | int bma280_attr_set(struct device *dev,
19 | enum sensor_channel chan,
20 | enum sensor_attribute attr,
21 | const struct sensor_value *val)
22 | {
23 | struct bma280_data *drv_data = dev->driver_data;
24 | u64_t slope_th;
25 |
26 | if (chan != SENSOR_CHAN_ACCEL_XYZ) {
27 | return -ENOTSUP;
28 | }
29 |
30 | if (attr == SENSOR_ATTR_SLOPE_TH) {
31 | /* slope_th = (val * 10^6 * 2^10) / BMA280_PMU_FULL_RAGE */
32 | slope_th = (u64_t)val->val1 * 1000000U + (u64_t)val->val2;
33 | slope_th = (slope_th * (1 << 10)) / BMA280_PMU_FULL_RANGE;
34 | if (i2c_reg_write_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
35 | BMA280_REG_SLOPE_TH, (u8_t)slope_th)
36 | < 0) {
37 | LOG_DBG("Could not set slope threshold");
38 | return -EIO;
39 | }
40 | } else if (attr == SENSOR_ATTR_SLOPE_DUR) {
41 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
42 | BMA280_REG_INT_5,
43 | BMA280_SLOPE_DUR_MASK,
44 | val->val1 << BMA280_SLOPE_DUR_SHIFT)
45 | < 0) {
46 | LOG_DBG("Could not set slope duration");
47 | return -EIO;
48 | }
49 | } else {
50 | return -ENOTSUP;
51 | }
52 |
53 | return 0;
54 | }
55 |
56 | static void bma280_gpio_callback(struct device *dev,
57 | struct gpio_callback *cb, u32_t pins)
58 | {
59 | struct bma280_data *drv_data =
60 | CONTAINER_OF(cb, struct bma280_data, gpio_cb);
61 |
62 | ARG_UNUSED(pins);
63 |
64 | gpio_pin_disable_callback(dev, CONFIG_BMA280_GPIO_PIN_NUM);
65 |
66 | #if defined(CONFIG_BMA280_TRIGGER_OWN_THREAD)
67 | k_sem_give(&drv_data->gpio_sem);
68 | #elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_THREAD)
69 | k_work_submit(&drv_data->work);
70 | #endif
71 | }
72 |
73 | static void bma280_thread_cb(void *arg)
74 | {
75 | struct device *dev = arg;
76 | struct bma280_data *drv_data = dev->driver_data;
77 | u8_t status = 0U;
78 | int err = 0;
79 |
80 | /* check for data ready */
81 | err = i2c_reg_read_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
82 | BMA280_REG_INT_STATUS_1, &status);
83 | if (status & BMA280_BIT_DATA_INT_STATUS &&
84 | drv_data->data_ready_handler != NULL &&
85 | err == 0) {
86 | drv_data->data_ready_handler(dev,
87 | &drv_data->data_ready_trigger);
88 | }
89 |
90 | /* check for any motion */
91 | err = i2c_reg_read_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
92 | BMA280_REG_INT_STATUS_0, &status);
93 | if (status & BMA280_BIT_SLOPE_INT_STATUS &&
94 | drv_data->any_motion_handler != NULL &&
95 | err == 0) {
96 | drv_data->any_motion_handler(dev,
97 | &drv_data->data_ready_trigger);
98 |
99 | /* clear latched interrupt */
100 | err = i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
101 | BMA280_REG_INT_RST_LATCH,
102 | BMA280_BIT_INT_LATCH_RESET,
103 | BMA280_BIT_INT_LATCH_RESET);
104 |
105 | if (err < 0) {
106 | LOG_DBG("Could not update clear the interrupt");
107 | return;
108 | }
109 | }
110 |
111 | gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM);
112 | }
113 |
114 | #ifdef CONFIG_BMA280_TRIGGER_OWN_THREAD
115 | static void bma280_thread(int dev_ptr, int unused)
116 | {
117 | struct device *dev = INT_TO_POINTER(dev_ptr);
118 | struct bma280_data *drv_data = dev->driver_data;
119 |
120 | ARG_UNUSED(unused);
121 |
122 | while (1) {
123 | k_sem_take(&drv_data->gpio_sem, K_FOREVER);
124 | bma280_thread_cb(dev);
125 | }
126 | }
127 | #endif
128 |
129 | #ifdef CONFIG_BMA280_TRIGGER_GLOBAL_THREAD
130 | static void bma280_work_cb(struct k_work *work)
131 | {
132 | struct bma280_data *drv_data =
133 | CONTAINER_OF(work, struct bma280_data, work);
134 |
135 | bma280_thread_cb(drv_data->dev);
136 | }
137 | #endif
138 |
139 | int bma280_trigger_set(struct device *dev,
140 | const struct sensor_trigger *trig,
141 | sensor_trigger_handler_t handler)
142 | {
143 | struct bma280_data *drv_data = dev->driver_data;
144 |
145 | if (trig->type == SENSOR_TRIG_DATA_READY) {
146 | /* disable data ready interrupt while changing trigger params */
147 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
148 | BMA280_REG_INT_EN_1,
149 | BMA280_BIT_DATA_EN, 0) < 0) {
150 | LOG_DBG("Could not disable data ready interrupt");
151 | return -EIO;
152 | }
153 |
154 | drv_data->data_ready_handler = handler;
155 | if (handler == NULL) {
156 | return 0;
157 | }
158 | drv_data->data_ready_trigger = *trig;
159 |
160 | /* enable data ready interrupt */
161 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
162 | BMA280_REG_INT_EN_1,
163 | BMA280_BIT_DATA_EN,
164 | BMA280_BIT_DATA_EN) < 0) {
165 | LOG_DBG("Could not enable data ready interrupt");
166 | return -EIO;
167 | }
168 | } else if (trig->type == SENSOR_TRIG_DELTA) {
169 | /* disable any-motion interrupt while changing trigger params */
170 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
171 | BMA280_REG_INT_EN_0,
172 | BMA280_SLOPE_EN_XYZ, 0) < 0) {
173 | LOG_DBG("Could not disable data ready interrupt");
174 | return -EIO;
175 | }
176 |
177 | drv_data->any_motion_handler = handler;
178 | if (handler == NULL) {
179 | return 0;
180 | }
181 | drv_data->any_motion_trigger = *trig;
182 |
183 | /* enable any-motion interrupt */
184 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
185 | BMA280_REG_INT_EN_0,
186 | BMA280_SLOPE_EN_XYZ,
187 | BMA280_SLOPE_EN_XYZ) < 0) {
188 | LOG_DBG("Could not enable data ready interrupt");
189 | return -EIO;
190 | }
191 | } else {
192 | return -ENOTSUP;
193 | }
194 |
195 | return 0;
196 | }
197 |
198 | int bma280_init_interrupt(struct device *dev)
199 | {
200 | struct bma280_data *drv_data = dev->driver_data;
201 |
202 | /* set latched interrupts */
203 | if (i2c_reg_write_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
204 | BMA280_REG_INT_RST_LATCH,
205 | BMA280_BIT_INT_LATCH_RESET |
206 | BMA280_INT_MODE_LATCH) < 0) {
207 | LOG_DBG("Could not set latched interrupts");
208 | return -EIO;
209 | }
210 |
211 | /* setup data ready gpio interrupt */
212 | drv_data->gpio = device_get_binding(CONFIG_BMA280_GPIO_DEV_NAME);
213 | if (drv_data->gpio == NULL) {
214 | LOG_DBG("Cannot get pointer to %s device",
215 | CONFIG_BMA280_GPIO_DEV_NAME);
216 | return -EINVAL;
217 | }
218 |
219 | gpio_pin_configure(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM,
220 | GPIO_DIR_IN | GPIO_INT | GPIO_INT_LEVEL |
221 | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
222 |
223 | gpio_init_callback(&drv_data->gpio_cb,
224 | bma280_gpio_callback,
225 | BIT(CONFIG_BMA280_GPIO_PIN_NUM));
226 |
227 | if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
228 | LOG_DBG("Could not set gpio callback");
229 | return -EIO;
230 | }
231 |
232 | /* map data ready interrupt to INT1 */
233 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
234 | BMA280_REG_INT_MAP_1,
235 | BMA280_INT_MAP_1_BIT_DATA,
236 | BMA280_INT_MAP_1_BIT_DATA) < 0) {
237 | LOG_DBG("Could not map data ready interrupt pin");
238 | return -EIO;
239 | }
240 |
241 | /* map any-motion interrupt to INT1 */
242 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
243 | BMA280_REG_INT_MAP_0,
244 | BMA280_INT_MAP_0_BIT_SLOPE,
245 | BMA280_INT_MAP_0_BIT_SLOPE) < 0) {
246 | LOG_DBG("Could not map any-motion interrupt pin");
247 | return -EIO;
248 | }
249 |
250 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
251 | BMA280_REG_INT_EN_1,
252 | BMA280_BIT_DATA_EN, 0) < 0) {
253 | LOG_DBG("Could not disable data ready interrupt");
254 | return -EIO;
255 | }
256 |
257 | /* disable any-motion interrupt */
258 | if (i2c_reg_update_byte(drv_data->i2c, BMA280_I2C_ADDRESS,
259 | BMA280_REG_INT_EN_0,
260 | BMA280_SLOPE_EN_XYZ, 0) < 0) {
261 | LOG_DBG("Could not disable data ready interrupt");
262 | return -EIO;
263 | }
264 |
265 | #if defined(CONFIG_BMA280_TRIGGER_OWN_THREAD)
266 | k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
267 |
268 | k_thread_create(&drv_data->thread, drv_data->thread_stack,
269 | CONFIG_BMA280_THREAD_STACK_SIZE,
270 | (k_thread_entry_t)bma280_thread, dev,
271 | 0, NULL, K_PRIO_COOP(CONFIG_BMA280_THREAD_PRIORITY),
272 | 0, K_NO_WAIT);
273 | #elif defined(CONFIG_BMA280_TRIGGER_GLOBAL_THREAD)
274 | drv_data->work.handler = bma280_work_cb;
275 | drv_data->dev = dev;
276 | #endif
277 |
278 | gpio_pin_enable_callback(drv_data->gpio, CONFIG_BMA280_GPIO_PIN_NUM);
279 |
280 | return 0;
281 | }
282 |
--------------------------------------------------------------------------------
/app/drivers/sensor/cst816s/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | zephyr_library()
4 |
5 | zephyr_library_sources_ifdef(CONFIG_CST816S cst816s.c)
6 | zephyr_library_sources_ifdef(CONFIG_CST816S_TRIGGER cst816s_trigger.c)
7 |
--------------------------------------------------------------------------------
/app/drivers/sensor/cst816s/Kconfig:
--------------------------------------------------------------------------------
1 | # CST816S Hynitron touchscreen
2 | # SPDX-License-Identifier: Apache-2.0
3 | #
4 | #menuconfig CST816S
5 | # bool "hynitron cst816 touchscreen "
6 | # depends on I2C
7 | # help
8 | # Enable driver for hynitron touchscreen.
9 | menuconfig CST816S
10 | bool "CST816S Touchscreen"
11 | depends on I2C
12 | help
13 | Enable driver for hynitron touchscreen.
14 |
15 | if CST816S
16 |
17 | choice
18 | prompt "Trigger mode"
19 | default CST816S_TRIGGER_NONE
20 | help
21 | Specify the type of triggering used by the driver.
22 |
23 | config CST816S_TRIGGER_NONE
24 | bool "No trigger"
25 |
26 | config CST816S_TRIGGER_GLOBAL_THREAD
27 | bool "Use global thread"
28 | depends on GPIO
29 | select CST816S_TRIGGER
30 |
31 | config CST816S_TRIGGER_OWN_THREAD
32 | bool "Use own thread"
33 | depends on GPIO
34 | select CST816S_TRIGGER
35 |
36 | endchoice
37 |
38 | config CST816S_TRIGGER
39 | bool
40 |
41 | config CST816S_THREAD_PRIORITY
42 | int "Thread priority"
43 | depends on CST816S_TRIGGER_OWN_THREAD && CST816S_TRIGGER
44 | default 10
45 | help
46 | Priority of thread used by the driver to handle interrupts.
47 |
48 | config CST816S_THREAD_STACK_SIZE
49 | int "Thread stack size"
50 | depends on CST816S_TRIGGER_OWN_THREAD && CST816S_TRIGGER
51 | default 512
52 | help
53 | Stack size of thread used by the driver to handle interrupts.
54 |
55 | endif # CST816S
56 |
--------------------------------------------------------------------------------
/app/drivers/sensor/cst816s/cst816s.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Intel Corporation
3 | * Copyright (c) 2020 Stephane Dorre
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | #define DT_DRV_COMPAT hynitron_cst816s
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include "cst816s.h"
17 |
18 | #define RESET_PIN DT_INST_GPIO_PIN(0, reset_gpios)
19 |
20 | LOG_MODULE_REGISTER(CST816S, CONFIG_SENSOR_LOG_LEVEL);
21 |
22 | static int cst816s_sample_fetch(const struct device *dev, enum sensor_channel chan)
23 | {
24 | struct cst816s_data *drv_data = dev->data;
25 | uint8_t buf[9];
26 | uint8_t msb;
27 | uint8_t lsb;
28 | __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
29 |
30 | /*
31 | * since all accel data register addresses are consecutive,
32 | * a burst read can be used to read all the samples
33 | */
34 | if (i2c_burst_read(drv_data->i2c, CST816S_I2C_ADDRESS,
35 | CST816S_REG_DATA, buf, 9) < 0) {
36 | LOG_DBG("Could not read data");
37 | return -EIO;
38 | }
39 |
40 | switch (buf[CST816S_REG_GESTURE_ID]) {
41 | case CST816S_GESTURE_NONE:
42 | drv_data->gesture = NONE;
43 | break;
44 | case CST816S_GESTURE_SLIDE_UP:
45 | drv_data->gesture = SLIDE_UP;
46 | break;
47 | case CST816S_GESTURE_SLIDE_DOWN:
48 | drv_data->gesture = SLIDE_DOWN;
49 | break;
50 | case CST816S_GESTURE_SLIDE_LEFT:
51 | drv_data->gesture = SLIDE_LEFT;
52 | break;
53 | case CST816S_GESTURE_SLIDE_RIGHT:
54 | drv_data->gesture = SLIDE_RIGHT;
55 | break;
56 | case CST816S_GESTURE_CLICK:
57 | drv_data->gesture = CLICK;
58 | break;
59 | case CST816S_GESTURE_DOUBLE_CLICK:
60 | drv_data->gesture = DOUBLE_CLICK;
61 | break;
62 | case CST816S_GESTURE_LONG_PRESS:
63 | drv_data->gesture = LONG_PRESS;
64 | break;
65 | }
66 |
67 | drv_data->number_touch_point = buf[CST816S_REG_FINGER_NUM];
68 |
69 | msb = buf[CST816S_REG_XPOS_H] & 0x0f;
70 | lsb = buf[CST816S_REG_XPOS_L];
71 | drv_data->touch_point_1.x = (msb<<8)|lsb;
72 |
73 | msb = buf[CST816S_REG_YPOS_H] & 0x0f;
74 | lsb = buf[CST816S_REG_YPOS_L];
75 | drv_data->touch_point_1.y = (msb<<8)|lsb;
76 |
77 | drv_data->action = (enum cst816s_action)(buf[CST816S_REG_XPOS_H] >> 6);
78 | return 0;
79 | }
80 |
81 | static int cst816s_channel_get(const struct device *dev,
82 | enum sensor_channel chan,
83 | struct sensor_value *val)
84 | {
85 | struct cst816s_data *drv_data = dev->data;
86 |
87 | if ((uint16_t)chan == CST816S_CHAN_GESTURE) {
88 | val->val1=drv_data->gesture;
89 | } else if ((uint16_t)chan == CST816S_CHAN_TOUCH_POINT_1) {
90 | val->val1=drv_data->touch_point_1.x;
91 | val->val2=drv_data->touch_point_1.y;
92 | } else if ((uint16_t)chan == CST816S_CHAN_TOUCH_POINT_2) {
93 | val->val1=drv_data->touch_point_2.x;
94 | val->val2=drv_data->touch_point_2.y;
95 | } else {
96 | return -ENOTSUP;
97 | }
98 |
99 | return 0;
100 | }
101 |
102 | static const struct sensor_driver_api cst816s_driver_api = {
103 | #if CONFIG_CST816S_TRIGGER
104 | .attr_set = cst816s_attr_set,
105 | .trigger_set = cst816s_trigger_set,
106 | #endif
107 | .sample_fetch = cst816s_sample_fetch,
108 | .channel_get = cst816s_channel_get,
109 | };
110 |
111 | static void cst816s_chip_reset(const struct device* dev)
112 | {
113 | struct cst816s_data *drv_data = dev->data;
114 |
115 | gpio_pin_set_raw(drv_data->reset_gpio, RESET_PIN, 0);
116 | k_msleep(5);
117 | gpio_pin_set_raw(drv_data->reset_gpio, RESET_PIN, 1);
118 | k_msleep(50);
119 | }
120 |
121 | static int cst816s_chip_init(const struct device *dev)
122 | {
123 | struct cst816s_data *drv_data = dev->data;
124 |
125 | cst816s_chip_reset(dev);
126 |
127 | if (i2c_reg_read_byte(drv_data->i2c, CST816S_I2C_ADDRESS,
128 | CST816S_REG_CHIP_ID, &drv_data->chip_id) < 0) {
129 | LOG_ERR("failed reading chip id");
130 | return -EIO;
131 | }
132 |
133 | if (drv_data->chip_id != CST816S_CHIP_ID) {
134 | LOG_ERR("CST816S wrong chip id: returned 0x%x", drv_data->chip_id);
135 | }
136 |
137 | if (i2c_reg_update_byte(drv_data->i2c, CST816S_I2C_ADDRESS,
138 | CST816S_REG_MOTION_MASK,
139 | (CST816S_MOTION_EN_DCLICK), (CST816S_MOTION_EN_DCLICK)) < 0) {
140 | LOG_ERR("Could not enable double click");
141 | return -EIO;
142 | }
143 |
144 | return 0;
145 | }
146 |
147 | int cst816s_init(const struct device *dev)
148 | {
149 | struct cst816s_data *drv_data = dev->data;
150 |
151 | drv_data->i2c = device_get_binding(DT_INST_BUS_LABEL(0));
152 | if (drv_data->i2c == NULL) {
153 | LOG_DBG("Could not get pointer to %s device",
154 | DT_INST_BUS_LABEL(0));
155 | return -EINVAL;
156 | }
157 |
158 | /* setup reset gpio */
159 | drv_data->reset_gpio = device_get_binding(
160 | DT_INST_GPIO_LABEL(0, reset_gpios));
161 | if (drv_data->reset_gpio == NULL) {
162 | LOG_DBG("Cannot get pointer to %s device",
163 | DT_INST_GPIO_LABEL(0, reset_gpios));
164 | return -EINVAL;
165 | }
166 |
167 | /* Configure pin as output and initialize it to high. */
168 | LOG_INF("configure OUTPUT ACTIVE");
169 | gpio_pin_configure(drv_data->reset_gpio, RESET_PIN,
170 | GPIO_OUTPUT
171 | | DT_INST_GPIO_FLAGS(0, reset_gpios));
172 |
173 | cst816s_chip_init(dev);
174 |
175 | #ifdef CONFIG_CST816S_TRIGGER
176 | if (cst816s_init_interrupt(dev) < 0) {
177 | LOG_DBG("Could not initialize interrupts");
178 | return -EIO;
179 | }
180 | #endif
181 | return 0;
182 | }
183 |
184 | struct cst816s_data cst816s_driver;
185 |
186 | DEVICE_AND_API_INIT(cst816s, DT_INST_LABEL(0), cst816s_init, &cst816s_driver,
187 | NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
188 | &cst816s_driver_api);
189 |
--------------------------------------------------------------------------------
/app/drivers/sensor/cst816s/cst816s.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016 Intel Corporation
3 | * Copyright (c) 2020 Stephane Dorre
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | #ifndef ZEPHYR_DRIVERS_SENSOR_CST816S_CST816S_H_
9 | #define ZEPHYR_DRIVERS_SENSOR_CST816S_CST816S_H_
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #define CST816S_I2C_ADDRESS 0x15
18 |
19 | #define CST816S_CHIP_ID 0xB4
20 |
21 | /***
22 | * TODO
23 | * - CST816S_REG_YPOS_H : Bits 4-7 => fingerID
24 | * - Reg addr 0x07 : Pressure ?
25 | * - Reg addr 0x08 : Bit 4-7: Area ?
26 | */
27 |
28 | /* See Register documentation here:
29 | * https://github.com/endian-albin/pinetime-hypnos/wiki/
30 | * Technical-documentation#cst816s-touch-controller
31 | */
32 |
33 | #define CST816S_REG_DATA 0x00
34 | #define CST816S_REG_GESTURE_ID 0x01
35 | #define CST816S_REG_FINGER_NUM 0x02
36 | #define CST816S_REG_XPOS_H 0x03
37 | #define CST816S_REG_XPOS_L 0x04
38 | #define CST816S_REG_YPOS_H 0x05
39 | #define CST816S_REG_YPOS_L 0x06
40 | #define CST816S_REG_BPC0H 0xB0
41 | #define CST816S_REG_BPC0L 0xB1
42 | #define CST816S_REG_BPC1H 0xB2
43 | #define CST816S_REG_BPC1L 0xB3
44 | #define CST816S_REG_POWER_MODE 0xA5
45 | #define CST816S_REG_CHIP_ID 0xA7
46 | #define CST816S_REG_PROJ_ID 0xA8
47 | #define CST816S_REG_FW_VERSION 0xA9
48 | #define CST816S_REG_MOTION_MASK 0xEC
49 | #define CST816S_REG_IRQ_PULSE_WIDTH 0xED
50 | #define CST816S_REG_NOR_SCAN_PER 0xEE
51 | #define CST816S_REG_MOTION_S1_ANGLE 0xEF
52 | #define CST816S_REG_LP_SCAN_RAW1H 0xF0
53 | #define CST816S_REG_LP_SCAN_RAW1L 0xF1
54 | #define CST816S_REG_LP_SCAN_RAW2H 0xF2
55 | #define CST816S_REG_LP_SCAN_RAW2L 0xF3
56 | #define CST816S_REG_LP_AUTO_WAKEUP_TIME 0xF4
57 | #define CST816S_REG_LP_SCAN_TH 0xF5
58 | #define CST816S_REG_LP_SCAN_WIN 0xF6
59 | #define CST816S_REG_LP_SCAN_FREQ 0xF7
60 | #define CST816S_REG_LP_SCAN_I_DAC 0xF8
61 | #define CST816S_REG_AUTOSLEEP_TIME 0xF9
62 | #define CST816S_REG_IRQ_CTL 0xFA
63 | #define CST816S_REG_DEBOUNCE_TIME 0xFB
64 | #define CST816S_REG_LONG_PRESS_TIME 0xFC
65 | #define CST816S_REG_IOCTL 0xFD
66 | #define CST816S_REG_DIS_AUTO_SLEEP 0xFE
67 |
68 | #define CST816S_GESTURE_NONE (0x00)
69 | #define CST816S_GESTURE_SLIDE_UP (0x01)
70 | #define CST816S_GESTURE_SLIDE_DOWN (0x02)
71 | #define CST816S_GESTURE_SLIDE_LEFT (0x03)
72 | #define CST816S_GESTURE_SLIDE_RIGHT (0x04)
73 | #define CST816S_GESTURE_CLICK (0x05)
74 | #define CST816S_GESTURE_DOUBLE_CLICK (0x0B)
75 | #define CST816S_GESTURE_LONG_PRESS (0x0C)
76 |
77 | #define CST816S_MOTION_EN_CON_LR (1<<2)
78 | #define CST816S_MOTION_EN_CON_UR (1<<1)
79 | #define CST816S_MOTION_EN_DCLICK (1<<0)
80 |
81 | #define CST816S_IRQ_EN_TEST (1<<7)
82 | #define CST816S_IRQ_EN_TOUCH (1<<6)
83 | #define CST816S_IRQ_EN_CHANGE (1<<5)
84 | #define CST816S_IRQ_EN_MOTION (1<<4)
85 | #define CST816S_IRQ_ONCE_WLP (1<<0)
86 |
87 | #define CST816S_IOCTL_SOFT_RTS (1<<2)
88 | #define CST816S_IOCTL_IIC_OD (1<<1)
89 | #define CST816S_IOCTL_EN_1V8 (1<<0)
90 |
91 | #define CST816S_POWER_MODE_SLEEP (0x03)
92 | #define CST816S_POWER_MODE_EXPERIMENTAL (0x05)
93 |
94 | typedef struct {
95 | int16_t x;
96 | int16_t y;
97 | } coordinate_t;
98 |
99 | struct cst816s_data {
100 | const struct device *i2c;
101 |
102 | uint8_t chip_id;
103 |
104 | enum cst816s_gesture gesture;
105 | uint8_t number_touch_point;
106 | enum cst816s_action action;
107 |
108 | coordinate_t touch_point_1;
109 | coordinate_t touch_point_2;
110 |
111 | const struct device *reset_gpio;
112 | #ifdef CONFIG_CST816S_TRIGGER
113 | const struct device *dev;
114 | const struct device *gpio;
115 | struct gpio_callback gpio_cb;
116 |
117 | struct sensor_trigger data_ready_trigger;
118 | sensor_trigger_handler_t data_ready_handler;
119 |
120 | #if defined(CONFIG_CST816S_TRIGGER_OWN_THREAD)
121 | K_THREAD_STACK_MEMBER(thread_stack, CONFIG_CST816S_THREAD_STACK_SIZE);
122 | struct k_thread thread;
123 | struct k_sem gpio_sem;
124 | #elif defined(CONFIG_CST816S_TRIGGER_GLOBAL_THREAD)
125 | struct k_work work;
126 | #endif
127 |
128 | #endif /* CONFIG_CST816S_TRIGGER */
129 | };
130 |
131 | #ifdef CONFIG_CST816S_TRIGGER
132 | int cst816s_trigger_set(const struct device *dev,
133 | const struct sensor_trigger *trig,
134 | sensor_trigger_handler_t handler);
135 |
136 | int cst816s_attr_set(const struct device *dev,
137 | enum sensor_channel chan,
138 | enum sensor_attribute attr,
139 | const struct sensor_value *val);
140 |
141 | int cst816s_init_interrupt(const struct device *dev);
142 | #endif
143 |
144 | #endif /* ZEPHYR_DRIVERS_SENSOR_CST816S_CST816S_H_ */
145 |
--------------------------------------------------------------------------------
/app/drivers/sensor/cst816s/cst816s_trigger.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Stephane Dorre
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #define DT_DRV_COMPAT hynitron_cst816s
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include "cst816s.h"
16 |
17 | #include
18 |
19 | #define INTERRUPT_PIN DT_INST_GPIO_PIN(0, int1_gpios)
20 |
21 | LOG_MODULE_DECLARE(CST816S, CONFIG_SENSOR_LOG_LEVEL);
22 |
23 | int cst816s_attr_set(const struct device *dev,
24 | enum sensor_channel chan,
25 | enum sensor_attribute attr,
26 | const struct sensor_value *val)
27 | {
28 | //struct cst816s_data *drv_data = dev->driver_data;
29 |
30 | if (chan != SENSOR_CHAN_ACCEL_XYZ) {
31 | return -ENOTSUP;
32 | }
33 |
34 | return 0;
35 | }
36 |
37 | static void cst816s_gpio_callback(const struct device *dev,
38 | struct gpio_callback *cb, uint32_t pins)
39 | {
40 | struct cst816s_data *drv_data =
41 | CONTAINER_OF(cb, struct cst816s_data, gpio_cb);
42 |
43 | ARG_UNUSED(pins);
44 |
45 | #if defined(CONFIG_CST816S_TRIGGER_OWN_THREAD)
46 | k_sem_give(&drv_data->gpio_sem);
47 | #elif defined(CONFIG_CST816S_TRIGGER_GLOBAL_THREAD)
48 | k_work_submit(&drv_data->work);
49 | #endif
50 | }
51 |
52 | static void cst816s_thread_cb(const struct device *dev)
53 | {
54 | struct cst816s_data *drv_data = dev->data;
55 |
56 | if (drv_data->data_ready_handler != NULL) {
57 | drv_data->data_ready_handler(dev, &drv_data->data_ready_trigger);
58 | }
59 | }
60 |
61 | #ifdef CONFIG_CST816S_TRIGGER_OWN_THREAD
62 | static void cst816s_thread(struct cst816s_data *drv_data)
63 | {
64 | while (true) {
65 | k_sem_take(&drv_data->gpio_sem, K_FOREVER);
66 | cst816s_thread_cb(drv_data->dev);
67 | }
68 | }
69 | #endif
70 |
71 | #ifdef CONFIG_CST816S_TRIGGER_GLOBAL_THREAD
72 | static void cst816s_work_cb(struct k_work *work)
73 | {
74 | struct cst816s_data *drv_data =
75 | CONTAINER_OF(work, struct cst816s_data, work);
76 |
77 | cst816s_thread_cb(drv_data->dev);
78 | }
79 | #endif
80 |
81 | int cst816s_trigger_set(const struct device *dev,
82 | const struct sensor_trigger *trig,
83 | sensor_trigger_handler_t handler)
84 | {
85 | struct cst816s_data *drv_data = dev->data;
86 |
87 | if (trig->type == SENSOR_TRIG_DATA_READY) {
88 |
89 | drv_data->data_ready_handler = handler;
90 | if (handler == NULL) {
91 | return 0;
92 | }
93 | drv_data->data_ready_trigger = *trig;
94 | }
95 | else {
96 | return -ENOTSUP;
97 | }
98 |
99 | return 0;
100 | }
101 |
102 | int cst816s_init_interrupt(const struct device *dev)
103 | {
104 | struct cst816s_data *drv_data = dev->data;
105 |
106 | /* setup data ready gpio interrupt */
107 | drv_data->gpio = device_get_binding(DT_INST_GPIO_LABEL(0, int1_gpios));
108 | if (drv_data->gpio == NULL) {
109 | LOG_DBG("Cannot get pointer to %s device",
110 | DT_INST_GPIO_LABEL(0, int1_gpios));
111 | return -EINVAL;
112 | }
113 |
114 | gpio_init_callback(&drv_data->gpio_cb,
115 | cst816s_gpio_callback,
116 | BIT(INTERRUPT_PIN));
117 |
118 | if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
119 | LOG_DBG("Could not set gpio callback");
120 | return -EIO;
121 | }
122 |
123 | gpio_pin_configure(drv_data->gpio,
124 | INTERRUPT_PIN, GPIO_INPUT | GPIO_PULL_UP
125 | | GPIO_INT_EDGE_FALLING | GPIO_ACTIVE_LOW);
126 |
127 | #if defined(CONFIG_CST816S_TRIGGER_OWN_THREAD)
128 | k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
129 |
130 | k_thread_create(&drv_data->thread, drv_data->thread_stack,
131 | CONFIG_CST816S_THREAD_STACK_SIZE,
132 | (k_thread_entry_t)cst816s_thread, drv_data,
133 | NULL, NULL, K_PRIO_COOP(CONFIG_CST816S_THREAD_PRIORITY),
134 | 0, K_NO_WAIT);
135 | #elif defined(CONFIG_CST816S_TRIGGER_GLOBAL_THREAD)
136 | drv_data->work.handler = cst816s_work_cb;
137 | drv_data->dev = dev;
138 | #endif
139 | return 0;
140 | }
141 |
--------------------------------------------------------------------------------
/app/drivers/sensor/hrs3300/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Makefile - MAX30101 heart rate sensor
2 | #
3 | # Copyright (c) 2017, NXP
4 | #
5 | # SPDX-License-Identifier: Apache-2.0
6 | #
7 | zephyr_library()
8 |
9 | zephyr_library_sources_ifdef(CONFIG_HRS3300 hrs3300.c)
10 |
--------------------------------------------------------------------------------
/app/drivers/sensor/hrs3300/Kconfig:
--------------------------------------------------------------------------------
1 | # HRS3300 heart rate sensor
2 |
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | menuconfig HRS3300
6 | bool "HRS3300 Pulse Oximeter and Heart Rate Sensor"
7 | select SENSOR
8 | depends on I2C && HAS_DTS_I2C
9 |
10 | if HRS3300
11 |
12 | config HRS3300_CMDS
13 | bool "Shell commands"
14 | depends on SHELL
15 | default y
16 | help
17 | Enable shell commands for HRS3300 sensor.
18 |
19 | config HRS3300_SMP_AVE
20 | int "Sample averaging"
21 | range 0 7
22 | default 0
23 | help
24 | To reduce the amount of data throughput, adjacent samples (in each
25 | individual channel) can be averaged and decimated on the chip by
26 | setting this register. Set to 0 for no averaging.
27 | 0 = 1 sample (no averaging)
28 | 1 = 2 samples
29 | 2 = 4 samples
30 | 3 = 8 samples
31 | 4 = 16 samples
32 | 5 = 32 samples
33 | 6 = 32 samples
34 | 7 = 32 samples
35 |
36 | config HRS3300_FIFO_ROLLOVER_EN
37 | bool "FIFO rolls on full"
38 | help
39 | Controls the behavior of the FIFO when the FIFO becomes completely
40 | filled with data. If set, the FIFO address rolls over to zero and the
41 | FIFO continues to fill with new data. If not set, then the FIFO is
42 | not updated until FIFO_DATA is read or the WRITE/READ pointer
43 | positions are changed.
44 |
45 | config HRS3300_FIFO_A_FULL
46 | int "FIFO almost full value"
47 | range 0 15
48 | default 0
49 | help
50 | Set the trigger for the FIFO_A_FULL interrupt
51 |
52 | choice HRS3300_MODE
53 | prompt "Mode control"
54 | default HRS3300_MULTI_LED_MODE
55 |
56 | config HRS3300_HEART_RATE_MODE
57 | bool "Heart rate mode"
58 | help
59 | Set to operate in heart rate only mode. The red LED channel is
60 | active.
61 |
62 | config HRS3300_SPO2_MODE
63 | bool "SpO2 mode"
64 | help
65 | Set to operate in SpO2 mode. The red and IR LED channels are active.
66 |
67 | config HRS3300_MULTI_LED_MODE
68 | bool "Multi-LED mode"
69 | help
70 | Set to operate in multi-LED mode. The green, red, and/or IR LED
71 | channels are active.
72 |
73 | endchoice
74 |
75 | config HRS3300_ADC_RGE
76 | int "ADC range control"
77 | range 0 3
78 | default 2
79 | help
80 | Set the ADC's full-scale range.
81 | 0 = 7.81 pA/LSB
82 | 1 = 15.63 pA/LSB
83 | 2 = 31.25 pA/LSB
84 | 3 = 62.5 pA/LSB
85 |
86 | config HRS3300_SR
87 | int "ADC sample rate control"
88 | range 0 7
89 | default 0
90 | help
91 | Set the effective sampling rate with one sample consisting of one
92 | pulse/conversion per active LED channel. In SpO2 mode, these means
93 | one IR pulse/conversion and one red pulse/conversion per sample
94 | period.
95 | 0 = 50 Hz
96 | 1 = 100 Hz
97 | 2 = 200 Hz
98 | 3 = 400 Hz
99 | 4 = 800 Hz
100 | 5 = 1000 Hz
101 | 6 = 1600 Hz
102 | 7 = 3200 Hz
103 |
104 | config HRS3300_LED1_PA
105 | hex "LED1 (red) pulse amplitude"
106 | range 0 0xff
107 | default 0xff
108 | help
109 | Set the pulse amplitude to control the LED1 (red) current. The actual
110 | measured LED current for each part can vary significantly due to the
111 | trimming methodology.
112 | 0x00 = 0.0 mA
113 | 0x01 = 0.2 mA
114 | 0x02 = 0.4 mA
115 | 0x0f = 3.1 mA
116 | 0xff = 50.0 mA
117 |
118 | config HRS3300_LED2_PA
119 | hex "LED2 (IR) pulse amplitude"
120 | range 0 0xff
121 | default 0x33
122 | help
123 | Set the pulse amplitude to control the LED2 (IR) current. The actual
124 | measured LED current for each part can vary significantly due to the
125 | trimming methodology.
126 | 0x00 = 0.0 mA
127 | 0x01 = 0.2 mA
128 | 0x02 = 0.4 mA
129 | 0x0f = 3.1 mA
130 | 0xff = 50.0 mA
131 |
132 | config HRS3300_LED3_PA
133 | hex "LED2 (green) pulse amplitude"
134 | range 0 0xff
135 | default 0xff
136 | help
137 | Set the pulse amplitude to control the LED3 (green) current. The
138 | actual measured LED current for each part can vary significantly due
139 | to the trimming methodology.
140 | 0x00 = 0.0 mA
141 | 0x01 = 0.2 mA
142 | 0x02 = 0.4 mA
143 | 0x0f = 3.1 mA
144 | 0xff = 50.0 mA
145 |
146 | if HRS3300_MULTI_LED_MODE
147 |
148 | config HRS3300_SLOT1
149 | int "Slot 1"
150 | range 0 7
151 | default 3
152 | help
153 | Set which LED and pulse amplitude are active in time slot 1.
154 | 0: None (disabled)
155 | 1: LED1 (red), LED1_PA
156 | 2: LED2 (IR), LED2_PA
157 | 3: LED3 (green), LED3_PA
158 | 4: None (disabled)
159 | 5: LED1 (red), PILOT_PA
160 | 6: LED2 (IR), PILOT_PA
161 | 7: LED3 (green), PILOT_PA
162 |
163 | config HRS3300_SLOT2
164 | int "Slot 2"
165 | range 0 7
166 | default 0
167 | help
168 | Set which LED and pulse amplitude are active in time slot 2.
169 | 0: None (disabled)
170 | 1: LED1 (red), LED1_PA
171 | 2: LED2 (IR), LED2_PA
172 | 3: LED3 (green), LED3_PA
173 | 4: None (disabled)
174 | 5: LED1 (red), PILOT_PA
175 | 6: LED2 (IR), PILOT_PA
176 | 7: LED3 (green), PILOT_PA
177 |
178 | config HRS3300_SLOT3
179 | int "Slot 3"
180 | range 0 7
181 | default 0
182 | help
183 | Set which LED and pulse amplitude are active in time slot 3.
184 | 0: None (disabled)
185 | 1: LED1 (red), LED1_PA
186 | 2: LED2 (IR), LED2_PA
187 | 3: LED3 (green), LED3_PA
188 | 4: None (disabled)
189 | 5: LED1 (red), PILOT_PA
190 | 6: LED2 (IR), PILOT_PA
191 | 7: LED3 (green), PILOT_PA
192 |
193 | config HRS3300_SLOT4
194 | int "Slot 4"
195 | range 0 7
196 | default 0
197 | help
198 | Set which LED and pulse amplitude are active in time slot 4.
199 | 0: None (disabled)
200 | 1: LED1 (red), LED1_PA
201 | 2: LED2 (IR), LED2_PA
202 | 3: LED3 (green), LED3_PA
203 | 4: None (disabled)
204 | 5: LED1 (red), PILOT_PA
205 | 6: LED2 (IR), PILOT_PA
206 | 7: LED3 (green), PILOT_PA
207 |
208 | endif # HRS3300_MULTI_LED_MODE
209 |
210 | endif # HRS3300
211 |
--------------------------------------------------------------------------------
/app/drivers/sensor/hrs3300/hrs3300.c:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #define MY_REGISTER3 (*(volatile uint8_t*)0x2000F002)
13 |
14 | LOG_MODULE_REGISTER(HRS3300, CONFIG_SENSOR_LOG_LEVEL);
15 |
16 | #define HRS3300_I2C_ADDRESS 0x44
17 |
18 | #define HRS3300_PDRIVE_12_5 0
19 | #define HRS3300_PDRIVE_20 1
20 | #define HRS3300_PDRIVE_30 2
21 | #define HRS3300_PDRIVE_40 3
22 |
23 | #define HRS3300_DEVICE_ID_ADDR 0x00
24 | #define HRS3300_DEVICE_ID 0x21
25 |
26 | #define HRS3300_ENABLED_ADDR 0x01
27 |
28 | #define HRS3300_HWT_800MS 0x0
29 | #define HRS3300_HWT_400MS 0x1
30 | #define HRS3300_HWT_200MS 0x2
31 | #define HRS3300_HWT_100MS 0x3
32 | #define HRS3300_HWT_75MS 0x4
33 | #define HRS3300_HWT_50MS 0x5
34 | #define HRS3300_HWT_12_5MS 0x6
35 | #define HRS3300_HWT_0MS 0x7
36 |
37 | struct hrs3300_reg_enable {
38 | u8_t reserved :3;
39 | u8_t pdrive1 :1;
40 | u8_t hwt :3;
41 | u8_t enable :1;
42 | };
43 |
44 | #define HRS3300_HRS_LED_DRIVER_SET_ADDR 0x0C
45 | struct hrs3300_reg_hrs_led_driver_set {
46 | u8_t reserved :5;
47 | u8_t pon :1;
48 | u8_t pdrive0 :1;
49 | u8_t reserved1 :1;
50 | };
51 |
52 |
53 | #define HRS3300_RESOLUTION_ADDR 0x16
54 | struct hrs3300_reg_resolution {
55 | u8_t als_res :4;
56 | u8_t reserved :4;
57 | };
58 |
59 | #define HRS3300_HGAIN_ADDR 0x17
60 | struct hrs3300_reg_hgain {
61 | u8_t reserved :2;
62 | u8_t hgain :3;
63 | u8_t reserved1 :3;
64 | };
65 |
66 | union hrs3300_reg {
67 | struct hrs3300_reg_enable enable;
68 | struct hrs3300_reg_hrs_led_driver_set hrs_led_driver_set;
69 | struct hrs3300_reg_resolution resolution;
70 | struct hrs3300_reg_hgain hgain;
71 | u8_t raw;
72 | };
73 |
74 | struct hrs3300_addr_reg {
75 | u8_t addr;
76 | union hrs3300_reg reg;
77 | };
78 |
79 | struct hrs3300_data {
80 | struct device *i2c;
81 | u32_t raw[2];
82 | struct hrs3300_addr_reg config[4];
83 | };
84 |
85 | struct hrs3300_config {
86 | };
87 |
88 | static u32_t get_hrs_adc(u8_t *buf)
89 | {
90 | return ((u32_t)buf[7] & 0xF) |
91 | (((u32_t)buf[2] & 0xf) << 4) |
92 | ((u32_t)buf[1] << 8) |
93 | (((u32_t)buf[7] & 0x30) << 16);
94 | }
95 |
96 | static u32_t get_als(u8_t *buf)
97 | {
98 | return ((u32_t)buf[6] & 0x7) |
99 | ((u32_t)buf[0] << 3) |
100 | ((u32_t)buf[5] << 10);
101 | }
102 |
103 | static int hrs3300_sample_fetch(struct device *dev, enum sensor_channel chan)
104 | {
105 | struct hrs3300_data *data = dev->driver_data;
106 | u8_t buf[8];
107 | int err;
108 |
109 | err = i2c_burst_read(data->i2c, HRS3300_I2C_ADDRESS, 0x8,
110 | buf, sizeof(buf));
111 | if (err < 0) {
112 | LOG_ERR("Failed to read data (err:%d)", err);
113 | return err;
114 | }
115 |
116 | data->raw[0] = get_hrs_adc(buf);
117 | data->raw[1] = get_als(buf);
118 |
119 | return 0;
120 | }
121 |
122 | //todo method to switch heart rate sensor off
123 | int hrs3300_attr_set(struct device *dev,
124 | enum sensor_channel chan,
125 | enum sensor_attribute attr,
126 | const struct sensor_value *val)
127 | {
128 | return 0;
129 | }
130 |
131 | static int hrs3300_channel_get(struct device *dev, enum sensor_channel chan,
132 | struct sensor_value *val)
133 | {
134 | struct hrs3300_data *data = dev->driver_data;
135 |
136 | val->val1 = data->raw[0];
137 | val->val2 = data->raw[1];
138 |
139 | return 0;
140 | }
141 |
142 | static const struct sensor_driver_api hrs3300_driver_api = {
143 | .sample_fetch = hrs3300_sample_fetch,
144 | .channel_get = hrs3300_channel_get,
145 | .attr_set = hrs3300_attr_set,
146 | };
147 |
148 | static int hrs3300_init(struct device *dev)
149 | {
150 | struct hrs3300_data *data = dev->driver_data;
151 | u8_t device_id;
152 | int err;
153 |
154 | /* Get the I2C device */
155 | data->i2c = device_get_binding(DT_INST_0_HX_HRS3300_BUS_NAME);
156 | if (!data->i2c) {
157 | LOG_ERR("Could not find I2C device");
158 | return -EINVAL;
159 | }
160 |
161 | err = i2c_reg_read_byte(data->i2c, HRS3300_I2C_ADDRESS,
162 | HRS3300_DEVICE_ID_ADDR, &device_id);
163 | if ((err < 0) || (device_id != HRS3300_DEVICE_ID)) {
164 | LOG_ERR("Failed to read device id (%d)", err);
165 | return err;
166 | }
167 |
168 | for (int i = 0; i < ARRAY_SIZE(data->config); i++) {
169 | err = i2c_reg_write_byte(data->i2c, HRS3300_I2C_ADDRESS,
170 | data->config[i].addr, data->config[i].reg.raw);
171 | if (err < 0) {
172 | LOG_ERR("Failed to write %x register (err:%d)",
173 | data->config[i].addr, err);
174 | return err;
175 | }
176 | }
177 |
178 | return 0;
179 | }
180 |
181 | static int write_reg(struct device *dev, struct hrs3300_addr_reg *reg)
182 | {
183 | struct hrs3300_data *data = dev->driver_data;
184 |
185 | return i2c_reg_write_byte(data->i2c, HRS3300_I2C_ADDRESS,
186 | reg->addr, reg->reg.raw);
187 | }
188 |
189 | static int hrs3300_en(struct device *dev, bool en)
190 | {
191 | struct hrs3300_data *data = dev->driver_data;
192 |
193 | data->config[0].reg.enable.enable = en ? 1 : 0;
194 | return write_reg(dev, &data->config[0]);
195 | }
196 |
197 | int hrs3300_enable(struct device *dev)
198 | {
199 | return hrs3300_en(dev, true);
200 | }
201 |
202 | int hrs3300_disable(struct device *dev)
203 | {
204 | return hrs3300_en(dev, false);
205 | }
206 |
207 | int hrs3300_hgain_set(struct device *dev, enum hrs3300_hgain val)
208 | {
209 | struct hrs3300_data *data = dev->driver_data;
210 | data->config[3].reg.hgain.hgain = val;
211 | return write_reg(dev, &data->config[3]);
212 | }
213 |
214 | int hrs3300_hgain_get(struct device *dev, enum hrs3300_hgain *val)
215 | {
216 | struct hrs3300_data *data = dev->driver_data;
217 |
218 | *val = data->config[3].reg.hgain.hgain;
219 |
220 | return 0;
221 | }
222 |
223 | int hrs3300_hwt_set(struct device *dev, enum hrs3300_hwt val)
224 | {
225 | struct hrs3300_data *data = dev->driver_data;
226 |
227 | data->config[0].reg.enable.hwt = val;
228 |
229 | return write_reg(dev, &data->config[0]);
230 | }
231 |
232 | int hrs3300_hwt_get(struct device *dev, enum hrs3300_hwt *val)
233 | {
234 | struct hrs3300_data *data = dev->driver_data;
235 |
236 | *val = data->config[0].reg.enable.hwt;
237 |
238 | return 0;
239 | }
240 |
241 | int hrs3300_pdrive_set(struct device *dev, enum hrs3300_pdrive val)
242 | {
243 | struct hrs3300_data *data = dev->driver_data;
244 | int err;
245 |
246 | data->config[0].reg.enable.pdrive1 = (val & 2) ? 1 : 0;
247 | data->config[1].reg.hrs_led_driver_set.pdrive0 = val & 1;
248 |
249 | err = write_reg(dev, &data->config[0]);
250 | if (err < 0) {
251 | return err;
252 | }
253 |
254 | return write_reg(dev, &data->config[1]);
255 | }
256 |
257 | int hrs3300_pdrive_get(struct device *dev, enum hrs3300_pdrive *val)
258 | {
259 | struct hrs3300_data *data = dev->driver_data;
260 |
261 | *val = data->config[1].reg.hrs_led_driver_set.pdrive0 |
262 | (data->config[0].reg.enable.pdrive1 << 1);
263 |
264 | return 0;
265 | }
266 |
267 | static struct hrs3300_config hrs3300_config;
268 | static struct hrs3300_data hrs3300_data = {
269 | .config = {
270 | {
271 | .addr = HRS3300_ENABLED_ADDR,
272 | .reg = {
273 | .enable = {
274 | .enable = 0,
275 | .pdrive1 = (HRS3300_PDRIVE_40 & 0x2) ?
276 | 1 : 0,
277 | .hwt = HRS3300_HWT_12_5MS
278 | }
279 | }
280 | },
281 | {
282 | .addr = HRS3300_HRS_LED_DRIVER_SET_ADDR,
283 | .reg = {
284 | .hrs_led_driver_set = {
285 | .pon = 1,
286 | .pdrive0 = HRS3300_PDRIVE_40 & 0x1,
287 | .reserved = 0x8
288 | }
289 | }
290 | },
291 | {
292 | .addr = HRS3300_RESOLUTION_ADDR,
293 | .reg = {
294 | .resolution = {
295 | .reserved = 0x6,
296 | .als_res = 0x8 /* 16bit*/
297 | }
298 | }
299 | },
300 | {
301 | .addr = HRS3300_HGAIN_ADDR,
302 | .reg = {
303 | .hgain = {
304 | .hgain = 0
305 | }
306 | }
307 | }
308 | }
309 | };
310 |
311 | DEVICE_AND_API_INIT(hrs3300, DT_INST_0_HX_HRS3300_LABEL, hrs3300_init,
312 | &hrs3300_data, &hrs3300_config,
313 | POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
314 | &hrs3300_driver_api);
315 |
316 | static int cmd_enable(const struct shell *shell, size_t argc, char **argv)
317 | {
318 | int err;
319 |
320 | err = hrs3300_enable(DEVICE_GET(hrs3300));
321 | shell_print(shell, "Enabled (err:%d)", err);
322 |
323 | return 0;
324 | }
325 |
326 | static int cmd_disable(const struct shell *shell, size_t argc, char **argv)
327 | {
328 | int err;
329 |
330 | err = hrs3300_disable(DEVICE_GET(hrs3300));
331 | shell_print(shell, "Disabled (err:%d)", err);
332 |
333 | return 0;
334 | }
335 |
336 | static int cmd_dump_registers(const struct shell *shell,
337 | size_t argc, char **argv)
338 | {
339 | static const u8_t addr[] = {0, 1, 8, 9, 10, 12, 13, 14, 15, 22, 23};
340 | struct hrs3300_data *data = DEVICE_GET(hrs3300)->driver_data;
341 | int err;
342 | u8_t val;
343 |
344 | for (int i = 0; i < ARRAY_SIZE(addr); i++) {
345 | err = i2c_reg_read_byte(data->i2c, HRS3300_I2C_ADDRESS, addr[i],
346 | &val);
347 | if (err < 0) {
348 | shell_error(shell, "Failed to read %x (err: %d)",
349 | addr[i], err);
350 | } else {
351 | shell_print(shell, "Reg:%x value:%x", addr[i], val);
352 | }
353 | }
354 |
355 | return 0;
356 | }
357 |
358 | static int cmd_sample(const struct shell *shell, size_t argc, char **argv)
359 | {
360 | int err;
361 | struct sensor_value value;
362 |
363 | err = sensor_sample_fetch(DEVICE_GET(hrs3300));
364 | if (err < 0) {
365 | shell_error(shell, "Failed to read (err:%d)", err);
366 | }
367 |
368 | err = sensor_channel_get(DEVICE_GET(hrs3300), 0, &value);
369 | if (err < 0) {
370 | shell_error(shell, "Failed to read channel (err:%d)", err);
371 | }
372 |
373 | shell_print(shell, "hrs:%d, als:%d", value.val1, value.val2);
374 |
375 | return 0;
376 | }
377 |
378 | static int cmd_read_gain(const struct shell *shell, size_t argc, char **argv)
379 | {
380 | enum hrs3300_hgain gain_reg;
381 | u8_t gain_val;
382 |
383 | hrs3300_hgain_get(DEVICE_GET(hrs3300), &gain_reg);
384 | gain_val = (gain_reg < 4) ? (1 << gain_reg) : 64;
385 |
386 | shell_print(shell, "Gain:%dx", gain_val);
387 |
388 | return 0;
389 | }
390 |
391 | static int cmd_set_gain1(const struct shell *shell, size_t argc, char **argv)
392 | {
393 | return hrs3300_hgain_set(DEVICE_GET(hrs3300), 0);
394 | }
395 |
396 | static int cmd_set_gain2(const struct shell *shell, size_t argc, char **argv)
397 | {
398 | return hrs3300_hgain_set(DEVICE_GET(hrs3300), 1);
399 | }
400 |
401 | static int cmd_set_gain4(const struct shell *shell, size_t argc, char **argv)
402 | {
403 | return hrs3300_hgain_set(DEVICE_GET(hrs3300), 2);
404 | }
405 |
406 | static int cmd_set_gain8(const struct shell *shell, size_t argc, char **argv)
407 | {
408 | return hrs3300_hgain_set(DEVICE_GET(hrs3300), 3);
409 | }
410 |
411 | static int cmd_set_gain64(const struct shell *shell, size_t argc, char **argv)
412 | {
413 | return hrs3300_hgain_set(DEVICE_GET(hrs3300), 4);
414 | }
415 |
416 | static int cmd_read_hwt(const struct shell *shell, size_t argc, char **argv)
417 | {
418 | enum hrs3300_hwt val;
419 | static const char *hwt[] = {"800", "400", "200", "100",
420 | "75", "50", "12.5", "0"};
421 |
422 | hrs3300_hwt_get(DEVICE_GET(hrs3300), &val);
423 |
424 | shell_print(shell, "HWT:%sms", hwt[val]);
425 |
426 | return 0;
427 | }
428 |
429 | static int cmd_set_hwt800(const struct shell *shell, size_t argc, char **argv)
430 | {
431 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 0);
432 | }
433 |
434 | static int cmd_set_hwt400(const struct shell *shell, size_t argc, char **argv)
435 | {
436 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 1);
437 | }
438 |
439 | static int cmd_set_hwt200(const struct shell *shell, size_t argc, char **argv)
440 | {
441 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 2);
442 | }
443 |
444 | static int cmd_set_hwt100(const struct shell *shell, size_t argc, char **argv)
445 | {
446 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 3);
447 | }
448 |
449 | static int cmd_set_hwt75(const struct shell *shell, size_t argc, char **argv)
450 | {
451 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 4);
452 | }
453 |
454 | static int cmd_set_hwt50(const struct shell *shell, size_t argc, char **argv)
455 | {
456 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 5);
457 | }
458 |
459 | static int cmd_set_hwt12_5(const struct shell *shell, size_t argc, char **argv)
460 | {
461 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 6);
462 | }
463 |
464 | static int cmd_set_hwt0(const struct shell *shell, size_t argc, char **argv)
465 | {
466 | return hrs3300_hwt_set(DEVICE_GET(hrs3300), 7);
467 | }
468 |
469 | static int cmd_read_pdrive(const struct shell *shell, size_t argc, char **argv)
470 | {
471 | enum hrs3300_pdrive val;
472 | static const char *pdrive[] = {"12.5", "20", "30", "40"};
473 |
474 | hrs3300_pdrive_get(DEVICE_GET(hrs3300), &val);
475 |
476 | shell_print(shell, "PDrive:%sms", pdrive[val]);
477 |
478 | return 0;
479 | }
480 |
481 | static int cmd_set_pdrive12_5(const struct shell *shell, size_t argc,
482 | char **argv)
483 | {
484 | return hrs3300_pdrive_set(DEVICE_GET(hrs3300), HRS3300_PDRIVE_12_5);
485 | }
486 |
487 | static int cmd_set_pdrive20(const struct shell *shell, size_t argc,
488 | char **argv)
489 | {
490 | return hrs3300_pdrive_set(DEVICE_GET(hrs3300), HRS3300_PDRIVE_20);
491 | }
492 |
493 | static int cmd_set_pdrive30(const struct shell *shell, size_t argc,
494 | char **argv)
495 | {
496 | return hrs3300_pdrive_set(DEVICE_GET(hrs3300), HRS3300_PDRIVE_30);
497 | }
498 |
499 | static int cmd_set_pdrive40(const struct shell *shell, size_t argc,
500 | char **argv)
501 | {
502 | return hrs3300_pdrive_set(DEVICE_GET(hrs3300), HRS3300_PDRIVE_40);
503 | }
504 |
505 | static int cmd_read(const struct shell *shell, size_t argc, char **argv,
506 | bool hrs)
507 | {
508 | int len = strtol(argv[1], NULL, 10);
509 | enum hrs3300_hwt freq_reg;
510 | u32_t ms[] = {800,400, 200, 100, 75, 50, 12, 0};
511 | int err;
512 | static u16_t samples[1024];
513 | struct sensor_value value;
514 | int sleep_ms;
515 |
516 | if (len == 0) {
517 | return 0;
518 | } else if (len > ARRAY_SIZE(samples)) {
519 | shell_error(shell, "Request too big, limited to %d",
520 | ARRAY_SIZE(samples));
521 | }
522 |
523 | err = hrs3300_hwt_get(DEVICE_GET(hrs3300), &freq_reg);
524 | if (err < 0) {
525 | shell_error(shell, "Failed to read hwt (err:%d)", err);
526 | return 0;
527 | }
528 |
529 | sleep_ms = ms[freq_reg];
530 |
531 | for (int i = 0; i < len; i++) {
532 | err = sensor_sample_fetch(DEVICE_GET(hrs3300));
533 | if (err < 0) {
534 | shell_error(shell, "Failed to read (err:%d)", err);
535 | return 0;
536 | }
537 |
538 | err = sensor_channel_get(DEVICE_GET(hrs3300), 0, &value);
539 | if (err < 0) {
540 | shell_error(shell, "Failed to read channel (err:%d)", err);
541 | return 0;
542 | }
543 |
544 | samples[i] = (u16_t)(hrs ? value.val1 : value.val2);
545 | if (sleep_ms == 12) {
546 | sleep_ms++;
547 | } else if (sleep_ms == 13) {
548 | sleep_ms--;
549 | }
550 |
551 | k_sleep(K_MSEC(sleep_ms));
552 | }
553 |
554 | for (int i = 0; i < len; i++) {
555 | shell_print(shell, "%d", samples[i]);
556 | }
557 |
558 | shell_print(shell, "Sampling period %d", sleep_ms);
559 |
560 | return 0;
561 | }
562 |
563 | static int cmd_read_hrs(const struct shell *shell, size_t argc, char **argv)
564 | {
565 | return cmd_read(shell, argc, argv, true);
566 | }
567 |
568 | static int cmd_read_als(const struct shell *shell, size_t argc, char **argv)
569 | {
570 | return cmd_read(shell, argc, argv, false);
571 | }
572 |
573 | SHELL_STATIC_SUBCMD_SET_CREATE(gain_cmds,
574 | SHELL_CMD_ARG(x1, NULL, "Control Gain", cmd_set_gain1, 1, 0),
575 | SHELL_CMD_ARG(x2, NULL, "Control Gain", cmd_set_gain2, 1, 0),
576 | SHELL_CMD_ARG(x4, NULL, "Control Gain", cmd_set_gain4, 1, 0),
577 | SHELL_CMD_ARG(x8, NULL, "Control Gain", cmd_set_gain8, 1, 0),
578 | SHELL_CMD_ARG(x64, NULL, "Control Gain", cmd_set_gain64, 1, 0),
579 | SHELL_SUBCMD_SET_END
580 | );
581 |
582 | SHELL_STATIC_SUBCMD_SET_CREATE(hwt_cmds,
583 | SHELL_CMD_ARG(800ms, NULL, "Set HWT", cmd_set_hwt800, 1, 0),
584 | SHELL_CMD_ARG(400ms, NULL, "Set HWT", cmd_set_hwt400, 1, 0),
585 | SHELL_CMD_ARG(200ms, NULL, "Set HWT", cmd_set_hwt200, 1, 0),
586 | SHELL_CMD_ARG(100ms, NULL, "Set HWT", cmd_set_hwt100, 1, 0),
587 | SHELL_CMD_ARG(75ms, NULL, "Set HWT", cmd_set_hwt75, 1, 0),
588 | SHELL_CMD_ARG(50ms, NULL, "Set HWT", cmd_set_hwt50, 1, 0),
589 | SHELL_CMD_ARG(12_5ms, NULL, "Set HWT", cmd_set_hwt12_5, 1, 0),
590 | SHELL_CMD_ARG(0ms, NULL, "Set HWT", cmd_set_hwt0, 1, 0),
591 | SHELL_SUBCMD_SET_END
592 | );
593 |
594 | SHELL_STATIC_SUBCMD_SET_CREATE(pdrive_cmds,
595 | SHELL_CMD_ARG(12_5mA, NULL, "Control PDrive", cmd_set_pdrive12_5, 1, 0),
596 | SHELL_CMD_ARG(20mA, NULL, "Control PDrive", cmd_set_pdrive20, 1, 0),
597 | SHELL_CMD_ARG(30mA, NULL, "Control PDrive", cmd_set_pdrive30, 1, 0),
598 | SHELL_CMD_ARG(40mA, NULL, "Control PDrive", cmd_set_pdrive40, 1, 0),
599 | SHELL_SUBCMD_SET_END
600 | );
601 |
602 | SHELL_STATIC_SUBCMD_SET_CREATE(read_cmds,
603 | SHELL_CMD_ARG(hrs, NULL, "Read samples", cmd_read_hrs, 2, 0),
604 | SHELL_CMD_ARG(als, NULL, "Read samples", cmd_read_als, 2, 0),
605 | SHELL_SUBCMD_SET_END
606 | );
607 |
608 | SHELL_STATIC_SUBCMD_SET_CREATE(hrs3300_cmds,
609 | SHELL_CMD_ARG(hgain, &gain_cmds, "Control Gain", cmd_read_gain, 1, 1),
610 | SHELL_CMD_ARG(hwt, &hwt_cmds, "Control HWT", cmd_read_hwt, 1, 1),
611 | SHELL_CMD_ARG(pdrive, &pdrive_cmds, "Control PDrive", cmd_read_pdrive, 1, 1),
612 | SHELL_CMD_ARG(read, &read_cmds, "Read HRS and ALS", cmd_read, 1, 0),
613 | SHELL_CMD_ARG(sample, NULL, "Sample HRS and ALS", cmd_sample, 1, 0),
614 | SHELL_CMD_ARG(dump, NULL, "Dump registers", cmd_dump_registers, 1, 0),
615 | SHELL_CMD_ARG(disable, NULL, "Disable", cmd_disable, 1, 0),
616 | SHELL_CMD_ARG(enable, NULL, "Enable", cmd_enable, 1, 0),
617 | SHELL_SUBCMD_SET_END
618 | );
619 |
620 | static int cmd_dummy(const struct shell *shell, size_t argc, char **argv)
621 | {
622 | return 0;
623 | }
624 |
625 | SHELL_COND_CMD_REGISTER(CONFIG_HRS3300_CMDS, hrs3300, &hrs3300_cmds,
626 | "HRS3300 shell commands", cmd_dummy);
627 |
--------------------------------------------------------------------------------
/app/drivers/sensor/hrs3300/hrs3300.h:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: Apache-2.0
3 | */
4 | #ifndef PINETIME_INCLUDE_HRS3300_H
5 | #define PINETIME_INCLUDE_HRS3300_H
6 |
7 | #include
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | enum hrs3300_hwt {
14 | HRS3300_HWT_800MS = 0x0,
15 | HRS3300_HWT_400MS = 0x1,
16 | HRS3300_HWT_200MS = 0x2,
17 | HRS3300_HWT_100MS = 0x3,
18 | HRS3300_HWT_75MS = 0x4,
19 | HRS3300_HWT_50MS = 0x5,
20 | HRS3300_HWT_12_5MS = 0x6,
21 | HRS3300_HWT_0MS = 0x7
22 | };
23 |
24 | enum hrs3300_pdrive {
25 | HRS3300_PDRIVE_12_5 = 0,
26 | HRS3300_PDRIVE_20 = 1,
27 | HRS3300_PDRIVE_30 = 2,
28 | HRS3300_PDRIVE_40 = 3
29 | };
30 |
31 | enum hrs3300_hgain {
32 | HRS3300_HGAIN_1 = 0,
33 | HRS3300_HGAIN_2 = 1,
34 | HRS3300_HGAIN_4 = 2,
35 | HRS3300_HGAIN_8 = 3,
36 | HRS3300_HGAIN_64 = 4,
37 | };
38 |
39 | /** @brief Enable measurement.
40 | *
41 | * @param dev Device.
42 | *
43 | * @return 0 on suucess, negative error code otherwise.
44 | */
45 | int hrs3300_enable(struct device *dev);
46 |
47 | /** @brief Disable measurement.
48 | *
49 | * @param dev Device.
50 | *
51 | * @return 0 on suucess, negative error code otherwise.
52 | */
53 | int hrs3300_disable(struct device *dev);
54 |
55 |
56 | /** @brief Set hgain.
57 | *
58 | * @param dev Device.
59 | * @param val Hgain.
60 | *
61 | * @return 0 on suucess, negative error code otherwise.
62 | */
63 | int hrs3300_hgain_set(struct device *dev, enum hrs3300_hgain val);
64 |
65 |
66 | /** @brief Get hgain.
67 | *
68 | * @param dev Device.
69 | * @param val Location to store hgain.
70 | *
71 | * @return 0 on suucess, negative error code otherwise.
72 | */
73 | int hrs3300_hgain_get(struct device *dev, enum hrs3300_hgain *val);
74 |
75 | /** @brief Set HWT.
76 | *
77 | * @param dev Device.
78 | * @param val Gain.
79 | *
80 | * @return 0 on suucess, negative error code otherwise.
81 | */
82 | int hrs3300_hwt_set(struct device *dev, enum hrs3300_hwt val);
83 |
84 | /** @brief Get HWT.
85 | *
86 | * @param dev Device.
87 | * @param val Location to store HWT.
88 | *
89 | * @return 0 on suucess, negative error code otherwise.
90 | */
91 | int hrs3300_hwt_get(struct device *dev, enum hrs3300_hwt *val);
92 |
93 | /** @brief Set PDrive.
94 | *
95 | * @param dev Device.
96 | * @param val Gain.
97 | *
98 | * @return 0 on suucess, negative error code otherwise.
99 | */
100 | int hrs3300_pdrive_set(struct device *dev, enum hrs3300_pdrive val);
101 |
102 | /** @brief Get PDrive.
103 | *
104 | * @param dev Device.
105 | * @param val Location to store PDrive.
106 | *
107 | * @return 0 on suucess, negative error code otherwise.
108 | */
109 | int hrs3300_pdrive_get(struct device *dev, enum hrs3300_pdrive *val);
110 |
111 | #ifdef __cplusplus
112 | }
113 | #endif
114 |
115 | #endif /* PINETIME_INCLUDE_HRS3300_H */
116 |
--------------------------------------------------------------------------------
/app/dts/bindings/sensor/bosch,bma421-i2c.yaml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2019, Linaro Limited
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | description: This is a representation of the BME280 Integrated environmental sensor
6 |
7 | compatible: "bosch,bma421"
8 |
9 | include: i2c-device.yaml
10 |
11 | properties:
12 | int1-gpios:
13 | type: phandle-array
14 | required: false
15 |
--------------------------------------------------------------------------------
/app/dts/bindings/sensor/hx,hrs3300.yaml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2018, NXP
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | description: This is a representation of the HRS3300 heart rate sensor
6 |
7 | compatible: "hx,hrs3300"
8 |
9 | include: i2c-device.yaml
10 |
--------------------------------------------------------------------------------
/app/dts/bindings/sensor/hynitron,cst816s.yaml:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 |
4 | description: This is a representation of the Hynitron,CST816S touchscreen sensor
5 |
6 | compatible: "hynitron,cst816s"
7 |
8 | include: i2c-device.yaml
9 |
10 | properties:
11 | int1-gpios:
12 | type: phandle-array
13 | required: false
14 | reset-gpios:
15 | type: phandle-array
16 | required: false
17 |
--------------------------------------------------------------------------------
/app/hypnos/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | cmake_minimum_required(VERSION 3.13.1)
4 |
5 | # Add the board
6 | list(APPEND BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
7 | list(APPEND DTS_ROOT ${CMAKE_CURRENT_LIST_DIR}/..)
8 |
9 | # Enable configurations through environment variables
10 | set(CONF_FILE ${CMAKE_CURRENT_LIST_DIR}/config/prj.conf ${CMAKE_CURRENT_LIST_DIR}/config/bootloader.conf)
11 | IF("$ENV{BOOTLOADER}" STREQUAL n)
12 | set(CONF_FILE ${CMAKE_CURRENT_LIST_DIR}/config/prj.conf)
13 | ENDIF()
14 | IF("$ENV{LOGGING}" STREQUAL y)
15 | set(CONF_FILE ${CONF_FILE} ${CMAKE_CURRENT_LIST_DIR}/config/logging_rtt.conf)
16 | ENDIF()
17 |
18 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
19 | include_directories(include)
20 | project(hypnos)
21 |
22 | FILE(GLOB app_sources src/*.c)
23 | target_sources(app PRIVATE ${app_sources})
24 |
25 | # Get current time
26 | string(TIMESTAMP CURRENT_TIME %Y-%m-%dT%H:%M:%S)
27 |
28 | # Get short commit hash
29 | execute_process(
30 | COMMAND ${GIT_EXECUTABLE} describe --tags --dirty
31 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
32 | OUTPUT_VARIABLE FW_BUILD_GIT
33 | OUTPUT_STRIP_TRAILING_WHITESPACE
34 | )
35 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCURRENT_TIME_OF_BUILD=\"${CURRENT_TIME}\" -DFW_BUILD=\"${FW_BUILD_GIT}\"")
36 |
--------------------------------------------------------------------------------
/app/hypnos/config/bootloader.conf:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | # Bootloader
4 | CONFIG_BOOTLOADER_MCUBOOT=y
5 |
6 | # Flash operations
7 | CONFIG_FLASH=y
8 | CONFIG_SPI_NOR=y
9 | CONFIG_SPI_2=y
10 | CONFIG_SPI_NRFX=y
11 | CONFIG_SPI_NOR_IDLE_IN_DPD=y
12 |
13 | # Allow for large Bluetooth data packets.
14 | CONFIG_BT_L2CAP_TX_MTU=252
15 | CONFIG_BT_L2CAP_RX_MTU=252
16 | CONFIG_BT_RX_BUF_LEN=260
17 |
18 | # Enable SMP over Bluetooth (unauthenticated).
19 | CONFIG_MCUMGR_SMP_BT=y
20 | CONFIG_MCUMGR_SMP_BT_AUTHEN=n
21 |
22 | # Enable the LittleFS file system.
23 | CONFIG_FILE_SYSTEM=y
24 | CONFIG_FILE_SYSTEM_LITTLEFS=y
25 |
26 | # Enable file system commands
27 | CONFIG_MCUMGR_CMD_FS_MGMT=y
28 |
29 | # Enable mcumgr.
30 | CONFIG_MCUMGR=y
31 |
32 | # Enable most core commands.
33 | CONFIG_MCUMGR_CMD_IMG_MGMT=y
34 | CONFIG_MCUMGR_CMD_OS_MGMT=y
35 |
--------------------------------------------------------------------------------
/app/hypnos/config/logging_rtt.conf:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | # Logging
4 | CONFIG_LOG=y
5 | CONFIG_USE_SEGGER_RTT=y
6 | CONFIG_RTT_CONSOLE=y
7 | CONFIG_CONSOLE=y
8 |
--------------------------------------------------------------------------------
/app/hypnos/config/prj.conf:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | # Battery status
4 | CONFIG_ADC=y
5 | CONFIG_ADC_ASYNC=y
6 |
7 | # GPIO
8 | CONFIG_GPIO=y
9 |
10 | # Time functions
11 | CONFIG_NEWLIB_LIBC=y
12 |
13 | # Display
14 | CONFIG_SPI=y
15 | CONFIG_DISPLAY=y
16 | CONFIG_ST7789V=y
17 | CONFIG_ST7789V_RGB565=y
18 |
19 | # Graphics
20 | CONFIG_LVGL=y
21 | CONFIG_LVGL_USE_LABEL=y
22 | CONFIG_LVGL_USE_IMG=y
23 | CONFIG_LVGL_COLOR_DEPTH_16=y
24 | CONFIG_LVGL_COLOR_16_SWAP=y
25 | CONFIG_LVGL_BITS_PER_PIXEL=24
26 | CONFIG_LVGL_HOR_RES_MAX=240
27 | CONFIG_LVGL_VER_RES_MAX=240
28 | CONFIG_LVGL_DISPLAY_DEV_NAME="DISPLAY"
29 | CONFIG_LVGL_FONT_MONTSERRAT_22=y
30 | CONFIG_LVGL_TXT_ENC_UTF8=y
31 | CONFIG_LVGL_USE_THEME_MONO=y
32 |
33 | # Touch screen
34 | CONFIG_SENSOR=y
35 | CONFIG_CST816S=y
36 | CONFIG_CST816S_TRIGGER_GLOBAL_THREAD=y
37 |
38 | # Bluetooth
39 | CONFIG_BT=y
40 | CONFIG_BT_PERIPHERAL=y
41 | CONFIG_BT_DIS=y
42 | CONFIG_BT_ATT_PREPARE_COUNT=5
43 | CONFIG_BT_DEVICE_NAME="Hypnos"
44 | CONFIG_BT_DEVICE_APPEARANCE=833
45 | CONFIG_BT_DEVICE_NAME_DYNAMIC=y
46 | CONFIG_BT_DEVICE_NAME_MAX=65
47 | CONFIG_BT_GATT_CLIENT=y
48 | CONFIG_BT_DIS_PNP=n
49 | CONFIG_BT_DIS_FW_REV=y
50 | CONFIG_BT_DIS_HW_REV=y
51 | CONFIG_BT_DIS_SW_REV=y
52 |
53 | # Let DIS information be read from settings
54 | CONFIG_BT_SETTINGS=y
55 | CONFIG_SETTINGS_RUNTIME=y
56 | CONFIG_SETTINGS=y
57 | CONFIG_SETTINGS_NONE=y
58 | CONFIG_BT_DIS_SETTINGS=y
59 | CONFIG_BT_DIS_STR_MAX=21
60 |
61 | # Remove warning
62 | CONFIG_BT_GATT_CACHING=n
63 |
64 | # Power management
65 | CONFIG_DEVICE_POWER_MANAGEMENT=y
66 |
67 | # Misc
68 | CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
69 |
--------------------------------------------------------------------------------
/app/hypnos/hypnos-photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albsod/pinetime-hypnos/8c634b89e0dc742042f6fad8515234618ecc1fa1/app/hypnos/hypnos-photo.png
--------------------------------------------------------------------------------
/app/hypnos/include/backlight.h:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | #ifndef BACKLIGHT__H
6 | #define BACKLIGHT__H
7 |
8 | #include
9 |
10 | void backlight_init(void);
11 | void backlight_enable(bool);
12 | bool backlight_is_enabled(void);
13 |
14 | #endif /* BACKLIGHT__H */
15 |
--------------------------------------------------------------------------------
/app/hypnos/include/battery.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef BATTERY__H
8 | #define BATTERY__H
9 |
10 | void battery_init();
11 | void battery_update_percentage();
12 | void battery_update_charging_status(bool);
13 | bool battery_get_charging_status();
14 | uint32_t battery_raw_to_mv(int16_t raw);
15 | uint32_t battery_mv_to_ppt(uint32_t mv);
16 | void battery_show_status();
17 | void battery_gfx_init();
18 |
19 | #endif /* BATTERY__H */
20 |
--------------------------------------------------------------------------------
/app/hypnos/include/bt.h:
--------------------------------------------------------------------------------
1 | #ifndef BT__H
2 | #define BT__H
3 |
4 | #include
5 |
6 | void bt_init(void);
7 |
8 | #endif /* BT__H */
9 |
--------------------------------------------------------------------------------
/app/hypnos/include/clock.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef CLOCK__H
8 | #define CLOCK__H
9 |
10 | #include
11 |
12 | void clock_init(void);
13 | void clock_increment_local_time(void);
14 | void clock_sync_time(cts_datetime_t *cts);
15 | void clock_show_time(void);
16 |
17 | #endif /* CLOCK__H */
18 |
--------------------------------------------------------------------------------
/app/hypnos/include/cts_sync.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications: Copyright (c) 2020 Endian Technologies AB
3 | * Copyright (c) 2016 Intel Corporation
4 | *
5 | * SPDX-License-Identifier: Apache-2.0
6 | */
7 |
8 | #ifndef CTS__H
9 | #define CTS__H
10 |
11 | #include
12 | #include
13 |
14 | void cts_sync_init(void);
15 | void cts_sync_loop(void);
16 | void cts_sync_enable(bool enable);
17 | void cts_update_datetime(struct tm *);
18 |
19 | typedef struct {
20 | uint16_t year;
21 | uint8_t month;
22 | uint8_t day;
23 | uint8_t hours;
24 | uint8_t minutes;
25 | uint8_t seconds;
26 | uint8_t day_of_week;
27 | uint8_t exact_time_256;
28 | uint8_t adjust_reason;
29 | } cts_datetime_t;
30 |
31 | #endif /* CTS__H */
32 |
--------------------------------------------------------------------------------
/app/hypnos/include/display.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef DISPLAY__H
8 | #define DISPLAY__H
9 |
10 | void display_init(void);
11 | void display_sleep(void);
12 | void display_wake_up(void);
13 |
14 | #endif /* DISPLAY__H */
15 |
--------------------------------------------------------------------------------
/app/hypnos/include/event_handler.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef EVENT_HANDLER__H
8 | #define EVENT_HANDLER__H
9 |
10 | #include
11 | #include
12 |
13 | void event_handler_init(void);
14 | void display_off_isr(struct k_timer *);
15 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
16 | void watchdog_refresh_isr(struct k_timer *);
17 | #endif
18 | void battery_percentage_isr(struct k_timer *);
19 | void battery_charging_isr(const struct device*, struct gpio_callback *, uint32_t);
20 | void button_pressed_isr(const struct device *, struct gpio_callback *, uint32_t);
21 | void touch_tap_isr(const struct device *, struct sensor_trigger *);
22 |
23 | #endif /* EVENT_HANDLER */
24 |
--------------------------------------------------------------------------------
/app/hypnos/include/gfx.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef GFX__H
8 | #define GFX__H
9 |
10 | enum bt_symbol {
11 | BT_CONNECTED,
12 | BT_ADVERTISING_ON,
13 | BT_ADVERTISING_OFF,
14 | };
15 |
16 | enum battery_symbol {
17 | BAT_CHARGE,
18 | BAT_FULL,
19 | BAT_3,
20 | BAT_2,
21 | BAT_1,
22 | BAT_EMPTY
23 | };
24 |
25 | void gfx_init(void);
26 | void gfx_battery_set_label(enum battery_symbol);
27 | void gfx_bt_set_label(enum bt_symbol);
28 | void gfx_time_set_label(char *);
29 | void gfx_date_set_label(char *);
30 | void gfx_update(void);
31 | void gfx_show_info(void);
32 | void gfx_show_watch(void);
33 |
34 | #endif /* GFX__H */
35 |
--------------------------------------------------------------------------------
/app/hypnos/include/gui.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef GUI__H
8 | #define GUI__H
9 |
10 | #include
11 |
12 | enum screen {
13 | WATCH,
14 | INFO
15 | };
16 |
17 | void gui_handle_touch_event(const struct device *, enum cst816s_gesture);
18 | int gui_handle_button_event(void);
19 |
20 | #endif /* GUI__H */
21 |
--------------------------------------------------------------------------------
/app/hypnos/include/log.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef LOGGING__H
8 | #define LOGGING__H
9 |
10 | #include
11 |
12 | LOG_MODULE_DECLARE(hypnos, LOG_LEVEL_INF);
13 |
14 | #endif /* LOGGING__H */
15 |
--------------------------------------------------------------------------------
/app/hypnos/include/version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef VERSION__H
8 | #define VERSION__H
9 |
10 | /* Stringify firmware build data included by cmake */
11 | #define _xstr(s) _str(s)
12 | #define _str(s) #s
13 | #define TIME_OF_BUILD _xstr(CURRENT_TIME_OF_BUILD)
14 | #define FW_VERSION _xstr(FW_BUILD)
15 |
16 | #endif /* VERSION__H */
17 |
--------------------------------------------------------------------------------
/app/hypnos/src/backlight.c:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-License-Identifier: Apache-2.0
3 | */
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "backlight.h"
10 | #include "log.h"
11 |
12 | /* ********** ********** DEFINES ********** ********** ********** */
13 | #define BACKLIGHT_PORT DT_GPIO_LABEL(DT_ALIAS(led1), gpios)
14 | #define BACKLIGHT_1 DT_GPIO_PIN(DT_ALIAS(led0), gpios)
15 | #define BACKLIGHT_2 DT_GPIO_PIN(DT_ALIAS(led1), gpios)
16 | #define BACKLIGHT_3 DT_GPIO_PIN(DT_ALIAS(led2), gpios)
17 | /* ********** ********** ********** ********** ********** */
18 |
19 | /* ********** ********** VARIABLES AND STRUCTS ********** ********** */
20 | static const struct device* backlight_dev;
21 | static bool backlight_enabled = false;
22 | /* ********** ********** ********** ********** ********** ********** */
23 |
24 | /* ********** ********** FUNCTIONS ********** ********** */
25 | void backlight_init()
26 | {
27 | backlight_dev = device_get_binding(BACKLIGHT_PORT);
28 | gpio_pin_configure(backlight_dev, BACKLIGHT_1, GPIO_OUTPUT);
29 | gpio_pin_configure(backlight_dev, BACKLIGHT_2, GPIO_OUTPUT);
30 | gpio_pin_configure(backlight_dev, BACKLIGHT_3, GPIO_OUTPUT);
31 | backlight_enable(true);
32 | LOG_DBG("Backlight init: Done");
33 | }
34 |
35 | void backlight_enable(bool enable)
36 | {
37 | gpio_pin_set_raw(backlight_dev, BACKLIGHT_1, enable ? 0 : 1);
38 | gpio_pin_set_raw(backlight_dev, BACKLIGHT_2, enable ? 0 : 1);
39 | gpio_pin_set_raw(backlight_dev, BACKLIGHT_3, enable ? 0 : 1);
40 | backlight_enabled = enable;
41 | }
42 |
43 | bool backlight_is_enabled()
44 | {
45 | return backlight_enabled;
46 | }
47 | /* ********** ********** ********** ********** ********** */
48 |
--------------------------------------------------------------------------------
/app/hypnos/src/battery.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | *
6 | * battery_mv_to_ppt, battery_level_point, battery_raw_to_mv:
7 | * Copyright (c) 2020 Nordic Semiconductor
8 | */
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "battery.h"
17 | #include "gfx.h"
18 | #include "log.h"
19 |
20 | #define CHANNEL_ID 7
21 | #define RESOLUTION 12
22 | #define DIVIDER 2
23 | #define COUNT_DOWN 5000
24 |
25 | /* ********** ********** VARIABLES ********** ********** */
26 | static const struct device* percentage_dev;
27 | static int16_t data[1];
28 | static uint32_t percentage;
29 | static bool charging;
30 | /* ********** ********** ********** ********** ********** */
31 |
32 | /* ********** ********** STRUCTS ********** ********** */
33 | struct battery_level_point {
34 | /** Remaining life at #lvl_mV. */
35 | uint16_t lvl_pptt;
36 |
37 | /** Battery voltage at #lvl_pptt remaining life. */
38 | uint16_t lvl_mV;
39 | };
40 |
41 | static const struct battery_level_point lipo[] = {
42 | { 10000, 4200 },
43 | { 5000, 3660},
44 | { 2100, 3600 },
45 | { 1000, 3560},
46 | { 0, 3100 },
47 | };
48 |
49 | static const struct adc_sequence sequence = {
50 | .channels = BIT(CHANNEL_ID),
51 | .buffer = data,
52 | .buffer_size = sizeof(data),
53 | .resolution = RESOLUTION,
54 | };
55 |
56 | static const struct adc_channel_cfg m_1st_channel_cfg = {
57 | .gain = ADC_GAIN_1_4,
58 | .reference = ADC_REF_INTERNAL,
59 | .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20),
60 | .channel_id = CHANNEL_ID,
61 | #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
62 | .input_positive = 8,
63 | #endif
64 | };
65 |
66 | /* ********** ********** ********** ********** ********** */
67 |
68 | /* ********** ********** FUNCTIONS ********** ********** */
69 | void battery_init()
70 | {
71 | percentage_dev = device_get_binding("ADC_0");
72 | if (percentage_dev == NULL) {
73 | LOG_ERR("Failed to get binding for ADC_0 device!");
74 | }
75 |
76 | if (adc_channel_setup(percentage_dev, &m_1st_channel_cfg) < 0) {
77 | LOG_ERR("Failed to setup channel for adc!");
78 | }
79 |
80 | LOG_DBG("Battery status init: Done");
81 | }
82 |
83 | void battery_update_percentage()
84 | {
85 | adc_read(percentage_dev, &sequence);
86 | uint32_t mv = battery_raw_to_mv(data[0]);
87 | percentage = battery_mv_to_ppt(mv)/100;
88 | }
89 |
90 | void battery_update_charging_status(bool value)
91 | {
92 | charging = value;
93 | }
94 |
95 | bool battery_get_charging_status()
96 | {
97 | return charging;
98 | }
99 |
100 | uint32_t battery_raw_to_mv(int16_t raw)
101 | {
102 | return (DIVIDER*600*(((uint32_t)raw*4*1000) >> RESOLUTION))/1000;
103 | }
104 |
105 | uint32_t battery_mv_to_ppt(uint32_t mv)
106 | {
107 | const struct battery_level_point *pb = lipo;
108 |
109 | if (mv >= pb->lvl_mV) {
110 | return pb->lvl_pptt;
111 | }
112 |
113 | while ((pb->lvl_pptt > 0)
114 | && (mv < pb->lvl_mV)) {
115 | ++pb;
116 | }
117 | if (mv < pb->lvl_mV) {
118 |
119 | return pb->lvl_pptt;
120 | }
121 |
122 | const struct battery_level_point *pa = pb - 1;
123 |
124 | return pb->lvl_pptt
125 | + ((pa->lvl_pptt - pb->lvl_pptt)
126 | * (mv - pb->lvl_mV)
127 | / (pa->lvl_mV - pb->lvl_mV));
128 | }
129 |
130 | void battery_show_status()
131 | {
132 | battery_update_percentage();
133 | if (charging) {
134 | LOG_INF("Battery status: %u%% (charging)",
135 | percentage);
136 | gfx_battery_set_label(BAT_CHARGE);
137 | } else {
138 | LOG_INF("Battery status: %u%% (discharging)",
139 | percentage);
140 |
141 | if (percentage > 89) {
142 | gfx_battery_set_label(BAT_FULL);
143 | } else if (percentage > 74) {
144 | gfx_battery_set_label(BAT_3);
145 | } else if (percentage > 49) {
146 | gfx_battery_set_label(BAT_2);
147 | } else if (percentage > 24) {
148 | gfx_battery_set_label(BAT_1);
149 | } else {
150 | gfx_battery_set_label(BAT_EMPTY);
151 | }
152 | }
153 | }
154 |
155 | /* ********** ********** ********** ********** ********** */
156 |
--------------------------------------------------------------------------------
/app/hypnos/src/bt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2014 Wind River Systems, Inc.
3 | * Copyright (c) 2015-2016 Intel Corporation
4 | * Copyright (c) 2020 Endian Technologies AB
5 | * Copyright (c) 2020 max00
6 | * Copyright (c) 2020 Prevas A/S
7 | *
8 | * SPDX-License-Identifier: Apache-2.0
9 | */
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #ifdef CONFIG_MCUMGR
27 | #include
28 | #endif
29 |
30 | #include "cts_sync.h"
31 | #include "gfx.h"
32 | #include "log.h"
33 | #include "version.h"
34 |
35 | /* ********** Function prototypes ********** */
36 | static void connected(struct bt_conn *conn, uint8_t err);
37 | static void disconnected(struct bt_conn *conn, uint8_t reason);
38 | static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);
39 | static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout);
40 |
41 | /* ********** Variables ********** */
42 |
43 | static struct k_work advertise_work;
44 |
45 | static const struct bt_data ad[] = {
46 | BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
47 | /* Device information */
48 | BT_DATA_BYTES(BT_DATA_UUID16_ALL,
49 | 0x0a, 0x18),
50 | /* Current time */
51 | BT_DATA_BYTES(BT_DATA_UUID16_ALL,
52 | 0x05, 0x18),
53 | #ifdef CONFIG_MCUMGR
54 | /* SMP */
55 | BT_DATA_BYTES(BT_DATA_UUID128_ALL,
56 | 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
57 | 0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d),
58 | #endif
59 | };
60 |
61 | static struct bt_conn_cb m_conn_callbacks = {
62 | .connected = connected,
63 | .disconnected = disconnected,
64 | .le_param_req = le_param_req,
65 | .le_param_updated = le_param_updated
66 | };
67 |
68 | static struct bt_le_adv_param param = BT_LE_ADV_PARAM_INIT(
69 | BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME,
70 | BT_GAP_ADV_SLOW_INT_MIN,
71 | BT_GAP_ADV_SLOW_INT_MAX,
72 | NULL
73 | );
74 |
75 | /* ********** Functions ********** */
76 | static int settings_runtime_load(void)
77 | {
78 | #if defined(CONFIG_BOARD_PINETIME)
79 | settings_runtime_set("bt/dis/model",
80 | "PineTime",
81 | sizeof("PineTime"));
82 | settings_runtime_set("bt/dis/manuf",
83 | "PINE64",
84 | sizeof("PINE64"));
85 | settings_runtime_set("bt/dis/hw",
86 | "1.0a",
87 | sizeof("1.0a"));
88 | #endif
89 | #if defined(CONFIG_BOARD_P8)
90 | settings_runtime_set("bt/dis/model",
91 | "P8",
92 | sizeof("P8"));
93 | settings_runtime_set("bt/dis/manuf",
94 | "Colmi",
95 | sizeof("Colmi"));
96 | #endif
97 | settings_runtime_set("bt/dis/sw",
98 | CONFIG_BT_DEVICE_NAME,
99 | sizeof(CONFIG_BT_DEVICE_NAME));
100 | settings_runtime_set("bt/dis/fw",
101 | FW_VERSION,
102 | sizeof(FW_VERSION));
103 | return 0;
104 | }
105 |
106 | static void advertise(struct k_work *work)
107 | {
108 | int rc;
109 |
110 | bt_le_adv_stop();
111 |
112 | rc = bt_le_adv_start(¶m, ad, ARRAY_SIZE(ad), NULL, 0);
113 | if (rc) {
114 | LOG_ERR("Advertising failed to start (rc %d)", rc);
115 | return;
116 | }
117 |
118 | LOG_INF("Advertising successfully started");
119 | }
120 |
121 | static void connected(struct bt_conn *conn, uint8_t err)
122 | {
123 | if (err) {
124 | return;
125 | }
126 | LOG_INF("connected");
127 | cts_sync_enable(true);
128 | gfx_bt_set_label(BT_CONNECTED);
129 | gfx_update();
130 | }
131 |
132 | static void disconnected(struct bt_conn *conn, uint8_t reason)
133 | {
134 | LOG_INF("disconnected (reason: %u)", reason);
135 | cts_sync_enable(false);
136 | gfx_bt_set_label(BT_ADVERTISING_ON);
137 | gfx_update();
138 | }
139 |
140 | static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
141 | {
142 | return true;
143 | }
144 |
145 | static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
146 | {
147 |
148 | }
149 |
150 | void bt_init(void)
151 | {
152 | int err = bt_enable(NULL);
153 | if (err) {
154 | LOG_ERR("Bluetooth init failed (err %d)", err);
155 | return;
156 | }
157 |
158 | settings_load();
159 | settings_runtime_load();
160 |
161 | k_work_init(&advertise_work, advertise);
162 | bt_conn_cb_register(&m_conn_callbacks);
163 |
164 | k_work_submit(&advertise_work);
165 | #ifdef CONFIG_MCUMGR
166 | /* Initialize the Bluetooth mcumgr transport. */
167 | smp_bt_register();
168 | #endif
169 | cts_sync_init();
170 |
171 | LOG_DBG("Bluetooth initialized");
172 | }
173 |
174 | void bt_adv_stop(void)
175 | {
176 | k_sleep(K_MSEC(400));
177 |
178 | int err = bt_le_adv_stop();
179 | if (err) {
180 | LOG_ERR("Advertising failed to stop (err %d)", err);
181 | return;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/app/hypnos/src/clock.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "battery.h"
12 | #include "bt.h"
13 | #include "version.h"
14 | #include "cts_sync.h"
15 | #include "log.h"
16 | #include "event_handler.h"
17 | #include "gfx.h"
18 |
19 | /* ********** ********** VARIABLES ********** ********** */
20 | static char time_label_str[32];
21 | static char date_label_str[32];
22 | static uint64_t uptime_ms;
23 | static uint64_t last_uptime_ms;
24 | static uint64_t elapsed_ms;
25 |
26 | static struct tm ti = {
27 | .tm_sec = 0,
28 | .tm_min = 0,
29 | .tm_hour = 0,
30 | .tm_mday = 0,
31 | .tm_mon = 0,
32 | .tm_year = 0,
33 | .tm_wday = 0,
34 | };
35 |
36 | /* ********** ********** FUNCTIONS *********** ********** */
37 | void clock_str_to_local_time(const char *str)
38 | {
39 | if (sscanf(str, "%d-%d-%dT%d:%d:%d", &ti.tm_year, &ti.tm_mon,
40 | &ti.tm_mday, &ti.tm_hour, &ti.tm_min, &ti.tm_sec) != 6) {
41 | LOG_ERR("Failed to parse time of build.");
42 | }
43 | ti.tm_year-=1900;
44 | ti.tm_mon-=1;
45 | mktime(&ti);
46 | }
47 |
48 | void clock_init()
49 | {
50 | /* Set time to time of build */
51 | clock_str_to_local_time(TIME_OF_BUILD);
52 | LOG_DBG("Time set to time of build");
53 | LOG_DBG("Clock init: Done");
54 | }
55 |
56 | void clock_update_elapsed_ms()
57 | {
58 | uptime_ms = k_uptime_get();
59 | elapsed_ms = uptime_ms - last_uptime_ms;
60 | last_uptime_ms = uptime_ms;
61 | }
62 |
63 | /* Called by cts sync */
64 | void clock_sync_time(cts_datetime_t *cts)
65 | {
66 | ti.tm_year = cts->year -1900;
67 | ti.tm_mon = cts->month -1;
68 | ti.tm_mday = cts->day;
69 | ti.tm_hour = cts->hours;
70 | ti.tm_min = cts->minutes;
71 | ti.tm_sec = cts->seconds;
72 | mktime(&ti);
73 | clock_update_elapsed_ms();
74 | }
75 |
76 | /* Called by event handler */
77 | void clock_increment_local_time()
78 | {
79 | clock_update_elapsed_ms();
80 | ti.tm_sec += elapsed_ms / 1000;
81 | mktime(&ti);
82 | }
83 |
84 | void clock_show_time()
85 | {
86 | strftime(time_label_str, 32, "%H:%M", &ti);
87 | strftime(date_label_str, 32, "%a %d %b", &ti);
88 | gfx_time_set_label(time_label_str);
89 | gfx_date_set_label(date_label_str);
90 | }
91 |
--------------------------------------------------------------------------------
/app/hypnos/src/cts_sync.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Dejvino
3 | * Copyright (c) 2020 Endian Technologies AB
4 | * Copyright (c) 2020 max00
5 | *
6 | * SPDX-License-Identifier: Apache-2.0
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include "log.h"
16 | #include "cts_sync.h"
17 | #include "clock.h"
18 |
19 | /* ********** Definitions ********** */
20 | #define CTS_SYNC_INTERVAL K_SECONDS(60)
21 |
22 | /* ********** Function prototypes ********** */
23 | static void cts_sync_timer_timeout_handler(struct k_timer *);
24 | static void cts_sync_processor(struct bt_conn *, void *);
25 |
26 | /* ********** Variables ********** */
27 | static struct k_timer m_cts_sync_timer;
28 | static struct bt_gatt_discover_params cts_discovery_params;
29 | static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
30 | static struct bt_gatt_read_params read_params;
31 | cts_datetime_t clock_datetime;
32 | static struct {
33 | int offset;
34 | cts_datetime_t datetime;
35 | } m_read_buf;
36 |
37 | /* ********** Functions ********** */
38 | void cts_sync_init()
39 | {
40 | k_timer_init(&m_cts_sync_timer, cts_sync_timer_timeout_handler, NULL);
41 | }
42 |
43 | void cts_sync_enable(bool enable)
44 | {
45 | if (enable) {
46 | k_timer_start(&m_cts_sync_timer, K_NO_WAIT, CTS_SYNC_INTERVAL);
47 | } else {
48 | k_timer_stop(&m_cts_sync_timer);
49 | }
50 | }
51 |
52 | static void sync_cts_to_clock(cts_datetime_t* cts_datetime)
53 | {
54 | if (cts_datetime->year + cts_datetime->day + cts_datetime->hours
55 | + cts_datetime->minutes + cts_datetime->seconds == 0) {
56 | LOG_WRN("Ignoring suspicious time data from companion application.");
57 | return;
58 | }
59 |
60 | LOG_INF("CTS sync to clock started.\n Y%04d D%03d T%2d:%2d:%2d",
61 | cts_datetime->year, cts_datetime->day,
62 | cts_datetime->hours, cts_datetime->minutes, cts_datetime->seconds);
63 |
64 | memcpy(&clock_datetime, cts_datetime, sizeof(clock_datetime));
65 | clock_sync_time(cts_datetime);
66 | LOG_INF("CTS sync to clock complete.");
67 | }
68 |
69 | void cts_update_datetime(struct tm *t)
70 | {
71 | t->tm_year = clock_datetime.year -1900;
72 | t->tm_mon = clock_datetime.month -1;
73 | t->tm_mday = clock_datetime.day;
74 | t->tm_hour = clock_datetime.hours;
75 | t->tm_min = clock_datetime.minutes;
76 | t->tm_sec = clock_datetime.seconds;
77 | }
78 |
79 | static void cts_sync_timer_timeout_handler(struct k_timer *tmr)
80 | {
81 | bt_conn_foreach(BT_CONN_TYPE_LE, cts_sync_processor, NULL);
82 | }
83 |
84 | uint8_t cts_sync_read(struct bt_conn *conn, uint8_t err,
85 | struct bt_gatt_read_params *params,
86 | const void *data, uint16_t length)
87 | {
88 | LOG_DBG("Reading CCC data: err %d, %d bytes, offset %d.", err, length, m_read_buf.offset);
89 |
90 | if (!data || length <= 0) {
91 | sync_cts_to_clock(&m_read_buf.datetime);
92 | return BT_GATT_ITER_STOP;
93 | }
94 |
95 | memcpy(&m_read_buf.datetime + m_read_buf.offset, data, length);
96 | m_read_buf.offset += length;
97 |
98 | return BT_GATT_ITER_CONTINUE;
99 | }
100 |
101 | uint8_t cts_sync_service_discovered(struct bt_conn* conn, const struct bt_gatt_attr* attr,
102 | struct bt_gatt_discover_params* params)
103 | {
104 | if (!attr) {
105 | LOG_INF("CTS Service Discovery completed");
106 | return BT_GATT_ITER_STOP;
107 | }
108 | LOG_DBG("Discovered attribute, handle: %u", attr->handle);
109 |
110 | memset(&read_params, 0, sizeof(read_params));
111 | read_params.func = cts_sync_read;
112 | read_params.by_uuid.uuid = (struct bt_uuid *) &uuid;
113 | read_params.by_uuid.start_handle = attr->handle;
114 | read_params.by_uuid.end_handle = 0xffff;
115 | m_read_buf.offset = 0;
116 | if (bt_gatt_read(conn, &read_params) < 0) {
117 | LOG_DBG("Could not initiate read of CCC data.");
118 | }
119 |
120 | return BT_GATT_ITER_STOP;
121 | }
122 |
123 | static void cts_sync_processor(struct bt_conn *conn, void *data)
124 | {
125 | memcpy(&uuid, BT_UUID_CTS_CURRENT_TIME, sizeof(uuid));
126 | cts_discovery_params.func = cts_sync_service_discovered;
127 | cts_discovery_params.start_handle = 0x0001;
128 | cts_discovery_params.end_handle = 0xFFFF;
129 | cts_discovery_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
130 | cts_discovery_params.uuid = (struct bt_uuid *) &uuid;
131 |
132 | if (bt_gatt_discover(conn, &cts_discovery_params) != 0) {
133 | LOG_ERR("CTS Sync > GATT discovery FAILED.");
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/app/hypnos/src/display.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "display.h"
12 | #include "log.h"
13 |
14 | /* ********** ********** VARIABLES AND STRUCTS ********** ********** */
15 | static const struct device *display_dev;
16 | /* ********** ********** ********** ********** ********** ********** */
17 |
18 | /* ********** ********** FUNCTIONS ********** ********** */
19 | void display_init(void)
20 | {
21 | display_dev = device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME);
22 | display_blanking_off(display_dev);
23 | LOG_DBG("Display init: Done");
24 | }
25 |
26 | void display_sleep(void)
27 | {
28 | (void)device_set_power_state(display_dev, DEVICE_PM_LOW_POWER_STATE, NULL,
29 | NULL);
30 | }
31 |
32 | void display_wake_up(void)
33 | {
34 | (void)device_set_power_state(display_dev, DEVICE_PM_ACTIVE_STATE, NULL,
35 | NULL);
36 | }
37 |
38 |
39 | /* ********** ********** ********** ********** ********** */
40 |
--------------------------------------------------------------------------------
/app/hypnos/src/event_handler.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "backlight.h"
13 | #include "battery.h"
14 | #include "bt.h"
15 | #include "clock.h"
16 | #include "display.h"
17 | #include "event_handler.h"
18 | #include "gui.h"
19 | #include "log.h"
20 |
21 | /* ********** defines ********** */
22 | #define BAT_CHA 12
23 | #define BTN_PORT DT_GPIO_LABEL(DT_ALIAS(sw0), gpios)
24 | #define BTN_IN DT_GPIO_PIN(DT_ALIAS(sw0), gpios)
25 | #define BTN_OUT 15
26 | #define EDGE (GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE)
27 | #define PULL_UP DT_GPIO_FLAGS(DT_ALIAS(sw0), gpios)
28 | #define TOUCH_PORT CONFIG_CST816S_NAME
29 | #define DISPLAY_TIMEOUT K_SECONDS(5)
30 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
31 | /* The watchdog released by the PineTime bootloader v5.0.0-rc1
32 | * will try to bite every 7 seconds.
33 | */
34 | #define WDT_REFRESH 6
35 | #endif
36 | /* ********** ******* ********** */
37 |
38 | /* ********** variables ********** */
39 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
40 | static struct k_timer watchdog_refresh_timer;
41 | #endif
42 | static struct k_timer display_off_timer;
43 | static const struct device *charging_dev;
44 | static struct gpio_callback charging_cb;
45 | static const struct device *button_dev;
46 | static struct gpio_callback button_cb;
47 | static const struct device *touch_dev;
48 | static struct sensor_trigger tap = {
49 | .type = SENSOR_TRIG_DATA_READY,
50 | .chan = SENSOR_CHAN_ACCEL_XYZ,
51 | };
52 | static enum cst816s_gesture gesture;
53 | static struct sensor_value touch_point;
54 |
55 | /* ********** ********* ********** */
56 |
57 | /* ********** init function ********** */
58 | void event_handler_init()
59 | {
60 | /* Initialize GPIOs */
61 | charging_dev = device_get_binding("GPIO_0");
62 | gpio_pin_configure(charging_dev, BAT_CHA, GPIO_INPUT | GPIO_INT_EDGE_BOTH);
63 | gpio_init_callback(&charging_cb, battery_charging_isr, BIT(BAT_CHA));
64 | button_dev = device_get_binding(BTN_PORT);
65 | gpio_pin_configure(button_dev, BTN_IN, GPIO_INPUT | GPIO_INT_EDGE_FALLING | PULL_UP);
66 | gpio_init_callback(&button_cb, button_pressed_isr, BIT(BTN_IN));
67 | touch_dev = device_get_binding(DT_LABEL(DT_INST(0, hynitron_cst816s)));
68 |
69 | /* Enable GPIOs */
70 | gpio_add_callback(charging_dev, &charging_cb);
71 | gpio_add_callback(button_dev, &button_cb);
72 | sensor_trigger_set(touch_dev, &tap, touch_tap_isr);
73 |
74 | /* Set button out pin to high to enable the button */
75 | uint32_t button_out = 1U;
76 | gpio_pin_configure(button_dev, BTN_OUT, GPIO_OUTPUT);
77 | gpio_pin_set_raw(button_dev, BTN_OUT, button_out);
78 |
79 | /* Start timers */
80 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
81 | if (NRF_WDT->RUNSTATUS) {
82 | LOG_INF("Watchdog detected. Let's kick it every %d seconds.",
83 | WDT_REFRESH);
84 | k_timer_init(&watchdog_refresh_timer, watchdog_refresh_isr,
85 | NULL);
86 | k_timer_start(&watchdog_refresh_timer, K_NO_WAIT,
87 | K_SECONDS(WDT_REFRESH));
88 | } else {
89 | LOG_INF("No watchdog detected.");
90 | }
91 | #endif
92 | k_timer_init(&display_off_timer, display_off_isr, NULL);
93 | k_timer_start(&display_off_timer, DISPLAY_TIMEOUT, K_NO_WAIT);
94 |
95 | /* Special cases */
96 | /* Get battery charging status */
97 | k_sleep(K_MSEC(10));
98 | uint32_t res = gpio_pin_get(charging_dev, BAT_CHA);
99 | battery_update_charging_status(res != 1U);
100 |
101 | /* Show time, date and battery status */
102 | clock_show_time();
103 | battery_show_status();
104 |
105 | LOG_DBG("Event handler init: Done");
106 | }
107 | /* ********** ************ ********** */
108 |
109 | /* ********** interrupt handlers ********** */
110 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
111 | void watchdog_refresh_isr(struct k_timer *wdt_refresh)
112 | {
113 | NRF_WDT->RR[0] = WDT_RR_RR_Reload;
114 | }
115 | #endif
116 |
117 | void display_off_isr(struct k_timer *light_off)
118 | {
119 | backlight_enable(false);
120 | display_sleep();
121 | }
122 |
123 | void battery_charging_isr(const struct device *gpiobat, struct gpio_callback *cb, uint32_t pins)
124 | {
125 | uint32_t res = gpio_pin_get(charging_dev, BAT_CHA);
126 | battery_update_charging_status(res != 1U);
127 | }
128 |
129 | void button_pressed_isr(const struct device *gpiobtn, struct gpio_callback *cb, uint32_t pins)
130 | {
131 | display_wake_up();
132 | backlight_enable(true);
133 | k_timer_start(&display_off_timer, DISPLAY_TIMEOUT, K_NO_WAIT);
134 |
135 | gui_handle_button_event();
136 | }
137 |
138 | void touch_tap_isr(const struct device *touch_dev, struct sensor_trigger *tap)
139 | {
140 | if (sensor_sample_fetch(touch_dev) < 0) {
141 | LOG_ERR("Touch sample update error.");
142 | }
143 |
144 | display_wake_up();
145 | backlight_enable(true);
146 | k_timer_start(&display_off_timer, DISPLAY_TIMEOUT, K_NO_WAIT);
147 |
148 | struct sensor_value gesture_val;
149 | sensor_channel_get(touch_dev, CST816S_CHAN_GESTURE, &gesture_val);
150 | gesture = gesture_val.val1;
151 | sensor_channel_get(touch_dev, CST816S_CHAN_TOUCH_POINT_1, &touch_point);
152 |
153 | LOG_INF("Gesture %d on x=%d, y=%d", gesture, touch_point.val1, touch_point.val2);
154 | gui_handle_touch_event(touch_dev, gesture);
155 | }
156 |
157 | /* ********** ************** ********** */
158 |
--------------------------------------------------------------------------------
/app/hypnos/src/fonts/rubik/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2015 The Rubik Project Authors,
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/app/hypnos/src/fonts/rubik/Rubik-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albsod/pinetime-hypnos/8c634b89e0dc742042f6fad8515234618ecc1fa1/app/hypnos/src/fonts/rubik/Rubik-Regular.ttf
--------------------------------------------------------------------------------
/app/hypnos/src/gfx.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include "gfx.h"
9 | #include "log.h"
10 | #include "version.h"
11 | #include
12 |
13 | /* ********** Macros and constants ********** */
14 | LV_FONT_DECLARE(rubik_regular_68);
15 | LV_FONT_DECLARE(rubik_regular_34);
16 |
17 | #define BAT_LABEL_MARGIN 3
18 | #define TIME_LABEL_VALIGNMENT -25
19 | #define DATE_LABEL_VALIGNMENT 30
20 | /* ********** ******* ********** */
21 |
22 | /* ********** Variables ********** */
23 | static lv_obj_t *battery_label;
24 | static lv_obj_t *bt_label;
25 | static lv_obj_t *time_label;
26 | static lv_obj_t *date_label;
27 | static lv_obj_t *info_label;
28 | static lv_style_t style;
29 | static lv_style_t style_time;
30 | static lv_style_t style_date;
31 |
32 | /* ********** Functions ********** */
33 | void gfx_init(void)
34 | {
35 | /* Create styles for time, date and the rest */
36 | lv_style_init(&style);
37 | lv_style_init(&style_time);
38 | lv_style_init(&style_date);
39 |
40 | /* Default style */
41 | lv_style_set_text_color(&style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
42 | lv_style_set_text_font(&style, LV_STATE_DEFAULT, &lv_font_montserrat_22);
43 |
44 | /* Battery label */
45 | battery_label = lv_label_create(lv_scr_act(), NULL);
46 | lv_obj_add_style(battery_label, LV_LABEL_PART_MAIN, &style);
47 | lv_label_set_text(battery_label, "");
48 |
49 | /* Bluetooth label */
50 | bt_label = lv_label_create(lv_scr_act(), NULL);
51 | lv_obj_align(bt_label, NULL, LV_ALIGN_IN_TOP_LEFT, 6, 4);
52 | lv_obj_add_style(bt_label, LV_LABEL_PART_MAIN, &style);
53 | lv_label_set_text(bt_label, LV_SYMBOL_WIFI);
54 |
55 | /* Time label and style */
56 | lv_style_set_text_font(&style_time, LV_STATE_DEFAULT, &rubik_regular_68);
57 | lv_style_set_text_color(&style_time, LV_STATE_DEFAULT, LV_COLOR_WHITE);
58 | time_label = lv_label_create(lv_scr_act(), NULL);
59 | lv_obj_add_style(time_label, LV_LABEL_PART_MAIN, &style_time);
60 | lv_label_set_text(time_label, "00:00");
61 | lv_obj_align(time_label, NULL, LV_ALIGN_CENTER, 0, TIME_LABEL_VALIGNMENT);
62 |
63 | /* Date label and style */
64 | lv_style_set_text_color(&style_date, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
65 | lv_style_set_text_font(&style_date, LV_STATE_DEFAULT, &rubik_regular_34);
66 | date_label = lv_label_create(lv_scr_act(), NULL);
67 | lv_obj_add_style(date_label, LV_LABEL_PART_MAIN, &style_date);
68 | lv_label_set_text(date_label, "Mon 10 Jan");
69 | lv_obj_align(date_label, NULL, LV_ALIGN_CENTER, 0, DATE_LABEL_VALIGNMENT);
70 | LOG_DBG("Graphics init: Done");
71 |
72 | /* Info label */
73 | info_label = lv_label_create(lv_scr_act(), NULL);
74 | lv_obj_add_style(info_label, LV_LABEL_PART_MAIN, &style);
75 | if (strlen(FW_VERSION) < 10) {
76 | lv_label_set_text(info_label, "Hypnos " FW_VERSION "\n\n"
77 | "This is Free Software" "\n"
78 | "without any warranty." "\n\n"
79 | "https://github.com/" "\n"
80 | "endian-albin/" "\n"
81 | "pinetime-hypnos");
82 | } else {
83 | lv_label_set_text(info_label, "Hypnos" "\n"
84 | FW_VERSION "\n\n"
85 | "This is Free Software" "\n"
86 | "without any warranty." "\n"
87 | "https://github.com/" "\n"
88 | "endian-albin/" "\n"
89 | "pinetime-hypnos");
90 | }
91 | lv_obj_set_hidden(info_label, true);
92 | }
93 |
94 | void gfx_update(void)
95 | {
96 | lv_task_handler();
97 | }
98 |
99 | void gfx_time_set_label(char *str)
100 | {
101 | lv_label_set_text(time_label, str);
102 | lv_obj_align(time_label, NULL, LV_ALIGN_CENTER, 0, TIME_LABEL_VALIGNMENT);
103 | }
104 |
105 | void gfx_date_set_label(char *str)
106 | {
107 | lv_label_set_text(date_label, str);
108 | lv_obj_align(date_label, NULL, LV_ALIGN_CENTER, 0, DATE_LABEL_VALIGNMENT);
109 | }
110 |
111 | void gfx_bt_set_label(enum bt_symbol s)
112 | {
113 | switch (s) {
114 | case BT_ADVERTISING_ON:
115 | lv_label_set_text(bt_label, LV_SYMBOL_WIFI);
116 | break;
117 | case BT_CONNECTED:
118 | lv_label_set_text(bt_label, LV_SYMBOL_BLUETOOTH);
119 | break;
120 | default:
121 | lv_label_set_text(bt_label, "");
122 | }
123 | }
124 |
125 | void gfx_battery_set_label(enum battery_symbol s)
126 | {
127 | switch (s) {
128 | case BAT_CHARGE:
129 | lv_label_set_text(battery_label, LV_SYMBOL_CHARGE);
130 | lv_obj_align(battery_label, NULL, LV_ALIGN_IN_TOP_RIGHT, -BAT_LABEL_MARGIN, BAT_LABEL_MARGIN);
131 | break;
132 | case BAT_FULL:
133 | lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_FULL);
134 | break;
135 | case BAT_3:
136 | lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_3);
137 | break;
138 | case BAT_2:
139 | lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_2);
140 | break;
141 | case BAT_1:
142 | lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_1);
143 | break;
144 | default:
145 | lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_EMPTY);
146 | }
147 | lv_obj_align(battery_label, NULL, LV_ALIGN_IN_TOP_RIGHT, -BAT_LABEL_MARGIN, 0);
148 | }
149 |
150 | void gfx_show_info(void)
151 | {
152 | lv_obj_set_hidden(time_label, true);
153 | lv_obj_set_hidden(date_label, true);
154 | lv_obj_set_hidden(bt_label, true);
155 | lv_obj_set_hidden(info_label, false);
156 | }
157 |
158 | void gfx_show_watch(void)
159 | {
160 | lv_obj_set_hidden(time_label, false);
161 | lv_obj_set_hidden(date_label, false);
162 | lv_obj_set_hidden(bt_label, false);
163 | lv_obj_set_hidden(info_label, true);
164 | }
165 |
--------------------------------------------------------------------------------
/app/hypnos/src/gui.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 | #include "gfx.h"
9 | #include "gui.h"
10 | #include "clock.h"
11 | #include "battery.h"
12 | #include "bt.h"
13 | #include "log.h"
14 |
15 | static enum screen sc;
16 |
17 | void gui_handle_touch_event(const struct device *touch_dev, enum cst816s_gesture gesture)
18 | {
19 | switch (gesture) {
20 | case SLIDE_UP ... SLIDE_RIGHT:
21 | if (sc == WATCH) {
22 | gfx_show_info();
23 | sc = INFO;
24 | break;
25 | }
26 | sc = WATCH;
27 | /* Fallthough */
28 | default:
29 | clock_increment_local_time();
30 | clock_show_time();
31 | battery_show_status();
32 | gfx_show_watch();
33 | }
34 | gfx_update();
35 | }
36 |
37 | int gui_handle_button_event(void)
38 | {
39 | clock_increment_local_time();
40 | clock_show_time();
41 | battery_show_status();
42 | gfx_update();
43 |
44 | return 1;
45 | }
46 |
--------------------------------------------------------------------------------
/app/hypnos/src/log.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Endian Technologies AB
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #include
8 |
9 | LOG_MODULE_REGISTER(hypnos, LOG_LEVEL_INF);
10 |
--------------------------------------------------------------------------------
/app/hypnos/src/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Hypnos: Smartwatch firmware for the PineTime
3 | * Copyright (c) 2020 Endian Technologies AB
4 | *
5 | * This is free software with ABSOLUTELY NO WARRANTY.
6 | *
7 | * SPDX-License-Identifier: Apache-2.0
8 | */
9 |
10 | #include
11 | #include "backlight.h"
12 | #include "battery.h"
13 | #include "bt.h"
14 | #include "clock.h"
15 | #include "cts_sync.h"
16 | #include "display.h"
17 | #include "event_handler.h"
18 | #include "gfx.h"
19 | #include "log.h"
20 | #ifdef CONFIG_BOOTLOADER_MCUBOOT
21 | #include "dfu/mcuboot.h"
22 | #endif
23 | #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
24 | #include
25 | #include
26 | #include "fs_mgmt/fs_mgmt.h"
27 | #include
28 | #endif
29 | #ifdef CONFIG_MCUMGR_CMD_OS_MGMT
30 | #include "os_mgmt/os_mgmt.h"
31 | #endif
32 | #ifdef CONFIG_MCUMGR_CMD_IMG_MGMT
33 | #include "img_mgmt/img_mgmt.h"
34 | #endif
35 |
36 | #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
37 | FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(cstorage);
38 | static struct fs_mount_t littlefs_mnt = {
39 | .type = FS_LITTLEFS,
40 | .fs_data = &cstorage,
41 | .storage_dev = (void *)FLASH_AREA_ID(storage),
42 | .mnt_point = "/lfs"
43 | };
44 | #endif
45 |
46 | /* ******** Functions ******** */
47 | void main(void)
48 | {
49 | LOG_INF("Welcome to Hypnos!");
50 | LOG_INF("This is free software with ABSOLUTELY NO WARRANTY.");
51 |
52 | gfx_init();
53 | clock_init();
54 | battery_init();
55 | display_init();
56 | event_handler_init();
57 | gfx_update();
58 | backlight_init();
59 |
60 | /* Register the built-in mcumgr command handlers. */
61 | #ifdef CONFIG_MCUMGR_CMD_FS_MGMT
62 | int rc = fs_mount(&littlefs_mnt);
63 | if (rc < 0) {
64 | LOG_ERR("Error mounting littlefs [%d]", rc);
65 | }
66 |
67 | fs_mgmt_register_group();
68 | #endif
69 | #ifdef CONFIG_MCUMGR_CMD_OS_MGMT
70 | os_mgmt_register_group();
71 | #endif
72 | #ifdef CONFIG_MCUMGR_CMD_IMG_MGMT
73 | img_mgmt_register_group();
74 | #endif
75 | bt_init();
76 |
77 | while (true) {
78 | k_cpu_idle();
79 | #ifdef CONFIG_LOG
80 | k_msleep(1); /* Allows messages to show up in the console */
81 | #endif
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/hypnos/watch_photo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albsod/pinetime-hypnos/8c634b89e0dc742042f6fad8515234618ecc1fa1/app/hypnos/watch_photo.jpg
--------------------------------------------------------------------------------
/app/include/battery.h:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #ifndef BATTERY_H__
7 | #define BATTERY_H__
8 |
9 |
10 | #ifdef __cplusplus
11 | extern "C" {
12 | #endif
13 |
14 | #include
15 |
16 | #ifdef __cplusplus
17 | }
18 | #endif
19 |
20 | /** @brief Battery events. */
21 | enum battery_evt {
22 | BATTERY_EVT_CHARGING, /* Ext power connected and charging. */
23 | BATTERY_EVT_NOT_CHARGING, /* Ext power connected, not charging. */
24 | BATTERY_EVT_DISCONNECTED, /* Ext power not connected. */
25 | };
26 |
27 | typedef void (*battery_callback_t)(enum battery_evt);
28 |
29 | /** @brief Battery monitor initialization.
30 | *
31 | * Initializes ADC and gpios for monitoring external power state. Callback is
32 | * called from interrupt context.
33 | *
34 | * @param callback Notifies ext power state changes. Can be NULL.
35 | *
36 | * @return 0 on success, negative number on error.
37 | */
38 | int battery_init(battery_callback_t callback);
39 |
40 | /** @brief Read raw ADC value.
41 | *
42 | * Must be called from thread context.
43 | *
44 | * @param raw Location to put raw value.
45 | *
46 | * @return 0 on success, negative number on error.
47 | */
48 | int battery_read(int16_t *raw);
49 |
50 | /** @brief Convert raw value to millivolts.
51 | *
52 | * @param raw Raw value.
53 | * @return Value in millivolts.
54 | */
55 | int battery_raw_to_mv(int16_t raw);
56 |
57 | /** @brief Coonvert millivolts to pptt (points per ten thousend)
58 | *
59 | * @param mv Millivots.
60 | * @return pptt value calculated based on estimated discharge curve.
61 | */
62 | int battery_mv_to_ppt(int mv);
63 |
64 | /** @brief Check if external power is connected.
65 | *
66 | * @return true if connected.
67 | */
68 | bool battery_is_powered(void);
69 |
70 | /** @brief Check if charging is active.
71 | *
72 | * @return true if charging.
73 | */
74 | bool battery_is_charging(void);
75 |
76 | #endif /* BATTERY_H__ */
77 |
--------------------------------------------------------------------------------
/app/include/drivers/sensor/cst816s.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Stephane Dorre
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_CTS816A_H_
8 | #define ZEPHYR_INCLUDE_DRIVERS_SENSOR_CTS816A_H_
9 |
10 | #include
11 |
12 | enum cst816s_gesture {
13 | NONE,
14 | SLIDE_UP,
15 | SLIDE_DOWN,
16 | SLIDE_LEFT,
17 | SLIDE_RIGHT,
18 | CLICK,
19 | DOUBLE_CLICK,
20 | LONG_PRESS,
21 | };
22 |
23 | enum cst816s_action {
24 | DOWN = 0,
25 | UP = 1,
26 | CONTACT = 2,
27 | };
28 |
29 | enum cst816s_channel {
30 | CST816S_CHAN_GESTURE = SENSOR_CHAN_PRIV_START,
31 | CST816S_CHAN_TOUCH_POINT_1,
32 | CST816S_CHAN_TOUCH_POINT_2,
33 | };
34 |
35 | /* If necessary at some point */
36 | /*
37 | enum cst816s_attribute {
38 | CST816S_ATTR_XXX = SENSOR_ATTR_PRIV_START,
39 | CST816S_ATTR_YYY,
40 | };
41 |
42 | enum cts816s_trigger {
43 | CST816S_TRIG_XXX = SENSOR_TRIG_PRIV_START,
44 | CST816S_TRIG_YYY,
45 | };
46 | */
47 |
48 | #endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_CTS816A_H_ */
--------------------------------------------------------------------------------
/app/pkglist:
--------------------------------------------------------------------------------
1 | accountsservice
2 | acl
3 | acpid
4 | adduser
5 | adwaita-icon-theme
6 | apparmor
7 | apport
8 | apport-symptoms
9 | apt
10 | apt-utils
11 | at
12 | at-spi2-core
13 | base-files
14 | base-passwd
15 | bash
16 | bash-completion
17 | bc
18 | bcache-tools
19 | bind9-host
20 | binutils
21 | binutils-common:amd64
22 | binutils-x86-64-linux-gnu
23 | blt
24 | bsdmainutils
25 | bsdutils
26 | btrfs-progs
27 | btrfs-tools
28 | busybox-initramfs
29 | busybox-static
30 | byobu
31 | bzip2
32 | ca-certificates
33 | ccache
34 | cloud-guest-utils
35 | cloud-init
36 | cloud-initramfs-copymods
37 | cloud-initramfs-dyn-netconf
38 | cmake
39 | cmake-data
40 | command-not-found
41 | command-not-found-data
42 | console-setup
43 | console-setup-linux
44 | coreutils
45 | cpio
46 | cpp
47 | cpp-7
48 | cron
49 | cryptsetup
50 | cryptsetup-bin
51 | curl
52 | dash
53 | dbus
54 | dbus-x11
55 | dconf-gsettings-backend:amd64
56 | dconf-service
57 | debconf
58 | debconf-i18n
59 | debianutils
60 | device-tree-compiler
61 | dfu-util
62 | diffutils
63 | dirmngr
64 | distro-info-data
65 | dmeventd
66 | dmidecode
67 | dmsetup
68 | dns-root-data
69 | dnsmasq-base
70 | dnsutils
71 | dosfstools
72 | dpkg
73 | e2fsprogs
74 | eatmydata
75 | ebtables
76 | ed
77 | eject
78 | ethtool
79 | fdisk
80 | file
81 | findutils
82 | fontconfig
83 | fontconfig-config
84 | fonts-dejavu-core
85 | fonts-droid-fallback
86 | fonts-lato
87 | fonts-lmodern
88 | fonts-noto-mono
89 | fonts-texgyre
90 | fonts-ubuntu-console
91 | friendly-recovery
92 | ftp
93 | fuse
94 | gawk
95 | gcc
96 | gcc-7
97 | gcc-7-base:amd64
98 | gcc-7-multilib
99 | gcc-8-base:amd64
100 | gcc-multilib
101 | gdisk
102 | geoip-database
103 | gettext-base
104 | ghostscript
105 | ghostscript-x
106 | gir1.2-glib-2.0:amd64
107 | git
108 | git-man
109 | glib-networking:amd64
110 | glib-networking-common
111 | glib-networking-services
112 | gnupg
113 | gnupg-l10n
114 | gnupg-utils
115 | gperf
116 | gpg
117 | gpg-agent
118 | gpg-wks-client
119 | gpg-wks-server
120 | gpgconf
121 | gpgsm
122 | gpgv
123 | grep
124 | groff-base
125 | gsettings-desktop-schemas
126 | gsfonts
127 | gtk-update-icon-cache
128 | gv
129 | gzip
130 | hdparm
131 | hicolor-icon-theme
132 | hostname
133 | htop
134 | humanity-icon-theme
135 | info
136 | init
137 | init-system-helpers
138 | initramfs-tools
139 | initramfs-tools-bin
140 | initramfs-tools-core
141 | install-info
142 | iproute2
143 | iptables
144 | iputils-ping
145 | iputils-tracepath
146 | irqbalance
147 | isc-dhcp-client
148 | isc-dhcp-common
149 | iso-codes
150 | javascript-common
151 | kbd
152 | keyboard-configuration
153 | klibc-utils
154 | kmod
155 | krb5-locales
156 | landscape-common
157 | language-selector-common
158 | latexmk
159 | less
160 | lib32asan4
161 | lib32atomic1
162 | lib32cilkrts5
163 | lib32gcc-7-dev
164 | lib32gcc1
165 | lib32gomp1
166 | lib32itm1
167 | lib32mpx2
168 | lib32quadmath0
169 | lib32stdc++6
170 | lib32ubsan0
171 | libaccountsservice0:amd64
172 | libacl1:amd64
173 | libapparmor1:amd64
174 | libapt-inst2.0:amd64
175 | libapt-pkg5.0:amd64
176 | libarchive13:amd64
177 | libargon2-0:amd64
178 | libasan4:amd64
179 | libasn1-8-heimdal:amd64
180 | libassuan0:amd64
181 | libasyncns0:amd64
182 | libatk-bridge2.0-0:amd64
183 | libatk1.0-0:amd64
184 | libatk1.0-data
185 | libatm1:amd64
186 | libatomic1:amd64
187 | libatspi2.0-0:amd64
188 | libattr1:amd64
189 | libaudit-common
190 | libaudit1:amd64
191 | libauthen-sasl-perl
192 | libavahi-client3:amd64
193 | libavahi-common-data:amd64
194 | libavahi-common3:amd64
195 | libbind9-160:amd64
196 | libbinutils:amd64
197 | libblkid1:amd64
198 | libbsd0:amd64
199 | libbz2-1.0:amd64
200 | libc-bin
201 | libc-dev-bin
202 | libc6:amd64
203 | libc6-dev:amd64
204 | libc6-dev-i386
205 | libc6-dev-x32
206 | libc6-i386
207 | libc6-x32
208 | libcairo-gobject2:amd64
209 | libcairo2:amd64
210 | libcap-ng0:amd64
211 | libcap2:amd64
212 | libcap2-bin
213 | libcc1-0:amd64
214 | libcilkrts5:amd64
215 | libcolord2:amd64
216 | libcom-err2:amd64
217 | libcroco3:amd64
218 | libcryptsetup12:amd64
219 | libcups2:amd64
220 | libcupsfilters1:amd64
221 | libcupsimage2:amd64
222 | libcurl3-gnutls:amd64
223 | libcurl4:amd64
224 | libdata-dump-perl
225 | libdatrie1:amd64
226 | libdb5.3:amd64
227 | libdbus-1-3:amd64
228 | libdconf1:amd64
229 | libdebconfclient0:amd64
230 | libdevmapper-event1.02.1:amd64
231 | libdevmapper1.02.1:amd64
232 | libdns-export1100
233 | libdns1100:amd64
234 | libdrm-amdgpu1:amd64
235 | libdrm-common
236 | libdrm-intel1:amd64
237 | libdrm-nouveau2:amd64
238 | libdrm-radeon1:amd64
239 | libdrm2:amd64
240 | libdumbnet1:amd64
241 | libeatmydata1:amd64
242 | libedit2:amd64
243 | libelf1:amd64
244 | libencode-locale-perl
245 | libepoxy0:amd64
246 | liberror-perl
247 | libestr0:amd64
248 | libevent-2.1-6:amd64
249 | libexpat1:amd64
250 | libext2fs2:amd64
251 | libfastjson4:amd64
252 | libfdisk1:amd64
253 | libffi6:amd64
254 | libfile-basedir-perl
255 | libfile-desktopentry-perl
256 | libfile-listing-perl
257 | libfile-mimeinfo-perl
258 | libflac8:amd64
259 | libfont-afm-perl
260 | libfontconfig1:amd64
261 | libfontenc1:amd64
262 | libfreetype6:amd64
263 | libfribidi0:amd64
264 | libfuse2:amd64
265 | libgcc-7-dev:amd64
266 | libgcc1:amd64
267 | libgcrypt20:amd64
268 | libgdbm-compat4:amd64
269 | libgdbm5:amd64
270 | libgdk-pixbuf2.0-0:amd64
271 | libgdk-pixbuf2.0-bin
272 | libgdk-pixbuf2.0-common
273 | libgeoip1:amd64
274 | libgirara-gtk3-3:amd64
275 | libgirepository-1.0-1:amd64
276 | libgl1:amd64
277 | libgl1-mesa-dri:amd64
278 | libgl1-mesa-glx:amd64
279 | libglapi-mesa:amd64
280 | libglib2.0-0:amd64
281 | libglib2.0-data
282 | libglvnd0:amd64
283 | libglx-mesa0:amd64
284 | libglx0:amd64
285 | libgmp10:amd64
286 | libgnutls30:amd64
287 | libgomp1:amd64
288 | libgpg-error0:amd64
289 | libgpm2:amd64
290 | libgraphite2-3:amd64
291 | libgs9:amd64
292 | libgs9-common
293 | libgssapi-krb5-2:amd64
294 | libgssapi3-heimdal:amd64
295 | libgtk-3-0:amd64
296 | libgtk-3-bin
297 | libgtk-3-common
298 | libharfbuzz-icu0:amd64
299 | libharfbuzz0b:amd64
300 | libhcrypto4-heimdal:amd64
301 | libheimbase1-heimdal:amd64
302 | libheimntlm0-heimdal:amd64
303 | libhogweed4:amd64
304 | libhtml-form-perl
305 | libhtml-format-perl
306 | libhtml-parser-perl
307 | libhtml-tagset-perl
308 | libhtml-tree-perl
309 | libhttp-cookies-perl
310 | libhttp-daemon-perl
311 | libhttp-date-perl
312 | libhttp-message-perl
313 | libhttp-negotiate-perl
314 | libhx509-5-heimdal:amd64
315 | libice6:amd64
316 | libicu60:amd64
317 | libidn11:amd64
318 | libidn2-0:amd64
319 | libijs-0.35:amd64
320 | libio-html-perl
321 | libio-socket-ssl-perl
322 | libip4tc0:amd64
323 | libip6tc0:amd64
324 | libipc-system-simple-perl
325 | libiptc0:amd64
326 | libirs160:amd64
327 | libisc-export169:amd64
328 | libisc169:amd64
329 | libisccc160:amd64
330 | libisccfg160:amd64
331 | libisl19:amd64
332 | libisns0:amd64
333 | libitm1:amd64
334 | libjbig0:amd64
335 | libjbig2dec0:amd64
336 | libjpeg-turbo8:amd64
337 | libjpeg8:amd64
338 | libjs-jquery
339 | libjson-c3:amd64
340 | libjson-glib-1.0-0:amd64
341 | libjson-glib-1.0-common
342 | libjsoncpp1:amd64
343 | libk5crypto3:amd64
344 | libkeyutils1:amd64
345 | libklibc
346 | libkmod2:amd64
347 | libkpathsea6:amd64
348 | libkrb5-26-heimdal:amd64
349 | libkrb5-3:amd64
350 | libkrb5support0:amd64
351 | libksba8:amd64
352 | liblcms2-2:amd64
353 | libldap-2.4-2:amd64
354 | libldap-common
355 | libllvm8:amd64
356 | liblocale-gettext-perl
357 | liblsan0:amd64
358 | liblvm2app2.2:amd64
359 | liblvm2cmd2.02:amd64
360 | liblwp-mediatypes-perl
361 | liblwp-protocol-https-perl
362 | liblwres160:amd64
363 | liblxc-common
364 | liblxc1
365 | liblz4-1:amd64
366 | liblzma5:amd64
367 | liblzo2-2:amd64
368 | libmagic-mgc
369 | libmagic1:amd64
370 | libmailtools-perl
371 | libmnl0:amd64
372 | libmount1:amd64
373 | libmpc3:amd64
374 | libmpdec2:amd64
375 | libmpfr6:amd64
376 | libmpx2:amd64
377 | libmspack0:amd64
378 | libncurses5:amd64
379 | libncursesw5:amd64
380 | libnet-dbus-perl
381 | libnet-http-perl
382 | libnet-smtp-ssl-perl
383 | libnet-ssleay-perl
384 | libnetfilter-conntrack3:amd64
385 | libnettle6:amd64
386 | libnewt0.52:amd64
387 | libnfnetlink0:amd64
388 | libnghttp2-14:amd64
389 | libnih1:amd64
390 | libnotify4:amd64
391 | libnpth0:amd64
392 | libnspr4:amd64
393 | libnss-systemd:amd64
394 | libnss3:amd64
395 | libntfs-3g88
396 | libnuma1:amd64
397 | libogg0:amd64
398 | libp11-kit0:amd64
399 | libpam-cap:amd64
400 | libpam-modules:amd64
401 | libpam-modules-bin
402 | libpam-runtime
403 | libpam-systemd:amd64
404 | libpam0g:amd64
405 | libpango-1.0-0:amd64
406 | libpangocairo-1.0-0:amd64
407 | libpangoft2-1.0-0:amd64
408 | libpaper-utils
409 | libpaper1:amd64
410 | libparted2:amd64
411 | libpcap0.8:amd64
412 | libpci3:amd64
413 | libpciaccess0:amd64
414 | libpcre3:amd64
415 | libperl5.26:amd64
416 | libpipeline1:amd64
417 | libpixman-1-0:amd64
418 | libplymouth4:amd64
419 | libpng16-16:amd64
420 | libpolkit-agent-1-0:amd64
421 | libpolkit-backend-1-0:amd64
422 | libpolkit-gobject-1-0:amd64
423 | libpoppler-glib8:amd64
424 | libpoppler73:amd64
425 | libpopt0:amd64
426 | libpotrace0
427 | libprocps6:amd64
428 | libproxy1v5:amd64
429 | libpsl5:amd64
430 | libptexenc1:amd64
431 | libpulse0:amd64
432 | libpulsedsp:amd64
433 | libpython-stdlib:amd64
434 | libpython2.7-minimal:amd64
435 | libpython2.7-stdlib:amd64
436 | libpython3-stdlib:amd64
437 | libpython3.6:amd64
438 | libpython3.6-minimal:amd64
439 | libpython3.6-stdlib:amd64
440 | libquadmath0:amd64
441 | libreadline5:amd64
442 | libreadline7:amd64
443 | librest-0.7-0:amd64
444 | librhash0:amd64
445 | libroken18-heimdal:amd64
446 | librsvg2-2:amd64
447 | librsvg2-common:amd64
448 | librtmp1:amd64
449 | libruby2.5:amd64
450 | libsasl2-2:amd64
451 | libsasl2-modules:amd64
452 | libsasl2-modules-db:amd64
453 | libseccomp2:amd64
454 | libselinux1:amd64
455 | libsemanage-common
456 | libsemanage1:amd64
457 | libsensors4:amd64
458 | libsepol1:amd64
459 | libsigsegv2:amd64
460 | libslang2:amd64
461 | libsm6:amd64
462 | libsmartcols1:amd64
463 | libsndfile1:amd64
464 | libsoup-gnome2.4-1:amd64
465 | libsoup2.4-1:amd64
466 | libsqlite3-0:amd64
467 | libss2:amd64
468 | libssl1.0.0:amd64
469 | libssl1.1:amd64
470 | libstdc++6:amd64
471 | libsynctex1:amd64
472 | libsystemd0:amd64
473 | libtasn1-6:amd64
474 | libtcl8.6:amd64
475 | libtexlua52:amd64
476 | libtexluajit2:amd64
477 | libtext-charwidth-perl
478 | libtext-iconv-perl
479 | libtext-wrapi18n-perl
480 | libthai-data
481 | libthai0:amd64
482 | libtie-ixhash-perl
483 | libtiff5:amd64
484 | libtimedate-perl
485 | libtinfo5:amd64
486 | libtk8.6:amd64
487 | libtry-tiny-perl
488 | libtsan0:amd64
489 | libubsan0:amd64
490 | libudev1:amd64
491 | libunistring2:amd64
492 | libunwind8:amd64
493 | liburi-perl
494 | libusb-1.0-0:amd64
495 | libutempter0:amd64
496 | libuuid1:amd64
497 | libuv1:amd64
498 | libvorbis0a:amd64
499 | libvorbisenc2:amd64
500 | libwayland-client0:amd64
501 | libwayland-cursor0:amd64
502 | libwayland-egl1:amd64
503 | libwind0-heimdal:amd64
504 | libwrap0:amd64
505 | libwww-perl
506 | libwww-robotrules-perl
507 | libx11-6:amd64
508 | libx11-data
509 | libx11-protocol-perl
510 | libx11-xcb1:amd64
511 | libx32asan4
512 | libx32atomic1
513 | libx32cilkrts5
514 | libx32gcc-7-dev
515 | libx32gcc1
516 | libx32gomp1
517 | libx32itm1
518 | libx32quadmath0
519 | libx32stdc++6
520 | libx32ubsan0
521 | libxau6:amd64
522 | libxaw7:amd64
523 | libxcb-dri2-0:amd64
524 | libxcb-dri3-0:amd64
525 | libxcb-glx0:amd64
526 | libxcb-present0:amd64
527 | libxcb-render0:amd64
528 | libxcb-shape0:amd64
529 | libxcb-shm0:amd64
530 | libxcb-sync1:amd64
531 | libxcb1:amd64
532 | libxcomposite1:amd64
533 | libxcursor1:amd64
534 | libxdamage1:amd64
535 | libxdmcp6:amd64
536 | libxext6:amd64
537 | libxfixes3:amd64
538 | libxft2:amd64
539 | libxi6:amd64
540 | libxinerama1:amd64
541 | libxkbcommon0:amd64
542 | libxml-parser-perl
543 | libxml-twig-perl
544 | libxml-xpathengine-perl
545 | libxml2:amd64
546 | libxmlsec1:amd64
547 | libxmlsec1-openssl:amd64
548 | libxmu6:amd64
549 | libxmuu1:amd64
550 | libxpm4:amd64
551 | libxrandr2:amd64
552 | libxrender1:amd64
553 | libxshmfence1:amd64
554 | libxslt1.1:amd64
555 | libxss1:amd64
556 | libxt6:amd64
557 | libxtables12:amd64
558 | libxtst6:amd64
559 | libxv1:amd64
560 | libxxf86dga1:amd64
561 | libxxf86vm1:amd64
562 | libyaml-0-2:amd64
563 | libzstd1:amd64
564 | libzzip-0-13:amd64
565 | linux-base
566 | linux-libc-dev:amd64
567 | lmodern
568 | locales
569 | login
570 | logrotate
571 | lsb-base
572 | lsb-release
573 | lshw
574 | lsof
575 | ltrace
576 | lvm2
577 | lxcfs
578 | lxd
579 | lxd-client
580 | make
581 | man-db
582 | manpages
583 | mawk
584 | mdadm
585 | mime-support
586 | mlocate
587 | mount
588 | mtr-tiny
589 | multiarch-support
590 | nano
591 | ncurses-base
592 | ncurses-bin
593 | ncurses-term
594 | net-tools
595 | netbase
596 | netcat-openbsd
597 | netplan.io
598 | networkd-dispatcher
599 | ninja-build
600 | notification-daemon
601 | nplan
602 | ntfs-3g
603 | open-iscsi
604 | open-vm-tools
605 | openssh-client
606 | openssh-server
607 | openssh-sftp-server
608 | openssl
609 | overlayroot
610 | parted
611 | passwd
612 | pastebinit
613 | patch
614 | pciutils
615 | perl
616 | perl-base
617 | perl-modules-5.26
618 | perl-openssl-defaults:amd64
619 | pinentry-curses
620 | plymouth
621 | plymouth-theme-ubuntu-text
622 | policykit-1
623 | pollinate
624 | poppler-data
625 | popularity-contest
626 | powermgmt-base
627 | preview-latex-style
628 | procps
629 | psmisc
630 | publicsuffix
631 | pulseaudio-utils
632 | python
633 | python-apt-common
634 | python-minimal
635 | python-pip-whl
636 | python2.7
637 | python2.7-minimal
638 | python3
639 | python3-apport
640 | python3-apt
641 | python3-asn1crypto
642 | python3-attr
643 | python3-automat
644 | python3-blinker
645 | python3-certifi
646 | python3-cffi-backend
647 | python3-chardet
648 | python3-click
649 | python3-colorama
650 | python3-commandnotfound
651 | python3-configobj
652 | python3-constantly
653 | python3-cryptography
654 | python3-dbus
655 | python3-debconf
656 | python3-debian
657 | python3-distro-info
658 | python3-distupgrade
659 | python3-distutils
660 | python3-gdbm:amd64
661 | python3-gi
662 | python3-httplib2
663 | python3-hyperlink
664 | python3-idna
665 | python3-incremental
666 | python3-jinja2
667 | python3-json-pointer
668 | python3-jsonpatch
669 | python3-jsonschema
670 | python3-jwt
671 | python3-lib2to3
672 | python3-markupsafe
673 | python3-minimal
674 | python3-netifaces
675 | python3-newt:amd64
676 | python3-oauthlib
677 | python3-openssl
678 | python3-pam
679 | python3-pip
680 | python3-pkg-resources
681 | python3-problem-report
682 | python3-pyasn1
683 | python3-pyasn1-modules
684 | python3-requests
685 | python3-requests-unixsocket
686 | python3-serial
687 | python3-service-identity
688 | python3-setuptools
689 | python3-six
690 | python3-software-properties
691 | python3-systemd
692 | python3-tk:amd64
693 | python3-twisted
694 | python3-twisted-bin:amd64
695 | python3-update-manager
696 | python3-urllib3
697 | python3-wheel
698 | python3-yaml
699 | python3-zope.interface
700 | python3.6
701 | python3.6-minimal
702 | rake
703 | readline-common
704 | rsync
705 | rsyslog
706 | ruby
707 | ruby-did-you-mean
708 | ruby-minitest
709 | ruby-net-telnet
710 | ruby-power-assert
711 | ruby-test-unit
712 | ruby2.5
713 | rubygems-integration
714 | run-one
715 | screen
716 | sed
717 | sensible-utils
718 | shared-mime-info
719 | snapd
720 | software-properties-common
721 | sosreport
722 | squashfs-tools
723 | ssh-import-id
724 | strace
725 | sudo
726 | systemd
727 | systemd-sysv
728 | sysvinit-utils
729 | t1utils
730 | tar
731 | tcl
732 | tcl8.6
733 | tcpdump
734 | telnet
735 | tex-common
736 | tex-gyre
737 | texlive-base
738 | texlive-binaries
739 | texlive-fonts-recommended
740 | texlive-latex-base
741 | texlive-latex-extra
742 | texlive-latex-recommended
743 | texlive-pictures
744 | texlive-plain-generic
745 | time
746 | tipa
747 | tk
748 | tk8.6
749 | tk8.6-blt2.5
750 | tmux
751 | tzdata
752 | ubuntu-advantage-tools
753 | ubuntu-keyring
754 | ubuntu-minimal
755 | ubuntu-mono
756 | ubuntu-release-upgrader-core
757 | ubuntu-server
758 | ubuntu-standard
759 | ubuntu-wsl
760 | ucf
761 | udev
762 | ufw
763 | uidmap
764 | unattended-upgrades
765 | unzip
766 | update-manager-core
767 | update-notifier-common
768 | ureadahead
769 | usbutils
770 | util-linux
771 | uuid-runtime
772 | vim
773 | vim-common
774 | vim-runtime
775 | vim-tiny
776 | wget
777 | whiptail
778 | wslu
779 | x11-common
780 | x11-utils
781 | x11-xserver-utils
782 | xauth
783 | xaw3dg:amd64
784 | xbitmaps
785 | xdelta3
786 | xdg-user-dirs
787 | xdg-utils
788 | xfsprogs
789 | xkb-data
790 | xterm
791 | xxd
792 | xz-utils
793 | xzdec
794 | zathura
795 | zathura-pdf-poppler
796 | zerofree
797 | zip
798 | zlib1g:amd64
799 |
--------------------------------------------------------------------------------
/app/subsys/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: Apache-2.0
2 |
3 | add_subdirectory_ifdef(CONFIG_BATTERY battery)
--------------------------------------------------------------------------------
/app/subsys/Kconfig:
--------------------------------------------------------------------------------
1 |
2 | rsource "battery/Kconfig"
3 |
--------------------------------------------------------------------------------
/app/subsys/battery/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | zephyr_library()
2 | zephyr_library_sources(battery.c)
3 |
--------------------------------------------------------------------------------
/app/subsys/battery/Kconfig:
--------------------------------------------------------------------------------
1 | config BATTERY
2 | bool "Battery measurement"
3 | select ADC
4 | select ADC_0
5 | #select CONFIG_NRFX_SAADC #if battery skips adc api
6 | help
7 | Enable battery measurement
8 |
9 | if BATTERY
10 |
11 | config BATTERY_SHELL
12 | bool "Shell commands"
13 | default y
14 | depends on SHELL
15 | help
16 | Enable shell commands for battery
17 |
18 | endif
19 |
--------------------------------------------------------------------------------
/app/subsys/battery/battery.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * SPDX-License-Identifier: Apache-2.0
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | LOG_MODULE_REGISTER(battery);
15 |
16 | #if !defined(CONFIG_BOARD_PINETIME)
17 | #error "Unsupported board."
18 | #endif
19 |
20 | #define USE_NRFX_SAADC 0
21 | #define RESOLUTION 12
22 |
23 | #define CHARGE_PIN 12
24 | #define EXT_POWER_PIN 19
25 | #define DIVIDER 2 /* On board resistor divider (full 2M, top 1M) */
26 |
27 |
28 | static struct device *adc;
29 | static struct device *gpio;
30 |
31 | #define CHANNEL_ID 1
32 | #define SAADC_OVERSAMPLE NRF_SAADC_OVERSAMPLE_8X
33 |
34 | /* Factors for selecting ADC settings:
35 | * - Max battery voltage: 4200mV
36 | * - After on board divider: 2100mV
37 | * - In order to fit below 600mV internal reference 1/4 gain must be applied.
38 | * - After 1/4 gain max voltage: 525mV (below reference)
39 | */
40 | static const struct adc_channel_cfg m_1st_channel_cfg = {
41 | .gain = ADC_GAIN_1_4,
42 | .reference = ADC_REF_INTERNAL,
43 | .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20),
44 | .channel_id = CHANNEL_ID,
45 | #if defined(CONFIG_ADC_CONFIGURABLE_INPUTS)
46 | .input_positive = NRF_SAADC_INPUT_AIN7,
47 | #endif
48 | };
49 |
50 | static struct k_sem sem;
51 | static bool charge_active;
52 | static bool ext_power_active;
53 | static battery_callback_t callback;
54 |
55 | struct battery_level_point {
56 | /** Remaining life at #lvl_mV. */
57 | uint16_t lvl_pptt;
58 |
59 | /** Battery voltage at #lvl_pptt remaining life. */
60 | uint16_t lvl_mV;
61 | };
62 |
63 | static const struct battery_level_point lipo[] = {
64 |
65 | /* "Curve" from https://forum.pine64.org/showthread.php?tid=8147
66 | */
67 |
68 | { 10000, 4200 },
69 | { 5000, 3660},
70 | { 2100, 3600 },
71 | { 1000, 3560},
72 | { 0, 3100 },
73 | };
74 |
75 | static void saadc_handler(nrfx_saadc_evt_t const * p_event)
76 | {
77 | if (p_event->type == NRFX_SAADC_EVT_DONE) {
78 | k_sem_give(&sem);
79 | }
80 | }
81 |
82 | static int init_nrfx_saadc(void)
83 | {
84 | #define OVERSAMPLE 0
85 | #define RESOLUTION_CFG \
86 | ((RESOLUTION == 12) ? NRF_SAADC_RESOLUTION_12BIT : \
87 | ((RESOLUTION == 10) ? NRF_SAADC_RESOLUTION_10BIT : \
88 | NRF_SAADC_RESOLUTION_14BIT))
89 | nrfx_err_t err;
90 |
91 | static const nrfx_saadc_channel_t channel = {
92 | .channel_config = {
93 | .resistor_p = NRF_SAADC_RESISTOR_DISABLED,
94 | .resistor_n = NRF_SAADC_RESISTOR_DISABLED,
95 | .gain = NRF_SAADC_GAIN1_6,
96 | .reference = NRF_SAADC_REFERENCE_VDD4,
97 | .acq_time = NRF_SAADC_ACQTIME_20US,
98 | .mode = NRF_SAADC_MODE_SINGLE_ENDED,
99 | .burst = OVERSAMPLE ? NRF_SAADC_BURST_ENABLED :
100 | NRF_SAADC_BURST_DISABLED
101 | },
102 | .pin_p = NRF_SAADC_INPUT_AIN7,
103 | .pin_n = NRF_SAADC_INPUT_DISABLED,
104 | .channel_index = 0
105 | };
106 |
107 | IRQ_CONNECT(DT_NORDIC_NRF_SAADC_ADC_0_IRQ_0,
108 | DT_NORDIC_NRF_SAADC_ADC_0_IRQ_0_PRIORITY,
109 | nrfx_isr, nrfx_saadc_irq_handler, 0);
110 |
111 | err = nrfx_saadc_init(5);
112 | if (err != NRFX_SUCCESS) {
113 | LOG_ERR("init failed %x", err);
114 | return -EIO;
115 | }
116 |
117 | err = nrfx_saadc_channels_config(&channel, 1);
118 | if (err != NRFX_SUCCESS) {
119 | LOG_ERR("channel config failed %x", err);
120 | return -EIO;
121 | }
122 |
123 | err = nrfx_saadc_simple_mode_set(BIT(0),
124 | RESOLUTION_CFG,
125 | OVERSAMPLE ? NRF_SAADC_OVERSAMPLE_8X :
126 | NRF_SAADC_OVERSAMPLE_DISABLED,
127 | saadc_handler);
128 | if (err != NRFX_SUCCESS) {
129 | LOG_ERR("mode set failed %x", err);
130 | return -EIO;
131 | }
132 |
133 |
134 | k_sem_init(&sem, 0, 1);
135 |
136 | return 0;
137 | }
138 |
139 | static void timeout_handler(struct k_timer *timer);
140 |
141 | K_TIMER_DEFINE(debounce_timer, timeout_handler, NULL);
142 |
143 | static void timeout_handler(struct k_timer *timer)
144 | {
145 | uint32_t ext_power_val;
146 | uint32_t charge_val;
147 | bool log_action;
148 |
149 | gpio_pin_read(gpio, CHARGE_PIN, &ext_power_val);
150 |
151 | if (ext_power_val) {
152 | log_action = true;
153 | ext_power_active = false;
154 | charge_active = false;
155 | if (callback) {
156 | callback(BATTERY_EVT_DISCONNECTED);
157 | }
158 | } else {
159 | log_action = !ext_power_active;
160 | ext_power_active = true;
161 | gpio_pin_read(gpio, CHARGE_PIN, &charge_val);
162 | charge_active = charge_val ? false : true;
163 |
164 | if (callback) {
165 | callback(charge_active ? BATTERY_EVT_CHARGING :
166 | BATTERY_EVT_NOT_CHARGING);
167 | }
168 | /* If power is connected use timer to periodically check if
169 | * charging is active.
170 | */
171 | k_timer_start(&debounce_timer, K_MSEC(50), 0);
172 | if (!log_action) {
173 | log_action = !charge_active;
174 | }
175 | }
176 |
177 | if (log_action) {
178 | LOG_INF("power pin change. Ext power %sconnected%s",
179 | ext_power_active ? "" : "not ",
180 | charge_active ? " (charging)" : "");
181 | }
182 | }
183 |
184 | bool battery_is_powered(void)
185 | {
186 | return ext_power_active;
187 | }
188 |
189 | bool battery_is_charging(void)
190 | {
191 | return charge_active;
192 | }
193 |
194 | static void pin_handler(struct device *gpiob, struct gpio_callback *cb,
195 | uint32_t pins)
196 | {
197 | static bool flop = true;
198 |
199 | gpio_pin_configure(gpio, EXT_POWER_PIN,
200 | GPIO_DIR_IN | GPIO_INT | GPIO_PUD_NORMAL |
201 | GPIO_INT_LEVEL |
202 | (flop ?
203 | GPIO_INT_ACTIVE_HIGH : GPIO_INT_ACTIVE_LOW));
204 | flop = !flop;
205 | k_timer_stop(&debounce_timer);
206 | k_timer_start(&debounce_timer, K_MSEC(2), 0);
207 |
208 | }
209 |
210 | static struct gpio_callback gpio_cb;
211 |
212 | static int charge_pins_init(void)
213 | {
214 | gpio = device_get_binding("GPIO_0");
215 | if (gpio == NULL) {
216 | return -ENODEV;
217 | }
218 |
219 | gpio_pin_configure(gpio, CHARGE_PIN,
220 | GPIO_DIR_IN | GPIO_PUD_NORMAL);
221 |
222 | gpio_pin_configure(gpio, EXT_POWER_PIN,
223 | GPIO_DIR_IN | GPIO_INT | GPIO_PUD_NORMAL |
224 | GPIO_INT_LEVEL | GPIO_INT_ACTIVE_LOW);
225 |
226 | gpio_init_callback(&gpio_cb, pin_handler, BIT(EXT_POWER_PIN));
227 |
228 | gpio_add_callback(gpio, &gpio_cb);
229 | gpio_pin_enable_callback(gpio, EXT_POWER_PIN);
230 |
231 | return 0;
232 | }
233 |
234 | static int adc_monitor_init(void)
235 | {
236 | if (USE_NRFX_SAADC) {
237 | return init_nrfx_saadc();
238 | }
239 |
240 | adc = device_get_binding(DT_ADC_0_NAME);
241 | if (adc == NULL) {
242 | return -ENODEV;
243 | }
244 |
245 | return adc_channel_setup(adc, &m_1st_channel_cfg);
246 | }
247 |
248 | int battery_init(battery_callback_t cb)
249 | {
250 | int err;
251 |
252 | err = adc_monitor_init();
253 | if (err < 0) {
254 | return err;
255 | }
256 |
257 | err = charge_pins_init();
258 | if (err < 0) {
259 | return err;
260 | }
261 |
262 | callback = cb;
263 |
264 | return 0;
265 | }
266 |
267 |
268 | int battery_read(int16_t *raw)
269 | {
270 | int16_t data[1];
271 | int err;
272 |
273 | const struct adc_sequence sequence = {
274 | .channels = BIT(CHANNEL_ID),
275 | .buffer = data,
276 | .buffer_size = sizeof(data),
277 | .resolution = RESOLUTION,
278 | };
279 |
280 | if (USE_NRFX_SAADC) {
281 | nrfx_saadc_buffer_set(raw, 1);
282 | nrfx_saadc_mode_trigger();
283 | return k_sem_take(&sem, K_MSEC(100));
284 | }
285 |
286 | err = adc_read(adc, &sequence);
287 | if (err < 0) {
288 | return err;
289 | }
290 |
291 | *raw = data[0];
292 |
293 | return 0;
294 | }
295 |
296 | int battery_raw_to_mv(int16_t raw)
297 | {
298 | return (DIVIDER*600*(((int)raw*4*1000) >> RESOLUTION))/1000;
299 | }
300 |
301 | /* converstion to pptt taken from
302 | * https://github.com/zephyrproject-rtos/zephyr/pull/21606
303 | */
304 | int battery_mv_to_ppt(int mv)
305 | {
306 | const struct battery_level_point *pb = lipo;
307 |
308 | if (mv >= pb->lvl_mV) {
309 | /* Measured voltage above highest point, cap at maximum. */
310 | return pb->lvl_pptt;
311 | }
312 | /* Go down to the last point at or below the measured voltage. */
313 | while ((pb->lvl_pptt > 0)
314 | && (mv < pb->lvl_mV)) {
315 | ++pb;
316 | }
317 | if (mv < pb->lvl_mV) {
318 | /* Below lowest point, cap at minimum */
319 | return pb->lvl_pptt;
320 | }
321 |
322 | /* Linear interpolation between below and above points. */
323 | const struct battery_level_point *pa = pb - 1;
324 |
325 | return pb->lvl_pptt
326 | + ((pa->lvl_pptt - pb->lvl_pptt)
327 | * (mv - pb->lvl_mV)
328 | / (pa->lvl_mV - pb->lvl_mV));
329 | }
330 |
331 | static int cmd_battery_status(const struct shell *shell,
332 | size_t argc, char **argv)
333 | {
334 | int err;
335 | int mv;
336 | int proc;
337 | int16_t raw;
338 |
339 | err = battery_read(&raw);
340 | if (err < 0) {
341 | shell_error(shell, "Failed to read");
342 | }
343 | mv = battery_raw_to_mv(raw);
344 | proc = battery_mv_to_ppt(mv);
345 | shell_print(shell, "Charger %sconnected%s",
346 | battery_is_powered() ? "" : "not ",
347 | battery_is_charging() ? " (charging)" : "");
348 | shell_print(shell, "raw:%d(0x%x) mV:%d level:%d.%02d%%",
349 | raw, raw, mv, proc/100, proc % 100);
350 |
351 | return 0;
352 | }
353 |
354 | SHELL_STATIC_SUBCMD_SET_CREATE(sub_battery,
355 | SHELL_CMD_ARG(status, NULL,
356 | "Status", cmd_battery_status, 1, 0),
357 | SHELL_SUBCMD_SET_END
358 | );
359 |
360 | SHELL_CMD_REGISTER(battery, &sub_battery, "Commands for battery monitor",
361 | NULL);
362 |
--------------------------------------------------------------------------------
/app/west.yml:
--------------------------------------------------------------------------------
1 | # The west manifest file for Hypnos.
2 | #
3 | # The per-installation west configuration file specifies the location of this
4 | # manifest file. The "path" option in the [manifest] section of .west/config
5 | # defines the folder that contains west.yml. The path is relative to the folder
6 | # that contains .west.
7 | #
8 | # You can create your own manifest files and put them in any
9 | # repository you want, to create your own custom Pinetime installation.
10 | # For example, you could create a manifest file in your own
11 | # out-of-tree application directory, which would pull the pinetime repository
12 | # in as an ordinary project.
13 | #
14 | # You can pass your manifest repositories to west init when creating a
15 | # new pinetime installation. See the west documentation for more
16 | # information.
17 |
18 | manifest:
19 | defaults:
20 | remote: app
21 |
22 | remotes:
23 | - name: app
24 | url-base: https://github.com/zephyrproject-rtos
25 |
26 | # External projects
27 | #
28 | projects:
29 | - name: cmsis
30 | path: modules/hal/cmsis
31 | revision: 542b2296e6d515b265e25c6b7208e8fea3014f90
32 | - name: hal_nordic
33 | path: modules/hal/nordic
34 | revision: d8a6ea9695ddf792bb18bb6035c13b1daac5d79c
35 | - name: lvgl
36 | path: modules/lib/gui/lvgl
37 | revision: 928b61c7c8ef5f770f10e6fd36d4fea0cf375b5e
38 | - name: littlefs
39 | path: modules/fs/littlefs
40 | revision: 9e4498d1c73009acd84bb36036ee5e2869112a6c
41 | - name: mcuboot
42 | revision: a5d79cf8ccb2c71e68ef32a71d6a2716e831d12e
43 | path: bootloader/mcuboot
44 | - name: mcumgr
45 | revision: 5051f9d900bbb194a23d4ce80f3c6dc6d6780cc2
46 | path: modules/lib/mcumgr
47 | - name: segger
48 | path: modules/debug/segger
49 | revision: 874d9e9696b00c09f9eeefe839028dc25fe44983
50 | - name: tinycbor
51 | path: modules/lib/tinycbor
52 | revision: 40daca97b478989884bffb5226e9ab73ca54b8c4
53 | - name: tinycrypt
54 | path: modules/crypto/tinycrypt
55 | revision: 3e9a49d2672ec01435ffbf0d788db6d95ef28de0
56 | - name: zephyr
57 | west-commands: scripts/west-commands.yml
58 | revision: v2.4.0
59 | self:
60 | path: app
61 |
--------------------------------------------------------------------------------
/app/zephyr/module.yml:
--------------------------------------------------------------------------------
1 | build:
2 | cmake: .
3 | kconfig: Kconfig.hypnos
4 |
--------------------------------------------------------------------------------