Compare commits
3 Commits
rei/develo
...
test-selfh
Author | SHA1 | Date |
---|---|---|
Jean-François Milants | 3cceccd7c5 | |
Jean-François Milants | 215c229c0e | |
Jean-François Milants | e77f3c9bdf |
|
@ -8,9 +8,9 @@ AlignConsecutiveDeclarations: false
|
|||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
|
@ -83,8 +83,6 @@ IndentGotoLabels: true
|
|||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
# Requires Clang >= 15, could also cause incorrect code formatting:
|
||||
# InsertBraces: true
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
Checks: '*,
|
||||
-altera-unroll-loops,
|
||||
-llvmlibc-callee-namespace,
|
||||
-llvmlibc-implementation-in-namespace,
|
||||
-llvmlibc-restrict-system-libc-headers,
|
||||
-llvm-header-guard,
|
||||
-llvm-namespace-comment,
|
||||
-google-build-using-namespace,
|
||||
-google-runtime-int,
|
||||
-google-readability-namespace-comments,
|
||||
-fuchsia-statically-constructed-objects,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"editor.formatOnSave": true,
|
||||
"clang-format.executable": "clang-format-12"
|
||||
"terminal.integrated.shell.linux": "/bin/bash"
|
||||
},
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
|
@ -35,4 +33,4 @@
|
|||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
// "remoteUser": "vscode"
|
||||
"remoteUser": "infinitime"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
|
@ -9,7 +10,6 @@ body:
|
|||
*Please, before opening a bug report, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Verification
|
||||
options:
|
||||
- label: I searched for similar bug reports and found none was relevant.
|
||||
required: true
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: PineTime community chat (Matrix)
|
||||
url: https://app.element.io/#/room/#pinetime:matrix.org
|
||||
about: Please ask questions about PineTime here.
|
||||
- name: PineTime developers chat (Matrix)
|
||||
url: https://app.element.io/#/room/#pinetime-dev:matrix.org
|
||||
about: Please ask questions about PineTime development here.
|
|
@ -1,5 +1,6 @@
|
|||
name: Feature Request
|
||||
description: File a feature request
|
||||
title: ""
|
||||
labels: ["feature request"]
|
||||
body:
|
||||
- type: markdown
|
||||
|
@ -9,7 +10,6 @@ body:
|
|||
*Please, before opening a feature request, check if similar issues already exist. In that case, use those issues to provide your feedback instead.*
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Verification
|
||||
options:
|
||||
- label: I searched for similar feature request and found none was relevant.
|
||||
required: true
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
name: Code formatting
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
paths:
|
||||
- '**.cpp'
|
||||
- '**.h'
|
||||
- '!src/libs/**'
|
||||
- '!src/FreeRTOS/**'
|
||||
|
||||
jobs:
|
||||
test-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1000
|
||||
|
||||
- name: Configure git
|
||||
run: |
|
||||
git fetch origin "$GITHUB_BASE_REF":"$GITHUB_BASE_REF" --depth=1000
|
||||
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install clang-format-12
|
||||
|
||||
- name: Check formatting
|
||||
run: tests/test-format.sh
|
||||
|
||||
- name: Upload patches
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: Patches
|
||||
path: ./*.patch
|
|
@ -1,66 +0,0 @@
|
|||
# GitHub Actions Workflow to build Simulator for PineTime Smart Watch LVGL Interface
|
||||
|
||||
name: Build PineTime LVGL Simulator
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
#########################################################################################
|
||||
# Download and Install Dependencies
|
||||
|
||||
- name: Install cmake
|
||||
uses: lukka/get-cmake@v3.18.3
|
||||
|
||||
- name: Install SDL2 development package
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install libsdl2-dev
|
||||
|
||||
- name: Install lv_font_conv
|
||||
run:
|
||||
npm i -g lv_font_conv@1.5.2
|
||||
|
||||
#########################################################################################
|
||||
# Checkout
|
||||
|
||||
- name: Checkout source files
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
#########################################################################################
|
||||
# get InfiniSim repo
|
||||
|
||||
- name: Get InfiniSim repo
|
||||
run: |
|
||||
git clone https://github.com/InfiniTimeOrg/InfiniSim.git --depth 1 --branch main
|
||||
git -C InfiniSim submodule update --init lv_drivers libpng
|
||||
|
||||
#########################################################################################
|
||||
# CMake
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -G Ninja -S InfiniSim -B build_lv_sim -DInfiniTime_DIR="${PWD}"
|
||||
|
||||
#########################################################################################
|
||||
# Build and Upload simulator
|
||||
|
||||
- name: Build simulator executable
|
||||
run: |
|
||||
cmake --build build_lv_sim
|
||||
|
||||
- name: Upload simulator executable
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: infinisim-${{ github.head_ref }}
|
||||
path: build_lv_sim/infinisim
|
|
@ -3,45 +3,163 @@
|
|||
# Based on https://github.com/JF002/InfiniTime/blob/master/doc/buildAndProgram.md
|
||||
# and https://github.com/JF002/InfiniTime/blob/master/bootloader/README.md
|
||||
|
||||
# Name of this Workflow
|
||||
name: Build PineTime Firmware
|
||||
|
||||
# When to run this Workflow...
|
||||
on:
|
||||
|
||||
# Run this Workflow when files are updated (Pushed) in the "master" and "develop" Branch
|
||||
push:
|
||||
branches: [ master, develop ]
|
||||
|
||||
# Also run this Workflow when a Pull Request is created or updated in the "master" and "develop" Branch
|
||||
pull_request:
|
||||
branches: [ master, develop ]
|
||||
|
||||
# Steps to run for the Workflow
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: infinitime/infinitime-build
|
||||
|
||||
# Run these steps on Ubuntu
|
||||
runs-on: self-hosted
|
||||
|
||||
steps:
|
||||
# This workaround fixes the error "unsafe repository (REPO is owned by someone else)".
|
||||
# See https://github.com/actions/checkout/issues/760 and https://github.com/actions/checkout/issues/766
|
||||
# The fix in "actions/checkout@v2" was not sufficient as the build process also uses git (to get the current
|
||||
# commit hash, for example).
|
||||
- name: Workaround permission issues
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
#########################################################################################
|
||||
# Download and Cache Dependencies
|
||||
|
||||
#- name: Install cmake
|
||||
# uses: lukka/get-cmake@v3.18.3
|
||||
|
||||
#- name: Check cache for Embedded Arm Toolchain arm-none-eabi-gcc
|
||||
# id: cache-toolchain
|
||||
# uses: actions/cache@v2
|
||||
# env:
|
||||
# cache-name: cache-toolchain-9-2020-q2
|
||||
# with:
|
||||
# path: ${{ runner.temp }}/arm-none-eabi
|
||||
# key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
# restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
|
||||
#- name: Install Embedded Arm Toolchain arm-none-eabi-gcc
|
||||
# if: steps.cache-toolchain.outputs.cache-hit != 'true' # Install toolchain if not found in cache
|
||||
# uses: fiam/arm-none-eabi-gcc@v1.0.4
|
||||
# with:
|
||||
# # GNU Embedded Toolchain for Arm release name, in the V-YYYY-qZ format (e.g. "9-2019-q4")
|
||||
# release: 9-2020-q2
|
||||
# # Directory to unpack GCC to. Defaults to a temporary directory.
|
||||
# directory: ${{ runner.temp }}/arm-none-eabi
|
||||
|
||||
- name: Check cache for nRF5 SDK
|
||||
id: cache-nrf5sdk
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-nrf5sdk
|
||||
with:
|
||||
path: ${{ runner.temp }}/nrf5_sdk
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
|
||||
- name: Install nRF5 SDK
|
||||
if: steps.cache-nrf5sdk.outputs.cache-hit != 'true' # Install SDK if not found in cache
|
||||
run: |
|
||||
cd ${{ runner.temp }}
|
||||
curl https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip -o nrf5_sdk.zip
|
||||
unzip nrf5_sdk.zip
|
||||
mv nRF5_SDK_15.3.0_59ac345 nrf5_sdk
|
||||
|
||||
- name: Check cache for MCUBoot
|
||||
id: cache-mcuboot
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-mcuboot
|
||||
with:
|
||||
path: ${{ runner.temp }}/mcuboot
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}
|
||||
|
||||
- name: Install MCUBoot
|
||||
if: steps.cache-mcuboot.outputs.cache-hit != 'true' # Install MCUBoot if not found in cache
|
||||
run: |
|
||||
cd ${{ runner.temp }}
|
||||
git clone --branch v1.7.2 https://github.com/mcu-tools/mcuboot
|
||||
|
||||
- name: Install imgtool dependencies
|
||||
run: |
|
||||
pip3 install --user -r ${{ runner.temp }}/mcuboot/scripts/requirements.txt
|
||||
|
||||
- name: Install adafruit-nrfutil
|
||||
run: |
|
||||
pip3 install --user wheel
|
||||
pip3 install --user setuptools
|
||||
pip3 install --user adafruit-nrfutil
|
||||
|
||||
#########################################################################################
|
||||
# Checkout
|
||||
|
||||
- name: Checkout source files
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build
|
||||
shell: bash
|
||||
env:
|
||||
SOURCES_DIR: .
|
||||
run: /opt/build.sh all
|
||||
# Unzip the package because Upload Artifact will zip up the files
|
||||
|
||||
- name: Show files
|
||||
run: set ; pwd ; ls -l
|
||||
|
||||
#########################################################################################
|
||||
# CMake
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=/home/alarm/nrf52/gcc-arm-none-eabi-9-2020-q2-update/ -DNRF5_SDK_PATH=${{ runner.temp }}/nrf5_sdk -DUSE_OPENOCD=1 -DBUILD_DFU=1 ../
|
||||
|
||||
#########################################################################################
|
||||
# Make and Upload DFU Package
|
||||
# pinetime-mcuboot-app.img must be flashed at address 0x8000 in the internal flash memory with OpenOCD:
|
||||
# program image.bin 0x8000
|
||||
|
||||
# For Debugging Builds: Remove "make" option "-j" for clearer output. Add "--trace" to see details.
|
||||
# For Faster Builds: Add "make" option "-j"
|
||||
|
||||
- name: Make pinetime-mcuboot-app
|
||||
run: |
|
||||
cd build
|
||||
make pinetime-mcuboot-app
|
||||
|
||||
- name: Unzip DFU package
|
||||
run: unzip ./build/output/pinetime-mcuboot-app-dfu-*.zip -d ./build/output/pinetime-mcuboot-app-dfu
|
||||
- name: Upload DFU artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
run: |
|
||||
# Unzip the package because Upload Artifact will zip up the files
|
||||
unzip build/src/pinetime-mcuboot-app-dfu*.zip -d build/src/pinetime-mcuboot-app-dfu
|
||||
|
||||
- name: Upload DFU package
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: InfiniTime DFU ${{ github.head_ref }}
|
||||
path: ./build/output/pinetime-mcuboot-app-dfu/*
|
||||
- name: Upload MCUBoot image artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
name: pinetime-mcuboot-app-dfu
|
||||
path: build/src/pinetime-mcuboot-app-dfu/*
|
||||
|
||||
#########################################################################################
|
||||
# Make and Upload Standalone Firmware
|
||||
|
||||
- name: Make pinetime-app
|
||||
run: |
|
||||
cd build
|
||||
make pinetime-app
|
||||
|
||||
- name: Upload standalone firmware
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: InfiniTime MCUBoot image ${{ github.head_ref }}
|
||||
path: ./build/output/pinetime-mcuboot-app-image-*.bin
|
||||
name: pinetime-app.out
|
||||
path: build/src/pinetime-app*.out
|
||||
|
||||
#########################################################################################
|
||||
# Finish
|
||||
|
||||
- name: Find output
|
||||
run: |
|
||||
find . -name "pinetime-app.*" -ls
|
||||
find . -name "pinetime-mcuboot-app.*" -ls
|
||||
|
||||
# Embedded Arm Toolchain and nRF5 SDK will only be cached if the build succeeds.
|
||||
# So make sure that the first build always succeeds, e.g. comment out the "Make" step.
|
||||
|
|
|
@ -43,7 +43,3 @@ Testing/Temporary/
|
|||
#VSCODE
|
||||
.vscode/.cortex-debug.registers.state.json
|
||||
.vscode/.cortex-debug.peripherals.state.json
|
||||
|
||||
#build files
|
||||
src/nRF5_SDK_15.3.0_59ac345
|
||||
src/arm-none-eabi
|
||||
|
|
|
@ -4,6 +4,3 @@
|
|||
[submodule "src/libs/littlefs"]
|
||||
path = src/libs/littlefs
|
||||
url = https://github.com/littlefs-project/littlefs.git
|
||||
[submodule "src/libs/QCBOR"]
|
||||
path = src/libs/QCBOR
|
||||
url = https://github.com/laurencelundblade/QCBOR.git
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
"servertype": "openocd",
|
||||
"runToMain": true,
|
||||
// Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb)
|
||||
"armToolchainPath": "${workspaceRoot}/../gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin",
|
||||
"armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-9-2020-q2-update/bin",
|
||||
"svdFile": "${workspaceRoot}/nrf52.svd",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(pinetime VERSION 1.9.0 LANGUAGES C CXX ASM)
|
||||
project(pinetime VERSION 1.6.0 LANGUAGES C CXX ASM)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
@ -66,7 +66,7 @@ execute_process(COMMAND git rev-parse --short HEAD
|
|||
OUTPUT_VARIABLE PROJECT_GIT_COMMIT_HASH
|
||||
RESULT_VARIABLE PROJECT_GIT_COMMIT_HASH_SUCCESS)
|
||||
|
||||
string(STRIP "${PROJECT_GIT_COMMIT_HASH}" PROJECT_GIT_COMMIT_HASH)
|
||||
string(STRIP ${PROJECT_GIT_COMMIT_HASH} PROJECT_GIT_COMMIT_HASH)
|
||||
|
||||
message("PROJECT_GIT_COMMIT_HASH_SUCCESS? " ${PROJECT_GIT_COMMIT_HASH_SUCCESS})
|
||||
|
||||
|
@ -100,7 +100,7 @@ else()
|
|||
endif()
|
||||
|
||||
set(VERSION_EDIT_WARNING "// Do not edit this file, it is automatically generated by CMAKE!")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/Version.h)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docker/post_build.sh.in ${CMAKE_CURRENT_BINARY_DIR}/post_build.sh)
|
||||
|
||||
|
||||
|
|
118
README.md
|
@ -1,38 +1,81 @@
|
|||
# [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)
|
||||
# InfiniTime
|
||||
|
||||
[![Build PineTime Firmware](https://github.com/InfiniTimeOrg/InfiniTime/workflows/Build%20PineTime%20Firmware/badge.svg?branch=master)](https://github.com/InfiniTimeOrg/InfiniTime/actions)
|
||||
|
||||
![InfiniTime logo](images/infinitime-logo-small.jpg "InfiniTime Logo")
|
||||
![InfiniTime logo](images/infinitime-logo.jpg "InfiniTime Logo")
|
||||
|
||||
Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++.
|
||||
The goal of this project is to design an open-source firmware for the [Pinetime smartwatch](https://www.pine64.org/pinetime/) :
|
||||
|
||||
- Code written in **modern C++**;
|
||||
- Build system based on **CMake**;
|
||||
- Based on **[FreeRTOS 10.0.0](https://freertos.org)** real-time OS.
|
||||
- Using **[LittleVGL/LVGL 7](https://lvgl.io/)** as UI library...
|
||||
- ... and **[NimBLE 1.3.0](https://github.com/apache/mynewt-nimble)** as BLE stack.
|
||||
|
||||
## New to InfiniTime?
|
||||
|
||||
- [Getting started with InfiniTime](doc/gettingStarted/gettingStarted-1.0.md)
|
||||
- [Updating the software](doc/gettingStarted/updating-software.md)
|
||||
- [About the firmware and bootloader](doc/gettingStarted/about-software.md)
|
||||
### Companion apps
|
||||
- [Gadgetbridge](https://gadgetbridge.org/) (Android)
|
||||
- [AmazFish](https://openrepos.net/content/piggz/amazfish/) (SailfishOS)
|
||||
- [Siglo](https://github.com/alexr4535/siglo) (Linux)
|
||||
- [InfiniLink](https://github.com/InfiniTimeOrg/InfiniLink) **[Experimental]** **[Unmaintained, looking for developers/maintainers]** (iOS)
|
||||
- [ITD](https://gitea.arsenm.dev/Arsen6331/itd) (Linux)
|
||||
- [Getting started with InfiniTime 1.0 (quick user guide, update bootloader and InfiniTime,...)](doc/gettingStarted/gettingStarted-1.0.md)
|
||||
- [Flash, upgrade (OTA), time synchronization,...](doc/gettingStarted/ota-gadgetbridge-nrfconnect.md)
|
||||
|
||||
## Development
|
||||
## Overview
|
||||
|
||||
![Pinetime screens](images/1.0.0/collage.png "PinetimeScreens")
|
||||
|
||||
As of now, here is the list of achievements of this project:
|
||||
|
||||
- Fast and optimized LCD driver
|
||||
- BLE communication
|
||||
- Rich user interface via display, touchscreen and pushbutton
|
||||
- Time synchronization via BLE
|
||||
- Notification via BLE
|
||||
- Heart rate measurements
|
||||
- Step counting
|
||||
- Wake-up on wrist rotation
|
||||
- Quick actions
|
||||
* Disable vibration on notification
|
||||
* Brightness settings
|
||||
* Flashlight
|
||||
* Settings
|
||||
- 3 watch faces:
|
||||
* Digital
|
||||
* Analog
|
||||
* [PineTimeStyle](https://wiki.pine64.org/wiki/PineTimeStyle)
|
||||
- Multiple 'apps' :
|
||||
* Music (control the playback of music on your phone)
|
||||
* Heart rate (measure your heart rate)
|
||||
* Navigation (displays navigation instructions coming from the companion app)
|
||||
* Notification (displays the last notification received)
|
||||
* Paddle (single player pong-like game)
|
||||
* Twos (2048 clone game)
|
||||
* Stopwatch
|
||||
* Steps (displays the number of steps taken)
|
||||
* Timer (set a countdown timer that will notify you when it expires)
|
||||
* Metronome (vibrates to a given bpm with a customizable beats per bar)
|
||||
- User settings:
|
||||
* Display timeout
|
||||
* Wake-up condition
|
||||
* Time format (12/24h)
|
||||
* Default watch face
|
||||
* Daily step goal
|
||||
* Battery status
|
||||
* Firmware validation
|
||||
* System information
|
||||
- Supported by 3 companion apps (development is in progress):
|
||||
* [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) (on Android via F-Droid)
|
||||
* [Amazfish](https://openrepos.net/content/piggz/amazfish) (on SailfishOS and Linux)
|
||||
* [Siglo](https://github.com/alexr4535/siglo) (on Linux)
|
||||
* **[Experimental]** [WebBLEWatch](https://hubmartin.github.io/WebBLEWatch/) Synchronize time directly from your web browser. [video](https://youtu.be/IakiuhVDdrY)
|
||||
* **[Experimental]** [Infini-iOS](https://github.com/xan-m/Infini-iOS) (on iOS)
|
||||
- OTA (Over-the-air) update via BLE
|
||||
- [Bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader) based on [MCUBoot](https://www.mcuboot.com)
|
||||
|
||||
## Documentation
|
||||
|
||||
### Develop
|
||||
- [Rough structure of the code](doc/code/Intro.md)
|
||||
- [How to implement an application](doc/code/Apps.md)
|
||||
- [Generate the fonts and symbols](src/displayapp/fonts/README.md)
|
||||
- [Creating a stopwatch in Pinetime(article)](https://pankajraghav.com/2021/04/03/PINETIME-STOPCLOCK.html)
|
||||
- [Tips on designing an app UI](doc/ui_guidelines.md)
|
||||
|
||||
### InfiniSim Simulator
|
||||
Use the [InfiniSim Simulator](https://github.com/InfiniTimeOrg/InfiniSim) to experience the `InfiniTime` user interface directly on your PC, to shorten the time until you get your hands on a real [PineTime smartwatch](https://www.pine64.org/pinetime/).
|
||||
Or use it to develop new Watchfaces, new Screens, or quickly iterate on the user interface.
|
||||
|
||||
### Contributing
|
||||
- [How to contribute?](/doc/contribute.md)
|
||||
- [Coding conventions](/doc/coding-convention.md)
|
||||
|
||||
### Build, flash and debug
|
||||
|
||||
|
@ -41,11 +84,16 @@ Or use it to develop new Watchfaces, new Screens, or quickly iterate on the user
|
|||
- [Files included in the release notes](doc/filesInReleaseNotes.md)
|
||||
- [Build the project](doc/buildAndProgram.md)
|
||||
- [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md)
|
||||
- [Flash the firmware using SWD interface](doc/SWD.md)
|
||||
- [Build the project with Docker](doc/buildWithDocker.md)
|
||||
- [Build the project with VSCode](doc/buildWithVScode.md)
|
||||
- [Bootloader, OTA and DFU](./bootloader/README.md)
|
||||
- [Stub using NRF52-DK](./doc/PinetimeStubWithNrf52DK.md)
|
||||
- Logging with JLink RTT.
|
||||
- Using files from the releases
|
||||
|
||||
### Contribute
|
||||
|
||||
- [How to contribute ?](doc/contribute.md)
|
||||
|
||||
### API
|
||||
|
||||
|
@ -55,6 +103,30 @@ Or use it to develop new Watchfaces, new Screens, or quickly iterate on the user
|
|||
|
||||
- [Memory analysis](./doc/MemoryAnalysis.md)
|
||||
|
||||
### Using the firmware
|
||||
|
||||
- [Integration with Gadgetbridge](doc/companionapps/Gadgetbridge.md)
|
||||
- [Integration with AmazFish](doc/companionapps/Amazfish.md)
|
||||
- [Firmware update, OTA](doc/companionapps/NrfconnectOTA.md)
|
||||
|
||||
## TODO - contribute
|
||||
|
||||
This project is far from being finished, and there are still a lot of things to do for this project to become a firmware usable by the general public.
|
||||
|
||||
Here a quick list out of my head of things to do for this project:
|
||||
|
||||
- Improve BLE communication stability and reliability
|
||||
- Improve OTA and MCUBoot bootloader
|
||||
- Add more functionalities : Alarm, chronometer, configuration, activities, heart rate logging, games,...
|
||||
- Add more BLE functionalities : call notifications, agenda, configuration, data logging,...
|
||||
- Measure power consumption and improve battery life
|
||||
- Improve documentation, take better pictures and video than mine
|
||||
- Improve the UI
|
||||
- Create companion app for multiple OSes (Linux, Android, iOS) and platforms (desktop, ARM, mobile). Do not forget the other devices from Pine64 like [the Pinephone](https://www.pine64.org/pinephone/) and the [Pinebook Pro](https://www.pine64.org/pinebook-pro/).
|
||||
- Design a simple CI (preferably self-hosted and easy to reproduce).
|
||||
|
||||
Do not hesitate to clone/fork the code, hack it and create pull-requests. I'll do my best to review and merge them :)
|
||||
|
||||
## Licenses
|
||||
|
||||
This project is released under the GNU General Public License version 3 or, at your option, any later version.
|
||||
|
|
|
@ -9,14 +9,14 @@ Integrating a BLE stack for the OTA functionality would have used to much memory
|
|||
|
||||
When it is run, this bootloader looks in the SPI flash memory if a new firmware is available. It there is one, it *swaps* the current firmware with the new one (the new one is copied in the main flash memory, and the current one is copied in the SPI flash memory) and run the new one. If the new one fails to run properly, the bootloader is able to revert to the old one and mark the new one as not working.
|
||||
|
||||
As this bootloader does not provide any OTA capability, it is not able to actually download a new version of the application. Providing OTA functionality is thus the responsibility of the application firmware.
|
||||
As this bootloader does not provide any OTA capability, it is not able to actually download a new version of the application. Providing OTA functionality is thus the responsability of the application firmware.
|
||||
|
||||
# About MCUBoot
|
||||
MCUBoot is run at boot time. In normal operation, it just jumps to the reset handler of the application firmware to run it. Once the application firmware is running, MCUBoot does not run at all.
|
||||
|
||||
![MCUBoot boot sequence diagram](../doc/bootloader/boot.png "MCUBoot boot sequence diagram")
|
||||
|
||||
But MCUBoot does much more than that : it can upgrade the firmware that is currently running by a new one, and it is also able to revert to the previous version of the firmware in case the new one does not run properly.
|
||||
But MCUBoot does much more than that : it can upgrade the firmware that is currently running by a new one, and it is also able to revert to the previous version of the firmware in case the new one does not run propertly.
|
||||
|
||||
To do this, it uses 2 memory 'slots' :
|
||||
- **The primary slot** : it contains the current firmware, the one that will be executed by MCUBoot
|
||||
|
@ -40,7 +40,7 @@ This chapter describes degraded cases that are handled by our bootloader and tho
|
|||
Case | Current bootloader | Solution
|
||||
-----|--------------------|----------------------------------------------
|
||||
Data got corrupted during file transfer | [OK] Application firmware does a CRC check before applying the update, and does not proceed if it fails. | N/A
|
||||
New firmware does not run at all (bad file) (1) | [NOK] MCU executes unknown instructions and will most likely end up in an infinite loop or freeze in an error handler. The bootloader does not run, it can do nothing, the MCU is stuck until next reset | [OK] The bootloader starts the watchdog just before running the new firmware. This way, the watchdog will reset the MCU after ~7s because the firmware does not refresh it. Bootloader reverts to the previous version of the firmware during the reset.
|
||||
New firmware does not run at all (bad file) (1) | [NOK] MCU executes unknown instructions and will most likely end up in an infinite loop or freeze in an error handler. The bootloader does not run, it can do nothing, the MCU is stucked until next reset | [OK] The bootloader starts the watchdog just before running the new firmware. This way, the watchdog will reset the MCU after ~7s because the firmware does not refresh it. Bootloader reverts to the previous version of the firmware during the reset.
|
||||
New firmware runs, does not set the valid bit and does not refresh the watchdog | [NOK] The new firmware runs until the next reset. The bootloader will be able to revert to the previous firmware only during the next reset. If the new firmware does not run properly and does not reset, the bootloader can do nothing until the next reset | [OK] The bootloader starts the watchdog just before running the new firmware. This way, the watchdog will reset the MCU after ~7s because the firmware does not refresh it. Bootloader reverts to the previous version of the firmware during the reset.
|
||||
New firmware does not run properly, does not set the valid bit but refreshes the watchdog | [NOK] The bootloader will be able to revert to the previous firmware only during the next reset. If the new firmware does not run properly and does not reset, the bootloader can do nothing until the next reset | [~] Wait for the battery to drain. The CPU will reset the next time the device is charged and will be able to rollback to the previous version.
|
||||
New firmware does not run properly but sets the valid bit and refreshes the watchdog | [NOK] The bootloader won't revert to the previous version because the valid flag is set | [~] Wait for the battery to drain. The CPU will reset the next time the device is charged. Then, the bootloader must provide a way for the user to force the rollback to the previous version
|
||||
|
@ -115,6 +115,8 @@ sudo dfu.py -z /home/jf/nrf52/bootloader/dfu.zip -a <pinetime MAC address> --leg
|
|||
|
||||
**Note** : dfu.py is a slightly modified version of [this repo](https://github.com/daniel-thompson/ota-dfu-python).
|
||||
|
||||
See [this page](../doc/CompanionApps/NrfconnectOTA.md) for more info about OTA with NRFConect
|
||||
|
||||
### Firmware validation
|
||||
Once the OTA is done, InfiniTime will reset the watch to apply the update. When the watch reboots, the new firmware is running.
|
||||
|
||||
|
@ -124,12 +126,12 @@ If the new firmware is working correctly, open the application menu and tap on t
|
|||
|
||||
Firmware validation application in the menu:
|
||||
|
||||
![Firmware Validation App](../doc/bootloader/firmwareValidationApp.jpg "Firmware Validation App")
|
||||
![Firmware Validation App](../doc/CompanionApps/firmwareValidationApp.jpg "Firmware Validation App")
|
||||
|
||||
The firmware is not validated yet. Tap 'Validate' to validate it, or 'Reset' to rollback to the previous version.
|
||||
|
||||
![Firmware Not Validated](../doc/bootloader/firmwareNoValidated.jpg "Firmware Not Validated")
|
||||
![Firmware Not Validated](../doc/CompanionApps/firmwareNoValidated.jpg "Firmware Not Validated")
|
||||
|
||||
The firmware is validated!
|
||||
|
||||
![Firmware Validated](../doc/bootloader/firmwareValidated.jpg "Firmware Validated")
|
||||
![Firmware Validated](../doc/CompanionApps/firmwareValidated.jpg "Firmware Validated")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
__pycache__
|
|
@ -236,7 +236,7 @@ class BleDfuControllerSecure(NrfBleDfuController):
|
|||
self._dfu_send_command(Procedures.EXECUTE)
|
||||
self._wait_and_parse_notify()
|
||||
|
||||
print("Init packet successfully transferred")
|
||||
print("Init packet successfully transfered")
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Send the Firmware image to peripheral device.
|
||||
|
@ -319,5 +319,5 @@ class BleDfuControllerSecure(NrfBleDfuController):
|
|||
self._dfu_send_command(Procedures.EXECUTE)
|
||||
self._wait_and_parse_notify()
|
||||
|
||||
# If everything executed correctly, return amount of bytes transferred
|
||||
# If everything executed correctly, return amount of bytes transfered
|
||||
return obj_max_size
|
||||
|
|
|
@ -106,6 +106,7 @@ macro(nRF5x_setup)
|
|||
${NRF5_SDK_PATH}/external/freertos/source/stream_buffer.c
|
||||
${NRF5_SDK_PATH}/external/freertos/source/tasks.c
|
||||
${NRF5_SDK_PATH}/external/freertos/source/timers.c
|
||||
${NRF5_SDK_PATH}/components/libraries/timer/app_timer_freertos.c
|
||||
)
|
||||
|
||||
# freertos include
|
||||
|
@ -334,6 +335,7 @@ endmacro(nRF5x_addAppFIFO)
|
|||
# adds app-level Timer libraries
|
||||
macro(nRF5x_addAppTimer)
|
||||
list(APPEND SDK_SOURCE_FILES
|
||||
"${NRF5_SDK_PATH}/components/libraries/timer/app_timer.c"
|
||||
)
|
||||
endmacro(nRF5x_addAppTimer)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ Cmake script for projects targeting Nordic Semiconductor nRF5x series devices us
|
|||
The script makes use of the following tools:
|
||||
|
||||
- nRF5x SDK by Nordic Semiconductor - SoC specific drivers and libraries (also includes a lot of examples)
|
||||
- JLink by Segger - interface software for the JLink family of programmers
|
||||
- JLink by Segger - interface software for the JLink familiy of programmers
|
||||
- nrfjprog by Nordic Semiconductor - Wrapper utility around JLink
|
||||
- arm-non-eabi-gcc by ARM and the GCC Team - compiler toolchain for embedded (= bare metal) ARM chips
|
||||
|
||||
|
@ -15,11 +15,11 @@ The script makes use of the following tools:
|
|||
|
||||
1. Download this repo (or add as submodule) to the directory `cmake-nRF5x` in your project
|
||||
|
||||
1. Search the SDK `example` directory for a `sdk_config.h`, `main.c` and a linker script (normally named `<project_name>_gcc_<chip family>.ld`) that fits your chip and project needs.
|
||||
1. Search the SDK `example` directory for a `sdk_config.h`, `main.c` and a linker script (normally named `<project_name>_gcc_<chip familly>.ld`) that fits your chip and project needs.
|
||||
|
||||
1. Copy the `sdk_config.h` and the project `main.c` into a new directory `src`. Modify them as required for your project.
|
||||
|
||||
1. Copy the linker script into the root of your project. Rename it to just `gcc_<chip family>.ld` For example:
|
||||
1. Copy the linker script into the root of your project. Rename it to just `gcc_<chip familly>.ld` For example:
|
||||
|
||||
```
|
||||
gcc_nrf51.ld
|
||||
|
|
167
doc/BLEFS.md
|
@ -1,167 +0,0 @@
|
|||
# BLE FS
|
||||
---
|
||||
|
||||
The BLE FS protocol in InfiniTime is mostly Adafruit's BLE file transfer protocol, as described in [adafruit/Adafruit_CircuitPython_BLE_File_Transfer](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer). There are some deviations, such as the status codes. These will be described later in the document.
|
||||
|
||||
---
|
||||
|
||||
## UUIDs
|
||||
|
||||
There are two relevant UUIDs in this protocol: the version characteristic, and the raw transfer characteristic.
|
||||
|
||||
### Version
|
||||
|
||||
UUID: `adaf0100-4669-6c65-5472-616e73666572`
|
||||
|
||||
The version characteristic returns the version of the protocol to which the sender adheres. It returns a single unsigned 32-bit integer. The latest version at the time of writing this is 4.
|
||||
|
||||
### Transfer
|
||||
|
||||
UUID: `adaf0200-4669-6c65-5472-616e73666572`
|
||||
|
||||
The transfer characteristic is responsible for all the data transfer between the client and the watch. It supports write and notify. Writing a packet on the characteristic results in a response via notify.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
The separator for paths is `/`, and absolute paths must start with `/`.
|
||||
|
||||
All of the following commands and responses are transferred via the transfer characteristic
|
||||
|
||||
### Read file
|
||||
|
||||
To begin reading a file, a header must first be sent. The header packet should be formatted like so:
|
||||
|
||||
- Command (single byte): `0x10`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- Unsigned 32-bit integer encoding the location at which to start reading the first chunk.
|
||||
- Unsigned 32-bit integer encoding the amount of bytes to be read.
|
||||
- File path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
To continue reading the file after this initial packet, the following packet should be sent until all the data has been received. No close command is required after the data has been received.
|
||||
|
||||
- Command (single byte): `0x12`
|
||||
- Status: `0x01`
|
||||
- 2 bytes of padding
|
||||
- Unsigned 32-bit integer encoding the location at which to start reading the next chunk.
|
||||
- Unsigned 32-bit integer encoding the amount of bytes to be read. This may be different from the size in the header.
|
||||
|
||||
Both of these commands receive the following response:
|
||||
|
||||
- Command (single byte): `0x11`
|
||||
- Status (signed 8-bit integer)
|
||||
- 2 bytes of padding
|
||||
- Unsigned 32-bit integer encoding the offset of this chunk
|
||||
- Unsigned 32-bit integer encoding the total size of the file
|
||||
- Unsigned 32-bit integer encoding the amount of data in the current chunk
|
||||
- Contents of the current chunk
|
||||
|
||||
### Write file
|
||||
|
||||
To begin writing to a file, a header must first be sent. The header packet should be formatted like so:
|
||||
|
||||
- Command (single byte): `0x20`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- Unsigned 32-bit integer encoding the location at which to start writing to the file.
|
||||
- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution. This will be used as the modification time. At the time of writing, this is not implemented in InfiniTime, but may be in the future.
|
||||
- Unsigned 32-bit integer encoding the size of the file that will be sent
|
||||
- File path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
To continue reading the file after this initial packet, the following packet should be sent until all the data has been sent and a response had been received with 0 free space. No close command is required after the data has been received.
|
||||
|
||||
- Command (single byte): `0x22`
|
||||
- Status: `0x01`
|
||||
- 2 bytes of padding.
|
||||
- Unsigned 32-bit integer encoding the location at which to write the next chunk.
|
||||
- Unsigned 32-bit integer encoding the amount of bytes to be written.
|
||||
- Data
|
||||
|
||||
Both of these commands receive the following response:
|
||||
|
||||
- Command (single byte): `0x21`
|
||||
- Status (signed 8-bit integer)
|
||||
- 2 bytes of padding
|
||||
- Unsigned 32-bit integer encoding the current offset in the file
|
||||
- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution. This will be used as the modification time. At the time of writing, this is not implemented in InfiniTime, but may be in the future.
|
||||
- Unsigned 32-bit integer encoding the amount of data the client can send until the file is full.
|
||||
|
||||
### Delete file
|
||||
|
||||
- Command (single byte): `0x30`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- File path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
The response to this packet will be as follows:
|
||||
|
||||
- Command (single byte): `0x31`
|
||||
- Status (signed 8-bit integer)
|
||||
|
||||
### Make directory
|
||||
|
||||
- Command (single byte): `0x40`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- 4 bytes of padding
|
||||
- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution.
|
||||
- File path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
The response to this packet will be as follows:
|
||||
|
||||
- Command (single byte): `0x41`
|
||||
- Status (signed 8-bit integer)
|
||||
- 6 bytes of padding
|
||||
- Unsigned 64-bit integer encoding the unix timestamp with nanosecond resolution.
|
||||
|
||||
### List directory
|
||||
|
||||
Paths returned by this command are relative to the path given in the request
|
||||
|
||||
- Command (single byte): `0x50`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- File path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
The response to this packet will be as follows. Responses will be sent until the final entry, which will have entry number == total entries
|
||||
|
||||
- Command (single byte): `0x51`
|
||||
- Status (signed 8-bit integer)
|
||||
- Unsigned 16-bit integer encoding the length of the file path.
|
||||
- Unsigned 32-bit integer encoding the entry number
|
||||
- Unsigned 32-bit integer encoding the total amount of entries
|
||||
- Flags: unsigned 32-bit integer
|
||||
+ Bit 0: Set when entry is a directory
|
||||
+ Bits 1-7: Reserved
|
||||
- Unsigned 64-bit integer encoding the unix timestamp of the modification time with nanosecond resolution
|
||||
- Unsigned 32-bit integer encoding the size of the file
|
||||
- Path: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
### Move file or directory
|
||||
|
||||
- Command (single byte): `0x60`
|
||||
- 1 byte of padding
|
||||
- Unsigned 16-bit integer encoding the length of the old path
|
||||
- Unsigned 16-bit integer encoding the length of the new path
|
||||
- Old path: UTF-8 encoded string that is _not_ null terminated.
|
||||
- 1 byte of padding
|
||||
- Newpath: UTF-8 encoded string that is _not_ null terminated.
|
||||
|
||||
The response to this packet will be as follows:
|
||||
|
||||
- Command (single byte): `0x61`
|
||||
- Status (signed 8-bit integer)
|
||||
|
||||
---
|
||||
|
||||
## Deviations
|
||||
|
||||
This section describes the differences between Adafruit's spec and InfiniTime's implementation.
|
||||
|
||||
### Status codes
|
||||
|
||||
The status codes returned by InfiniTime are a signed 8-bit integer, rather than an unsigned one as described in the spec.
|
||||
|
||||
InfiniTime uses LittleFS error codes rather than the ones described in the spec. Those codes can be found in [lfs.h](https://github.com/littlefs-project/littlefs/blob/master/lfs.h#L70).
|
|
@ -32,13 +32,13 @@ In this analysis, I used [Linkermapviz](https://github.com/PromyLOPh/linkermapvi
|
|||
|
||||
### Linkermapviz
|
||||
|
||||
[Linkermapviz](https://github.com/PromyLOPh/linkermapviz) parses the MAP file and displays its content on an HTML page as a graphic:
|
||||
[Linkermapviz](https://github.com/PromyLOPh/linkermapviz) parses the MAP file and displays its content in a graphical way into an HTML page:
|
||||
|
||||
![linkermapviz](./memoryAnalysis/linkermapviz.png)
|
||||
|
||||
Using this tool, you can compare the relative size of symbols. This can be helpful for checking memory usage at a glance.
|
||||
Using this tool, you can easily see the size of each symbol relative to the other one, and check what is using most of the space,...
|
||||
|
||||
Also, as Linkermapviz is written in Python, you can easily modify and adapt it to your firmware or export data in another format. For example, [here it is modified to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). This file could later be opened in LibreOffice Calc where sort/filter functionality could be used to search for specific symbols in specific files...
|
||||
Also, as Linkermapviz is written in Python, you can easily modify it to adapt it to your firmware, export data in another format,... For example, [I modified it to parse the contents of the MAP file and export it in a CSV file](https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620). I could later on open this file in LibreOffice Calc and use sort/filter functionality to search for specific symbols in specific files...
|
||||
|
||||
### Puncover
|
||||
[Puncover](https://github.com/HBehrens/puncover) is another useful tools that analyses the binary file generated by the compiler (the .out file that contains all debug information). It provides valuable information about the symbols (data and code): name, position, size, max stack of each functions, callers, callees...
|
||||
|
@ -46,27 +46,27 @@ Also, as Linkermapviz is written in Python, you can easily modify and adapt it t
|
|||
|
||||
Puncover is really easy to install:
|
||||
|
||||
- Clone the repo and cd into the cloned directory
|
||||
- Setup a venv
|
||||
- clone the repo and cd into the cloned directory
|
||||
- setup a venv
|
||||
- `python -m virtualenv venv`
|
||||
- `source venv/bin/activate`
|
||||
- Install : `pip install .`
|
||||
- Run : `puncover --gcc_tools_base=/path/to/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory`
|
||||
- Run : `puncover --gcc_tools_base=/path/to/gcc-arm-none-eabi-9-2020-q2-update/bin/arm-none-eabi- --elf_file /path/to/build/directory/src/pinetime-app-1.1.0.out --src_root /path/to/sources --build_dir /path/to/build/directory`
|
||||
- Replace
|
||||
* `/path/to/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin` with the path to your gcc-arm-none-eabi toolchain
|
||||
* `/path/to/gcc-arm-none-eabi-9-2020-q2-update/bin` with the path to your gcc-arm-none-eabi toolchain
|
||||
* `/path/to/build/directory/src/pinetime-app-1.1.0.out` with the path to the binary generated by GCC (.out file)
|
||||
* `/path/to/sources` with the path to the root folder of the sources (checkout directory)
|
||||
* `/path/to/build/directory` with the path to the build directory
|
||||
- Launch a browser at http://localhost:5000/
|
||||
|
||||
### Analysis
|
||||
Using the MAP file and tools, we can easily see what symbols are using most of the flash memory. In this case, unsurprisingly, fonts and graphics are the largest use of flash memory.
|
||||
Using the MAP file and tools, we can easily see what symbols are using most of the FLASH memory space. In this case, with no surprise, fonts and graphics are the biggest flash space consumer.
|
||||
|
||||
![Puncover](./memoryAnalysis/puncover-all-symbols.png)
|
||||
|
||||
This way, you can easily check what needs to be optimized. We should find a way to store big static data (like fonts and graphics) in the external flash memory, for example.
|
||||
This way, you can easily check what needs to be optimized : we should find a way to store big static data (like fonts and graphics) in the external flash memory, for example.
|
||||
|
||||
It's always a good idea to check the flash memory space when working on the project. This way, you can easily check that your developments are using a reasonable amount of space.
|
||||
It's always a good idea to check the flash memory space when working on the project : this way, you can easily check that your developments are using a reasonable amount of space.
|
||||
|
||||
### Links
|
||||
- Analysis with linkermapviz : https://github.com/InfiniTimeOrg/InfiniTime/issues/313#issuecomment-842338620
|
||||
|
@ -150,7 +150,7 @@ You can then display the file using objdump:
|
|||
hexdump ram.bin -v | less
|
||||
```
|
||||
|
||||
The stack is positioned at the end of the RAM -> 0xFFFF. Its size is 8192 bytes, so the end of the stack is at 0xE000.
|
||||
The stack is positionned at the end of the RAM -> 0xFFFF. Its size is 8192 bytes, so the end of the stack is at 0xE000.
|
||||
On the following dump, the maximum stack usage is 520 bytes (0xFFFF - 0xFDF8):
|
||||
|
||||
```
|
||||
|
@ -210,7 +210,7 @@ NRF_LOG_INFO("heap : %d", m.uordblks);
|
|||
```
|
||||
|
||||
#### Analysis
|
||||
According to my experimentation, InfiniTime uses ~6000bytes of heap most of the time. Except when the Navigation app is launched, where the heap usage exceeds 9500 bytes (meaning that the heap overflows and could potentially corrupt the stack). This is a bug that should be fixed in #362.
|
||||
According to my experimentation, InfiniTime uses ~6000bytes of heap most of the time. Except when the Navigation app is launched, where the heap usage increases to... more than 9500 bytes (meaning that the heap overflows and could potentially corrupt the stack!!!). This is a bug that should be fixed in #362.
|
||||
|
||||
To know exactly what's consuming heap memory, you can `wrap` functions like `malloc()` into your own functions. In this wrapper, you can add logging code or put breakpoints:
|
||||
|
||||
|
@ -245,7 +245,7 @@ Using this technique, I was able to trace all malloc calls at boot (boot -> digi
|
|||
- https://www.embedded.com/mastering-stack-and-heap-for-system-reliability-part-3-avoiding-heap-errors/
|
||||
|
||||
## LVGL
|
||||
I did a deep analysis of the usage of the buffer dedicated to lvgl (managed by lv_mem).
|
||||
I did a deep analysis of the usage of the buffer dedicated for lvgl (managed by lv_mem).
|
||||
This buffer is used by lvgl to allocated memory for drivers (display/touch), screens, themes, and all widgets created by the apps.
|
||||
|
||||
The usage of this buffer can be monitored using this code :
|
||||
|
@ -256,7 +256,7 @@ lv_mem_monitor(&mon);
|
|||
NRF_LOG_INFO("\t Free %d / %d -- max %d", mon.free_size, mon.total_size, mon.max_used);
|
||||
```
|
||||
|
||||
The most interesting metric is `mon.max_used` which specifies the maximum number of bytes used from this buffer since the initialization of lvgl.
|
||||
The most interesting metric is `mon.max_used` which specifies the maximum number of bytes that were used from this buffer since the initialization of lvgl.
|
||||
According to my measurements, initializing the theme, display/touch driver and screens cost **4752** bytes!
|
||||
Then, initializing the digital clock face costs **1541 bytes**.
|
||||
For example a simple lv_label needs **~140 bytes** of memory.
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# Motion Service
|
||||
## Introduction
|
||||
The motion service exposes step count and raw X/Y/Z motion value as READ and NOTIFY characteristics.
|
||||
|
||||
## Service
|
||||
The service UUID is **00030000-78fc-48fe-8e23-433b3a1942d0**
|
||||
|
||||
## Characteristics
|
||||
### Step count (UUID 00030001-78fc-48fe-8e23-433b3a1942d0)
|
||||
The current number of steps represented as a single `uint32_t` (4 bytes) value.
|
||||
|
||||
### Raw motion values (UUID 00030002-78fc-48fe-8e23-433b3a1942d0)
|
||||
The current raw motion values. This is a 3 `int16_t` array:
|
||||
|
||||
- [0] : X
|
||||
- [1] : Y
|
||||
- [2] : Z
|
|
@ -1,6 +1,6 @@
|
|||
# Navigation Service
|
||||
## Introduction
|
||||
The navigation ble service provides 4 characteristics to allow the watch to display navigation instructions from a companion application. This service is intended to be used when performing some outdoor activities, for example running or cycling.
|
||||
The navigation ble service provides 4 characteristics to allow the the watch to display navigation instructions from a companion application. The intended purpose is when performing some outdoor activities, for example running or cycling.
|
||||
|
||||
The 4 characteristics are:
|
||||
flag (string) - Upcoming icon name
|
||||
|
@ -13,7 +13,7 @@ The service UUID is 00010000-78fc-48fe-8e23-433b3a1942d0
|
|||
|
||||
## Characteristics
|
||||
## Flags (UUID 00010001-78fc-48fe-8e23-433b3a1942d0)
|
||||
All included icons are from pure-maps, which provides the actual routing from the client. The icon names ultimately come from the mapbox project "direction-icons", See https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation See the end of this document for the full list of supported icon names.
|
||||
All included icons are from pure-maps, which provides the actual routing from the client. The icon names ultimately come from the mapbox project "direction-icons", See https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation See the end of this document for the full lsit of supported icon names.
|
||||
|
||||
## Narrative (UUID 00010002-78fc-48fe-8e23-433b3a1942d0)
|
||||
This is a client supplied string describing the upcoming instruction such as "At the roundabout take the first exit".
|
||||
|
@ -22,7 +22,7 @@ This is a client supplied string describing the upcoming instruction such as "At
|
|||
This is a short string describing the distance to the upcoming instruction such as "50 m".
|
||||
|
||||
## Progress (UUID 00010004-78fc-48fe-8e23-433b3a1942d0)
|
||||
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
|
||||
The percent complete in a uint8. The watch displays this as an overall progress in a progress bar.
|
||||
|
||||
## Full icon list
|
||||
* arrive
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# Build a stub for PineTime using NRF52-DK
|
||||
[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official development kit for the NRF52832 SoC from Nordic Semiconductor used in the PineTime.
|
||||
[NRF52-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK) is the official developpment kit for NRF52832 SoC from Nordic Semiconductor.
|
||||
|
||||
This development kit can be very useful for PineTime development:
|
||||
* You can use its embedded JLink SWD programmer/debugger to program and debug your code on the PineTime
|
||||
* As it's based on the same SoC than the PineTime, you can program it to actually run the same code as the PineTime.
|
||||
It can be very useful for PineTime development:
|
||||
* You can use it embedded JLink SWD programmer/debugger to program and debug you code on the PineTime
|
||||
* As it's based on the same SoC than the PineTime, you can program it to actually run the same code than the PineTime.
|
||||
|
||||
This page is about the 2nd point. We will build a stub that will allow us to run the same code you can run on the PineTime. This will allow you to work more easily if you don't have a PineTime dev kit around, if you don't want to modify your dev kit for SWD programming, or if you want to use some feature from the NRF52-DK (like power measurement).
|
||||
This page is about the 2nd point : we will build a stub that will allow us to run the same code than the one you could run on the PineTime. This will allow you to work more easily if you don't have a PineTime dev kit around, if you don't want to modify your dev kit for SWD programming, or if you want to use some feature from the DK (like power measurement).
|
||||
|
||||
This stub only implements the display, the button and the BLE radio. The other features from the pintime are missing:
|
||||
* heart rate sensor
|
||||
|
@ -41,7 +41,7 @@ You just need to make the following connections:
|
|||
| P0.13 | Button IN (D3 in my case) |
|
||||
| GND | GND |
|
||||
|
||||
You also need to enable the I/O expander to disconnect pins from the buttons and LED on the NRF52-DK and leave them available on the pin headers:
|
||||
You also need to enable the I/O expander to disconnect pins from buttons and led on the NRF52-DK and leave them available on the pin headers:
|
||||
|
||||
| NRF52 -DK | NRF52- DK |
|
||||
| --------- | --------- |
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# The SPI LCD driver
|
||||
## Introduction
|
||||
The LCD controller that drives the display of the Pinetime is the [Sitronix ST7789V](https://wiki.pine64.org/images/5/54/ST7789V_v1.6.pdf). This controller is easy to integrate with an MCU thanks to its SPI interface, and has some interesting features like:
|
||||
The LCD controller that drive the display of the Pinetime is the Sitronix ST7789V. This controller is easy to integrate with an MCU thanks to its SPI interface, and has some interesting features like:
|
||||
- an on-chip display data RAM that can store the whole framebuffer
|
||||
- partial screen update
|
||||
- hardware assisted vertical scrolling
|
||||
|
|
14
doc/SWD.md
|
@ -1,14 +0,0 @@
|
|||
# How to flash InfiniTime using the SWD interface
|
||||
Download the files **bootloader.bin**, **image-x.y.z.bin** and **pinetime-graphics-x.y.z.bin** from the release page:
|
||||
|
||||
![Image file](gettingStarted/imageFile.png)
|
||||
|
||||
The bootloader reads a boot logo from the external SPI flash memory. The first step consists of flashing a tool in the MCU that will flash the boot logo into this SPI flash memory. This first step is optional but recommended (the bootloader will display garbage on screen for a few second if you don't do it).
|
||||
Using your SWD tool, flash **pinetime-graphics-x.y.z.bin** at offset **0x0000**. Reset the MCU and wait for a few seconds until the logo is completely drawn on the display.
|
||||
|
||||
Then, using your SWD tool, flash these file at the following offsets:
|
||||
|
||||
- bootloader.bin : **0x0000**
|
||||
- image-x.y.z.bin : **0x8000**
|
||||
|
||||
Reset and voilà, you're running InfiniTime on your PineTime!
|
273
doc/ble.md
|
@ -2,67 +2,23 @@
|
|||
## Introduction
|
||||
This page describes the BLE implementation and API built in this firmware.
|
||||
|
||||
**Note**: I'm a beginner in BLE related technologies and the information in this document reflects my current knowledge and understanding of the BLE stack. This information might be erroneous or incomplete. Feel free to submit a PR if you think you can improve it.
|
||||
|
||||
---
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [BLE Connection](#ble-connection)
|
||||
- [BLE FS](#ble-fs)
|
||||
- [BLE UUIDs](#ble-uuids)
|
||||
- [BLE Services](#ble-services)
|
||||
- [CTS](#cts)
|
||||
- [ANS](#ans)
|
||||
- [Getting Information](#getting-information)
|
||||
- [Firmware Version](#firmware-version)
|
||||
- [Battery Level](#battery-level)
|
||||
- [Heart Rate](#heart-rate)
|
||||
- [Notifications](#notifications)
|
||||
- [New Alert](#new-alert)
|
||||
- [Notification Event](#notification-event)
|
||||
- [Firmware Upgrades](#firmware-upgrades)
|
||||
- [Step one](#step-one)
|
||||
- [Step two](#step-two)
|
||||
- [Step three](#step-three)
|
||||
- [Step four](#step-four)
|
||||
- [Step five](#step-five)
|
||||
- [Step six](#step-six)
|
||||
- [Step seven](#step-seven)
|
||||
- [Step eight](#step-eight)
|
||||
- [Step nine](#step-nine)
|
||||
- [Music Control](#music-control)
|
||||
- [Events](#events)
|
||||
- [Status](#status)
|
||||
- [Artist, Track, and Album](#artist-track-and-album)
|
||||
- [Time](#time)
|
||||
|
||||
---
|
||||
**Note** : I'm a beginner in BLE related technologies and the information of this document reflect my current knowledge and understanding of the BLE stack. These informations might be erroneous or incomplete. Feel free to submit a PR if you think you can improve these.
|
||||
|
||||
## BLE Connection
|
||||
When starting, the firmware starts BLE advertising. It sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
|
||||
When starting the firmware start a BLE advertising : it sends small messages that can be received by any *central* device in range. This allows the device to announce its presence to other devices.
|
||||
|
||||
A companion application (running on a PC, Raspberry Pi, smartphone, etc.) which receives this advertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys, etc.
|
||||
A companion application (running on a PC, RaspberryPi, smartphone) which received this avertising packet can request a connection to the device. This connection procedure allows the 2 devices to negotiate communication parameters, security keys,...
|
||||
|
||||
When the connection is established, the PineTime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
|
||||
When the connection is established, the pinetime will try to discover services running on the companion application. For now **CTS** (**C**urrent **T**ime **S**ervice) and **ANS** (**A**lert **N**otification **S**ervice) are supported.
|
||||
|
||||
If **CTS** is detected, it'll request the current time to the companion application. If **ANS** is detected, it will listen to new notifications coming from the companion application.
|
||||
|
||||
![BLE connection sequence diagram](ble/connection_sequence.png "BLE connection sequence diagram")
|
||||
|
||||
---
|
||||
|
||||
## BLE FS
|
||||
|
||||
The documentation for BLE FS can be found here:
|
||||
[BLEFS.md](./BLEFS.md)
|
||||
|
||||
---
|
||||
|
||||
## BLE UUIDs
|
||||
When possible, InfiniTime tries to implement BLE services defined by the BLE specification.
|
||||
|
||||
When the service does not exist in the BLE specification, InfiniTime implements custom services. Custom services are identified by a UUID, as are all BLE services. Here is how to define the UUID of custom services in InfiniTime:
|
||||
When the service does not exist in the BLE specification, InfiniTime implement custom services. As all BLE services, custom services are identified by a UUID. Here is how to define the UUID of custom services in InfiniTime:
|
||||
|
||||
```
|
||||
- Base UUID : xxxxxxxx-78fc-48fe-8e23-433b3a1942d0
|
||||
|
@ -73,25 +29,14 @@ When the service does not exist in the BLE specification, InfiniTime implements
|
|||
The following custom services are implemented in InfiniTime:
|
||||
|
||||
- Since InfiniTime 0.8:
|
||||
* Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
|
||||
|
||||
```
|
||||
* Music Service : 00000000-78fc-48fe-8e23-433b3a1942d0
|
||||
```
|
||||
|
||||
- Since InfiniTime 0.11:
|
||||
* [Navigation Service](NavigationService.md) : 00010000-78fc-48fe-8e23-433b3a1942d0
|
||||
|
||||
|
||||
- Since InfiniTime 0.13
|
||||
* Call characteristic (extension to the Alert Notification Service): 00020001-78fc-48fe-8e23-433b3a1942d0
|
||||
|
||||
|
||||
- Since InfiniTime 1.7:
|
||||
* [Motion Service](MotionService.md): 00030000-78fc-48fe-8e23-433b3a1942d0
|
||||
|
||||
|
||||
- Since InfiniTime 1.8:
|
||||
* [Weather Service](/src/components/ble/weather/WeatherService.h): 00040000-78fc-48fe-8e23-433b3a1942d0
|
||||
|
||||
---
|
||||
```
|
||||
* Navigation Service : 00010000-78fc-48fe-8e23-433b3a1942d0
|
||||
```
|
||||
|
||||
## BLE services
|
||||
[List of standard BLE services](https://www.bluetooth.com/specifications/gatt/services/)
|
||||
|
@ -104,197 +49,3 @@ The following custom services are implemented in InfiniTime:
|
|||
|
||||
![ANS sequence diagram](./ble/ans_sequence.png "ANS sequence diagram")
|
||||
|
||||
---
|
||||
|
||||
### Getting Information
|
||||
|
||||
The InfiniTime firmware exposes some information about itself through BLE. The BLE characteristic UUIDs for this information are as follows:
|
||||
|
||||
- Firmware Version: `00002a26-0000-1000-8000-00805f9b34fb`
|
||||
- Battery Level: `00002a19-0000-1000-8000-00805f9b34fb`
|
||||
- Heart Rate: `00002a37-0000-1000-8000-00805f9b34fb`
|
||||
|
||||
#### Firmware Version
|
||||
|
||||
Reading a value from the firmware version characteristic will yield a UTF-8 encoded string containing the version of InfiniTime being run on the device. Example: `1.6.0`.
|
||||
|
||||
#### Battery Level
|
||||
|
||||
Reading from the battery level characteristic yields a single byte of data. This byte can be converted to an unsigned 8-bit integer which will be the battery percentage. This characteristic allows notifications for updates as the value changes.
|
||||
|
||||
#### Heart Rate
|
||||
|
||||
Reading from the heart rate characteristic yields two bytes of data. I am not sure of the function of the first byte. It appears to always be zero. The second byte can be converted to an unsigned 8-bit integer which is the current heart rate. This characteristic also allows notifications for updates as the value changes.
|
||||
|
||||
---
|
||||
|
||||
### Notifications
|
||||
|
||||
InfiniTime uses the Alert Notification Service (ANS) for notifications. The relevant UUIDs are as follows:
|
||||
|
||||
- New Alert: `00002a46-0000-1000-8000-00805f9b34fb`
|
||||
- Notification Event: `00020001-78fc-48fe-8e23-433b3a1942d0`
|
||||
|
||||
#### New Alert
|
||||
|
||||
The new alert characteristic allows sending new notifications to InfiniTime. It requires the following format:
|
||||
|
||||
```
|
||||
<category><amount>\x00<\x00-separated data>
|
||||
```
|
||||
|
||||
For example, here is what a normal notification looks like in Golang (language of `itd`):
|
||||
|
||||
```go
|
||||
// \x00 is the category for simple alert, and there is one new notification, hence \x01.
|
||||
"\x00\x01\x00Test Title\x00Test Body"
|
||||
```
|
||||
|
||||
A call notification looks like so:
|
||||
|
||||
```go
|
||||
// \x03 is the category for calls, and there is one new call notification, hence \x01.
|
||||
"\x03\x01\x00Mary"
|
||||
```
|
||||
|
||||
The `\x00` stands for hexadecimal `00` which means null.
|
||||
|
||||
Here is the list of categories and commands:
|
||||
|
||||
- Simple Alert: `0`
|
||||
- Email: `1`
|
||||
- News: `2`
|
||||
- Call Notification: `3`
|
||||
- Missed Call: `4`
|
||||
- SMS/MMS: `5`
|
||||
- Voicemail: `6`
|
||||
- Schedule: `7`
|
||||
- High Prioritized Alert: `8`
|
||||
- Instant Message: `9`
|
||||
- All Alerts: `0xFF`
|
||||
|
||||
These lists and information were retrieved from the following pages in the Nordic docs:
|
||||
|
||||
- [Alert Notification Service Client](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.2.0%2Fgroup__ble__ans__c.html)
|
||||
- [Alert Notification Application](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v13.0.0%2Fble_sdk_app_alert_notification.html)
|
||||
|
||||
#### Notification Event
|
||||
|
||||
A call notification in InfiniTime contains three buttons. Decline, Accept, and Mute. The notification event characteristic contains the button tapped by the user on a call notification. This characteristic only allows notify, **not** read.
|
||||
|
||||
Enabling notifications from this characteristic, you get a single byte whenever the user taps a button on the call notification. This byte is an unsigned 8-bit integer that signifies one of the buttons. The numbers are as follows:
|
||||
|
||||
- 0: Declined
|
||||
- 1: Accepted
|
||||
- 2: Muted
|
||||
|
||||
---
|
||||
|
||||
### Firmware Upgrades
|
||||
|
||||
Firmware upgrades in InfiniTime are probably the most complex of the BLE operations. It is a nine step process requiring multiple commands be sent to multiple characteristics. The relevant UUIDs are as follows:
|
||||
|
||||
- Control Point: `00001531-1212-efde-1523-785feabcd123`
|
||||
- Packet: `00001532-1212-efde-1523-785feabcd123`
|
||||
|
||||
A DFU upgrade archive for InfiniTime consists of multiple files. The most important being the .bin and .dat files. The first is the actual firmware, while the second is a packet that initializes DFU. Both are needed for a DFU upgrade.
|
||||
|
||||
The first thing to do is to enable notifications on the control point characteristic. This will be needed for verifying that the proper responses are being sent back from InfiniTime.
|
||||
|
||||
#### Step one
|
||||
|
||||
For the first step, write `0x01`, `0x04` to the control point characteristic. This will signal InfiniTime that a DFU upgrade is to be started.
|
||||
|
||||
#### Step two
|
||||
|
||||
In step two, send the total size in bytes of the firmware file to the packet characteristic. This value should be an unsigned 32-bit integer encoded as little-endian. In front of this integer should be 8 null bytes. This is because there are three items that can be updated and each 4 bytes is for one of those. The last four are for the InfiniTime application, so those are the ones that need to be set.
|
||||
|
||||
#### Step three
|
||||
|
||||
Before running step three, wait for a response from the control point. This response should be `0x10`, `0x01`, `0x01` which indicates a successful DFU start. In step three, send `0x02`, `0x00` to the control point. This will signal InfiniTime to expect the init packet on the packet characteristic.
|
||||
|
||||
#### Step four
|
||||
|
||||
The previous step prepared InfiniTime for this one. In this step, send the contents of the .dat init packet file to the packet characteristic. After this, send `0x02`, `0x01` indicating that the packet has been sent.
|
||||
|
||||
#### Step five
|
||||
|
||||
Before running this step, wait to receive `0x10`, `0x02`, `0x01` which indicates that the packet has been received. During this step, send the packet receipt interval to the control point. The firmware file will be sent in segments of 20 bytes each. The packet receipt interval indicates how many segments should be received before sending a receipt containing the amount of bytes received so that it can be confirmed to be the same as the amount sent. This is very useful for detecting packet loss. `itd` uses `0x08`, `0x0A` which indicates 10 segments.
|
||||
|
||||
#### Step six
|
||||
|
||||
In step six, write `0x03` to the control point, indicating that the firmware will be sent next on the packet characteristic.
|
||||
|
||||
#### Step seven
|
||||
|
||||
This step is the most difficult. Here, the actual firmware is sent to InfiniTime.
|
||||
|
||||
As mentioned before, the firmware file must be split up into segments of 20 bytes each and sent to the packet characteristic one by one. Every 10 segments (or whatever you have set the interval to), check for a response starting with `0x11`. The rest of the response will be the amount of bytes received encoded as a little-endian unsigned 32-bit integer. Confirm that this matches the amount of bytes sent, and then continue sending more segments.
|
||||
|
||||
#### Step eight
|
||||
|
||||
Before running this step, wait to receive `0x10`, `0x03`, `0x01` which indicates a successful receipt of the firmware image. In this step, write `0x04` to the control point to signal InfiniTime to validate the image it has received.
|
||||
|
||||
#### Step nine
|
||||
|
||||
Before running this step, wait to receive `0x10`, `0x04`, `0x01` which indicates that the image has been validated. In this step, send `0x05` to the control point as a command with no response. This signals InfiniTime to activate the new firmware and reboot.
|
||||
|
||||
Once all of these steps are complete, the DFU is complete. Don't forget to validate the firmware in the settings.
|
||||
|
||||
---
|
||||
|
||||
### Music Control
|
||||
|
||||
InfiniTime contains a music controller app which is meant to control the music playback and volume through the companion.
|
||||
|
||||
The following UUIDs are relevant to this:
|
||||
|
||||
- Events: `00000001-78fc-48fe-8e23-433b3a1942d0`
|
||||
- Status: `00000002-78fc-48fe-8e23-433b3a1942d0`
|
||||
- Artist: `00000003-78fc-48fe-8e23-433b3a1942d0`
|
||||
- Track: `00000004-78fc-48fe-8e23-433b3a1942d0`
|
||||
- Album: `00000005-78fc-48fe-8e23-433b3a1942d0`
|
||||
|
||||
#### Events
|
||||
|
||||
The events characteristic is meant to respond to user input in the music controller app.
|
||||
|
||||
Enabling notifications on this characteristic gives you a single byte upon any event. This byte can be converted to an unsigned 8-bit integer which corresponds to each possible event. Here are the events:
|
||||
|
||||
- App Opened: `0xe0`
|
||||
- Play: `0x00`
|
||||
- Pause: `0x01`
|
||||
- Next: `0x03`
|
||||
- Previous: `0x04`
|
||||
- Volume up: `0x05`
|
||||
- Volume down: `0x06`
|
||||
|
||||
#### Status
|
||||
|
||||
The status characteristic allows setting the playing status of music. Send `0x01` to the status characteristic for playing, and `0x00` for paused.
|
||||
|
||||
#### Artist, Track, and Album
|
||||
|
||||
These characteristics all work the same way. Simply send a UTF-8 encoded string to the relevant characteristic in order to set the value in the app.
|
||||
|
||||
---
|
||||
|
||||
### Time
|
||||
|
||||
InfiniTime allows setting its time via the Current Time Service (CTS)
|
||||
|
||||
The UUID for the current time characteristic is: `00002a2b-0000-1000-8000-00805f9b34fb`
|
||||
|
||||
This characteristic expects a particular format:
|
||||
|
||||
- Year (`uint16`)
|
||||
- Month (`uint8`)
|
||||
- Day (`uint8`)
|
||||
- Hour (`uint8`)
|
||||
- Minute (`uint8`)
|
||||
- Second (`uint8`)
|
||||
- Weekday (`uint8`)
|
||||
- Microsecond divided by `1e6*256` (`uint8`)
|
||||
- Binary 0001 (`uint8`)
|
||||
|
||||
Write all of these together, encoded as little-endian, to the current time characteristic.
|
||||
|
|
|
@ -3,7 +3,7 @@ Pinetime --> CompanionApp: Start advertising
|
|||
|
||||
group BLE Connection
|
||||
CompanionApp -> Pinetime: Connection request
|
||||
CompanionApp <-> Pinetime: Connection parameters negotiation, security procedure,...
|
||||
CompanionApp <-> Pinetime: Connection parameters negociation, security procedure,...
|
||||
end
|
||||
|
||||
group Service Discovery
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Branches
|
||||
The branching model of this project is based on the workflow named [Git flow](https://nvie.com/posts/a-successful-git-branching-model/).
|
||||
|
||||
The project is based on 2 main branches:
|
||||
It is based on 2 main branches:
|
||||
- **master** : this branch is always ready to be deployed. It means that at any time, we should be able to build the branch and release a new version of the application.
|
||||
- **develop** : this branch contains the latest development that will be integrated in the next release once it's considered as stable.
|
||||
|
||||
New features should be implemented in **feature branches** created from **develop**. When the feature is ready, a pull-request is created and it'll be merge into **develop** when it is successfully reviewed and accepted.
|
||||
New features should be implemented in **feature branches** created from **develop**. When the feature is ready, a pull-request is created and it'll be merge into **develop** when it is succesfully reviewed and accepted.
|
||||
|
||||
To release a new version of the application, when develop is considered stable, a **release** branch is created from **develop**. This can be considered as a *release candidate* branch. When everything is OK, this release branch is merged into **master** and the release is generated (a tag is applied to git, the release note is finalized, binaries are built,...) from **master**.
|
||||
|
||||
Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if multiple bugs are discovered.
|
||||
Git flow also supports the creation of **hotfix** branches when a bug is discovered in a released version. The **hotfix** branch is created from **master** and will be used only to implement a fix to this bug. Multiple hotfix branches can be created for the same release if more than one bugs are discovered.
|
|
@ -1,21 +1,10 @@
|
|||
# Build
|
||||
## Dependencies
|
||||
To build this project, you'll need:
|
||||
- A cross-compiler : [ARM-GCC (arm-none-eabi 11.2-2022.02)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/downloads)
|
||||
- A cross-compiler : [ARM-GCC (9-2020-q2-update)](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update)
|
||||
- The NRF52 SDK 15.3.0 : [nRF-SDK v15.3.0](https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip)
|
||||
- The Python 3 modules `cbor`, `intelhex`, `click` and `cryptography` modules for the `mcuboot` tool (see [requirements.txt](../tools/mcuboot/requirements.txt))
|
||||
- To keep the system clean, you can install python modules into a python virtual environment (`venv`)
|
||||
```sh
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install wheel
|
||||
python -m pip install -r tools/mcuboot/requirements.txt
|
||||
```
|
||||
- The `cbor` and `intelhex` modules for Python 3
|
||||
- A reasonably recent version of CMake (I use 3.16.5)
|
||||
- lv_font_conv, to generate the font .c files
|
||||
- see [lv_font_conv](https://github.com/lvgl/lv_font_conv#install-the-script)
|
||||
- install npm (commonly done via the package manager, ensure node's version is at least 12)
|
||||
- install lv_font_conv: `npm install lv_font_conv`
|
||||
|
||||
## Build steps
|
||||
### Clone the repo
|
||||
|
@ -31,7 +20,7 @@ CMake configures the project according to variables you specify the command line
|
|||
|
||||
Variable | Description | Example|
|
||||
----------|-------------|--------|
|
||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/`|
|
||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`-DARM_NONE_EABI_TOOLCHAIN_PATH=/home/jf/nrf52/gcc-arm-none-eabi-9-2020-q2-update/`|
|
||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`-DNRF5_SDK_PATH=/home/jf/nrf52/Pinetime/sdk`|
|
||||
**USE_JLINK, USE_GDB_CLIENT and USE_OPENOCD**|Enable *JLink* mode, *GDB Client* (Black Magic Probe) mode or *OpenOCD* mode (set the one you want to use to `1`)|`-DUSE_JLINK=1`
|
||||
**CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug`
|
||||
|
@ -47,7 +36,7 @@ By default, this variable is set to *Release*. It compiles the code with size an
|
|||
The *Debug* mode disables all optimizations, which makes the code easier to debug. However, the binary size will likely be too big to fit in the internal flash memory. If you want to build and debug a *Debug* binary, you'll need to disable some parts of the code. For example, the icons for the **Navigation** app use a lot of memory space. You can comment the content of `m_iconMap` in the [Navigation](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/src/displayapp/screens/Navigation.h#L148) application to free some memory.
|
||||
|
||||
####(**) Note about **BUILD_DFU**:
|
||||
DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mechanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option.
|
||||
DFU files are the files you'll need to install your build of InfiniTime using OTA (over-the-air) mecanism. To generate the DFU file, the Python tool [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil) is needed on your system. Check that this tool is properly installed before enabling this option.
|
||||
|
||||
#### CMake command line for JLink
|
||||
```
|
||||
|
@ -235,33 +224,3 @@ Loading section .sec7, size 0xdf08 lma 0x40000
|
|||
Start address 0x0, load size 314200
|
||||
Transfer rate: 45 KB/sec, 969 bytes/write.
|
||||
```
|
||||
|
||||
### How to generate files needed by the factory
|
||||
These files are needed by the Pine64 factory to flash InfiniTime as the default firmware on the PineTimes.
|
||||
|
||||
Two files are needed: an **HEX (.hex)** file that contains the content of the internal flash memory (bootloader + InfiniTime) and a **binary (.bin)** file that contains the content of the external flash memory (recovery firmware).
|
||||
|
||||
#### merged-internal.hex
|
||||
First, convert the bootloader to hex:
|
||||
```
|
||||
<ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex ./bootloader.bin ./bootloader.hex
|
||||
```
|
||||
where `bootloader.bin` is the [last stable version](https://github.com/JF002/pinetime-mcuboot-bootloader/releases) of the [bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader).
|
||||
|
||||
Then, convert the MCUBoot image of InfiniTime:
|
||||
```
|
||||
<ARM TOOLCHAIN>/bin/arm-none-eabi-objcopy -I binary -O ihex --change-addresses 0x8000 ./pinetime-mcuboot-app-image-1.6.0.bin ./pinetime-mcuboot-app-image-1.6.0.hex
|
||||
```
|
||||
where `pinetime-mcuboot-app-image-1.6.0.bin` is [the bin of the last MCUBoot image](https://github.com/InfiniTimeOrg/InfiniTime/releases) of [InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime).
|
||||
|
||||
Pay attention to the parameter `--change-addresses 0x8000`. It's needed to ensure the image will be flashed at the offset expected by the bootloader (0x8000).
|
||||
|
||||
Finally, merge them together with **mergehex**:
|
||||
```
|
||||
/opt/mergehex/mergehex -m ./bootloader.hex ./pinetime-mcuboot-app-image-1.6.0.hex -o merged-internal.hex
|
||||
```
|
||||
|
||||
This file must be flashed at offset **0x00** of the internal memory of the NRF52832.
|
||||
|
||||
#### spinor.bin
|
||||
This file is the MCUBoot image of the last stable version of the recovery firmware. It must be flashed at offset **0x00** of the external SPINOR flash memory.
|
||||
|
|
|
@ -1,58 +1,60 @@
|
|||
# Build the project using Docker
|
||||
|
||||
A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and AMD64 architectures.
|
||||
These images make the build of the firmware and the generation of the DFU file for OTA quite easy, as well as preventing clashes with any other toolchains or development environments you may have installed.
|
||||
A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and AMD64 architectures. These images make the build of the firmware and the generation of the DFU file for OTA quite easy, as well as preventing clashes with any other toolchains or development environments you may have installed.
|
||||
|
||||
Based on Ubuntu 22.04 with the following build dependencies:
|
||||
Based on Ubuntu 18.04 with the following build dependencies:
|
||||
|
||||
* ARM GCC Toolchain
|
||||
* nRF SDK
|
||||
* MCUBoot
|
||||
* adafruit-nrfutil
|
||||
* lv_font_conv
|
||||
|
||||
## Run a container to build the project
|
||||
|
||||
The `infinitime-build` image contains all the dependencies you need.
|
||||
The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
|
||||
The `infinitime-build` image contains all the dependencies you need. The default `CMD` will compile sources found in `/sources`, so you need only mount your code.
|
||||
|
||||
Before continuing, make sure you first build the image as indicated in the [Build the image](#build-the-image) section, or check the [Using the image from Docker Hub](#using-the-image-from-docker-hub) section if you prefer to use a pre-made image.
|
||||
|
||||
This example will build the firmware, generate the MCUBoot image and generate the DFU file.
|
||||
For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**:
|
||||
This example will build the firmware, generate the MCUBoot image and generate the DFU file. For cloning the repo, see [these instructions](../doc/buildAndProgram.md#clone-the-repo). Outputs will be written to **<project_root>/build/output**:
|
||||
|
||||
```bash
|
||||
cd <project_root> # e.g. cd ./work/Pinetime
|
||||
docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) infinitime-build
|
||||
docker run --rm -it -v $(pwd):/sources infinitime-build
|
||||
```
|
||||
|
||||
By default, the container runs as `root`, which is not convenient as all the files generated by the build will also belong to `root`.
|
||||
The parameter `--user` overrides that default behavior.
|
||||
The command above will run as your current user.
|
||||
|
||||
If you only want to build a single CMake target, you can pass it in as the first parameter to the build script.
|
||||
This means calling the script explicitly as it will override the `CMD`.
|
||||
Here's an example for `pinetime-app`:
|
||||
If you only want to build a single CMake target, you can pass it in as the first parameter to the build script. This means calling the script explicitly as it will override the `CMD`. Here's an example For `pinetime-app`:
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) infinitime-build /opt/build.sh pinetime-app
|
||||
docker run --rm -it -v $(pwd):/sources infinitime-build /opt/build.sh pinetime-app
|
||||
```
|
||||
|
||||
The image is built using 1000:1000 for the user id and group id. If this is different to your user or group ids (run `id -u` and `id -g` to find out what your id values are if you are unsure), you will need to override them via the `--user` parameter in order to prevent permission errors with the output files (and the cmake build cache).
|
||||
|
||||
Running with this image is the same as above, you just specify the ids to `docker run`
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $(pwd):/sources --user $(id -u):$(id -g) pfeerick/infinitime-build
|
||||
```
|
||||
|
||||
Or you can specify your user id and group id (by number, not by name) directly:
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v $(pwd):/sources --user 1234:1234 infinitime-build
|
||||
```
|
||||
|
||||
## Using the image from Docker Hub
|
||||
|
||||
The image is available via Docker Hub for both the amd64 and arm64v8 architectures at [infinitime/infinitime-build](https://hub.docker.com/repository/docker/infinitime/infinitime-build).
|
||||
The image is avaiable via Docker Hub for both the amd64 and arm64v8 architectures at [pfeerick/infinitime-build](https://hub.docker.com/repository/docker/pfeerick/infinitime-build).
|
||||
|
||||
You can run it using the following command:
|
||||
It can be pulled (downloaded) using the following command:
|
||||
|
||||
```bash
|
||||
docker run --rm -it -v ${PWD}:/sources --user $(id -u):$(id -g) infinitime/infinitime-build
|
||||
docker pull pfeerick/infinitime-build
|
||||
```
|
||||
|
||||
The default `latest` tag *should* automatically identify the correct image architecture, but if for some reason Docker does not, you can specify it manually:
|
||||
|
||||
* For AMD64 (x86_64) systems: `docker pull --platform linux/amd64 infinitime/infinitime-build`
|
||||
* For AMD64 (x86_64) systems: `docker pull pfeerick/infinitime-build:amd64`
|
||||
|
||||
* For ARM64v8 (ARM64/aarch64) systems: `docker pull --platform linux/arm64 infinitime/infinitime-build`
|
||||
* For ARM64v8 (ARM64/aarch64) systems: `docker pull pfeerick/infinitime-build:arm64v8`
|
||||
|
||||
## Build the image
|
||||
|
||||
|
@ -61,5 +63,11 @@ You can build the image yourself if you like!
|
|||
The following commands must be run from the root of the project. This operation will take some time but, when done, a new image named *infinitime-build* is available.
|
||||
|
||||
```bash
|
||||
docker build -t infinitime-build ./docker
|
||||
```
|
||||
docker image build -t infinitime-build ./docker
|
||||
```
|
||||
|
||||
The `PUID` and `PGID` build arguments are used to set the user and group ids used in the container, meaning you will not need to specify it later unless they change for some reason. Specifying them is not mandatory, as this can be over-ridden at build time via the `--user` flag, but doing so will make the command you need to run later a bit shorter. In the below examples, they are set to your current user id and group id automatically. You can specify them manually, but they must be specified by number, not by name.
|
||||
|
||||
```bash
|
||||
docker image build -t infinitime-build --build-arg PUID=$(id -u) --build-arg PGID=$(id -g) ./docker
|
||||
```
|
||||
|
|
|
@ -8,7 +8,7 @@ To support as many setups as possible the VS Code configuration files expect the
|
|||
|
||||
Variable | Description | Example
|
||||
----------|-------------|--------
|
||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi`
|
||||
**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update`
|
||||
**NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345`
|
||||
|
||||
## VS Code Extensions
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
# Apps
|
||||
This page will teach you:
|
||||
- what screens and apps are in InfiniTime
|
||||
- what apps in InfiniTime are
|
||||
- how to implement your own app
|
||||
|
||||
## Theory
|
||||
|
||||
The user interface of InfiniTime is made up of **screens**.
|
||||
Screens that are opened from the app launcher are considered **apps**.
|
||||
Apps are the things you can launch from the app selection you get by swiping up.
|
||||
At the moment, settings and even the app launcher itself or the clock are implemented very similarly, this might change in the future though.
|
||||
Every app in InfiniTime is it's own class.
|
||||
An instance of the class is created when the app is launched, and destroyed when the user exits the app.
|
||||
Apps run inside the "displayapp" task (briefly discussed [here](./Intro.md)).
|
||||
An instance of the class is created when the app is launched and destroyed when the user exits the app.
|
||||
They run inside the "displayapp" task (briefly discussed [here](./Intro.md)).
|
||||
Apps are responsible for everything drawn on the screen when they are running.
|
||||
By default, apps only do something (as in a function is executed) when they are created or when a touch event is detected.
|
||||
|
||||
|
@ -21,24 +20,30 @@ A destructor is needed to clean up LVGL and restore any changes (for example re-
|
|||
App classes can override `bool OnButtonPushed()`, `bool OnTouchEvent(TouchEvents event)` and `bool OnTouchEvent(uint16_t x, uint16_t y)` to implement their own functionality for those events.
|
||||
If an app only needs to display some text and do something upon a touch screen button press,
|
||||
it does not need to override any of these functions, as LVGL can also handle touch events for you.
|
||||
If you have any doubts, you can always look at how the other apps function for reference.
|
||||
If you have any doubts, you can always look at how the other apps are doing things.
|
||||
|
||||
### Continuous updating
|
||||
If your app needs to be updated continuously, you can do so by overriding the `Refresh()` function in your class
|
||||
If your app needs to be updated continuously, yo can do so by overriding the `Refresh()` function in your class
|
||||
and calling `lv_task_create` inside the constructor.
|
||||
|
||||
An example call could look like this:
|
||||
```cpp
|
||||
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
|
||||
```
|
||||
|
||||
An example call could look like this: <br>
|
||||
`taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);` <br>
|
||||
With `taskRefresh` being a member variable of your class and of type `lv_task_t*`.
|
||||
Remember to delete the task again using `lv_task_del`.
|
||||
The function `RefreshTaskCallback` is inherited from `Screen` and just calls your `Refresh` function.
|
||||
The function `RefreshTaskCallback` is inherited from screen and just calls your `Refresh` function.
|
||||
|
||||
### Apps with multiple screens
|
||||
InfiniTime provides a mini-library in [displayapp/screens/ScreenList.h](/src/displayapp/screens/ScreenList.h)
|
||||
which makes it relatively easy to add multiple screens to your app.
|
||||
To use it, #include it in the header file of your app and add a ScreenList member to your class.
|
||||
The template argument should be the number of screens you need.
|
||||
You will also need to add `CreateScreen` functions that return `std::unique_ptr<Screen>`
|
||||
to your class, one for every screen you have.
|
||||
There are still some things left to to that I won't cover here.
|
||||
To figure them out, have a look at the "apps" ApplicationList, Settings and SystemInfo.
|
||||
|
||||
|
||||
## Creating your own app
|
||||
A minimal app could look like this:
|
||||
|
||||
A minimal app could look like this: <br>
|
||||
MyApp.h:
|
||||
```cpp
|
||||
#pragma once
|
||||
|
@ -46,14 +51,14 @@ MyApp.h:
|
|||
#include "displayapp/screens/Screen.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace PineTime {
|
||||
namespace Applications {
|
||||
namespace Screens {
|
||||
class MyApp : public Screen {
|
||||
public:
|
||||
MyApp(DisplayApp* app);
|
||||
~MyApp() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,13 +66,13 @@ namespace Pinetime {
|
|||
|
||||
MyApp.cpp:
|
||||
```cpp
|
||||
#include "displayapp/screens/MyApp.h"
|
||||
#include "MyApp.h"
|
||||
#include "displayapp/DisplayApp.h"
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
MyApp::MyApp(DisplayApp* app) : Screen(app) {
|
||||
lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr);
|
||||
lv_obj_t* title = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text_static(title, "My test application");
|
||||
lv_label_set_align(title, LV_LABEL_ALIGN_CENTER);
|
||||
lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);
|
||||
|
@ -90,10 +95,12 @@ Now, go to the function `DisplayApp::LoadApp` and add another case to the switch
|
|||
The case will be the id you gave your app earlier.
|
||||
If your app needs any additional arguments, this is the place to pass them.
|
||||
|
||||
If you want to add your app in the app launcher, add your app in [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp) to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp).
|
||||
If you want your app to be launched from the regular app launcher, go to [displayapp/screens/ApplicationList.cpp](/src/displayapp/screens/ApplicationList.cpp).
|
||||
Add your app to one of the `CreateScreen` functions, or add another `CreateScreen` function if there are no empty spaces for your app. <br>
|
||||
If your app is a setting, do the same procedure in [displayapp/screens/settings/Settings.cpp](/src/displayapp/screens/settings/Settings.cpp).
|
||||
|
||||
You should now be able to [build](../buildAndProgram.md) the firmware
|
||||
and flash it to your PineTime. Yay!
|
||||
|
||||
Please remember to pay attention to the [UI guidelines](../ui_guidelines.md)
|
||||
when designing an app that you want to be included in InfiniTime.
|
||||
when designing an app that you want to include in mainstream InfiniTime.
|
||||
|
|
|
@ -21,12 +21,11 @@ Both functions are located inside [systemtask/SystemTask.cpp](/src/systemtask/Sy
|
|||
It also starts the **task "displayapp"**, which is responsible for launching and running apps, controlling the screen and handling touch events (or forwarding them to the active app).
|
||||
You can find the "displayapp" task inside [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp).
|
||||
There are also other tasks that are responsible for Bluetooth ("ll" and "ble" inside [libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c](/src/libs/mynewt-nimble/porting/npl/freertos/src/nimble_port_freertos.c))
|
||||
and periodic tasks like heartrate measurements ([heartratetask/HeartRateTask.cpp](/src/heartratetask/HeartRateTask.cpp)).
|
||||
|
||||
and periodic tasks like heartrate measurements ([heartratetask/HeartRateTask.cpp](/src/heartratetask/HeartRateTask.cpp)). <br>
|
||||
While it is possible for you to create your own task when you need it, it is recommended to just add functionality to `SystemTask::Work()` if possible.
|
||||
If you absolutely need to create another task, try to estimate how much [stack space](https://www.freertos.org/FAQMem.html#StackSize) (in words/4-byte packets)
|
||||
If you absolutely need to create another task, try to guess how much [stack space](https://www.freertos.org/FAQMem.html#StackSize) (in words/4-byte packets)
|
||||
it will need instead of just typing in a large-ish number.
|
||||
You can use `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
|
||||
You can use the define `configMINIMAL_STACK_SIZE` which is currently set to 120 words.
|
||||
|
||||
## Controllers
|
||||
Controllers in InfiniTime are singleton objects that can provide access to certain resources to apps.
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
# Coding convention
|
||||
|
||||
## Language
|
||||
|
||||
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
||||
|
||||
C code is accepted if it comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||
|
||||
## Coding style
|
||||
|
||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||
|
||||
Using an autoformatter is highly recommended, but make sure it's configured properly.
|
||||
|
||||
There are preconfigured autoformatter rules for:
|
||||
|
||||
* CLion (IntelliJ) in [.idea/codeStyles/Project.xml](/.idea/codeStyles/Project.xml)
|
||||
* `clang-format`
|
||||
|
||||
Also use `clang-tidy` to check the code for other issues.
|
||||
|
||||
If there are no preconfigured rules for your IDE, you can use one of the existing ones to configure your IDE.
|
||||
|
||||
- **Indentation** : 2 spaces, no tabulation
|
||||
- **Opening brace** at the end of the line
|
||||
- **Naming** : Choose self-describing variable name
|
||||
- **class** : PascalCase
|
||||
- **namespace** : PascalCase
|
||||
- **variable** : camelCase, **no** prefix/suffix ('_', 'm_',...) for class members
|
||||
- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`)
|
||||
- **Includes** :
|
||||
- files from the project : `#include "relative/path/to/the/file.h"`
|
||||
- external files and std : `#include <file.h>`
|
||||
- use includes relative to included directories like `src`, not relative to the current file. Don't do: `#include "../file.h"`
|
||||
- Only use [primary spellings for operators and tokens](https://en.cppreference.com/w/cpp/language/operator_alternative)
|
||||
- Use auto sparingly. Don't use auto for [fundamental/built-in types](https://en.cppreference.com/w/cpp/language/types) and [fixed width integer types](https://en.cppreference.com/w/cpp/types/integer), except when initializing with a cast to avoid duplicating the type name.
|
||||
- Examples:
|
||||
- `auto* app = static_cast<DisplayApp*>(instance);`
|
||||
- `auto number = static_cast<uint8_t>(variable);`
|
||||
- `uint8_t returnValue = MyFunction();`
|
||||
- Use nullptr instead of NULL
|
|
@ -0,0 +1,16 @@
|
|||
# Amazfish
|
||||
[Amazfish](https://openrepos.net/content/piggz/amazfish) is a companion app that supports many smartwatches and activity trackers running on [SailfishOS](https://sailfishos.org/).
|
||||
|
||||
## Features
|
||||
The following features are implemented:
|
||||
- Scanning & detection of Pinetime-JF / InfiniTime
|
||||
- Connection / disconnection
|
||||
- Time synchronization
|
||||
- Notifications
|
||||
- Music control
|
||||
- Navigation with Puremaps
|
||||
|
||||
## Demo
|
||||
[This video](https://seafile.codingfield.com/f/21c5d023452740279e36/) shows how to connect to the Pinetime and control the playback of the music on the phone.
|
||||
Amazfish and Sailfish OS are running on the [Pinephone](https://www.pine64.org/pinephone/), another awesome device from Pine64.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Integration with Gadgetbridge
|
||||
[Gadgetbridge](https://gadgetbridge.org/) is an Android application that supports many smartwatches and fitness trackers.
|
||||
|
||||
The integration of InfiniTime (previously Pinetime-JF) is now merged into the master branch (https://codeberg.org/Freeyourgadget/Gadgetbridge/) and initial support is available [starting with version 0.47](https://codeberg.org/Freeyourgadget/Gadgetbridge/src/branch/master/CHANGELOG.md). Note that the official version is only available on F-Droid (as of May 2021), and the unofficial fork available on the Play Store is outdated and does not support Infinitime.
|
||||
|
||||
## Features
|
||||
The following features are implemented:
|
||||
- Scanning & detection of Pinetime-JF / InfiniTime
|
||||
- Connection / disconnection
|
||||
- Notifications
|
||||
|
||||
## Demo
|
||||
[This video](https://seafile.codingfield.com/f/0a2920b9d765462385e4/) shows how to scan, connect, send notification (using the debug screen) and disconnect from the Pinetime.
|
|
@ -0,0 +1,12 @@
|
|||
# OTA using NRFConnect
|
||||
[NRFConnect](https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Connect-for-mobile) is a powerful application (running on Android and iOS) which allows to scan and connect to BLE devices.
|
||||
|
||||
## Features
|
||||
- Scanning, connect, disconnect
|
||||
- Time synchronization
|
||||
- OTA
|
||||
|
||||
InfiniTime implements the Nordic DFU protocol for the OTA functionality. NRFConnect also supports this protocol.
|
||||
|
||||
# Demo
|
||||
[This video](https://seafile.codingfield.com/f/a52b69683a05472a90c7/) shows how to use NRFConnect to update the firmware running on the Pinetime.
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 187 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
@ -14,6 +14,10 @@ As the documentation is part of the source code, you can submit your improvement
|
|||
|
||||
You want to fix a bug, add a cool new functionality or improve the code? See *How to submit a pull request below*.
|
||||
|
||||
## Spread the word
|
||||
|
||||
The Pinetime is a cool open source project that deserves to be known. Talk about it around you, on social networks, on your blog,... and let people know that we are working on an open source firmware for a smartwatch!
|
||||
|
||||
# How to submit a pull request?
|
||||
|
||||
## TL;DR
|
||||
|
@ -21,7 +25,7 @@ You want to fix a bug, add a cool new functionality or improve the code? See *Ho
|
|||
- Create a branch from develop
|
||||
- Work on a single subject in this branch. Create multiple branches/pulls-requests if you want to work on multiple subjects (bugs, features,...)
|
||||
- Test your modifications on the actual hardware
|
||||
- Check your code against the [coding conventions](/doc/coding-convention.md) and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy)
|
||||
- Check the code formatting against our coding conventions and [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy)
|
||||
- Clean your code and remove files that are not needed
|
||||
- Write documentation related to your new feature if applicable
|
||||
- Create a pull request and write a great description about it: what does your PR do, why, how,... Add pictures and video if possible
|
||||
|
@ -34,9 +38,9 @@ If you want to fix a bug, add functionality or improve the code, you'll first ne
|
|||
|
||||
When your feature branch is ready, **make sure it actually works** and **do not forget to write documentation** about it if it's relevant.
|
||||
|
||||
**Creating a pull request containing modifications that haven't been tested is strongly discouraged.** If for any reason you cannot test your modifications, but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code.
|
||||
**Creating a pull request containing modifications that haven't been tested is strongly discouraged.** If, for any reason, you cannot test your modifications but want to publish them anyway, **please mention it in the description**. This way, other contributors might be willing to test it and provide feedback about your code.
|
||||
|
||||
Before submitting a PR, check your code against the [coding conventions](/doc/coding-convention.md). This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You should use them to ensure correct formatting of your code.
|
||||
Also, before submitting your PR, check the coding style of your code against the **coding conventions** detailed below. This project also provides [clang-format](../.clang-format) and [clang-tidy](../.clang-tidy) configuration files. You can use them to ensure correct formatting of your code.
|
||||
|
||||
Don't forget to check the files you are going to commit and remove those which aren't necessary (config files from your IDE, for example). Remove old comments, commented code,...
|
||||
|
||||
|
@ -46,16 +50,47 @@ Other contributors can post comments about the pull request, maybe ask for more
|
|||
|
||||
Once the pull request is reviewed and accepted, it'll be merged into **develop** and will be released in the next version of the firmware.
|
||||
|
||||
## Why all these rules?
|
||||
## Why all these rules?
|
||||
|
||||
Reviewing pull requests is a **very time consuming task**. Everything you do to make reviewing easier will **get your PR merged faster**.
|
||||
Reviewing pull requests is a **very time consuming task** for the creator of this project ([JF002](https://github.com/JF002)) and for other contributors who take the time to review them. Everything you do to make reviewing easier will **get your PR merged faster**.
|
||||
|
||||
Reviewers will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context.
|
||||
When reviewing PRs, the author and contributors will first look at the **description**. If it's easy to understand what the PR does, why the modification is needed or interesting and how it's done, a good part of the work is already done : we understand the PR and its context.
|
||||
|
||||
Reviewing **a few files that were modified for a single purpose** is a lot easier than reviewing 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all the changes make sense. Also, it's possible that we agree on some modification but not on another, so we won't be able to merge the PR because of the changes that are not accepted.
|
||||
Then, reviewing **a few files that were modified for a single purpose** is a lot more easier than to review 30 files modified for many reasons (bug fix, UI improvements, typos in doc,...), even if all these changes make sense. Also, it's possible that we agree on some modification but not on some other, so we won't be able to merge the PR because of the changes that are not accepted.
|
||||
|
||||
The code base should be kept as consistent as possible. If the formatting of your code is not consistent with the rest of the code base, we'll ask you to review it.
|
||||
We do our best to keep the code as consistent as possible. If the formatting of the code in your PR is not consistent with our code base, we'll ask you to review it, which will take more time.
|
||||
|
||||
Lastly the changes are tested. If it doesn't work out of the box, we'll ask you to review your code and to ensure that it works as expected.
|
||||
The last step of the review consists of **testing** the modification. If it doesn't work out of the box, we'll ask your to review your code and to ensure that it works as expected.
|
||||
|
||||
It's totally normal for a PR to need some more work even after it was created, that's why we review them. But every round trip takes time, so it's good practice to try to reduce them as much as possible by following those simple rules.
|
||||
|
||||
# Coding convention
|
||||
|
||||
## Language
|
||||
|
||||
The language of this project is **C++**, and all new code must be written in C++. (Modern) C++ provides a lot of useful tools and functionalities that are beneficial for embedded software development like `constexpr`, `template` and anything that provides zero-cost abstraction.
|
||||
|
||||
C code is accepted if it comes from another library like FreeRTOS, NimBLE, LVGL or the NRF-SDK.
|
||||
|
||||
## Coding style
|
||||
|
||||
The most important rule to follow is to try to keep the code as easy to read and maintain as possible.
|
||||
|
||||
Using an autoformatter is highly recommended, but make sure it's configured properly.
|
||||
|
||||
There are preconfigured autoformatter rules for:
|
||||
|
||||
* CLion (IntelliJ) in .idea/codeStyles/Project.xml
|
||||
|
||||
If there are no preconfigured rules for your IDE, you can use one of the existing ones to configure your IDE.
|
||||
|
||||
- **Indentation** : 2 spaces, no tabulation
|
||||
- **Opening brace** at the end of the line
|
||||
- **Naming** : Choose self-describing variable name
|
||||
- **class** : PascalCase
|
||||
- **namespace** : PascalCase
|
||||
- **variable** : camelCase, **no** prefix/suffix ('_', 'm_',...) for class members
|
||||
- **Include guard** : `#pragma once` (no `#ifdef __MODULE__ / #define __MODULE__ / #endif`)
|
||||
- **Includes** :
|
||||
- files from the project : `#include "relative/path/to/the/file.h"`
|
||||
- external files and std : `#include <file.h>`
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
# Firmware, InfiniTime, Bootloader, Recovery firmware, OTA, DFU... What is it?
|
||||
|
||||
You may have already encountered these words by reading the announcement, release notes, or [the wiki guide](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0) and you may find them confusing if you're not familiar with the project.
|
||||
|
||||
A **firmware** is software running on the embedded hardware of a device.
|
||||
|
||||
InfiniTime has three distinct firmwares:
|
||||
|
||||
- **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** is the operating system.
|
||||
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying firmware updates and runs before booting into InfiniTime.
|
||||
- **The recovery firmware** is a special *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly.
|
||||
|
||||
**OTA** (**O**ver **T**he **A**ir) refers to updating of the firmware over BLE (**B**luetooth **L**ow **E**nergy). This is a functionality that allows the user to update the firmware on their device wirelessly.
|
||||
|
||||
**DFU** (**D**evice **F**irmware **U**pdate) is the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implements the (legacy) DFU protocol from Nordic Semiconductor (NRF).
|
||||
|
||||
## Bootloader
|
||||
|
||||
Most of the time, the bootloader just runs without your intervention (updating and loading the firmware).
|
||||
|
||||
However, you can use the bootloader to rollback to the previous firmware, or load the recovery firmware using the push button:
|
||||
|
||||
- Press and hold the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the current one.
|
||||
- Press and hold the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
|
||||
|
||||
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
|
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 156 KiB |
|
@ -1,57 +1,119 @@
|
|||
# Getting started with InfiniTime
|
||||
# Getting started with InfiniTime 1.0
|
||||
|
||||
On April 22 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as an *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime.
|
||||
On April 22 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime.
|
||||
|
||||
It is highly recommended to update the firmware to the latest version when you receive your watch and when a new InfiniTime version is released. More information on updating the firmware [here](/doc/gettingStarted/updating-software.md).
|
||||
## Firmware, InfiniTime, Bootloader, Recovery firmware, OTA, DFU... What is it?
|
||||
|
||||
## InfiniTime quick user guide
|
||||
You might have already seen these words by reading the announcement, release notes, or [the wiki guide](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0) and, you may find them misleading if you're not familiar with the project.
|
||||
|
||||
Basically, a **firmware** is just a software running on the embedded hardware of a device, the PineTime in this case.
|
||||
**InfiniTime** is based on 3 distinct **firmwares**:
|
||||
- **[InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime)** itself, this is the *application firmware* running on the PineTime. This is the main firmware which provides most of the functionalities you'll use on a daily basis : bluetooth low-energy (BLE) connectivity, applications, watchfaces,...
|
||||
- **[The bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader)** is responsible for safely applying **updates** of the *application firmware*, reverting them in case of issues and load the recovery firmware when requested.
|
||||
- **The recovery firmware** is a specific *application firmware* than can be loaded by the bootloader on user request. This firmware can be useful in case of serious issue, when the main application firmware cannot perform an OTA update correctly. Currently, this recovery firmware is based on [InfiniTime 0.14.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1).
|
||||
|
||||
**OTA** and **DFU** refer to the update of the firmware over BLE (**B**luetooth **L**ow **E**nergy). **OTA** means **O**ver **T**he **A**ir, this is a functionality that allows the user to update the firmware how their device using a wireless communication like BLE. When we talk about **DFU** (**D**igital **F**irmware **U**pdate), we refer to the file format and protocol used to send the update of the firmware to the watch over-the-air. InfiniTime implement the (legacy) DFU protocol from Nordic Semiconductor (NRF).
|
||||
|
||||
## How to check the version of InfiniTime and the bootloader?
|
||||
|
||||
Since September 2020, all PineTimes (devkits or sealed) are flashed using the **[first iteration of the bootloader](https://github.com/lupyuen/pinetime-rust-mynewt/releases/tag/v4.1.7)** and **[InfiniTime 0.7.1](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.7.1)**. There was no recovery firmware at that time.
|
||||
|
||||
The bootloader only runs when the watch starts (from an empty battery, for example) or after a reset (after a successful OTA or a manual reset - long push on the button).
|
||||
|
||||
You can recognize this first iteration of the bootloader with it greenish **PINETIME** logo.
|
||||
|
||||
![Old bootloader logo](oldbootloaderlogo.jpg)
|
||||
|
||||
You can check the version of InfiniTime by opening the app *SystemInfo*. For version < 1.0:
|
||||
|
||||
![InfiniTime 0.7.1 Application menu](appmenu-071.jpg)
|
||||
![InfiniTime 0.7.1 version](version-071.jpg)
|
||||
|
||||
And for version >= 1.0 :
|
||||
|
||||
![InfiniTime 1.0 version](version-1.0.jpg)
|
||||
|
||||
PineTime shipped from June 2021 (to be confirmed) will be flashed with the [new version of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0), the [recovery firmware](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1) and [InfiniTime 1.0](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/1.0.0).
|
||||
|
||||
The bootloader is easily recognizable with it white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
|
||||
|
||||
![Bootloader 1.0](bootloader-1.0.jpg)
|
||||
|
||||
## How to update your PineTime?
|
||||
|
||||
To update your PineTime, you can use one of the compatible companion applications. Here are the main ones:
|
||||
|
||||
- **[Amazfish](https://github.com/piggz/harbour-amazfish)** (Desktop Linux, mobile Linux, SailfishOS, runs on the PinebookPro and the Pinephone)
|
||||
- **[Gadgetbridge](https://www.gadgetbridge.org/)** (Android)
|
||||
- **[Siglo](https://github.com/alexr4535/siglo)** (Linux, GTK based)
|
||||
- **NRFConnect** (closed source, Android & iOS).
|
||||
|
||||
See [this page](ota-gadgetbridge-nrfconnect.md) for more info about the OTA procedure using Gadgetbridge and NRFConnect.
|
||||
|
||||
### From InfiniTime 0.7.1 / old bootloader
|
||||
|
||||
If your PineTime is currently running InfiniTime 0.7.1 and the old bootloader, we strongly recommend you update them to more recent version (Bootloader 1.0.0 and InfiniTime 1.0.0 as of now). We also recommend you install the recovery firmware once the bootloader is up-do-date.
|
||||
|
||||
Using the companion app of your choice, you'll need to apply the OTA procedure for these 3 firmwares in this sequence (failing to follow this specific order might temporarily or permanently brick your device):
|
||||
|
||||
1. Flash the latest version of InfiniTime. The file to upload is named **pinetime-mcuboot-app-dfu-x.y.z.zip**. Here is the link to [InfiniTime 1.0](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip).
|
||||
2. Update the bootloader by applying the OTA procedure with the file named [**reloader-mcuboot.zip** from the repo of the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/download/1.0.0/reloader-mcuboot.zip).
|
||||
3. Install the recovery firmware by applying the OTA procedure with the file named [**pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip** from the version 0.14.1 of InfiniTime](https://github.com/InfiniTimeOrg/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip).
|
||||
|
||||
You'll find more info about this process in [this wiki page](https://wiki.pine64.org/wiki/Upgrade_PineTime_to_InfiniTime_1.0.0). You can also see the procedure in video [here](https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529) and [here (from Amazfish)](https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e)
|
||||
|
||||
### From version > 1.0
|
||||
|
||||
If you are already running the new "1.0.0" bootloader, all you have to do is update your version of InfiniTime when it'll be available. We'll write specific instructions when (if) we release a new version of the bootloader.
|
||||
|
||||
### Firmware validation
|
||||
|
||||
The bootloader requires a (manual) validation of the firmware. If the watch reset with an updated firmware that was not validated, the bootloader will consider it as non-functioning and will revert to the previous version of the firmware. This is a safety feature to prevent bricking your device with a faulty firmware.
|
||||
|
||||
You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure:
|
||||
|
||||
- From the watchface, swipe **right** to display the *Quick Actions menu*
|
||||
- Open the **Settings** app by tapping the *gear* icon on the bottom right
|
||||
- Swipe down and tap on the entry named **Firmware**
|
||||
- This app shows the version that is currently running. If it's not validated yet, it displays 2 buttons:
|
||||
- **Validate** to validate your firmware
|
||||
- **Reset** to reset the watch and revert to the previously running version of the firmware
|
||||
|
||||
## InfiniTime 1.0 quick user guide
|
||||
|
||||
### Setting the time
|
||||
|
||||
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00).
|
||||
|
||||
You can sync the time using companion apps.
|
||||
|
||||
- Gadgetbridge automatically synchronizes the time when you connect it to your watch. More information on Gadgetbridge [here](/doc/gettingStarted/ota-gadgetbridge.md)
|
||||
- [Sync the time with NRFConnect](/doc/gettingStarted/time-nrfconnect.md)
|
||||
- Sync the time with your browser https://hubmartin.github.io/WebBLEWatch/
|
||||
|
||||
You can also set the time in the settings without a companion app. (version >1.7.0)
|
||||
|
||||
InfiniTime doesn't handle daylight savings automatically, so make sure to set the correct time or sync it with a companion app.
|
||||
|
||||
### Digital watch face
|
||||
|
||||
![Digital watch face](ui/watchface.jpg)
|
||||
|
||||
This is what the default digital watch face looks like. You can change watch faces in the settings.
|
||||
|
||||
The indicator on the top left is visible if you have unread notifications
|
||||
|
||||
On the top right there are status icons
|
||||
|
||||
- The battery icon shows roughly how much charge is remaining
|
||||
- The Bluetooth icon is visible when the watch is connected to a companion app
|
||||
- A plug icon is shown when the watch is plugged into a charger.
|
||||
|
||||
On the bottom left you can see your heart rate if you have the measurement enabled in the heart rate app.
|
||||
|
||||
On the bottom right you can see how many steps you have taken today.
|
||||
By default, InfiniTime starts on the digital watchface. It'll probably display the epoch time (1 Jan 1970, 00:00). The time will be automatically synchronized once you connect on of the companion app to your PineTime using BLE connectivity. InfiniTime does not provide any way to manually set the time for now.
|
||||
|
||||
### Navigation in the menu
|
||||
|
||||
![Application menu](ui/applist.jpg)
|
||||
![Notifications](ui/notifications.jpg)
|
||||
![Quick actions](ui/quicksettings.jpg)
|
||||
![Settings](ui/settings.jpg)
|
||||
![Quick actions](quickactions.jpg)
|
||||
![Settings](settings.jpg)
|
||||
![Application menu](appmenu.jpg)
|
||||
|
||||
- Swipe **down** to display the notification panel. Notification sent by your companion app will be displayed in this panel.
|
||||
- Swipe **up** to display the application menus. Apps (stopwatch, music, step, games,...) can be started from this menu.
|
||||
- Swipe **down** to display the notification panel. Notification sent by your companion app will be displayed here.
|
||||
- Swipe **right** to display the Quick Actions menu. This menu allows you to
|
||||
- Set the brightness of the display
|
||||
- Start the **flashlight** app
|
||||
- Enable/disable notifications (Do Not Disturb mode)
|
||||
- Enable/disable vibrations on notifications (Do Not Disturb mode)
|
||||
- Enter the **settings** menu
|
||||
- Swipe up and down to see all options
|
||||
- Click the button to go back a screen.
|
||||
- You can hold the button for a short time to return to the watch face. (version >1.7.0)
|
||||
- Settings
|
||||
- Display timeout
|
||||
- Wake up event (Tap, wrist rotation)
|
||||
- Time format (12/24H)
|
||||
- Default watchface (digital / analog)
|
||||
- Battery info
|
||||
- Firmware validation
|
||||
- About (system info, firmware version,...)
|
||||
|
||||
### Bootloader
|
||||
|
||||
Most of the time, the bootloader just runs without your intervention (update and load the firmware).
|
||||
|
||||
However, you can enable 2 functionalities using the push button:
|
||||
|
||||
- Push the button until the pine cone is drawn in **blue** to force the rollback of the previous version of the firmware, even if you've already validated the updated one
|
||||
- Push the button until the pine cone is drawn in **red** to load the recovery firmware. This recovery firmware only provides BLE connectivity and OTA functionality.
|
||||
|
||||
More info about the bootloader in [its project page](https://github.com/JF002/pinetime-mcuboot-bootloader/blob/master/README.md).
|
||||
|
|
After Width: | Height: | Size: 114 KiB |
|
@ -0,0 +1,109 @@
|
|||
# Flash and upgrade InfiniTime
|
||||
If you just want to flash or upgrade InfiniTime on your PineTime, this page is for you!
|
||||
|
||||
- [InfiniTime releases and versions](#infinitime-releases-and-versions)
|
||||
- [How to upgrade Over-The-Air (OTA)](#how-to-upgrade-over-the-air-ota)
|
||||
- [Using Gadgetbridge](#using-gadgetbridge)
|
||||
- [Using NRFConnect](#Using-nrfconnect)
|
||||
- [How to flash InfiniTime using the SWD interface](#how-to-flash-infinitime-using-the-swd-interface)
|
||||
|
||||
## InfiniTime releases and versions
|
||||
All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/InfiniTimeOrg/InfiniTime/releases).
|
||||
|
||||
Versions that are tagged as **RELEASE CANDIDATE** are pre-release versions, that are available for testing before actually releasing a new stable version. If you want to help us debug the project and provide stable versions to other user, you can use them. If you want stable and tested version, you should not flash these release candidate version.
|
||||
|
||||
Release files are available under the *Assets* button.
|
||||
|
||||
## How to upgrade Over-The-Air (OTA)
|
||||
OTA is the easiest method to upgrade InfiniTime. Note that it's only possible is your PineTime is already running InfiniTime (>= 0.7.1).
|
||||
|
||||
2 companion apps provide support for OTA :
|
||||
- [Gadgetbridge](https://gadgetbridge.org/) (open source, runs on Android, [available on F-Droid](https://f-droid.org/packages/nodomain.freeyourgadget.gadgetbridge/)).
|
||||
- [NRFConnect](https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Connect-for-mobile) (close source, runs on Android and iOS).
|
||||
|
||||
Both applications need you to download the **DFU file** of InfiniTime. This file contains the new version of InfiniTime that will be flashed into your device. It's called **dfu-x.y.z.zip** (ex: dfu-0.9.0.zip) in the release note.
|
||||
![Dfu file](dfuFile.png )
|
||||
|
||||
### Using Gadgetbridge
|
||||
Launch Gadgetbridge and tap on the **"+"** button on the bottom right to add a new device:
|
||||
|
||||
![Gadgetbridge 0](gadgetbridge0.jpg)
|
||||
|
||||
Wait for the scan to complete, your PineTime should be detected:
|
||||
|
||||
![Gadgetbridge 1](gadgetbridge1.jpg)
|
||||
|
||||
Tap on it. Gadgdetbridge will pair and connect to your device:
|
||||
|
||||
![Gadgetbridge 2](gadgetbridge2.jpg)
|
||||
|
||||
Now that Gadgetbridge is connected to your PineTime, use a file browser application (I'm using Seafile to browse my NAS) and browse to the DFU file (image-xxx.zip) you downloaded previously. Tap on it and open it using the Gadgetbridge application/firmware installer:
|
||||
|
||||
![Gadgetbridge 3](gadgetbridge3.jpg)
|
||||
|
||||
Read carefully the warning and tap **Install**:
|
||||
|
||||
![Gadgetbridge 4](gadgetbridge4.jpg)
|
||||
|
||||
Wait for the transfer to finish. Your PineTime should reset and reboot with the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![Gadgetbridge 5](gadgetbridge5.jpg)
|
||||
|
||||
### Using NRFConnect
|
||||
Open NRFConnect. Swipe down in the *Scanner* tab and wait for your device to appear:
|
||||
|
||||
![NRFConnect 0](nrfconnect0.jpg)
|
||||
|
||||
Tap on the *Connect* button on the right of your device. NRFConnect will connect to your PineTime and discover its characteristics. Tap on the **DFU** button on the top right:
|
||||
|
||||
![NRFConnect 1](nrfconnect1.jpg)
|
||||
|
||||
Select **Distribution packet (ZIP)**:
|
||||
|
||||
![NRFConnect 2](nrfconnect2.jpg)
|
||||
|
||||
Browse to the DFU file you downloaded previously, the DFU transfer will start automatically. When the transfer is finished, your PineTime will reset and restart on the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![NRFConnect 3](nrfconnect3.jpg)
|
||||
|
||||
## How to flash InfiniTime using the SWD interface
|
||||
Download the files **bootloader.bin**, **image-x.y.z.bin** and **pinetime-graphics-x.y.z.bin** from the release page:
|
||||
|
||||
![Image file](imageFile.png )
|
||||
|
||||
The bootloader reads a boot logo from the external SPI flash memory. The first step consists in flashing a tool in the MCU that will flash the boot logo into this SPI flash memory. This first step is optional but recommanded (the bootloader will display garbage on screen for a few second if you don't do it).
|
||||
Using your SWD tool, flash **pinetime-graphics-x.y.z.bin** at offset **0x0000**. Reset the MCU and wait for a few second, until the logo is completely drawn on the display.
|
||||
|
||||
Then, using your SWD tool, flash those file at specific offset:
|
||||
|
||||
- bootloader.bin : **0x0000**
|
||||
- image-x.y.z.bin : **0x8000**
|
||||
|
||||
Reset and voilà, you're running InfiniTime on your PineTime!
|
||||
|
||||
If you are using OpenOCD with a STLinkV2, you can find more info [on this page](../openOCD.md).
|
||||
|
||||
## How to synchronize the time
|
||||
|
||||
### Using Gadgetbridge
|
||||
Good news! Gadgetbridge **automatically** synchronizes the time when connecting to your PineTime!
|
||||
|
||||
### Using any Chromium-based web browser
|
||||
You can use it from your PC, Mac, Android. Browsers now have BLE support.
|
||||
https://hubmartin.github.io/WebBLEWatch/
|
||||
|
||||
### Using NRFConnect
|
||||
You must enable the **CTS** *GATT server* into NRFConnect so that InfiniTime can synchronize the time with your smartphone.
|
||||
|
||||
Launch NRFConnect, tap the sandwich button on the top left and select *Configure GATT server*:
|
||||
|
||||
![NRFConnect CTS 0](nrfconnectcts0.jpg)
|
||||
|
||||
|
||||
Tap *Add service* and select the server configuration *Current Time service*. Tap OK and connect to your PineTime, it should automcatically sync the time once the connection is established!
|
||||
|
||||
![NRFConnect CTS 1](nrfconnectcts1.jpg)
|
|
@ -1,29 +0,0 @@
|
|||
# Connecting to Gadgetbridge
|
||||
|
||||
Launch Gadgetbridge and tap on the **"+"** button on the bottom right to add a new device:
|
||||
|
||||
![Gadgetbridge 0](gadgetbridge0.jpg)
|
||||
|
||||
Wait for the scan to complete, your PineTime should be detected:
|
||||
|
||||
![Gadgetbridge 1](gadgetbridge1.jpg)
|
||||
|
||||
Tap on it. Gadgdetbridge will pair and connect to your device:
|
||||
|
||||
![Gadgetbridge 2](gadgetbridge2.jpg)
|
||||
|
||||
# Updating with Gadgetbridge
|
||||
|
||||
Now that Gadgetbridge is connected to your PineTime, use a file browser application and find the DFU file (`pinetime-mcuboot-app-dfu-x.x.x.zip`) you downloaded previously. Tap on it and open it using the Gadgetbridge application/firmware installer:
|
||||
|
||||
![Gadgetbridge 3](gadgetbridge3.jpg)
|
||||
|
||||
Read the warning carefully and tap **Install**:
|
||||
|
||||
![Gadgetbridge 4](gadgetbridge4.jpg)
|
||||
|
||||
Wait for the transfer to finish. Your PineTime should reset and reboot with the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![Gadgetbridge 5](gadgetbridge5.jpg)
|
|
@ -1,22 +0,0 @@
|
|||
# Updating with NRFConnect
|
||||
|
||||
Open NRFConnect. Swipe down in the *Scanner* tab and wait for your device to appear:
|
||||
|
||||
![NRFConnect 0](nrfconnect0.jpg)
|
||||
|
||||
Tap on the *Connect* button on the right of your device. NRFConnect will connect to your PineTime and discover its characteristics. Tap on the **DFU** button on the top right:
|
||||
|
||||
![NRFConnect 1](nrfconnect1.jpg)
|
||||
|
||||
Select **Distribution packet (ZIP)**:
|
||||
|
||||
![NRFConnect 2](nrfconnect2.jpg)
|
||||
|
||||
Find the DFU file (`pinetime-mcuboot-app-dfu-x.x.x.zip`) you downloaded previously, the DFU transfer will start automatically. When the transfer is finished, your PineTime will reset and restart on the new version of InfiniTime!
|
||||
|
||||
Don't forget to **validate** your firmware. In the InfiniTime go to the settings (swipe right, select gear icon) and Firmware option and click **validate**. Otherwise after reboot the previous firmware will be used.
|
||||
|
||||
![NRFConnect 3](nrfconnect3.jpg)
|
||||
|
||||
# Demo
|
||||
[This video](https://seafile.codingfield.com/f/a52b69683a05472a90c7/) shows how to use NRFConnect to update the firmware running on the Pinetime.
|
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 127 KiB |
|
@ -1,11 +0,0 @@
|
|||
### Syncing time
|
||||
|
||||
You must enable the **CTS** *GATT server* in NRFConnect so that InfiniTime can synchronize the time with your smartphone.
|
||||
|
||||
Launch NRFConnect, tap the sandwich button on the top left and select *Configure GATT server*:
|
||||
|
||||
![NRFConnect CTS 0](nrfconnectcts0.jpg)
|
||||
|
||||
Tap *Add service* and select the server configuration *Current Time service*. Tap OK and connect to your PineTime, it should automcatically sync the time once the connection is established!
|
||||
|
||||
![NRFConnect CTS 1](nrfconnectcts1.jpg)
|
Before Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 135 KiB |
Before Width: | Height: | Size: 101 KiB |
|
@ -1,41 +0,0 @@
|
|||
# Updating InfiniTime
|
||||
|
||||
If you just want to flash or upgrade InfiniTime on your PineTime, this page is for you! If you want more information about the software and the update procedure, check out [this](/doc/gettingStarted/about-software.md) page.
|
||||
|
||||
## Checking the version of InfiniTime
|
||||
|
||||
You can check the InfiniTime version by first swiping right on the watchface to open quick settings, tapping the cogwheel to open settings, swipe up until you find an entry named "About" and tap on it.
|
||||
|
||||
![InfiniTime 1.0 version](version-1.0.jpg)
|
||||
|
||||
PineTimes shipped after June 2021 will ship with the latest version of [the bootloader](https://github.com/JF002/pinetime-mcuboot-bootloader/releases/tag/1.0.0) and [recovery firmware](https://github.com/InfiniTimeOrg/InfiniTime/releases/tag/0.14.1)
|
||||
|
||||
The bootloader is run right before booting into InfiniTime. It is easily recognizable with its white pine cone that is progressively drawn in green. It also displays its own version on the bottom (1.0.0 as of now).
|
||||
|
||||
![Bootloader 1.0](bootloader-1.0.jpg)
|
||||
|
||||
## Updating with companion apps
|
||||
|
||||
To update your PineTime, you can use one of the [compatible companion applications](/README.md#companion-apps).
|
||||
|
||||
The updating process differs slightly on every companion app, so you'll need to familiarize yourself with the companion app of your choice.
|
||||
|
||||
All releases of InfiniTime are available on the [release page of the GitHub repo](https://github.com/InfiniTimeOrg/InfiniTime/releases) under assets.
|
||||
|
||||
To update the firmware, you need to download the DFU of the firmware version that you'd like to install, for example `pinetime-mcuboot-app-dfu-1.6.0.zip`, and flash it with your companion app.
|
||||
|
||||
We have prepared instructions for flashing InfiniTime with Gadgetbridge and NRFConnect.
|
||||
|
||||
- [Updating with Gadgetbridge](/doc/gettingStarted/ota-gadgetbridge.md)
|
||||
- [Updating with NRFConnect](/doc/gettingStarted/ota-nrfconnect.md)
|
||||
|
||||
## Firmware validation
|
||||
|
||||
Firmware updates must be manually validated. If the firmware isn't validated and the watch resets, the watch will revert to the previous firmware. This is a safety feature to prevent bricking your device with faulty firmware.
|
||||
|
||||
You can validate your updated firmware on InfiniTime >= 1.0 by following this simple procedure:
|
||||
|
||||
- From the watchface, swipe **right** to display the *quick settings menu*
|
||||
- Open settings by tapping the cogwheel on the bottom right
|
||||
- Swipe up until you find an entry named **Firmware** and tap on it
|
||||
- If the firmware is not validated yet, you can either validate the running firmware, or reset and revert to the previous firmware version
|
After Width: | Height: | Size: 109 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 114 KiB |
|
@ -1,12 +1,12 @@
|
|||
# OpenOCD and STLink
|
||||
OpenOCD (**Open O**n **C**hip **D**ebugger) is an open source tool that interfaces with many SWD/JTAG debugger to provide debugging and *in-system* programming for embedded target devices.
|
||||
|
||||
OpenOCD supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
|
||||
It supports the **NRF52** (the CPU of the PineTime) and the **STLinkV2**, a cheap SWD debugger.
|
||||
|
||||
OpenOCD works on X86 computers, ARM/ARM64 computers, and SBCs (like the RaspberryPi and Pine64 Pinebook Pro)!
|
||||
It works on X86 computers, as well as ARM/ARM64 computers and SBC (like the RaspberryPi and Pine64 Pinebook Pro) !
|
||||
|
||||
## Installation
|
||||
We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 properly.
|
||||
We will build OpenOCD from sources, as packages from Linux distributions are most of the time outdated and do not support the NRF52 correctly.
|
||||
|
||||
- Fetch the sources from GIT, and build and install it:
|
||||
|
||||
|
@ -27,7 +27,7 @@ sudo cp contrib/60-openocd.rules /etc/udev/rules.d/
|
|||
sudo udevadm control --reload-rules
|
||||
```
|
||||
|
||||
- You can now plug your STLinkV2 into a USB port and run OpenOCD to see if it's working correctly:
|
||||
- You can now plug your STLinkV2 in a USB port and run OpenOCD to see if it's working correctly:
|
||||
|
||||
```
|
||||
$ openocd -f interface/stlink.cfg -f target/nrf52.cfg
|
||||
|
@ -63,7 +63,7 @@ gdb_breakpoint_override hard
|
|||
|
||||
source [find target/nrf52.cfg]
|
||||
```
|
||||
This file specifies to OpenOCD which debugger and target it will be connected to.
|
||||
This file specifies to OpenOCD which debugger and target it will be connected to..
|
||||
|
||||
Then, we use various *user files* to use OpenOCD to flash InfiniTime binary files.
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
- Buttons should generally be at least 50px high
|
||||
- Buttons should generally be on the bottom edge
|
||||
- Make interactable objects **big**
|
||||
- Recommendations for inner padding, aka distance between buttons:
|
||||
- When aligning 4 objects: 4px, e.g. Settings
|
||||
- When aligning 3 objects: 6px, e.g. App list
|
||||
- When aligning 2 objects: 10px, e.g. Quick settings
|
||||
- When using a page indicator, leave 8px for it on the right side
|
||||
- It is acceptable to leave 8px on the left side as well to center the content
|
||||
- Top bar takes at least 20px + padding
|
||||
- Top bar right icons move 8px to the left when using a page indicator
|
||||
- A black background helps to hide the screen border, allowing the UI to look less cramped when utilizing the entire display area.
|
||||
- A switch should be twice as wide as it is tall.
|
||||
|
||||
![example layouts](./ui/example.png)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Versioning
|
||||
The versioning of this project is based on [Semantic versioning](https://semver.org/):
|
||||
The versioning of this project is based on [Semantic versionning](https://semver.org/) :
|
||||
|
||||
- The **patch** is incremented when a bug is fixed on a **released** version (most of the time using a **hotfix** branch).
|
||||
- The **minor** is incremented when a new version with new features is released. It corresponds to a merge of **develop** into **master**.
|
||||
- The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project.
|
||||
- The **patch** is incremented when we fix a bug on a **released** version (most of the time using a **hotfix** branch).
|
||||
- The **minor** is incremented when we release a new version with new features. It corresponds to a merge of **develop** into **master**.
|
||||
- The **major** should be incremented when a breaking change is made to the application. We still have to define what is a breaking change in the context of this project. For now, I suggest that it stays **0** until we have a fully functioning firmware suited for the final user.
|
|
@ -1,4 +1,4 @@
|
|||
FROM ubuntu:22.04
|
||||
FROM ubuntu:18.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update -qq \
|
||||
|
@ -11,27 +11,21 @@ RUN apt-get update -qq \
|
|||
make \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python-is-python3 \
|
||||
tar \
|
||||
unzip \
|
||||
wget \
|
||||
curl \
|
||||
# aarch64 packages
|
||||
wget \
|
||||
# aarch64 packages
|
||||
libffi-dev \
|
||||
libssl-dev \
|
||||
python3-dev \
|
||||
python \
|
||||
git \
|
||||
apt-utils \
|
||||
&& curl -sL https://deb.nodesource.com/setup_18.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& rm -rf /var/cache/apt/* /var/lib/apt/lists/*;
|
||||
|
||||
# Git needed for PROJECT_GIT_COMMIT_HASH variable setting
|
||||
|
||||
RUN pip3 install adafruit-nrfutil
|
||||
RUN pip3 install -Iv cryptography==3.3
|
||||
RUN pip3 install cbor
|
||||
RUN npm i lv_font_conv@1.5.2 -g
|
||||
|
||||
# build.sh knows how to compile
|
||||
COPY build.sh /opt/
|
||||
|
@ -44,5 +38,10 @@ RUN bash -c "source /opt/build.sh; GetNrfSdk;"
|
|||
# McuBoot
|
||||
RUN bash -c "source /opt/build.sh; GetMcuBoot;"
|
||||
|
||||
ARG PUID=1000
|
||||
ARG PGID=1000
|
||||
RUN groupadd --system --gid $PGID infinitime && useradd --system --uid $PUID --gid $PGID infinitime
|
||||
|
||||
USER infinitime:infinitime
|
||||
ENV SOURCES_DIR /sources
|
||||
CMD ["/opt/build.sh"]
|
||||
|
|
|
@ -9,23 +9,21 @@ set -e
|
|||
export TOOLS_DIR="${TOOLS_DIR:=/opt}"
|
||||
export SOURCES_DIR="${SOURCES_DIR:=/sources}"
|
||||
export BUILD_DIR="${BUILD_DIR:=$SOURCES_DIR/build}"
|
||||
export OUTPUT_DIR="${OUTPUT_DIR:=$SOURCES_DIR/build/output}"
|
||||
export OUTPUT_DIR="${OUTPUT_DIR:=$BUILD_DIR/output}"
|
||||
|
||||
export BUILD_TYPE=${BUILD_TYPE:=Release}
|
||||
export GCC_ARM_VER=${GCC_ARM_VER:="11.2-2022.02"}
|
||||
export GCC_ARM_VER=${GCC_ARM_VER:="gcc-arm-none-eabi-9-2020-q2-update"}
|
||||
export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"}
|
||||
|
||||
MACHINE="$(uname -m)"
|
||||
[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64"
|
||||
|
||||
export GCC_ARM_PATH="gcc-arm-$GCC_ARM_VER-$MACHINE-arm-none-eabi"
|
||||
|
||||
main() {
|
||||
local target="$1"
|
||||
|
||||
mkdir -p "$TOOLS_DIR"
|
||||
|
||||
[[ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ]] && GetGcc
|
||||
|
||||
[[ ! -d "$TOOLS_DIR/$GCC_ARM_VER" ]] && GetGcc
|
||||
[[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk
|
||||
[[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot
|
||||
|
||||
|
@ -33,14 +31,15 @@ main() {
|
|||
|
||||
CmakeGenerate
|
||||
CmakeBuild $target
|
||||
BUILD_RESULT=$?
|
||||
BUILD_RESULT=$?
|
||||
if [ "$DISABLE_POSTBUILD" != "true" -a "$BUILD_RESULT" == 0 ]; then
|
||||
source "$BUILD_DIR/post_build.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
GetGcc() {
|
||||
wget -q https://developer.arm.com/-/media/Files/downloads/gnu/$GCC_ARM_VER/binrel/$GCC_ARM_PATH.tar.xz -O - | tar -xJ -C $TOOLS_DIR/
|
||||
GCC_SRC="$GCC_ARM_VER-$MACHINE-linux.tar.bz"
|
||||
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/$GCC_SRC -O - | tar -xj -C $TOOLS_DIR/
|
||||
}
|
||||
|
||||
GetMcuBoot() {
|
||||
|
@ -55,14 +54,18 @@ GetNrfSdk() {
|
|||
}
|
||||
|
||||
CmakeGenerate() {
|
||||
# We can swap the CD and trailing SOURCES_DIR for -B and -S respectively
|
||||
# once we go to newer CMake (Ubuntu 18.10 gives us CMake 3.10)
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
cmake -G "Unix Makefiles" \
|
||||
-S "$SOURCES_DIR" \
|
||||
-B "$BUILD_DIR" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DUSE_OPENOCD=1 \
|
||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_PATH" \
|
||||
-DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_VER" \
|
||||
-DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \
|
||||
-DBUILD_DFU=1
|
||||
-DBUILD_DFU=1 \
|
||||
"$SOURCES_DIR"
|
||||
cmake -L -N .
|
||||
}
|
||||
|
||||
CmakeBuild() {
|
||||
|
@ -73,4 +76,4 @@ CmakeBuild() {
|
|||
fi
|
||||
}
|
||||
|
||||
[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!"
|
||||
[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!"
|
|
@ -15,10 +15,12 @@ cp "$BUILD_DIR/src/pinetime-mcuboot-app-dfu-$PROJECT_VERSION.zip" "$OUTPUT_DIR/p
|
|||
cp "$BUILD_DIR/src/pinetime-mcuboot-recovery-loader-image-$PROJECT_VERSION.bin" "$OUTPUT_DIR/pinetime-mcuboot-recovery-loader-image-$PROJECT_VERSION.bin"
|
||||
cp "$BUILD_DIR/src/pinetime-mcuboot-recovery-loader-dfu-$PROJECT_VERSION.zip" "$OUTPUT_DIR/pinetime-mcuboot-recovery-loader-dfu-$PROJECT_VERSION.zip"
|
||||
|
||||
|
||||
mkdir -p "$OUTPUT_DIR/src"
|
||||
cp $BUILD_DIR/src/*.bin "$OUTPUT_DIR/src/"
|
||||
cp $BUILD_DIR/src/*.hex "$OUTPUT_DIR/src/"
|
||||
cp $BUILD_DIR/src/*.out "$OUTPUT_DIR/src/"
|
||||
cp $BUILD_DIR/src/*.map "$OUTPUT_DIR/src/"
|
||||
cd "$BUILD_DIR"
|
||||
cp src/*.bin "$OUTPUT_DIR/src"
|
||||
cp src/*.hex "$OUTPUT_DIR/src"
|
||||
cp src/*.out "$OUTPUT_DIR/src"
|
||||
cp src/*.map "$OUTPUT_DIR/src"
|
||||
|
||||
ls -RUv1 "$OUTPUT_DIR" | sed 's;^\([^/]\); \1;g'
|
After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 31 KiB |
|
@ -13659,12 +13659,12 @@ POSSIBILITY OF SUCH DAMAGE.\n
|
|||
<usage>read</usage>
|
||||
<enumeratedValue>
|
||||
<name>NotPresent</name>
|
||||
<description>Read: no overrun occurred</description>
|
||||
<description>Read: no overrun occured</description>
|
||||
<value>0</value>
|
||||
</enumeratedValue>
|
||||
<enumeratedValue>
|
||||
<name>Present</name>
|
||||
<description>Read: overrun occurred</description>
|
||||
<description>Read: overrun occured</description>
|
||||
<value>1</value>
|
||||
</enumeratedValue>
|
||||
</enumeratedValues>
|
||||
|
|
|
@ -31,10 +31,6 @@ const bool BootloaderVersion::IsValid() {
|
|||
|
||||
void BootloaderVersion::SetVersion(uint32_t v) {
|
||||
BootloaderVersion::version = v;
|
||||
snprintf(BootloaderVersion::versionString,
|
||||
BootloaderVersion::VERSION_STR_LEN,
|
||||
"%ld.%ld.%ld",
|
||||
BootloaderVersion::Major(),
|
||||
BootloaderVersion::Minor(),
|
||||
BootloaderVersion::Patch());
|
||||
snprintf(BootloaderVersion::versionString, BootloaderVersion::VERSION_STR_LEN, "%ld.%ld.%ld",
|
||||
BootloaderVersion::Major(), BootloaderVersion::Minor(), BootloaderVersion::Patch());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Pinetime {
|
||||
class BootloaderVersion {
|
||||
public:
|
||||
|
@ -12,7 +9,6 @@ namespace Pinetime {
|
|||
static const char* VersionString();
|
||||
static const bool IsValid();
|
||||
static void SetVersion(uint32_t v);
|
||||
|
||||
private:
|
||||
static uint32_t version;
|
||||
static constexpr size_t VERSION_STR_LEN = 12;
|
||||
|
|
|
@ -42,6 +42,7 @@ set(SDK_SOURCE_FILES
|
|||
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_gpiote.c"
|
||||
"${NRF5_SDK_PATH}/modules/nrfx/soc/nrfx_atomic.c"
|
||||
"${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_saadc.c"
|
||||
"${NRF5_SDK_PATH}/components/libraries/timer/app_timer.h"
|
||||
|
||||
# FreeRTOS
|
||||
${NRF5_SDK_PATH}/external/freertos/source/croutine.c
|
||||
|
@ -52,6 +53,7 @@ set(SDK_SOURCE_FILES
|
|||
${NRF5_SDK_PATH}/external/freertos/source/stream_buffer.c
|
||||
${NRF5_SDK_PATH}/external/freertos/source/tasks.c
|
||||
${NRF5_SDK_PATH}/external/freertos/source/timers.c
|
||||
${NRF5_SDK_PATH}/components/libraries/timer/app_timer_freertos.c
|
||||
|
||||
# Libs
|
||||
"${NRF5_SDK_PATH}/components/libraries/atomic/nrf_atomic.c"
|
||||
|
@ -152,7 +154,6 @@ set(NIMBLE_SRC
|
|||
libs/mynewt-nimble/nimble/controller/src/ble_ll_supp_cmd.c
|
||||
libs/mynewt-nimble/nimble/controller/src/ble_ll_hci_ev.c
|
||||
libs/mynewt-nimble/nimble/controller/src/ble_ll_rfmgmt.c
|
||||
libs/mynewt-nimble/nimble/controller/src/ble_ll_resolv.c
|
||||
libs/mynewt-nimble/porting/nimble/src/os_cputime.c
|
||||
libs/mynewt-nimble/porting/nimble/src/os_cputime_pwr2.c
|
||||
libs/mynewt-nimble/porting/nimble/src/os_mbuf.c
|
||||
|
@ -356,17 +357,37 @@ set(LVGL_SRC
|
|||
libs/lvgl/src/lv_widgets/lv_win.c
|
||||
)
|
||||
|
||||
set(QCBOR_SRC
|
||||
libs/QCBOR/src/ieee754.c
|
||||
libs/QCBOR/src/qcbor_decode.c
|
||||
libs/QCBOR/src/qcbor_encode.c
|
||||
libs/QCBOR/src/qcbor_err_to_str.c
|
||||
libs/QCBOR/src/UsefulBuf.c
|
||||
list(APPEND IMAGE_FILES
|
||||
displayapp/icons/battery/os_battery_error.c
|
||||
displayapp/icons/battery/os_battery_100.c
|
||||
displayapp/icons/battery/os_battery_090.c
|
||||
displayapp/icons/battery/os_battery_080.c
|
||||
displayapp/icons/battery/os_battery_070.c
|
||||
displayapp/icons/battery/os_battery_060.c
|
||||
displayapp/icons/battery/os_battery_050.c
|
||||
displayapp/icons/battery/os_battery_040.c
|
||||
displayapp/icons/battery/os_battery_030.c
|
||||
displayapp/icons/battery/os_battery_020.c
|
||||
displayapp/icons/battery/os_battery_010.c
|
||||
displayapp/icons/battery/os_battery_005.c
|
||||
|
||||
displayapp/icons/battery/os_batterycharging_100.c
|
||||
displayapp/icons/battery/os_batterycharging_090.c
|
||||
displayapp/icons/battery/os_batterycharging_080.c
|
||||
displayapp/icons/battery/os_batterycharging_070.c
|
||||
displayapp/icons/battery/os_batterycharging_060.c
|
||||
displayapp/icons/battery/os_batterycharging_050.c
|
||||
displayapp/icons/battery/os_batterycharging_040.c
|
||||
displayapp/icons/battery/os_batterycharging_030.c
|
||||
displayapp/icons/battery/os_batterycharging_020.c
|
||||
displayapp/icons/battery/os_batterycharging_010.c
|
||||
displayapp/icons/battery/os_batterycharging_005.c
|
||||
|
||||
displayapp/icons/bluetooth/os_bt_connected.c
|
||||
displayapp/icons/bluetooth/os_bt_disconnected.c
|
||||
|
||||
)
|
||||
|
||||
list(APPEND IMAGE_FILES
|
||||
displayapp/icons/battery/batteryicon.c
|
||||
)
|
||||
list(APPEND SOURCE_FILES
|
||||
BootloaderVersion.cpp
|
||||
logging/NrfLogger.cpp
|
||||
|
@ -374,17 +395,18 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/Screen.cpp
|
||||
displayapp/screens/Clock.cpp
|
||||
displayapp/screens/Tile.cpp
|
||||
displayapp/screens/Meter.cpp
|
||||
displayapp/screens/InfiniPaint.cpp
|
||||
displayapp/screens/Paddle.cpp
|
||||
displayapp/screens/StopWatch.cpp
|
||||
displayapp/screens/BatteryIcon.cpp
|
||||
displayapp/screens/BleIcon.cpp
|
||||
displayapp/screens/NotificationIcon.cpp
|
||||
displayapp/screens/Brightness.cpp
|
||||
displayapp/screens/SystemInfo.cpp
|
||||
displayapp/screens/Label.cpp
|
||||
displayapp/screens/FirmwareUpdate.cpp
|
||||
displayapp/screens/Music.cpp
|
||||
displayapp/screens/Weather.cpp
|
||||
displayapp/screens/Navigation.cpp
|
||||
displayapp/screens/Metronome.cpp
|
||||
displayapp/screens/Motion.cpp
|
||||
|
@ -399,13 +421,9 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/BatteryInfo.cpp
|
||||
displayapp/screens/Steps.cpp
|
||||
displayapp/screens/Timer.cpp
|
||||
displayapp/screens/PassKey.cpp
|
||||
displayapp/screens/Error.cpp
|
||||
displayapp/screens/Alarm.cpp
|
||||
displayapp/screens/Styles.cpp
|
||||
displayapp/screens/Agenda.cpp
|
||||
displayapp/Colors.cpp
|
||||
displayapp/widgets/Counter.cpp
|
||||
|
||||
## Settings
|
||||
displayapp/screens/settings/QuickSettings.cpp
|
||||
|
@ -415,18 +433,15 @@ list(APPEND SOURCE_FILES
|
|||
displayapp/screens/settings/SettingWakeUp.cpp
|
||||
displayapp/screens/settings/SettingDisplay.cpp
|
||||
displayapp/screens/settings/SettingSteps.cpp
|
||||
displayapp/screens/settings/SettingPineTimeStyle.cpp
|
||||
displayapp/screens/settings/SettingSetDate.cpp
|
||||
displayapp/screens/settings/SettingSetTime.cpp
|
||||
displayapp/screens/settings/SettingChimes.cpp
|
||||
displayapp/screens/settings/SettingShakeThreshold.cpp
|
||||
displayapp/screens/settings/SettingBluetooth.cpp
|
||||
|
||||
## Watch faces
|
||||
displayapp/icons/bg_clock.c
|
||||
displayapp/screens/WatchFaceAnalog.cpp
|
||||
displayapp/screens/WatchFaceDigital.cpp
|
||||
displayapp/screens/WatchFaceTerminal.cpp
|
||||
displayapp/screens/WatchFacePineTimeStyle.cpp
|
||||
displayapp/screens/PineTimeStyle.cpp
|
||||
|
||||
##
|
||||
|
||||
|
@ -456,15 +471,12 @@ list(APPEND SOURCE_FILES
|
|||
components/ble/CurrentTimeService.cpp
|
||||
components/ble/AlertNotificationService.cpp
|
||||
components/ble/MusicService.cpp
|
||||
components/ble/weather/WeatherService.cpp
|
||||
components/ble/NavigationService.cpp
|
||||
components/ble/AgendaService.cpp
|
||||
displayapp/fonts/lv_font_navi_80.c
|
||||
components/ble/BatteryInformationService.cpp
|
||||
components/ble/FSService.cpp
|
||||
components/ble/ImmediateAlertService.cpp
|
||||
components/ble/ServiceDiscovery.cpp
|
||||
components/ble/HeartRateService.cpp
|
||||
components/ble/MotionService.cpp
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/motor/MotorController.cpp
|
||||
components/settings/Settings.cpp
|
||||
|
@ -477,10 +489,15 @@ list(APPEND SOURCE_FILES
|
|||
FreeRTOS/port_cmsis.c
|
||||
|
||||
displayapp/LittleVgl.cpp
|
||||
displayapp/fonts/jetbrains_mono_extrabold_compressed.c
|
||||
displayapp/fonts/jetbrains_mono_bold_20.c
|
||||
displayapp/fonts/jetbrains_mono_76.c
|
||||
displayapp/fonts/jetbrains_mono_42.c
|
||||
displayapp/fonts/lv_font_sys_48.c
|
||||
displayapp/fonts/open_sans_light.c
|
||||
displayapp/lv_pinetime_theme.c
|
||||
|
||||
systemtask/SystemTask.cpp
|
||||
systemtask/SystemMonitor.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
|
||||
heartratetask/HeartRateTask.cpp
|
||||
|
@ -489,7 +506,6 @@ list(APPEND SOURCE_FILES
|
|||
components/heartrate/Ptagc.cpp
|
||||
components/heartrate/HeartRateController.cpp
|
||||
|
||||
buttonhandler/ButtonHandler.cpp
|
||||
touchhandler/TouchHandler.cpp
|
||||
)
|
||||
|
||||
|
@ -524,15 +540,11 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
components/ble/CurrentTimeService.cpp
|
||||
components/ble/AlertNotificationService.cpp
|
||||
components/ble/MusicService.cpp
|
||||
components/ble/weather/WeatherService.cpp
|
||||
components/ble/BatteryInformationService.cpp
|
||||
components/ble/FSService.cpp
|
||||
components/ble/ImmediateAlertService.cpp
|
||||
components/ble/ServiceDiscovery.cpp
|
||||
components/ble/NavigationService.cpp
|
||||
components/ble/AgendaService.cpp
|
||||
components/ble/HeartRateService.cpp
|
||||
components/ble/MotionService.cpp
|
||||
components/firmwarevalidator/FirmwareValidator.cpp
|
||||
components/settings/Settings.cpp
|
||||
components/timer/TimerController.cpp
|
||||
|
@ -543,7 +555,6 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
FreeRTOS/port_cmsis.c
|
||||
|
||||
systemtask/SystemTask.cpp
|
||||
systemtask/SystemMonitor.cpp
|
||||
drivers/TwiMaster.cpp
|
||||
components/gfx/Gfx.cpp
|
||||
components/rle/RleDecoder.cpp
|
||||
|
@ -554,7 +565,6 @@ list(APPEND RECOVERY_SOURCE_FILES
|
|||
components/heartrate/Ptagc.cpp
|
||||
components/motor/MotorController.cpp
|
||||
components/fs/FS.cpp
|
||||
buttonhandler/ButtonHandler.cpp
|
||||
touchhandler/TouchHandler.cpp
|
||||
)
|
||||
|
||||
|
@ -581,7 +591,6 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES
|
|||
|
||||
set(INCLUDE_FILES
|
||||
|
||||
${CMAKE_CURRENT_BINARY_DIR}/src/Version.h
|
||||
BootloaderVersion.h
|
||||
logging/Logger.h
|
||||
logging/NrfLogger.h
|
||||
|
@ -591,12 +600,15 @@ set(INCLUDE_FILES
|
|||
displayapp/screens/Screen.h
|
||||
displayapp/screens/Clock.h
|
||||
displayapp/screens/Tile.h
|
||||
displayapp/screens/Meter.h
|
||||
displayapp/screens/InfiniPaint.h
|
||||
displayapp/screens/StopWatch.h
|
||||
displayapp/screens/Paddle.h
|
||||
displayapp/screens/DropDownDemo.h
|
||||
displayapp/screens/BatteryIcon.h
|
||||
displayapp/screens/BleIcon.h
|
||||
displayapp/screens/NotificationIcon.h
|
||||
displayapp/screens/Brightness.h
|
||||
displayapp/screens/SystemInfo.h
|
||||
displayapp/screens/ScreenList.h
|
||||
displayapp/screens/Label.h
|
||||
|
@ -611,7 +623,6 @@ set(INCLUDE_FILES
|
|||
displayapp/screens/Timer.h
|
||||
displayapp/screens/Alarm.h
|
||||
displayapp/Colors.h
|
||||
displayapp/widgets/Counter.h
|
||||
drivers/St7789.h
|
||||
drivers/SpiNorFlash.h
|
||||
drivers/SpiMaster.h
|
||||
|
@ -630,9 +641,6 @@ set(INCLUDE_FILES
|
|||
components/datetime/DateTimeController.h
|
||||
components/brightness/BrightnessController.h
|
||||
components/motion/MotionController.h
|
||||
components/firmwarevalidator/FirmwareValidator.h
|
||||
components/ble/BleController.h
|
||||
components/ble/NotificationManager.h
|
||||
components/ble/NimbleController.h
|
||||
components/ble/DeviceInformationService.h
|
||||
components/ble/CurrentTimeClient.h
|
||||
|
@ -640,13 +648,10 @@ set(INCLUDE_FILES
|
|||
components/ble/DfuService.h
|
||||
components/firmwarevalidator/FirmwareValidator.h
|
||||
components/ble/BatteryInformationService.h
|
||||
components/ble/FSService.h
|
||||
components/ble/ImmediateAlertService.h
|
||||
components/ble/ServiceDiscovery.h
|
||||
components/ble/BleClient.h
|
||||
components/ble/HeartRateService.h
|
||||
components/ble/MotionService.h
|
||||
components/ble/weather/WeatherService.h
|
||||
components/settings/Settings.h
|
||||
components/timer/TimerController.h
|
||||
components/alarm/AlarmController.h
|
||||
|
@ -673,12 +678,10 @@ set(INCLUDE_FILES
|
|||
components/heartrate/Ptagc.h
|
||||
components/heartrate/HeartRateController.h
|
||||
components/motor/MotorController.h
|
||||
buttonhandler/ButtonHandler.h
|
||||
touchhandler/TouchHandler.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}/src # include generated files like Version.h
|
||||
.
|
||||
../
|
||||
libs/
|
||||
|
@ -773,7 +776,7 @@ link_directories(
|
|||
)
|
||||
|
||||
|
||||
set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -ftree-vrp -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions)
|
||||
set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wno-unknown-pragmas -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions)
|
||||
add_definitions(-DCONFIG_GPIO_AS_PINRESET)
|
||||
add_definitions(-DNIMBLE_CFG_CONTROLLER)
|
||||
add_definitions(-DOS_CPUTIME_FREQ)
|
||||
|
@ -790,24 +793,15 @@ if (NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif ()
|
||||
|
||||
add_subdirectory(displayapp/fonts)
|
||||
target_compile_options(infinitime_fonts PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
# NRF SDK
|
||||
add_library(nrf-sdk STATIC ${SDK_SOURCE_FILES})
|
||||
target_include_directories(nrf-sdk SYSTEM PUBLIC . ../)
|
||||
target_include_directories(nrf-sdk SYSTEM PUBLIC ${INCLUDES_FROM_LIBS})
|
||||
target_compile_options(nrf-sdk PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
|
@ -835,25 +829,6 @@ target_compile_options(lvgl PRIVATE
|
|||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
# QCBOR
|
||||
add_library(QCBOR STATIC ${QCBOR_SRC})
|
||||
target_include_directories(QCBOR SYSTEM PUBLIC libs/QCBOR/inc)
|
||||
# This is required with the current configuration
|
||||
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_FLOAT_HW_USE)
|
||||
# These are for space-saving
|
||||
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_PREFERRED_FLOAT)
|
||||
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_EXP_AND_MANTISSA)
|
||||
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS)
|
||||
#target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS)
|
||||
target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS)
|
||||
target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN)
|
||||
set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C)
|
||||
target_compile_options(QCBOR PRIVATE
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
# LITTLEFS_SRC
|
||||
add_library(littlefs STATIC ${LITTLEFS_SRC})
|
||||
target_include_directories(littlefs SYSTEM PUBLIC . ../)
|
||||
|
@ -872,12 +847,12 @@ set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime
|
|||
set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld")
|
||||
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES})
|
||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME})
|
||||
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs)
|
||||
target_compile_options(${EXECUTABLE_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
|
@ -893,14 +868,15 @@ add_custom_command(TARGET ${EXECUTABLE_NAME}
|
|||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_FILE_NAME}.out "${EXECUTABLE_FILE_NAME}.hex"
|
||||
COMMENT "post build steps for ${EXECUTABLE_FILE_NAME}")
|
||||
|
||||
|
||||
# Build binary intended to be used by bootloader
|
||||
set(EXECUTABLE_MCUBOOT_NAME "pinetime-mcuboot-app")
|
||||
set(EXECUTABLE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
set(IMAGE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
|
||||
set(IMAGE_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.bin)
|
||||
set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
|
||||
set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld")
|
||||
add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs)
|
||||
set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
|
@ -920,7 +896,7 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
|||
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_MCUBOOT_FILE_NAME}.out
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_FILE_NAME}.bin"
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_FILE_NAME}.hex"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_FILE_NAME}.hex ${IMAGE_MCUBOOT_FILE_NAME}
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_FILE_NAME}.bin ${IMAGE_MCUBOOT_FILE_NAME}
|
||||
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
|
||||
)
|
||||
|
||||
|
@ -936,7 +912,7 @@ endif()
|
|||
set(EXECUTABLE_RECOVERY_NAME "pinetime-recovery")
|
||||
set(EXECUTABLE_RECOVERY_FILE_NAME ${EXECUTABLE_RECOVERY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
add_executable(${EXECUTABLE_RECOVERY_NAME} ${RECOVERY_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs)
|
||||
set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_FILE_NAME})
|
||||
target_compile_definitions(${EXECUTABLE_RECOVERY_NAME} PUBLIC "PINETIME_IS_RECOVERY")
|
||||
target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC
|
||||
|
@ -963,10 +939,10 @@ add_custom_command(TARGET ${EXECUTABLE_RECOVERY_NAME}
|
|||
# InfiniTime recovery firmware (mcuboot)
|
||||
set(EXECUTABLE_RECOVERY_MCUBOOT_NAME "pinetime-mcuboot-recovery")
|
||||
set(EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
|
||||
set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.bin)
|
||||
set(DFU_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
|
||||
add_executable(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} ${RECOVERY_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs)
|
||||
set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME})
|
||||
target_compile_definitions(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC "PINETIME_IS_RECOVERY")
|
||||
target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC
|
||||
|
@ -979,17 +955,16 @@ target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC
|
|||
|
||||
set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES
|
||||
SUFFIX ".out"
|
||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT_MCUBOOT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
|
||||
LINK_FLAGS "-mthumb -mabi=aapcs -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -Wl,--print-memory-usage --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.bin"
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.hex"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.hex ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}
|
||||
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME} "${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.bin"
|
||||
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.bin recoveryImage > recoveryImage.h
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.out "${EXECUTABLE_RECOVERYY_MCUBOOT_FILE_NAME}.hex"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}.bin ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}
|
||||
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME} recoveryImage > recoveryImage.h
|
||||
COMMENT "post build steps for ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}"
|
||||
)
|
||||
|
||||
|
@ -1005,7 +980,7 @@ endif()
|
|||
set(EXECUTABLE_RECOVERYLOADER_NAME "pinetime-recovery-loader")
|
||||
set(EXECUTABLE_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_RECOVERYLOADER_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
add_executable(${EXECUTABLE_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_RECOVERYLOADER_NAME} nrf-sdk)
|
||||
set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERYLOADER_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
|
@ -1035,10 +1010,10 @@ add_custom_command(TARGET ${EXECUTABLE_RECOVERYLOADER_NAME}
|
|||
# Build binary that writes the recovery image (MCUBoot version)
|
||||
set(EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME "pinetime-mcuboot-recovery-loader")
|
||||
set(EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
set(IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.hex)
|
||||
set(IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-image-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.bin)
|
||||
set(DFU_MCUBOOT_RECOVERYLOADER_FILE_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip)
|
||||
add_executable(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts)
|
||||
target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk)
|
||||
set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3>
|
||||
|
@ -1062,9 +1037,8 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME}
|
|||
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin"
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.out "${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.hex ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}
|
||||
COMMAND ${CMAKE_OBJCOPY} -I ihex -O binary ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME} "${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin"
|
||||
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin recoveryLoaderImage > recoveryLoaderImage.h
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/mcuboot/imgtool.py create --align 4 --version 1.0.0 --header-size 32 --slot-size 475136 --pad-header ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}.bin ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME}
|
||||
COMMAND python3 ${CMAKE_SOURCE_DIR}/tools/bin2c.py ${IMAGE_MCUBOOT_RECOVERYLOADER_FILE_NAME} recoveryLoaderImage > recoveryLoaderImage.h
|
||||
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}"
|
||||
)
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 1
|
||||
#define configTIMER_TASK_PRIORITY (1)
|
||||
#define configTIMER_TASK_PRIORITY (0)
|
||||
#define configTIMER_QUEUE_LENGTH 32
|
||||
#define configTIMER_TASK_STACK_DEPTH (300)
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
@VERSION_EDIT_WARNING@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Pinetime {
|
||||
class Version {
|
||||
public:
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
enum class ButtonActions { None, Click, DoubleClick, LongPress, LongerPress };
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#include "buttonhandler/ButtonHandler.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
void ButtonTimerCallback(TimerHandle_t xTimer) {
|
||||
auto* sysTask = static_cast<Pinetime::System::SystemTask*>(pvTimerGetTimerID(xTimer));
|
||||
sysTask->PushMessage(Pinetime::System::Messages::HandleButtonTimerEvent);
|
||||
}
|
||||
|
||||
void ButtonHandler::Init(Pinetime::System::SystemTask* systemTask) {
|
||||
buttonTimer = xTimerCreate("buttonTimer", pdMS_TO_TICKS(200), pdFALSE, systemTask, ButtonTimerCallback);
|
||||
}
|
||||
|
||||
ButtonActions ButtonHandler::HandleEvent(Events event) {
|
||||
static constexpr TickType_t doubleClickTime = pdMS_TO_TICKS(200);
|
||||
static constexpr TickType_t longPressTime = pdMS_TO_TICKS(400);
|
||||
static constexpr TickType_t longerPressTime = pdMS_TO_TICKS(2000);
|
||||
|
||||
if (event == Events::Press) {
|
||||
buttonPressed = true;
|
||||
} else if (event == Events::Release) {
|
||||
releaseTime = xTaskGetTickCount();
|
||||
buttonPressed = false;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case States::Idle:
|
||||
if (event == Events::Press) {
|
||||
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
|
||||
xTimerStart(buttonTimer, 0);
|
||||
state = States::Pressed;
|
||||
}
|
||||
break;
|
||||
case States::Pressed:
|
||||
if (event == Events::Press) {
|
||||
if (xTaskGetTickCount() - releaseTime < doubleClickTime) {
|
||||
xTimerStop(buttonTimer, 0);
|
||||
state = States::Idle;
|
||||
return ButtonActions::DoubleClick;
|
||||
}
|
||||
} else if (event == Events::Release) {
|
||||
xTimerChangePeriod(buttonTimer, doubleClickTime, 0);
|
||||
xTimerStart(buttonTimer, 0);
|
||||
} else if (event == Events::Timer) {
|
||||
if (buttonPressed) {
|
||||
xTimerChangePeriod(buttonTimer, longPressTime - doubleClickTime, 0);
|
||||
xTimerStart(buttonTimer, 0);
|
||||
state = States::Holding;
|
||||
} else {
|
||||
state = States::Idle;
|
||||
return ButtonActions::Click;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case States::Holding:
|
||||
if (event == Events::Release) {
|
||||
xTimerStop(buttonTimer, 0);
|
||||
state = States::Idle;
|
||||
return ButtonActions::Click;
|
||||
} else if (event == Events::Timer) {
|
||||
xTimerChangePeriod(buttonTimer, longerPressTime - longPressTime - doubleClickTime, 0);
|
||||
xTimerStart(buttonTimer, 0);
|
||||
state = States::LongHeld;
|
||||
return ButtonActions::LongPress;
|
||||
}
|
||||
break;
|
||||
case States::LongHeld:
|
||||
if (event == Events::Release) {
|
||||
xTimerStop(buttonTimer, 0);
|
||||
state = States::Idle;
|
||||
} else if (event == Events::Timer) {
|
||||
state = States::Idle;
|
||||
return ButtonActions::LongerPress;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ButtonActions::None;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "buttonhandler/ButtonActions.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include <FreeRTOS.h>
|
||||
#include <timers.h>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
class ButtonHandler {
|
||||
public:
|
||||
enum class Events : uint8_t { Press, Release, Timer };
|
||||
void Init(Pinetime::System::SystemTask* systemTask);
|
||||
ButtonActions HandleEvent(Events event);
|
||||
|
||||
private:
|
||||
enum class States : uint8_t { Idle, Pressed, Holding, LongHeld };
|
||||
TickType_t releaseTime = 0;
|
||||
TimerHandle_t buttonTimer;
|
||||
bool buttonPressed = false;
|
||||
States state = States::Idle;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -15,8 +15,9 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "components/alarm/AlarmController.h"
|
||||
#include "AlarmController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include "app_timer.h"
|
||||
#include "task.h"
|
||||
#include <chrono>
|
||||
|
||||
|
@ -26,16 +27,20 @@ using namespace std::chrono_literals;
|
|||
AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
|
||||
}
|
||||
|
||||
APP_TIMER_DEF(alarmAppTimer);
|
||||
|
||||
namespace {
|
||||
void SetOffAlarm(TimerHandle_t xTimer) {
|
||||
auto controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer));
|
||||
controller->SetOffAlarmNow();
|
||||
void SetOffAlarm(void* p_context) {
|
||||
auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(p_context);
|
||||
if (controller != nullptr) {
|
||||
controller->SetOffAlarmNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AlarmController::Init(System::SystemTask* systemTask) {
|
||||
app_timer_create(&alarmAppTimer, APP_TIMER_MODE_SINGLE_SHOT, SetOffAlarm);
|
||||
this->systemTask = systemTask;
|
||||
alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm);
|
||||
}
|
||||
|
||||
void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
|
||||
|
@ -44,12 +49,12 @@ void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
|
|||
}
|
||||
|
||||
void AlarmController::ScheduleAlarm() {
|
||||
// Determine the next time the alarm needs to go off and set the timer
|
||||
xTimerStop(alarmTimer, 0);
|
||||
// Determine the next time the alarm needs to go off and set the app_timer
|
||||
app_timer_stop(alarmAppTimer);
|
||||
|
||||
auto now = dateTimeController.CurrentDateTime();
|
||||
alarmTime = now;
|
||||
time_t ttAlarmTime = std::chrono::system_clock::to_time_t(std::chrono::time_point_cast<std::chrono::system_clock::duration>(alarmTime));
|
||||
time_t ttAlarmTime = std::chrono::system_clock::to_time_t(alarmTime);
|
||||
tm* tmAlarmTime = std::localtime(&ttAlarmTime);
|
||||
|
||||
// If the time being set has already passed today,the alarm should be set for tomorrow
|
||||
|
@ -75,9 +80,8 @@ void AlarmController::ScheduleAlarm() {
|
|||
|
||||
// now can convert back to a time_point
|
||||
alarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmAlarmTime));
|
||||
auto secondsToAlarm = std::chrono::duration_cast<std::chrono::seconds>(alarmTime - now).count();
|
||||
xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0);
|
||||
xTimerStart(alarmTimer, 0);
|
||||
auto mSecToAlarm = std::chrono::duration_cast<std::chrono::milliseconds>(alarmTime - now).count();
|
||||
app_timer_start(alarmAppTimer, APP_TIMER_TICKS(mSecToAlarm), this);
|
||||
|
||||
state = AlarmState::Set;
|
||||
}
|
||||
|
@ -87,7 +91,7 @@ uint32_t AlarmController::SecondsToAlarm() {
|
|||
}
|
||||
|
||||
void AlarmController::DisableAlarm() {
|
||||
xTimerStop(alarmTimer, 0);
|
||||
app_timer_stop(alarmAppTimer);
|
||||
state = AlarmState::Not_Set;
|
||||
}
|
||||
|
||||
|
@ -97,12 +101,14 @@ void AlarmController::SetOffAlarmNow() {
|
|||
}
|
||||
|
||||
void AlarmController::StopAlerting() {
|
||||
systemTask->PushMessage(System::Messages::StopRinging);
|
||||
|
||||
// Alarm state is off unless this is a recurring alarm
|
||||
if (recurrence == RecurType::None) {
|
||||
state = AlarmState::Not_Set;
|
||||
} else {
|
||||
state = AlarmState::Set;
|
||||
// set next instance
|
||||
ScheduleAlarm();
|
||||
}
|
||||
systemTask->PushMessage(System::Messages::StopRinging);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <timers.h>
|
||||
#include <cstdint>
|
||||
#include "app_timer.h"
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
@ -59,7 +58,6 @@ namespace Pinetime {
|
|||
private:
|
||||
Controllers::DateTime& dateTimeController;
|
||||
System::SystemTask* systemTask = nullptr;
|
||||
TimerHandle_t alarmTimer;
|
||||
uint8_t hours = 7;
|
||||
uint8_t minutes = 0;
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "components/battery/BatteryController.h"
|
||||
#include "BatteryController.h"
|
||||
#include "drivers/PinMap.h"
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <nrfx_saadc.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
/* Copyright (C) 2021 Adam Pigg
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "components/ble/AgendaService.h"
|
||||
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
namespace {
|
||||
// 3fdaYYXX-e246-472e-b7e0-d2b0f3d9c17a
|
||||
constexpr ble_uuid128_t CharUuid(uint8_t x, uint8_t y) {
|
||||
return ble_uuid128_t {.u = {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x7a, 0xc1, 0xd9, 0xf3, 0xb0, 0xd2, 0xe0, 0xb7, 0x2e, 0x47, 0x46, 0xe2, x, y, 0xda, 0x3f}};
|
||||
}
|
||||
|
||||
// 00010000-78fc-48fe-8e23-433b3a1942d0
|
||||
constexpr ble_uuid128_t BaseUuid() {
|
||||
return CharUuid(0x00, 0x00);
|
||||
}
|
||||
|
||||
constexpr ble_uuid128_t agendaUuid {BaseUuid()};
|
||||
|
||||
constexpr ble_uuid128_t agendaItemCharUuid {CharUuid(0x01, 0x00)};
|
||||
/*constexpr ble_uuid128_t navNarrativeCharUuid {CharUuid(0x02, 0x00)};
|
||||
constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)};
|
||||
constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)};*/
|
||||
|
||||
int AgendaCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto agendaService = static_cast<Pinetime::Controllers::AgendaService*>(arg);
|
||||
return agendaService->OnCommand(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Pinetime::Controllers::AgendaService::AgendaService(Pinetime::System::SystemTask& system) : m_system(system) {
|
||||
characteristicDefinition[0] = {.uuid = &agendaItemCharUuid.u,
|
||||
.access_cb = AgendaCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ};
|
||||
|
||||
characteristicDefinition[1] = {0};
|
||||
|
||||
serviceDefinition[0] = {.type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = &agendaUuid.u, .characteristics = characteristicDefinition};
|
||||
serviceDefinition[1] = {0};
|
||||
}
|
||||
|
||||
void Pinetime::Controllers::AgendaService::Init() {
|
||||
int res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
m_agenda_times[0] = 1655327841;
|
||||
m_agenda_pieces[0] = "C++ Fumbling";
|
||||
}
|
||||
|
||||
int Pinetime::Controllers::AgendaService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) {
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
size_t notifSize = OS_MBUF_PKTLEN(ctxt->om);
|
||||
uint8_t data[notifSize + 1];
|
||||
data[notifSize] = '\0';
|
||||
os_mbuf_copydata(ctxt->om, 0, notifSize, data);
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, &agendaItemCharUuid.u) == 0) {
|
||||
if (notifSize >= 5) {
|
||||
uint8_t itemIndex = (uint8_t) data[0];
|
||||
uint32_t itemTime = ((uint32_t) data[1]) << 24 | ((uint32_t) data[2]) << 16 | ((uint32_t) data[3]) << 8 | ((uint32_t) data[4]);
|
||||
char* sAgendaItem = (char*) &data[5];
|
||||
if (itemIndex < AGENDA_CAPACITY) { // don't allow a buffer overflow
|
||||
m_agenda_times[itemIndex] = itemTime;
|
||||
// implicit std::string copy/conversion here:
|
||||
m_agenda_pieces[itemIndex] = sAgendaItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Pinetime::Controllers::AgendaService::getAgendaTime(uint8_t index) {
|
||||
if (index < AGENDA_CAPACITY) {
|
||||
return m_agenda_times[index];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Pinetime::Controllers::AgendaService::getAgendaPiece(uint8_t index) {
|
||||
if (index < AGENDA_CAPACITY) {
|
||||
return m_agenda_pieces[index];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/* Copyright (C) 2021 Adam Pigg
|
||||
|
||||
This file is part of InfiniTime.
|
||||
|
||||
InfiniTime is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
InfiniTime is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#define min // workaround: nimble's min/max macros conflict with libstdc++
|
||||
#define max
|
||||
#include <host/ble_gap.h>
|
||||
#include <host/ble_uuid.h>
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
|
||||
class AgendaService {
|
||||
public:
|
||||
static const uint8_t AGENDA_CAPACITY = 35;
|
||||
|
||||
explicit AgendaService(Pinetime::System::SystemTask& system);
|
||||
|
||||
void Init();
|
||||
|
||||
int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt);
|
||||
|
||||
uint32_t getAgendaTime(uint8_t index);
|
||||
|
||||
std::string getAgendaPiece(uint8_t index);
|
||||
|
||||
private:
|
||||
struct ble_gatt_chr_def characteristicDefinition[2];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
|
||||
uint32_t m_agenda_times[AGENDA_CAPACITY];
|
||||
std::string m_agenda_pieces[AGENDA_CAPACITY];
|
||||
|
||||
Pinetime::System::SystemTask& m_system;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
#include "components/ble/AlertNotificationClient.h"
|
||||
#include "AlertNotificationClient.h"
|
||||
#include <algorithm>
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include <nrf_log.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
constexpr ble_uuid16_t AlertNotificationClient::ansServiceUuid;
|
||||
|
@ -26,11 +25,8 @@ namespace {
|
|||
return client->OnCharacteristicsDiscoveryEvent(conn_handle, error, chr);
|
||||
}
|
||||
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(uint16_t conn_handle,
|
||||
const struct ble_gatt_error* error,
|
||||
uint16_t chr_val_handle,
|
||||
const struct ble_gatt_dsc* dsc,
|
||||
void* arg) {
|
||||
int OnAlertNotificationDescriptorDiscoveryEventCallback(
|
||||
uint16_t conn_handle, const struct ble_gatt_error* error, uint16_t chr_val_handle, const struct ble_gatt_dsc* dsc, void* arg) {
|
||||
auto client = static_cast<AlertNotificationClient*>(arg);
|
||||
return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <host/ble_gap.h>
|
||||
#undef max
|
||||
#undef min
|
||||
#include "components/ble/BleClient.h"
|
||||
#include "BleClient.h"
|
||||
|
||||
namespace Pinetime {
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "components/ble/AlertNotificationService.h"
|
||||
#include "AlertNotificationService.h"
|
||||
#include <hal/nrf_rtc.h>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "components/ble/NotificationManager.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
@ -53,9 +53,8 @@ int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle
|
|||
|
||||
// Ignore notifications with empty message
|
||||
const auto packetLen = OS_MBUF_PKTLEN(ctxt->om);
|
||||
if (packetLen <= headerSize) {
|
||||
if (packetLen <= headerSize)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t bufferSize = std::min(packetLen + stringTerminatorSize, maxBufferSize);
|
||||
auto messageSize = std::min(maxMessageSize, (bufferSize - headerSize));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "components/ble/BatteryInformationService.h"
|
||||
#include <nrf_log.h>
|
||||
#include "BatteryInformationService.h"
|
||||
#include "components/battery/BatteryController.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
|
|
@ -18,7 +18,6 @@ namespace Pinetime {
|
|||
|
||||
int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level);
|
||||
|
||||
private:
|
||||
Controllers::Battery& batteryController;
|
||||
static constexpr uint16_t batteryInformationServiceId {0x180F};
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#include "components/ble/BleController.h"
|
||||
#include "BleController.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
bool Ble::IsConnected() const {
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
void Ble::Connect() {
|
||||
isConnected = true;
|
||||
}
|
||||
|
@ -14,18 +10,6 @@ void Ble::Disconnect() {
|
|||
isConnected = false;
|
||||
}
|
||||
|
||||
bool Ble::IsRadioEnabled() const {
|
||||
return isRadioEnabled;
|
||||
}
|
||||
|
||||
void Ble::EnableRadio() {
|
||||
isRadioEnabled = true;
|
||||
}
|
||||
|
||||
void Ble::DisableRadio() {
|
||||
isRadioEnabled = false;
|
||||
}
|
||||
|
||||
void Ble::StartFirmwareUpdate() {
|
||||
isFirmwareUpdating = true;
|
||||
}
|
||||
|
|
|
@ -9,17 +9,15 @@ namespace Pinetime {
|
|||
public:
|
||||
using BleAddress = std::array<uint8_t, 6>;
|
||||
enum class FirmwareUpdateStates { Idle, Running, Validated, Error };
|
||||
enum class AddressTypes { Public, Random, RPA_Public, RPA_Random };
|
||||
enum class AddressTypes { Public, Random };
|
||||
|
||||
Ble() = default;
|
||||
bool IsConnected() const;
|
||||
bool IsConnected() const {
|
||||
return isConnected;
|
||||
}
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
bool IsRadioEnabled() const;
|
||||
void EnableRadio();
|
||||
void DisableRadio();
|
||||
|
||||
void StartFirmwareUpdate();
|
||||
void StopFirmwareUpdate();
|
||||
void FirmwareUpdateTotalBytes(uint32_t totalBytes);
|
||||
|
@ -50,23 +48,15 @@ namespace Pinetime {
|
|||
void AddressType(AddressTypes t) {
|
||||
addressType = t;
|
||||
}
|
||||
void SetPairingKey(uint32_t k) {
|
||||
pairingKey = k;
|
||||
}
|
||||
uint32_t GetPairingKey() const {
|
||||
return pairingKey;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isConnected = false;
|
||||
bool isRadioEnabled = true;
|
||||
bool isFirmwareUpdating = false;
|
||||
uint32_t firmwareUpdateTotalBytes = 0;
|
||||
uint32_t firmwareUpdateCurrentBytes = 0;
|
||||
FirmwareUpdateStates firmwareUpdateState = FirmwareUpdateStates::Idle;
|
||||
BleAddress address;
|
||||
AddressTypes addressType;
|
||||
uint32_t pairingKey = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#include "components/ble/CurrentTimeClient.h"
|
||||
#include "CurrentTimeClient.h"
|
||||
#include <hal/nrf_rtc.h>
|
||||
#include <nrf_log.h>
|
||||
#include "components/datetime/DateTimeController.h"
|
||||
|
@ -85,21 +85,10 @@ int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_g
|
|||
// TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent
|
||||
CtsData result;
|
||||
os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result);
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d",
|
||||
result.year,
|
||||
result.month,
|
||||
result.dayofmonth,
|
||||
result.hour,
|
||||
result.minute,
|
||||
result.second);
|
||||
dateTimeController.SetTime(result.year,
|
||||
result.month,
|
||||
result.dayofmonth,
|
||||
0,
|
||||
result.hour,
|
||||
result.minute,
|
||||
result.second,
|
||||
nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
} else {
|
||||
NRF_LOG_INFO("Error retrieving current time: %d", error->status);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#undef max
|
||||
#undef min
|
||||
#include <cstdint>
|
||||
#include "components/ble/BleClient.h"
|
||||
#include "BleClient.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Controllers {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "components/ble/CurrentTimeService.h"
|
||||
#include "CurrentTimeService.h"
|
||||
#include <hal/nrf_rtc.h>
|
||||
#include <nrf_log.h>
|
||||
|
||||
|
@ -29,22 +29,11 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl
|
|||
CtsData result;
|
||||
os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result);
|
||||
|
||||
NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d",
|
||||
result.year,
|
||||
result.month,
|
||||
result.dayofmonth,
|
||||
result.hour,
|
||||
result.minute,
|
||||
result.second);
|
||||
NRF_LOG_INFO(
|
||||
"Received data: %d-%d-%d %d:%d:%d", result.year, result.month, result.dayofmonth, result.hour, result.minute, result.second);
|
||||
|
||||
m_dateTimeController.SetTime(result.year,
|
||||
result.month,
|
||||
result.dayofmonth,
|
||||
0,
|
||||
result.hour,
|
||||
result.minute,
|
||||
result.second,
|
||||
nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
m_dateTimeController.SetTime(
|
||||
result.year, result.month, result.dayofmonth, 0, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG));
|
||||
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
CtsData currentDateTime;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "components/ble/DeviceInformationService.h"
|
||||
#include "DeviceInformationService.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#define min // workaround: nimble's min/max macros conflict with libstdc++
|
||||
#define max
|
||||
#include <host/ble_gap.h>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "components/ble/DfuService.h"
|
||||
#include "DfuService.h"
|
||||
#include <cstring>
|
||||
#include "components/ble/BleController.h"
|
||||
#include "drivers/SpiNorFlash.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include <nrf_log.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
@ -119,10 +118,8 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
|||
bootloaderSize = om->om_data[4] + (om->om_data[5] << 8) + (om->om_data[6] << 16) + (om->om_data[7] << 24);
|
||||
applicationSize = om->om_data[8] + (om->om_data[9] << 8) + (om->om_data[10] << 16) + (om->om_data[11] << 24);
|
||||
bleController.FirmwareUpdateTotalBytes(applicationSize);
|
||||
NRF_LOG_INFO("[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d",
|
||||
softdeviceSize,
|
||||
bootloaderSize,
|
||||
applicationSize);
|
||||
NRF_LOG_INFO(
|
||||
"[DFU] -> Start data received : SD size : %d, BT size : %d, app size : %d", softdeviceSize, bootloaderSize, applicationSize);
|
||||
|
||||
// wait until SystemTask has finished waking up all devices
|
||||
while (systemTask.IsSleeping()) {
|
||||
|
@ -167,10 +164,10 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
|
|||
|
||||
if ((nbPacketReceived % nbPacketsToNotify) == 0 && bytesReceived != applicationSize) {
|
||||
uint8_t data[5] {static_cast<uint8_t>(Opcodes::PacketReceiptNotification),
|
||||
static_cast<uint8_t>(bytesReceived & 0x000000FFu),
|
||||
static_cast<uint8_t>(bytesReceived >> 8u),
|
||||
static_cast<uint8_t>(bytesReceived >> 16u),
|
||||
static_cast<uint8_t>(bytesReceived >> 24u)};
|
||||
(uint8_t)(bytesReceived & 0x000000FFu),
|
||||
(uint8_t)(bytesReceived >> 8u),
|
||||
(uint8_t)(bytesReceived >> 16u),
|
||||
(uint8_t)(bytesReceived >> 24u)};
|
||||
NRF_LOG_INFO("[DFU] -> Send packet notification: %d bytes received", bytesReceived);
|
||||
notificationManager.Send(connectionHandle, controlPointCharacteristicHandle, data, 5);
|
||||
}
|
||||
|
@ -246,7 +243,7 @@ int DfuService::ControlPointHandler(uint16_t connectionHandle, os_mbuf* om) {
|
|||
NRF_LOG_INFO("[DFU] -> Receive firmware image requested, but we are not in Start Init");
|
||||
return 0;
|
||||
}
|
||||
// TODO the chunk size is dependent of the implementation of the host application...
|
||||
// TODO the chunk size is dependant of the implementation of the host application...
|
||||
dfuImage.Init(20, applicationSize, expectedCrc);
|
||||
NRF_LOG_INFO("[DFU] -> Starting receive firmware");
|
||||
state = States::Data;
|
||||
|
@ -425,9 +422,9 @@ uint16_t DfuService::DfuImage::ComputeCrc(uint8_t const* p_data, uint32_t size,
|
|||
uint16_t crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
|
||||
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
crc = static_cast<uint8_t>(crc >> 8) | (crc << 8);
|
||||
crc = (uint8_t)(crc >> 8) | (crc << 8);
|
||||
crc ^= p_data[i];
|
||||
crc ^= static_cast<uint8_t>(crc & 0xFF) >> 4;
|
||||
crc ^= (uint8_t)(crc & 0xFF) >> 4;
|
||||
crc ^= (crc << 8) << 4;
|
||||
crc ^= ((crc & 0xFF) << 4) << 1;
|
||||
}
|
||||
|
|
|
@ -1,330 +0,0 @@
|
|||
#include <nrf_log.h>
|
||||
#include "FSService.h"
|
||||
#include "components/ble/BleController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
constexpr ble_uuid16_t FSService::fsServiceUuid;
|
||||
constexpr ble_uuid128_t FSService::fsVersionUuid;
|
||||
constexpr ble_uuid128_t FSService::fsTransferUuid;
|
||||
|
||||
int FSServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* fsService = static_cast<FSService*>(arg);
|
||||
return fsService->OnFSServiceRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
||||
FSService::FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs)
|
||||
: systemTask {systemTask},
|
||||
fs {fs},
|
||||
characteristicDefinition {{.uuid = &fsVersionUuid.u,
|
||||
.access_cb = FSServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.val_handle = &versionCharacteristicHandle},
|
||||
{
|
||||
.uuid = &fsTransferUuid.u,
|
||||
.access_cb = FSServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &transferCharacteristicHandle,
|
||||
},
|
||||
{0}},
|
||||
serviceDefinition {
|
||||
{/* Device Information Service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = &fsServiceUuid.u,
|
||||
.characteristics = characteristicDefinition},
|
||||
{0},
|
||||
} {
|
||||
}
|
||||
|
||||
void FSService::Init() {
|
||||
int res = 0;
|
||||
res = ble_gatts_count_cfg(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
|
||||
res = ble_gatts_add_svcs(serviceDefinition);
|
||||
ASSERT(res == 0);
|
||||
}
|
||||
|
||||
int FSService::OnFSServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) {
|
||||
if (attributeHandle == versionCharacteristicHandle) {
|
||||
NRF_LOG_INFO("FS_S : handle = %d", versionCharacteristicHandle);
|
||||
int res = os_mbuf_append(context->om, &fsVersion, sizeof(fsVersion));
|
||||
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
if (attributeHandle == transferCharacteristicHandle) {
|
||||
return FSCommandHandler(connectionHandle, context->om);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FSService::FSCommandHandler(uint16_t connectionHandle, os_mbuf* om) {
|
||||
auto command = static_cast<commands>(om->om_data[0]);
|
||||
NRF_LOG_INFO("[FS_S] -> FSCommandHandler Command %d", command);
|
||||
// Just always make sure we are awake...
|
||||
systemTask.PushMessage(Pinetime::System::Messages::StartFileTransfer);
|
||||
vTaskDelay(10);
|
||||
while (systemTask.IsSleeping()) {
|
||||
vTaskDelay(100); // 50ms
|
||||
}
|
||||
lfs_dir_t dir = {0};
|
||||
lfs_info info = {0};
|
||||
lfs_file f = {0};
|
||||
switch (command) {
|
||||
case commands::READ: {
|
||||
NRF_LOG_INFO("[FS_S] -> Read");
|
||||
auto* header = (ReadHeader*) om->om_data;
|
||||
uint16_t plen = header->pathlen;
|
||||
if (plen > maxpathlen) { //> counts for null term
|
||||
return -1;
|
||||
}
|
||||
memcpy(filepath, header->pathstr, plen);
|
||||
filepath[plen] = 0; // Copy and null terminate string
|
||||
ReadResponse resp;
|
||||
os_mbuf* om;
|
||||
resp.command = commands::READ_DATA;
|
||||
resp.status = 0x01;
|
||||
resp.chunkoff = header->chunkoff;
|
||||
int res = fs.Stat(filepath, &info);
|
||||
if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) {
|
||||
resp.status = (int8_t) res;
|
||||
resp.chunklen = 0;
|
||||
resp.totallen = 0;
|
||||
om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse));
|
||||
} else {
|
||||
resp.chunklen = std::min(header->chunksize, info.size); // TODO add mtu somehow
|
||||
resp.totallen = info.size;
|
||||
fs.FileOpen(&f, filepath, LFS_O_RDONLY);
|
||||
fs.FileSeek(&f, header->chunkoff);
|
||||
uint8_t fileData[resp.chunklen] = {0};
|
||||
resp.chunklen = fs.FileRead(&f, fileData, resp.chunklen);
|
||||
om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse));
|
||||
os_mbuf_append(om, fileData, resp.chunklen);
|
||||
fs.FileClose(&f);
|
||||
}
|
||||
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::READ_PACING: {
|
||||
NRF_LOG_INFO("[FS_S] -> Readpacing");
|
||||
auto* header = (ReadHeader*) om->om_data;
|
||||
ReadResponse resp;
|
||||
resp.command = commands::READ_DATA;
|
||||
resp.status = 0x01;
|
||||
resp.chunkoff = header->chunkoff;
|
||||
int res = fs.Stat(filepath, &info);
|
||||
if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) {
|
||||
resp.status = (int8_t) res;
|
||||
resp.chunklen = 0;
|
||||
resp.totallen = 0;
|
||||
} else {
|
||||
resp.chunklen = std::min(header->chunksize, info.size); // TODO add mtu somehow
|
||||
resp.totallen = info.size;
|
||||
fs.FileOpen(&f, filepath, LFS_O_RDONLY);
|
||||
fs.FileSeek(&f, header->chunkoff);
|
||||
}
|
||||
os_mbuf* om;
|
||||
if (resp.chunklen > 0) {
|
||||
uint8_t fileData[resp.chunklen] = {0};
|
||||
resp.chunklen = fs.FileRead(&f, fileData, resp.chunklen);
|
||||
om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse));
|
||||
os_mbuf_append(om, fileData, resp.chunklen);
|
||||
} else {
|
||||
resp.chunklen = 0;
|
||||
om = ble_hs_mbuf_from_flat(&resp, sizeof(ReadResponse));
|
||||
}
|
||||
fs.FileClose(&f);
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::WRITE: {
|
||||
NRF_LOG_INFO("[FS_S] -> Write");
|
||||
auto* header = (WriteHeader*) om->om_data;
|
||||
uint16_t plen = header->pathlen;
|
||||
if (plen > maxpathlen) { //> counts for null term
|
||||
return -1; // TODO make this actually return a BLE notif
|
||||
}
|
||||
memcpy(filepath, header->pathstr, plen);
|
||||
filepath[plen] = 0; // Copy and null terminate string
|
||||
fileSize = header->totalSize;
|
||||
WriteResponse resp;
|
||||
resp.command = commands::WRITE_PACING;
|
||||
resp.offset = header->offset;
|
||||
resp.modTime = 0;
|
||||
|
||||
int res = fs.FileOpen(&f, filepath, LFS_O_RDWR | LFS_O_CREAT);
|
||||
if (res == 0) {
|
||||
fs.FileClose(&f);
|
||||
resp.status = (res == 0) ? 0x01 : (int8_t) res;
|
||||
}
|
||||
resp.freespace = std::min(fs.getSize() - (fs.GetFSSize() * fs.getBlockSize()), fileSize - header->offset);
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(WriteResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::WRITE_DATA: {
|
||||
NRF_LOG_INFO("[FS_S] -> WriteData");
|
||||
auto* header = (WritePacing*) om->om_data;
|
||||
WriteResponse resp;
|
||||
resp.command = commands::WRITE_PACING;
|
||||
resp.offset = header->offset;
|
||||
int res = 0;
|
||||
|
||||
if (!(res = fs.FileOpen(&f, filepath, LFS_O_RDWR | LFS_O_CREAT))) {
|
||||
if ((res = fs.FileSeek(&f, header->offset)) >= 0) {
|
||||
res = fs.FileWrite(&f, header->data, header->dataSize);
|
||||
}
|
||||
fs.FileClose(&f);
|
||||
}
|
||||
if (res < 0) {
|
||||
resp.status = (int8_t) res;
|
||||
}
|
||||
resp.freespace = std::min(fs.getSize() - (fs.GetFSSize() * fs.getBlockSize()), fileSize - header->offset);
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(WriteResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::DELETE: {
|
||||
NRF_LOG_INFO("[FS_S] -> Delete");
|
||||
auto* header = (DelHeader*) om->om_data;
|
||||
uint16_t plen = header->pathlen;
|
||||
char path[plen + 1] = {0};
|
||||
memcpy(path, header->pathstr, plen);
|
||||
path[plen] = 0; // Copy and null terminate string
|
||||
DelResponse resp {};
|
||||
resp.command = commands::DELETE_STATUS;
|
||||
int res = fs.FileDelete(path);
|
||||
resp.status = (res == 0) ? 0x01 : (int8_t) res;
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(DelResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::MKDIR: {
|
||||
NRF_LOG_INFO("[FS_S] -> MKDir");
|
||||
auto* header = (MKDirHeader*) om->om_data;
|
||||
uint16_t plen = header->pathlen;
|
||||
char path[plen + 1] = {0};
|
||||
memcpy(path, header->pathstr, plen);
|
||||
path[plen] = 0; // Copy and null terminate string
|
||||
MKDirResponse resp {};
|
||||
resp.command = commands::MKDIR_STATUS;
|
||||
resp.modification_time = 0;
|
||||
int res = fs.DirCreate(path);
|
||||
resp.status = (res == 0) ? 0x01 : (int8_t) res;
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(MKDirResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::LISTDIR: {
|
||||
NRF_LOG_INFO("[FS_S] -> ListDir");
|
||||
ListDirHeader* header = (ListDirHeader*) om->om_data;
|
||||
uint16_t plen = header->pathlen;
|
||||
char path[plen + 1] = {0};
|
||||
path[plen] = 0; // Copy and null terminate string
|
||||
memcpy(path, header->pathstr, plen);
|
||||
|
||||
ListDirResponse resp {};
|
||||
|
||||
resp.command = commands::LISTDIR_ENTRY;
|
||||
resp.status = 0x01;
|
||||
resp.totalentries = 0;
|
||||
resp.entry = 0;
|
||||
resp.modification_time = 0;
|
||||
int res = fs.DirOpen(path, &dir);
|
||||
if (res != 0) {
|
||||
resp.status = (int8_t) res;
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
};
|
||||
while (fs.DirRead(&dir, &info)) {
|
||||
resp.totalentries++;
|
||||
}
|
||||
fs.DirRewind(&dir);
|
||||
while (true) {
|
||||
res = fs.DirRead(&dir, &info);
|
||||
if (res <= 0) {
|
||||
break;
|
||||
}
|
||||
switch (info.type) {
|
||||
case LFS_TYPE_REG: {
|
||||
resp.flags = 0;
|
||||
resp.file_size = info.size;
|
||||
break;
|
||||
}
|
||||
case LFS_TYPE_DIR: {
|
||||
resp.flags = 1;
|
||||
resp.file_size = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// strcpy(resp.path, info.name);
|
||||
resp.path_length = strlen(info.name);
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse));
|
||||
os_mbuf_append(om, info.name, resp.path_length);
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
/*
|
||||
* Todo Figure out how to know when the previous Notify was TX'd
|
||||
* For now just delay 100ms to make sure that the data went out...
|
||||
*/
|
||||
vTaskDelay(100); // Allow stuff to actually go out over the BLE conn
|
||||
resp.entry++;
|
||||
}
|
||||
assert(fs.DirClose(&dir) == 0);
|
||||
resp.file_size = 0;
|
||||
resp.path_length = 0;
|
||||
resp.flags = 0;
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(ListDirResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
break;
|
||||
}
|
||||
case commands::MOVE: {
|
||||
NRF_LOG_INFO("[FS_S] -> Move");
|
||||
MoveHeader* header = (MoveHeader*) om->om_data;
|
||||
uint16_t plen = header->OldPathLength;
|
||||
// Null Terminate string
|
||||
header->pathstr[plen] = 0;
|
||||
char path[header->NewPathLength + 1] = {0};
|
||||
memcpy(path, &header->pathstr[plen + 1], header->NewPathLength);
|
||||
path[header->NewPathLength] = 0; // Copy and null terminate string
|
||||
MoveResponse resp {};
|
||||
resp.command = commands::MOVE_STATUS;
|
||||
int8_t res = (int8_t) fs.Rename(header->pathstr, path);
|
||||
resp.status = (res == 0) ? 1 : res;
|
||||
auto* om = ble_hs_mbuf_from_flat(&resp, sizeof(MoveResponse));
|
||||
ble_gattc_notify_custom(connectionHandle, transferCharacteristicHandle, om);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NRF_LOG_INFO("[FS_S] -> done ");
|
||||
systemTask.PushMessage(Pinetime::System::Messages::StopFileTransfer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Loads resp with file data given a valid filepath header and resp
|
||||
void FSService::prepareReadDataResp(ReadHeader* header, ReadResponse* resp) {
|
||||
// uint16_t plen = header->pathlen;
|
||||
resp->command = commands::READ_DATA;
|
||||
resp->chunkoff = header->chunkoff;
|
||||
resp->status = 0x01;
|
||||
struct lfs_info info = {};
|
||||
int res = fs.Stat(filepath, &info);
|
||||
if (res == LFS_ERR_NOENT && info.type != LFS_TYPE_DIR) {
|
||||
resp->status = 0x03;
|
||||
resp->chunklen = 0;
|
||||
resp->totallen = 0;
|
||||
} else {
|
||||
lfs_file f;
|
||||
resp->chunklen = std::min(header->chunksize, info.size);
|
||||
resp->totallen = info.size;
|
||||
fs.FileOpen(&f, filepath, LFS_O_RDONLY);
|
||||
fs.FileSeek(&f, header->chunkoff);
|
||||
resp->chunklen = fs.FileRead(&f, resp->chunk, resp->chunklen);
|
||||
fs.FileClose(&f);
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
#pragma once
|
||||
#define min // workaround: nimble's min/max macros conflict with libstdc++
|
||||
#define max
|
||||
#include <host/ble_gap.h>
|
||||
#undef max
|
||||
#undef min
|
||||
|
||||
#include "components/fs/FS.h"
|
||||
|
||||
namespace Pinetime {
|
||||
namespace System {
|
||||
class SystemTask;
|
||||
}
|
||||
namespace Controllers {
|
||||
class Ble;
|
||||
class FSService {
|
||||
public:
|
||||
FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs);
|
||||
void Init();
|
||||
|
||||
int OnFSServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context);
|
||||
void NotifyFSRaw(uint16_t connectionHandle);
|
||||
|
||||
private:
|
||||
Pinetime::System::SystemTask& systemTask;
|
||||
Pinetime::Controllers::FS& fs;
|
||||
static constexpr uint16_t FSServiceId {0xFEBB};
|
||||
static constexpr uint16_t fsVersionId {0x0100};
|
||||
static constexpr uint16_t fsTransferId {0x0200};
|
||||
uint16_t fsVersion = {0x0004};
|
||||
static constexpr uint16_t maxpathlen = 256;
|
||||
static constexpr ble_uuid16_t fsServiceUuid {
|
||||
.u {.type = BLE_UUID_TYPE_16},
|
||||
.value = {0xFEBB}}; // {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0xBB, 0xFE, 0xAF, 0xAD}};
|
||||
|
||||
static constexpr ble_uuid128_t fsVersionUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0x00, 0x01, 0xAF, 0xAD}};
|
||||
|
||||
static constexpr ble_uuid128_t fsTransferUuid {
|
||||
.u {.type = BLE_UUID_TYPE_128},
|
||||
.value = {0x72, 0x65, 0x66, 0x73, 0x6e, 0x61, 0x72, 0x54, 0x65, 0x6c, 0x69, 0x46, 0x00, 0x02, 0xAF, 0xAD}};
|
||||
|
||||
struct ble_gatt_chr_def characteristicDefinition[3];
|
||||
struct ble_gatt_svc_def serviceDefinition[2];
|
||||
uint16_t versionCharacteristicHandle;
|
||||
uint16_t transferCharacteristicHandle;
|
||||
|
||||
enum class commands : uint8_t {
|
||||
INVALID = 0x00,
|
||||
READ = 0x10,
|
||||
READ_DATA = 0x11,
|
||||
READ_PACING = 0x12,
|
||||
WRITE = 0x20,
|
||||
WRITE_PACING = 0x21,
|
||||
WRITE_DATA = 0x22,
|
||||
DELETE = 0x30,
|
||||
DELETE_STATUS = 0x31,
|
||||
MKDIR = 0x40,
|
||||
MKDIR_STATUS = 0x41,
|
||||
LISTDIR = 0x50,
|
||||
LISTDIR_ENTRY = 0x51,
|
||||
MOVE = 0x60,
|
||||
MOVE_STATUS = 0x61
|
||||
};
|
||||
enum class FSState : uint8_t {
|
||||
IDLE = 0x00,
|
||||
READ = 0x01,
|
||||
WRITE = 0x02,
|
||||
};
|
||||
FSState state;
|
||||
char filepath[maxpathlen]; // TODO ..ugh fixed filepath len
|
||||
int fileSize;
|
||||
using ReadHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t pathlen;
|
||||
uint32_t chunkoff;
|
||||
uint32_t chunksize;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using ReadResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint16_t padding;
|
||||
uint32_t chunkoff;
|
||||
uint32_t totallen;
|
||||
uint32_t chunklen;
|
||||
uint8_t chunk[];
|
||||
};
|
||||
using ReadPacing = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint16_t padding;
|
||||
uint32_t chunkoff;
|
||||
uint32_t chunksize;
|
||||
};
|
||||
|
||||
using WriteHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t pathlen;
|
||||
uint32_t offset;
|
||||
uint64_t modTime;
|
||||
uint32_t totalSize;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using WriteResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint16_t padding;
|
||||
uint32_t offset;
|
||||
uint64_t modTime;
|
||||
uint32_t freespace;
|
||||
};
|
||||
|
||||
using WritePacing = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint16_t padding;
|
||||
uint32_t offset;
|
||||
uint32_t dataSize;
|
||||
uint8_t data[];
|
||||
};
|
||||
using ListDirHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t pathlen;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using ListDirResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint16_t path_length;
|
||||
uint32_t entry;
|
||||
uint32_t totalentries;
|
||||
uint32_t flags;
|
||||
uint64_t modification_time;
|
||||
uint32_t file_size;
|
||||
char path[];
|
||||
};
|
||||
|
||||
using MKDirHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t pathlen;
|
||||
uint32_t padding2;
|
||||
uint64_t time;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using MKDirResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
uint32_t padding1;
|
||||
uint16_t padding2;
|
||||
uint64_t modification_time;
|
||||
};
|
||||
|
||||
using DelHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t pathlen;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using DelResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
};
|
||||
using MoveHeader = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t padding;
|
||||
uint16_t OldPathLength;
|
||||
uint16_t NewPathLength;
|
||||
char pathstr[];
|
||||
};
|
||||
|
||||
using MoveResponse = struct __attribute__((packed)) {
|
||||
commands command;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
int FSCommandHandler(uint16_t connectionHandle, os_mbuf* om);
|
||||
void prepareReadDataResp(ReadHeader* header, ReadResponse* resp);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
#include "components/ble/HeartRateService.h"
|
||||
#include "HeartRateService.h"
|
||||
#include "components/heartrate/HeartRateController.h"
|
||||
#include "systemtask/SystemTask.h"
|
||||
#include <nrf_log.h>
|
||||
|
||||
using namespace Pinetime::Controllers;
|
||||
|
||||
|
@ -9,7 +8,7 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
|
|||
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
|
||||
|
||||
namespace {
|
||||
int HeartRateServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) {
|
||||
auto* heartRateService = static_cast<HeartRateService*>(arg);
|
||||
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
|
||||
}
|
||||
|
@ -20,7 +19,7 @@ HeartRateService::HeartRateService(Pinetime::System::SystemTask& system, Control
|
|||
: system {system},
|
||||
heartRateController {heartRateController},
|
||||
characteristicDefinition {{.uuid = &heartRateMeasurementUuid.u,
|
||||
.access_cb = HeartRateServiceCallback,
|
||||
.access_cb = HeartRateServiceServiceCallback,
|
||||
.arg = this,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &heartRateMeasurementHandle},
|
||||
|
@ -57,9 +56,6 @@ int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t a
|
|||
}
|
||||
|
||||
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
||||
if (!heartRateMeasurementNotificationEnable)
|
||||
return;
|
||||
|
||||
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
|
||||
auto* om = ble_hs_mbuf_from_flat(buffer, 2);
|
||||
|
||||
|
@ -71,13 +67,3 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
|
|||
|
||||
ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om);
|
||||
}
|
||||
|
||||
void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
|
||||
if (attributeHandle == heartRateMeasurementHandle)
|
||||
heartRateMeasurementNotificationEnable = true;
|
||||
}
|
||||
|
||||
void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) {
|
||||
if (attributeHandle == heartRateMeasurementHandle)
|
||||
heartRateMeasurementNotificationEnable = false;
|
||||
}
|