mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-23 13:03:13 +00:00
Remove wiki from github (#216)
This commit is contained in:
parent
90894cade2
commit
14d77afc5a
118 changed files with 3 additions and 3545 deletions
82
.github/deploy_wiki.sh
vendored
82
.github/deploy_wiki.sh
vendored
|
@ -1,82 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
function debug() {
|
|
||||||
echo "::debug file=${BASH_SOURCE[0]},line=${BASH_LINENO[0]}::$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
function warning() {
|
|
||||||
echo "::warning file=${BASH_SOURCE[0]},line=${BASH_LINENO[0]}::$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
function error() {
|
|
||||||
echo "::error file=${BASH_SOURCE[0]},line=${BASH_LINENO[0]}::$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
function add_mask() {
|
|
||||||
echo "::add-mask::$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "$GITHUB_ACTOR" ]; then
|
|
||||||
error "GITHUB_ACTOR environment variable is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$GITHUB_REPOSITORY" ]; then
|
|
||||||
error "GITHUB_REPOSITORY environment variable is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$GH_PERSONAL_ACCESS_TOKEN" ]; then
|
|
||||||
error "GH_PERSONAL_ACCESS_TOKEN environment variable is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$WIKI_PATH" ]; then
|
|
||||||
echo "WIKI_PATH environment variable is not set"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
add_mask "${GH_PERSONAL_ACCESS_TOKEN}"
|
|
||||||
|
|
||||||
if [ -z "${WIKI_COMMIT_MESSAGE:-}" ]; then
|
|
||||||
debug "WIKI_COMMIT_MESSAGE not set, using default"
|
|
||||||
WIKI_COMMIT_MESSAGE='Automatically publish wiki'
|
|
||||||
fi
|
|
||||||
|
|
||||||
GIT_REPOSITORY_URL="https://${GH_PERSONAL_ACCESS_TOKEN}@github.com/$GITHUB_REPOSITORY.wiki.git"
|
|
||||||
|
|
||||||
debug "Checking out wiki repository"
|
|
||||||
tmp_dir=$(mktemp -d -t ci-XXXXXXXXXX)
|
|
||||||
(
|
|
||||||
cd "$tmp_dir" || exit 1
|
|
||||||
git init
|
|
||||||
git config user.name "$GITHUB_ACTOR"
|
|
||||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
|
||||||
git pull "$GIT_REPOSITORY_URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
debug "Rsync contents of $WIKI_PATH"
|
|
||||||
rsync -q -a --delete --exclude=.git "$GITHUB_WORKSPACE/$WIKI_PATH/" "$tmp_dir"
|
|
||||||
|
|
||||||
if [ ! -r "$tmp_dir/Home.md" ]; then
|
|
||||||
debug "Copy README.md to wiki/Home.md"
|
|
||||||
rsync -q -a "$GITHUB_WORKSPACE/README.md" "$tmp_dir/Home.md"
|
|
||||||
fi
|
|
||||||
|
|
||||||
debug "Rewriting images path to absolute"
|
|
||||||
(
|
|
||||||
cd "$tmp_dir" || exit 1
|
|
||||||
find . -type f -exec sed -Ei 's@([ (])([^( ]+)(\/wiki_static\/.+?\.(png|jpe?g|svg)[ \)])@\1https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master\3@' {} \;
|
|
||||||
)
|
|
||||||
|
|
||||||
debug "Committing and pushing changes"
|
|
||||||
(
|
|
||||||
cd "$tmp_dir" || exit 1
|
|
||||||
git add .
|
|
||||||
git commit -m "$WIKI_COMMIT_MESSAGE"
|
|
||||||
git push --set-upstream "$GIT_REPOSITORY_URL" master
|
|
||||||
)
|
|
||||||
|
|
||||||
rm -rf "$tmp_dir"
|
|
||||||
exit 0
|
|
||||||
|
|
23
.github/workflows/publish_wiki.yml
vendored
23
.github/workflows/publish_wiki.yml
vendored
|
@ -1,23 +0,0 @@
|
||||||
name: Publish the wiki
|
|
||||||
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
paths:
|
|
||||||
- 'wiki/**'
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout branch
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Upload Documentation to Wiki
|
|
||||||
run: bash ./.github/deploy_wiki.sh
|
|
||||||
env:
|
|
||||||
GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
|
|
||||||
WIKI_PATH: "wiki"
|
|
||||||
|
|
48
README.md
48
README.md
|
@ -6,25 +6,19 @@
|
||||||
|
|
||||||
Welcome to [Flipper Zero](https://flipperzero.one/zero)'s Firmware repo! Our goal is to create nice and clean code along with good documentation, to make it a pleasure for everyone to work with. This repo will become completely public closer to the device shipping date.
|
Welcome to [Flipper Zero](https://flipperzero.one/zero)'s Firmware repo! Our goal is to create nice and clean code along with good documentation, to make it a pleasure for everyone to work with. This repo will become completely public closer to the device shipping date.
|
||||||
|
|
||||||
**We are open for changes!** You can suggest changes for any part of the code, wiki, guidelines, workflow, automation, etc.
|
**We are open for changes!** You can suggest changes for any part of the code, workflow, automation, etc.
|
||||||
|
|
||||||
If you are deary to start, please read [contribution guide](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Contributing) about creating issue, editing wiki, improving codebase and configuring environment.
|
If you are deary to start, please read [contribution guide](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Contributing) about creating issue, editing wiki, improving codebase and configuring environment.
|
||||||
|
|
||||||
# Developer blog
|
|
||||||
|
|
||||||
You can read project updates in our developer blog:
|
|
||||||
|
|
||||||
**[Developer blog index](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Developer-blog)**
|
|
||||||
|
|
||||||
# Firmware
|
# Firmware
|
||||||
|
|
||||||
**[Firmware page](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Firmware)**
|
**[Firmware page](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Firmware)**
|
||||||
|
|
||||||
## Update firmware
|
## Update firmware
|
||||||
|
|
||||||
Flipper Zero's firmware consists of two components: [Bootloader](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Bootloader) and main firmware. Bootloader controls firmware update process over USB. You need working bootloader installed before update firmware over USB.
|
Flipper Zero's firmware consists of two components: Bootloader and main firmware. Bootloader controls firmware update process over USB. You need working bootloader installed before update firmware over USB.
|
||||||
|
|
||||||
1. Download latest [Firmware](http://missed_link) ⚠️ **TODO** permanent link to latest firmware from master ⚠️
|
1. Download latest [Firmware](https://update.flipperzero.one/full_firmware_latest.bin)
|
||||||
|
|
||||||
2. Reboot Flipper to [Firmware update mode](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/UI#reboot-to-bootloader-firmware-update-mode)
|
2. Reboot Flipper to [Firmware update mode](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/UI#reboot-to-bootloader-firmware-update-mode)
|
||||||
|
|
||||||
|
@ -41,42 +35,6 @@ Or you can use your dev. board:
|
||||||
|
|
||||||
`docker-compose exec dev make -C firmware TARGET=f2 APP_*=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples)
|
`docker-compose exec dev make -C firmware TARGET=f2 APP_*=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples)
|
||||||
|
|
||||||
## Architecture and components
|
|
||||||
|
|
||||||
Flipper consists of the two main parts:
|
|
||||||
|
|
||||||
* Core: OS, HAL, FS, bootloader, FURI
|
|
||||||
* Applications: features like RFID or Tamagotchi, and also background tasks like button debouncing and backlight control.
|
|
||||||
|
|
||||||
### User Interface
|
|
||||||
|
|
||||||
[User Interface](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/UI)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* [Basic Features](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Basic-features)
|
|
||||||
* [SD-card](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/SD-Card)
|
|
||||||
* [Sub-1 GHz radio](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Sub-1-GHz-radio) (Transceiver Based on CC1101 chip for 315/433/868 MHz)
|
|
||||||
* [125 kHz RFID](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/125-kHz-RFID)
|
|
||||||
* [Infrared](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Infrared)
|
|
||||||
* [iButton contact keys](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/iButton)
|
|
||||||
* [USB](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/USB)
|
|
||||||
* [Bluetooth](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Bluetooth)
|
|
||||||
* [GPIO/HW Modules](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/GPIO)
|
|
||||||
* [NFC](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/NFC)
|
|
||||||
* [U2F](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/U2F)
|
|
||||||
* [Dolphin](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Dolphin)
|
|
||||||
* [Plugins](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Plugins)
|
|
||||||
|
|
||||||
# Hardware
|
|
||||||
|
|
||||||
**[Hardware page](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware)**
|
|
||||||
|
|
||||||
# Tools
|
|
||||||
|
|
||||||
* [St-Link](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/ST-Link)
|
|
||||||
* [VPN](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/VPN)
|
|
||||||
|
|
||||||
# Links
|
# Links
|
||||||
|
|
||||||
* Discord server: [flipperzero.one/discord](https://flipperzero.one/discord)
|
* Discord server: [flipperzero.one/discord](https://flipperzero.one/discord)
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
rm -rf flipperzero-firmware-community.wiki/*
|
|
||||||
cp -RL wiki/* flipperzero-firmware-community.wiki/
|
|
||||||
cp README.md flipperzero-firmware-community.wiki/Home.md
|
|
||||||
cd flipperzero-firmware-community.wiki && git add * && git commit -a -m "deployed by script" && git push -f
|
|
|
@ -1,21 +0,0 @@
|
||||||
# Discord
|
|
||||||
|
|
||||||
For quick communication and voice calls we use Discord. Please ask for `Contributor` role to use developers channels.
|
|
||||||
|
|
||||||
## Link to Discord server: https://flipperzero.one/discord
|
|
||||||
|
|
||||||
Separating roles and channels in this way:
|
|
||||||
|
|
||||||
### Roles
|
|
||||||
|
|
||||||
* Everyone
|
|
||||||
* Contributors — everyone who has access to our Github
|
|
||||||
* Staff — people working in-house
|
|
||||||
* Admins — staff members who can manage permissions
|
|
||||||
|
|
||||||
### Channels
|
|
||||||
|
|
||||||
Right now I just separate contributors from everyone, to prevent a flood. Later we can create more voice and text channels for firmware/hardware/creative department.
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/774290/90881195-6536de80-e3b2-11ea-8b14-c7ac5b69c10c.png)
|
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
([see issue about this page](https://github.com/Flipper-Zero/flipperzero-firmware-community/labels/Area%3AContributing))
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
If you are just beginning in Flipper, **Read the [wiki](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki)**. It describes general things like contribution, building and testing, and tell about main features. Flipper consists of two main parts:
|
|
||||||
|
|
||||||
* Core: OS, HAL, FS, bootloader, FURI
|
|
||||||
* Applications: features like RFID or Tamagotchi, and also background tasks like button debouncing and control the backlight.
|
|
||||||
|
|
||||||
## General Tips and principles
|
|
||||||
|
|
||||||
* **Ask around for help!** If you have any questions, feel free to create an [`need help` issue](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=&labels=need+help&template=need-help.md&title=), send an email to devel@flipperdevices.com or use our [Discord server](https://flipperzero.one/discord) ([read more about discord](Communication)). The earlier you check your feature design with other people, the less likely it is that it is denied during the review process.
|
|
||||||
* **Verify your concept early!** If you work on your own until the code looks good enough to show publicly, you might miss some design flaws others might have spotted earlier.
|
|
||||||
* **Keep it simple!** Try to use what is already there and don't change existing APIs if not absolutely necessary.
|
|
||||||
* **State your intentions** Create issue before you start your work. It will prevent a very frustrating situation where several people are doing the same job the same time.
|
|
||||||
* **Make tests `(incomplete)`**
|
|
||||||
* **Make docs** you can do very cool things but other people cannot use if it is not described in the documentation
|
|
||||||
* **We are open to changes.** You can suggest changes to any part of the code, wiki, guidelines, workflow, automation, etc. by creating issue or PR if you understand how it can be done better.
|
|
||||||
|
|
||||||
## Welcome message
|
|
||||||
|
|
||||||
Good point to add something about yourself. Create [welcome issue](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=glitchcore%2C+zhovner&labels=welcome&template=welcome.md&title=), tell community about yourself, what tasks you can take and what help do you need. You can find another users messages by [message tag](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=is%3Aissue+label%3Awelcome+).
|
|
||||||
|
|
||||||
## Status of wiki sections
|
|
||||||
|
|
||||||
* Some sections mark as `incomplete`. This means that there is not even a description of how the feature can be implemented. You can start [discussion](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=&labels=discussion&template=discuss-issue.md&title=) thread or directly begin to write wiki page (see [Contributing](#contributing)).
|
|
||||||
* Some sections mark as `not implemented`. It have description but there is nothing that would make this description into reality.
|
|
||||||
* Some sections mark as `not documented`. There is some implementation and you can add some documentation here.
|
|
||||||
* If section of wiki has no mark, this is actual documentation for part of Flipper.
|
|
||||||
|
|
||||||
## How to edit Wiki
|
|
||||||
|
|
||||||
> ⚠️ **Do not edit Wiki direcrly in web-interface. Your changes will be lost after automatic rebuild**
|
|
||||||
|
|
||||||
1. Edit files in `wiki` and `wiki_static` files in your branch
|
|
||||||
2. Create PR with `documentation` label
|
|
||||||
3. Wait for automatic rebuild after merged in master branch
|
|
||||||
|
|
||||||
The [Wiki](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki) connected to this repostiry is automatically generated from `.md` files located in repository via Github Actions.
|
|
||||||
|
|
||||||
|
|
||||||
**Folder structure:**
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── wiki # Actual wiki pages in markdown format
|
|
||||||
├── wiki_static # Static files for wiki: images, pdf, samples
|
|
||||||
```
|
|
||||||
|
|
||||||
## Backlog
|
|
||||||
|
|
||||||
Some tasks were postponed, you can find it by tag [backlog](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=label%3Abacklog+), maybe you are ready to implement something of it.
|
|
||||||
|
|
||||||
|
|
||||||
# Maintainers
|
|
||||||
|
|
||||||
Every section/page of wiki and related part of code has its own maintainers. Maintainers list and related code folders is placed at the bottom of page or section.
|
|
||||||
|
|
||||||
To become a maintainer of some section/page, create issue or write to devel@flipperdevices.com.
|
|
||||||
|
|
||||||
If contributors cannot reach consensus during a discussion or code review, you can add a [needs moderating](https://github.com/Flipper-Zero/flipperzero-firmware-community/labels/needs%20moderating) label. Maintainers has the final say in the discussion.
|
|
||||||
|
|
||||||
If maintainers cannot reach consensus, Flipper devices CTO ([`@glitchcore`](https://github.com/glitchcore)) has the final say in the discussion.
|
|
||||||
|
|
||||||
# Issues
|
|
||||||
|
|
||||||
Please notice that we use a bunch of tags to label the issues.
|
|
||||||
|
|
||||||
All issues are, if possible, tied to sections in the wiki with `Area:<wiki page name>` labels.
|
|
||||||
|
|
||||||
Full list of labels you can find at [labels list page](https://github.com/Flipper-Zero/flipperzero-firmware-community/labels).
|
|
||||||
|
|
||||||
# Contributing
|
|
||||||
|
|
||||||
If you want to add some features or suggest some changes, do following steps:
|
|
||||||
|
|
||||||
1. Choose section which you want to improve
|
|
||||||
2. Check existing issues and PR by `Area` tag. Maybe somebody create discussion about your improvement or already doing some work.
|
|
||||||
3. Choose your way:
|
|
||||||
* If you have some idea about new feature, you can create **[feature request](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=&labels=feature+request&template=feature_request.md&title=)**
|
|
||||||
* If you find some bug, you can create **[bug report](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=&labels=bug&template=bug_report.md&title=)**
|
|
||||||
* You can ask for help if you are not sure how to implement your idea or discuss implementation details by creating **[discuss issue](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/new?assignees=&labels=discussion&template=discuss-issue.md&title=)**.
|
|
||||||
4. Otherwise, make you improvement:
|
|
||||||
* Clone actual repository.
|
|
||||||
* Create a branch
|
|
||||||
* Make commits
|
|
||||||
* Push your branch and create a [pull request](#pull-requests)
|
|
||||||
* Wait for maintainers feedback.
|
|
||||||
* Your code is merged in master branch
|
|
||||||
5. If you can do only part of work, create PR with `WIP` label. Describe what you have already done and what remains to be done and other people can help you.
|
|
||||||
|
|
||||||
## Coding Style
|
|
||||||
|
|
||||||
Flipper Zero source code is formatted using clang-format for C code and rustfmt for rust. We use the [Kernel Code Style](https://www.kernel.org/doc/html/latest/process/coding-style.html) with minor changes, you can see the rules in .clang-format file. The Github CI tests will automatically check the code format and fail if the format is incorrect.
|
|
||||||
|
|
||||||
Also, you can check and fix format with syntax_check.sh script.
|
|
||||||
|
|
||||||
## Pull requests
|
|
||||||
|
|
||||||
1. Don't forget reference issues or other PR
|
|
||||||
2. Add `Area:` label to PR
|
|
||||||
3. Remember that smaller PRs tend to be merged faster, so keep your changes as concise as possible. They should be confined to a single explainable change, and be runnable on their own. So don't hesitate to split your PRs into smaller ones when possible.
|
|
||||||
4. If you only create description at wiki but no implementation existing, don't forget to add `not implemented` mark.
|
|
||||||
5. We strongly recommend documenting your code and creating wiki descriptions at the same time as improvement the code. If you have no energy left for documentation, at least mark the appropriate section of the wiki as `not documented`, or you can create `WIP` PR and wait for help.
|
|
||||||
|
|
||||||
### Large and static files storage (incomplete)
|
|
||||||
|
|
||||||
_Maintainers of this page: [`@glitchcore`](https://github.com/glitchcore)_
|
|
|
@ -1,12 +0,0 @@
|
||||||
# Integration testing
|
|
||||||
|
|
||||||
* **[Bootloader testcase](Bootloader-test)**
|
|
||||||
* **[Input testcase](Input-test)**
|
|
||||||
* **[General testcase](General-building-test)**
|
|
||||||
* **[NFC and LF RFID testcase](NFC-LF-RFID-test)**
|
|
||||||
|
|
||||||
# Unit testing
|
|
||||||
|
|
||||||
1. We use [minunit](https://github.com/barrust/c-utils#minunit) as testing framework
|
|
||||||
2. Tests root placed in `applications/tests/minuint_test.c`
|
|
||||||
3. There is `Run local tests` job in `CI` pipeline (`.github/workflows/ci.yml`)
|
|
148
wiki/UI.md
148
wiki/UI.md
|
@ -1,148 +0,0 @@
|
||||||
# Controls
|
|
||||||
|
|
||||||
Flipper Zero have 5 button directional pad.
|
|
||||||
Buttons `← Left`, `→ Right`, `↑ Up`, `↓ Down` can be pressed only one at a time, and **CAN'T BE used in combination**.
|
|
||||||
Buttons `◉ OK` and `⮌ Back` is independed from other buttons and can be used for combinations.
|
|
||||||
|
|
||||||
```
|
|
||||||
Up
|
|
||||||
↑
|
|
||||||
Left ← (OK) → Right
|
|
||||||
↓
|
|
||||||
Down ⮌ Back
|
|
||||||
```
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/controls.png)
|
|
||||||
|
|
||||||
On directinal pad only one button out of 4 can be pressed at once. `◉ OK` and `⮌ Back` buttons are indepandent.
|
|
||||||
|
|
||||||
# Reboot combination
|
|
||||||
|
|
||||||
Reset combination triggers hard reboot that cannot be intercepted by any software. Used when application freezes or as normal way to reboot device.
|
|
||||||
|
|
||||||
1. Press and hold `Left ←` + `⮌ Back` for reset
|
|
||||||
2. Release to normal boot
|
|
||||||
|
|
||||||
![Reboot combination](../wiki_static/ui/reboot-combo.png)
|
|
||||||
|
|
||||||
# Reboot to Bootloader (Firmware update mode)
|
|
||||||
|
|
||||||
Same as hard reboot, but stay in Firmware Update mode after boot. Useful when firmware is broken and user cannot boot in normal mode.
|
|
||||||
|
|
||||||
1. Press and hold `Left ←` + `⮌ Back` for reset
|
|
||||||
2. Release `Left ←` and keep holding `⮌ Back` until `Firmware Update` mode appears
|
|
||||||
3. Release `⮌ Back`
|
|
||||||
|
|
||||||
To exit from `Firmware Update` mode use [reboot combination](#reboot-combination)
|
|
||||||
|
|
||||||
![Reboot to Bootloader](./../wiki_static/ui/reboot-to-bootloader.png)
|
|
||||||
|
|
||||||
# DFU mode (Rescue mode)
|
|
||||||
|
|
||||||
Reboot to rescue DFU mode. Useful when firmware and bootloader is broken.
|
|
||||||
|
|
||||||
1. Press and hold `Left ←` + `⮌ Back` + `◉ OK`
|
|
||||||
2. Release `Left ←` + `⮌ Back` and keep `◉ OK` pressed
|
|
||||||
3. Release `◉ OK`
|
|
||||||
|
|
||||||
To exit from `Firmware Update` mode use [reboot combination](#reboot-combination)
|
|
||||||
|
|
||||||
![](../wiki_static/ui/reboot-to-dfu.png)
|
|
||||||
|
|
||||||
# Menu structure
|
|
||||||
|
|
||||||
![](../wiki_static/ui/menu-navigation.png)
|
|
||||||
|
|
||||||
# Standby screen
|
|
||||||
|
|
||||||
On standby screen we can see battery, status bar and dolphin animation. Animation can cover the status bar according to the battery charge width.
|
|
||||||
|
|
||||||
![](../wiki_static/ui/UI-Standby.png)
|
|
||||||
|
|
||||||
![](../wiki_static/ui/UI-Standby-status-1.png)
|
|
||||||
|
|
||||||
![](../wiki_static/ui/UI-Standby-status-88.png)
|
|
||||||
|
|
||||||
## Status Bar Icons
|
|
||||||
|
|
||||||
- SD Card mounted
|
|
||||||
- SD Card failed
|
|
||||||
- USB connected
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-statusbar.png)
|
|
||||||
|
|
||||||
# Main menu
|
|
||||||
|
|
||||||
Active row is always in the middle of the screen.
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-main-menu-screen.png)
|
|
||||||
|
|
||||||
### Main menu sctructure
|
|
||||||
|
|
||||||
- Sub-1 GHz
|
|
||||||
- RFID 125kHz
|
|
||||||
- NFC
|
|
||||||
- Infrared
|
|
||||||
- iButton
|
|
||||||
- Bluetooth
|
|
||||||
- Bad USB
|
|
||||||
- GPIO
|
|
||||||
- NFC
|
|
||||||
- U2F
|
|
||||||
- File Manager
|
|
||||||
- Plugins
|
|
||||||
- Games
|
|
||||||
- Passport
|
|
||||||
- Settings
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/main-menu-full.png)
|
|
||||||
|
|
||||||
|
|
||||||
### Active row
|
|
||||||
|
|
||||||
Font: `u8g2_font_Born2bSportyV2_tf`
|
|
||||||
Size: 9 px
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-active-row-text.png)
|
|
||||||
|
|
||||||
### Non-active row
|
|
||||||
|
|
||||||
Font: `u8g2_font_HelvetiPixel_tr`
|
|
||||||
Size: 8 px
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-non-active-row-text.png)
|
|
||||||
|
|
||||||
### Icon
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-icon.png)
|
|
||||||
|
|
||||||
### Scrollbar
|
|
||||||
|
|
||||||
Scrollbar has 32 dots and a simple thumb.
|
|
||||||
|
|
||||||
![](./../wiki_static/ui/UI-Scrollbar-and-thumb.png)
|
|
||||||
|
|
||||||
# Application menu
|
|
||||||
|
|
||||||
Font: `u8g2_font_HelvetiPixel_tr`
|
|
||||||
Size: 8 px
|
|
||||||
|
|
||||||
![](../wiki_static/ui/UI-app-menu.png)
|
|
||||||
|
|
||||||
# Application screen with buttons
|
|
||||||
|
|
||||||
Font: `u8g2_font_HelvetiPixel_tr`
|
|
||||||
Size: 8 px
|
|
||||||
|
|
||||||
Minimum button width is 38 px.
|
|
||||||
Maximum button width is 63 px.
|
|
||||||
|
|
||||||
![](../wiki_static/ui/UI-app-menu-buttons.png)
|
|
||||||
|
|
||||||
# Pass-code lock
|
|
||||||
|
|
||||||
Flipper will store your secrets like U2F token and house keys. What if Flipper gets lost?
|
|
||||||
|
|
||||||
Well, no problem! For this case, we made a locking feature. You can lock Flipper and unlock it with the special pass-combo, like in good old fighting games (for example, →↑↑←↓↑↓). Users can set a pass-combo of any length, and all functions will be blocked until the combo is entered, including firmware flashing.
|
|
||||||
|
|
||||||
![](https://ksr-ugc.imgix.net/assets/030/153/925/13404091a9c1bb3390a67afe279a0051_original.gif?ixlib=rb-2.1.0&w=700&fit=max&v=1597158235&auto=format&gif-q=50&q=92&s=06a640ecaa809487b004c1bead0fd9cc)
|
|
|
@ -1,9 +0,0 @@
|
||||||
### For quick communication and voice calls we use Discord: [flipperzero.one/discord](https://flipperzero.one/discord)
|
|
||||||
|
|
||||||
(please ask for `Contributor` role to use developers channels in Discord)
|
|
||||||
|
|
||||||
[read more about discord](Communication)
|
|
||||||
|
|
||||||
Community forum: [forum.flipperzero.one](https://forum.flipperzero.one)
|
|
||||||
|
|
||||||
Project website: [flipperzero.one](https://flipperzero.one)
|
|
|
@ -1,53 +0,0 @@
|
||||||
### ⚠️ Warning ⚠️
|
|
||||||
|
|
||||||
_Do not edit this Wiki in web-interface. Read [How to edit Wiki](Contributing#how-to-edit-wiki)_
|
|
||||||
|
|
||||||
# [Home](Home)
|
|
||||||
|
|
||||||
# [Developer blog](Developer-blog)
|
|
||||||
|
|
||||||
# [Contributing](Contributing)
|
|
||||||
* [Communication](Communication)
|
|
||||||
|
|
||||||
# Firmware
|
|
||||||
|
|
||||||
* [Architecture](Firmware)
|
|
||||||
* [Environment](Environment)
|
|
||||||
* [Flipper-applications](Flipper-applications)
|
|
||||||
* [FURI](FURI)
|
|
||||||
* [Timers](Timers)
|
|
||||||
* [UI](UI)
|
|
||||||
|
|
||||||
# [Examples](Application-examples)
|
|
||||||
|
|
||||||
* [Blink](Blink-app)
|
|
||||||
* [UART write](UART-write)
|
|
||||||
* [Inter-process communication](IPC-example)
|
|
||||||
|
|
||||||
# Hardware
|
|
||||||
|
|
||||||
* [Hardware-specification](Hardware-specification)
|
|
||||||
* [F1B1C0.0](Hardware-version-F1B1C0.0)
|
|
||||||
* [F2B0C1.1](Hardware-version-F2B0C1.1)
|
|
||||||
|
|
||||||
# [Testing](Testing)
|
|
||||||
|
|
||||||
* [Bootloader testcase](Bootloader-test)
|
|
||||||
* [Input testcase](Input-test)
|
|
||||||
* [General testcase](General-building-test)
|
|
||||||
|
|
||||||
# Features
|
|
||||||
|
|
||||||
* [Sub-1 GHz radio](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Sub-1-GHz-radio)
|
|
||||||
* [SD-Card](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/SD-Card)
|
|
||||||
* [125 kHz RFID](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/125-kHz-RFID)
|
|
||||||
* [Infrared](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Infrared)
|
|
||||||
* [iButton](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/iButton)
|
|
||||||
* [USB](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/USB)
|
|
||||||
* [Bluetooth](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Bluetooth)
|
|
||||||
* [GPIO/HW Modules](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/GPIO)
|
|
||||||
* [NFC](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/NFC)
|
|
||||||
* [U2F](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/U2F)
|
|
||||||
* [Dolphin](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Dolphin)
|
|
||||||
* [USB](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/USB)
|
|
||||||
* [Plugins](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Plugins)
|
|
|
@ -1,59 +0,0 @@
|
||||||
![Flipper Zero RFID](https://habrastorage.org/webt/jd/fb/yb/jdfbybzgw6qvg5kjeuvfg8w0iou.png)
|
|
||||||
|
|
||||||
Low-frequency proximity cards are widely used in access control systems around the world. It's pretty dumb, keeps only a short few-byte ID, and has no authentication mechanism, allowing it to be easily read, cloned, and emulated by anyone. A 125 kHz antenna is located on the bottom of Flipper's body.
|
|
||||||
|
|
||||||
## Card types supported
|
|
||||||
|
|
||||||
### Mandatory
|
|
||||||
* EM400x, EM410x, EM420x
|
|
||||||
* HID Prox (Proxcard, ISOProx, ProxKey). Not project Keysy told: _Emulation not supported on multiClass readers, can still clone to rewritable_
|
|
||||||
* HID Indala (Motorola Indala)
|
|
||||||
* Write to T55x7 compatible keycard/keyfob
|
|
||||||
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
* Noralsy (KCP3000)
|
|
||||||
* Farpointe Pyramid
|
|
||||||
* Keri (KC-10X, MT-10X, PKT-10X)
|
|
||||||
* Kantech ioProx
|
|
||||||
* DoorKing (DKProx) [Not DKProx Long Range]
|
|
||||||
* AWID (Low frequency only – CS-AWID, GR-AWID, KT-AWID, PW-AWID)
|
|
||||||
Keysy note: (Emulation not supported, can still clone to rewritable)
|
|
||||||
* Radio Key (SecuraKey RKKT-01, RKKT-02)
|
|
||||||
* Viking
|
|
||||||
* Visa2000
|
|
||||||
* Schlage IBF iButton (RFID portion only)
|
|
||||||
|
|
||||||
### Exotic
|
|
||||||
* Pet tags
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### Reading
|
|
||||||
* Read specific card type, save ID
|
|
||||||
* card type detection (testing all protocols one by one, and read ID if found)
|
|
||||||
|
|
||||||
### Emulation
|
|
||||||
* Emulate saved cards
|
|
||||||
* Enter card ID and card type manually to saved ID library
|
|
||||||
_You can also emulate the card by entering its ID manually, so you can easily send it to your friend in a text format. Thus, Flipper owners can exchange card dumps with each other remotely without ever touching a physical card._
|
|
||||||
|
|
||||||
### Write card
|
|
||||||
* Write to T55x7 compatible keycard/keyfob
|
|
||||||
|
|
||||||
|
|
||||||
## Links
|
|
||||||
|
|
||||||
* https://scanlime.org/2008/09/using-an-avr-as-an-rfid-tag/
|
|
||||||
* [ESP8266 em4100 emulator](https://github.com/Crypter/ESP-RFID)
|
|
||||||
* https://www.kickstarter.com/projects/1708444109/rfidler-a-software-defined-rfid-reader-writer-emul
|
|
||||||
* https://github.com/AlexMalov/EasyKeyDublicatorRFID
|
|
||||||
* https://shop.hak5.org/products/keysy
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
## Main menu
|
|
||||||
|
|
||||||
* Read
|
|
||||||
* Saved Keys
|
|
||||||
* Enter manually
|
|
|
@ -1,6 +0,0 @@
|
||||||
Bluetooth module will allow you to interact with Flipper using your smartphone, as well as transfer interfaces like UART and SPI to your computer wirelessly.
|
|
||||||
|
|
||||||
|
|
||||||
## Bluetooth Serial adapter
|
|
||||||
|
|
||||||
User can connect Flipper Zero to UART port via GPIO and get access via Bluetooth
|
|
|
@ -1,3 +0,0 @@
|
||||||
* Dolphin Levels — каждое активное хакерское действие увеличивает уровень дельфина
|
|
||||||
* Dolphin emotional status — если долго не играть, то дельфин начинает вести себя тупо, становится неактивным, заванивается, протухает
|
|
||||||
* Dolphin games
|
|
|
@ -1,5 +0,0 @@
|
||||||
![](https://blog.flipperzero.one/content/images/size/w2400/2020/10/jgrON6e.png)
|
|
||||||
|
|
||||||
Flipper Zero can be used as a versatile tool for hardware hacking. Its 12 built-in GPIO pins are 5V tolerant and allow you to connect it to any piece of hardware while running your own code, controlling it with buttons and printing debug messages to the LCD display.
|
|
||||||
|
|
||||||
You can use it as a handy firmware flashing, debugging, and fuzzing device, as well as USB to UART/SPI/I2C/etc adapter connected to the PC.
|
|
|
@ -1,27 +0,0 @@
|
||||||
The infrared transmitter can send any signal to control electronics such as TV, air conditioners, stereo systems, and others.
|
|
||||||
![](./../../wiki_static/applications/Infrared/infrared-transceiver.jpg)
|
|
||||||
|
|
||||||
## Signal library
|
|
||||||
|
|
||||||
Flipper contains a built-in library of common remote commands like:
|
|
||||||
|
|
||||||
* Switching ON/OFF and changing volume of popular TV brands
|
|
||||||
* Switching ON/OFF of popular air conditioners brands
|
|
||||||
|
|
||||||
This library is constantly updated by Flipper community users that upload new signals to Flipper's IR remote database. This library is **located on SD-card and not included on firmware**.
|
|
||||||
|
|
||||||
## Infrared learning feature
|
|
||||||
|
|
||||||
![](../../wiki_static/applications/Infrared/infrared-learning.jpg)
|
|
||||||
|
|
||||||
At the same time, the IR receiver can catch signals and save them to the memory, so you can store any of your personal remotes and transmit it later, as well as upload it to the public database to share with other Flipper users.
|
|
||||||
|
|
||||||
Flipper's infrared receiver can automatically detect baud rate, frequency, and modulation of most IR remotes signals and captures it without any configuration. To learn new signal, user should point IR remote directly into Flipper receiver on distance 10-15 cm.
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
## Main menu
|
|
||||||
|
|
||||||
* Library
|
|
||||||
* Read
|
|
||||||
* Saved signals
|
|
|
@ -1,179 +0,0 @@
|
||||||
## Supported card types
|
|
||||||
|
|
||||||
Flipper Zero can read and emulate:
|
|
||||||
|
|
||||||
* ISO-14443A/B
|
|
||||||
* Mifare Classic 1k/4k
|
|
||||||
* Mifare Ultralight
|
|
||||||
* NFC Forum protocols (NDEF)
|
|
||||||
|
|
||||||
|
|
||||||
## Card detector
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/NFC/nfc-card-detector.png)
|
|
||||||
|
|
||||||
Card type is often unknown. Card detector runs tests against the unknown card to determine it's type. These tests are not 100% accurate, but they help to start exploring. If the test finished successfully, it can recommend to run a suitable application for the card type.
|
|
||||||
|
|
||||||
### Card detector routine:
|
|
||||||
|
|
||||||
1. Check if card `ISO-14443` `A` or `B` or `FeliCa`
|
|
||||||
2. Check the 6 byte of `SAK` to determine if `ISO-14443-4` compliant
|
|
||||||
3. Match combination of UID, SAK, ATQA, ATS, ATR from database
|
|
||||||
4. Try to authenticate as Mifare, EMV, etc..
|
|
||||||
5. Return founded type and suggest suitable application or return error
|
|
||||||
|
|
||||||
## Reader detector
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/NFC/nfc-wall-reader.png)
|
|
||||||
|
|
||||||
Wall readers usually looks the same, but may accept various types type of cards. With reader detector feature we can emulate dummy card on Flipper and sniff commands that reader send to card.
|
|
||||||
|
|
||||||
|
|
||||||
### Reader detector
|
|
||||||
|
|
||||||
1. Silently read WUPA (0x52) or REQA (0x26) without triggering SELECT on reader
|
|
||||||
2. Emulate dummy card
|
|
||||||
2.1 Answer on ATQA
|
|
||||||
2.2 Answer on SELECT
|
|
||||||
2.3 ...
|
|
||||||
3. Consistently emulate popular cards before valid authentication from reader found
|
|
||||||
|
|
||||||
## Reader mode
|
|
||||||
|
|
||||||
* Mifare classic reader _How to select dictionary?_
|
|
||||||
* Brute force
|
|
||||||
* Save dump
|
|
||||||
* Write dump to SD-card
|
|
||||||
* Mifare Ultralight reader
|
|
||||||
* Save dump
|
|
||||||
* Write dump?
|
|
||||||
* EMV reader
|
|
||||||
* Simple UID reader
|
|
||||||
|
|
||||||
## Write/Emulate mode
|
|
||||||
|
|
||||||
Saved dumps stored on SD-card and accessible from `Saved dumps` menu. All saved dumps can be emulated or written to card if possible. User can view dump info and choose the action:
|
|
||||||
|
|
||||||
* Emulate
|
|
||||||
* Write
|
|
||||||
* Edit? _(Editing big dumps can be can be difficult)_
|
|
||||||
|
|
||||||
# USB NFC Reader [Not implemented]
|
|
||||||
![](./../../wiki_static/applications/NFC/usb-nfc-reader.png)
|
|
||||||
|
|
||||||
There are many use cases that impossible to run directly on Flipper Zero. Most of these cases require powerful CPU for cryptographic attacks:
|
|
||||||
|
|
||||||
- Mifare classic attacks: `mfoc` (Nested), `mfcuk` (Dark Side)
|
|
||||||
- Mifare Plus attack: Hard Nested
|
|
||||||
|
|
||||||
We can use Flipper Zero as a regular USB NFC adapter along with `LibNFC` library, so all existing software will work out of the box without any modifications. This mode must be run from menu `NFC -> USB NFC adapter`. In this mode all commands from PC should be forwarded directly to NFC chip `ST25R3916` via USB serial interface.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Chat log with <a href="https://github.com/doegox">Philippe @doegox Teuwen</a> about LibNFC driver for ST25R3916</summary>
|
|
||||||
|
|
||||||
> [Pavel Zhovner]: About ST chip support in libnfc: I understand that libnfc is tightly tied to PNxxx and I can't fully imagine how big this work will be :slight_smile: Our main goal is to keep compatibility for user space applications like mfterm, mfoc and so on. I don't know much about Libnfc userspace API, and in my imagination, we just need to write a low level driver for ST25R3916 and the rest will work out of the box, maybe I'm wrong. Here how I imagine this. We already start to implementing commands forwarding daemon.
|
|
||||||
|
|
||||||
![](../../wiki_static/applications/NFC/libnfc_proxy_scheme.png)
|
|
||||||
|
|
||||||
> [doegox]: ther are intermediate APIs within libnfc, as I said yesterday maybe not super well layered
|
|
||||||
with directories buses/chips/drivers
|
|
||||||
and struct like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
const struct nfc_driver pn53x_usb_driver = {
|
|
||||||
.name = PN53X_USB_DRIVER_NAME,
|
|
||||||
.scan_type = NOT_INTRUSIVE,
|
|
||||||
.scan = pn53x_usb_scan,
|
|
||||||
.open = pn53x_usb_open,
|
|
||||||
.close = pn53x_usb_close,
|
|
||||||
.strerror = pn53x_strerror,
|
|
||||||
|
|
||||||
.initiator_init = pn53x_initiator_init,
|
|
||||||
.initiator_init_secure_element = NULL, // No secure-element support
|
|
||||||
.initiator_select_passive_target = pn53x_initiator_select_passive_target,
|
|
||||||
.initiator_poll_target = pn53x_initiator_poll_target,
|
|
||||||
.initiator_select_dep_target = pn53x_initiator_select_dep_target,
|
|
||||||
.initiator_deselect_target = pn53x_initiator_deselect_target,
|
|
||||||
.initiator_transceive_bytes = pn53x_initiator_transceive_bytes,
|
|
||||||
.initiator_transceive_bits = pn53x_initiator_transceive_bits,
|
|
||||||
.initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed,
|
|
||||||
.initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed,
|
|
||||||
.initiator_target_is_present = pn53x_initiator_target_is_present,
|
|
||||||
|
|
||||||
.target_init = pn53x_target_init,
|
|
||||||
.target_send_bytes = pn53x_target_send_bytes,
|
|
||||||
.target_receive_bytes = pn53x_target_receive_bytes,
|
|
||||||
.target_send_bits = pn53x_target_send_bits,
|
|
||||||
.target_receive_bits = pn53x_target_receive_bits,
|
|
||||||
|
|
||||||
.device_set_property_bool = pn53x_usb_set_property_bool,
|
|
||||||
.device_set_property_int = pn53x_set_property_int,
|
|
||||||
.get_supported_modulation = pn53x_usb_get_supported_modulation,
|
|
||||||
.get_supported_baud_rate = pn53x_get_supported_baud_rate,
|
|
||||||
.device_get_information_about = pn53x_get_information_about,
|
|
||||||
|
|
||||||
.abort_command = pn53x_usb_abort_command,
|
|
||||||
.idle = pn53x_idle,
|
|
||||||
.powerdown = pn53x_PowerDown,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
> [doegox]: so if you can write ST equivalents to these pn53x_*, and map them to the generic names of the left column, that should work :) in a new driver
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Schematic
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/NFC/ST25R3916-schematic.png)
|
|
||||||
|
|
||||||
|
|
||||||
# Menu
|
|
||||||
![](./../../wiki_static/applications/NFC/nfc-ui.png)
|
|
||||||
|
|
||||||
<!--- Menu structure -->
|
|
||||||
# NFC
|
|
||||||
|
|
||||||
## Detect card
|
|
||||||
|
|
||||||
- Activating RF field and wait for card.
|
|
||||||
Run tests when card found.
|
|
||||||
- Found match
|
|
||||||
- Mifare Classic found.
|
|
||||||
Run Mifare reader?
|
|
||||||
- No found
|
|
||||||
- Cannot detect card type
|
|
||||||
|
|
||||||
## Reader detector
|
|
||||||
|
|
||||||
- Passive listen for WUPA/REQA-B
|
|
||||||
- Commands live stream
|
|
||||||
0x26
|
|
||||||
0x26
|
|
||||||
0x26
|
|
||||||
- Start active emulating
|
|
||||||
- .
|
|
||||||
- Mifare reader found
|
|
||||||
- .
|
|
||||||
- EMV reader found
|
|
||||||
|
|
||||||
## Read card
|
|
||||||
|
|
||||||
- Mifare Classic
|
|
||||||
- Mifare Ultralight
|
|
||||||
- EMV get PAN
|
|
||||||
- what more?
|
|
||||||
|
|
||||||
## Saved dumps
|
|
||||||
|
|
||||||
- mfc_a6b804bf
|
|
||||||
- home
|
|
||||||
- mfu_04bfac72
|
|
||||||
- emv_paywave_1007
|
|
||||||
|
|
||||||
## USB NFC Reader
|
|
||||||
|
|
||||||
- Activates instantly.
|
|
||||||
No more display updates
|
|
||||||
<!--- Menu structure end -->
|
|
|
@ -1,6 +0,0 @@
|
||||||
Users can add their own applications. Third party apps placed in `Plugins` menu.
|
|
||||||
|
|
||||||
## Plugins list
|
|
||||||
|
|
||||||
* USB -> UART
|
|
||||||
* Servo
|
|
|
@ -1,63 +0,0 @@
|
||||||
<img width="450" src="https://habrastorage.org/webt/la/fp/fz/lafpfzh4fsihzkdx0x_e5hofmdi.png" />
|
|
||||||
|
|
||||||
Flipper Zero support **optional** micro SD-card for expanding file system. It can store additional assets, plugins, libraries and so on. There is official SD-card image supplied with firmware updates, user can upload it using desktop firmware update util
|
|
||||||
|
|
||||||
# Supported cards
|
|
||||||
|
|
||||||
- micro SD HC class 1? **TODO: What actually types are NOT supported?**
|
|
||||||
- FAT/exFAT filesystem
|
|
||||||
- GPT and MBR partitioning table **TODO: Not clear in FatFS library docs**
|
|
||||||
- Max size: up to 2TB **TODO: not tested, on 8GB confirmed**
|
|
||||||
- Read/Write speed: up to 500 kbit/s **TODO: not clearly tested**
|
|
||||||
- Built-in filesystem **TODO: not sure**
|
|
||||||
|
|
||||||
# File manager
|
|
||||||
|
|
||||||
File manager allows user to:
|
|
||||||
|
|
||||||
- See information of filesystem
|
|
||||||
- Format sd-card to exFAT
|
|
||||||
- View files list
|
|
||||||
- View file info
|
|
||||||
- Run executable file: `.bin`, `.py`
|
|
||||||
- Delete file
|
|
||||||
|
|
||||||
## SD-card not inserted
|
|
||||||
|
|
||||||
If SD-card is not inserted, statusbar is empty. File manager application menu only shows help text "SD-card not found".
|
|
||||||
**TODO:** Do we need `Scan for sd-card` action when card not found automatically?
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/sd-card/sd-card-not-found.jpg)
|
|
||||||
|
|
||||||
## SD-card inserted and mounted correctly
|
|
||||||
|
|
||||||
When SD-card with correct fylesystem inserted, Flipper automatically trying to mount filesystem. If filesystem mounted correcly, the normal SD-card icon brings in statusbar.
|
|
||||||
|
|
||||||
![](./../../wiki_static/ui/status-bar-sdcard-ok.png)
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/sd-card/sd-card-file-manager-ok.jpg)
|
|
||||||
|
|
||||||
## SD-card inserted and mount failed
|
|
||||||
|
|
||||||
If SD-card cannot be mounted because of not supported filesystem or any other reason, statusbar icon indicates this error. User can go to `File Manager` and see the info about failed card and the exact error code or full message. Also can format the whole card to supported filesystem and partition table.
|
|
||||||
|
|
||||||
![](./../../wiki_static/ui/status-bar-sdcard-fail.png)
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/sd-card/sd-card-error.jpg)
|
|
||||||
|
|
||||||
|
|
||||||
### Card Info
|
|
||||||
|
|
||||||
Press `← Left` to see the card info:
|
|
||||||
|
|
||||||
- Size
|
|
||||||
- Partition type: GPT, MBR
|
|
||||||
- Partitions with title and size
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/sd-card/sd-card-info.jpg)
|
|
||||||
|
|
||||||
### Format (erase card)
|
|
||||||
|
|
||||||
Press `→ Right` to format card. One action should completely erase card and create one parition with recommended filesystem (exFAT?).
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/sd-card/sd-card-format.jpg)
|
|
|
@ -1,49 +0,0 @@
|
||||||
To communicate with the real world systems, Flipper Zero has a built-in radio module based on TI CC1101 chip. It supports both transmitting and receiving digital signals within the 300-928 MHz frequency range. This is the operating range for a wide class of devices and access control systems such as garage doors remotes, boom barriers, IoT sensors, and remote keyless systems.
|
|
||||||
|
|
||||||
Out of the box, Flipper Zero can emulate remotes for popular garage doors and barriers. You can keep hundreds of remotes in Flipper's memory as well as create a blank remote for the new wireless gate. Just select the right brand of the system in the Flipper menu, register a new key in your garage/barrier receiver, and give it a unique name for easy navigation between your remotes.
|
|
||||||
|
|
||||||
CC1101 is well known universal transceiver designed for low-power wireless applications. And with a ready-to-use open-source library, developers can interact with the radio subsystem without limitations. You can write any wireless application, like custom protocol or decoder, as well as use it for connecting with IoT devices and access systems.
|
|
||||||
|
|
||||||
|
|
||||||
## Frequency Scaner (Spectrum analyzer)
|
|
||||||
|
|
||||||
User should be able to detect which frequency used in specific device. For example detect if unknown remote transmit on 433MHz or 868MHz
|
|
||||||
|
|
||||||
![frequency scan example](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/rf_scan.png)
|
|
||||||
|
|
||||||
## Signal Analyzer
|
|
||||||
|
|
||||||
Detect frequency and modulation:
|
|
||||||
|
|
||||||
* ASK
|
|
||||||
* FSK
|
|
||||||
|
|
||||||
## Protocol Decoder
|
|
||||||
|
|
||||||
* Works on 315/433/868 MHz
|
|
||||||
|
|
||||||
Flipper Zero has an integrated decoder for popular remote control algorithms such as Keeloq and others, so you can analyze an unknown radio system to figure out the protocol under the hood.
|
|
||||||
|
|
||||||
## Signal recorder
|
|
||||||
|
|
||||||
Furthermore, Flipper can record the samples of radio signals to analyze it later with more sophisticated tools on the computer, as well as replay the saved samples. Many remotes and IoT devices such as doorbells, sensors, and radio sockets don't use any encryption at all — in this case, Flipper can replay the signal, even if the protocol wasn't recognized.
|
|
||||||
|
|
||||||
|
|
||||||
### Protocol Decoder demo
|
|
||||||
|
|
||||||
https://www.youtube.com/watch?v=AeCGLFKsxCU
|
|
||||||
* Detect protocol and parse it
|
|
||||||
* Analyze if it's secure on not
|
|
||||||
|
|
||||||
|
|
||||||
## Common Dummy Remote
|
|
||||||
|
|
||||||
User can use flipper as normal dummy remote for their own reciever like garage door.
|
|
||||||
For this flipper should have library of popular remotes brands.
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
## Main menu
|
|
||||||
|
|
||||||
* Sniffer
|
|
||||||
* Saved
|
|
|
@ -1,9 +0,0 @@
|
||||||
Flipper Zero can act as a fully functional U2F key, that works with any U2F-enabled services such as Google, Twitter, Facebook, Dropbox, LastPass, Amazon AWS, and many others.
|
|
||||||
|
|
||||||
Universal 2nd Factor (U2F) protocol is an open standard for hardware security tokens used for secure authentication. Developed by Google, Yubico, and NXP, U2F acts as a universal key that is designed to add another layer to the traditional login+password authentication method.
|
|
||||||
|
|
||||||
Even if your password gets compromised, an attacker will not be able to log in to your account. This method is much stronger than the usual SMS 2nd-factor method, as it doesn’t involve any third-parties like a cell phone operator.
|
|
||||||
|
|
||||||
### Links
|
|
||||||
|
|
||||||
https://github.com/solokeys/solo
|
|
|
@ -1,32 +0,0 @@
|
||||||
Flipper Zero can connects to host system via USB 2.0 in several possible modes. When USB connected to host, the menu for choosing USB mode appears:
|
|
||||||
|
|
||||||
- Serial port (Default mode)
|
|
||||||
- Firmware Update (reboot to bootloader)
|
|
||||||
- Mass storage, mount SD card filesystem **TODO: only SD Card filesystem or not?**
|
|
||||||
- Bad USB mode (HID device emulation)
|
|
||||||
- USB NFC Reader
|
|
||||||
|
|
||||||
# Serial port (Default mode)
|
|
||||||
|
|
||||||
Activating when Flipper Zero operates in normal mode. Allow to communicate with PC from any application or forward commands from UART/I2C/SPI interfaces from external GPIO. When `Serial Port` mode activated, the USB port icon brings shown in status bar.
|
|
||||||
|
|
||||||
![](./../../wiki_static/ui/status-bar-usb.png)
|
|
||||||
|
|
||||||
# Firmware Update (Bootloader DFU Mode)
|
|
||||||
|
|
||||||
![](./../../wiki_static/ui/USB-firmware-update-mode.jpg)
|
|
||||||
|
|
||||||
To activate `Firmware Update` mode Flipper Zero must reboot to bootloader. Firmware mode activating only when chosen from menu or triggered from desktop application via `Serial Port` mode.
|
|
||||||
|
|
||||||
# Bad USB mode
|
|
||||||
|
|
||||||
Flipper Zero can emulate a USB slave device, allowing it to be recognized by the computer as a regular input device, such as HID keyboard just as USB Rubber Ducky. You can write your own keyboard payloads to type any key sequence, as well as fuzzing USB stack on a target device.
|
|
||||||
|
|
||||||
Allow user to run scripts from menu. User should choose script before connecting to victim PC.
|
|
||||||
|
|
||||||
1. User selects payload on filesystem
|
|
||||||
2. Press on it with central button, then payload executed, if here a USB connection. Otherwise, it got message "Awaiting connection"
|
|
||||||
3. After connection established, it shows progress of execution
|
|
||||||
4. At end of execution, it says "ok", user can start script again by pressing central button, or return to list payloads by pressing "back"
|
|
||||||
|
|
||||||
- Mass storage, mount SD card filesystem
|
|
|
@ -1,27 +0,0 @@
|
||||||
Flipper Zero has a built-in 1-Wire pad to read iButton (DS1990A) keys, also known as TouchMemory or Dallas keys. This technology is quite old but still widely used around the world. It's based on 1-Wire protocol and doesn't have any authentication, so Flipper can easily read these keys, save IDs into the memory, write IDs to blank keys, and emulate the key itself.
|
|
||||||
|
|
||||||
* **Reading & Writing & Emulating**
|
|
||||||
* **Protocol detection**: юзер может определить тип ключа поднося ключ к флипперу и тип считывателя поднося флиппер к домофону (цифрал, даллас и т.д.)
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/iButton/ibutton.jpg)
|
|
||||||
|
|
||||||
## Reading
|
|
||||||
|
|
||||||
`iButton(1-Wire) -> Reading`
|
|
||||||
|
|
||||||
Flipper will wait for iButton tag. While waiting red LED is blinking.
|
|
||||||
Lean tag on iButton reader in the back side of Flipper Zero:
|
|
||||||
|
|
||||||
**Video demo**
|
|
||||||
[![Flipper Zero Reading ibutton](https://img.youtube.com/vi/QE7Nb5r5m_Q/0.jpg)](https://www.youtube.com/watch?v=QE7Nb5r5m_Q)
|
|
||||||
|
|
||||||
![](./../../wiki_static/applications/iButton/read1.jpeg)
|
|
||||||
![](./../../wiki_static/applications/iButton/read2.jpeg)
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
## Main menu
|
|
||||||
|
|
||||||
* Read
|
|
||||||
* Saved Keys
|
|
||||||
* Enter manually
|
|
|
@ -1,120 +0,0 @@
|
||||||
# [[1 sep 2020] First update of phase 1](First-update-of-phase-1)
|
|
||||||
|
|
||||||
## Peoples and management
|
|
||||||
|
|
||||||
1. We have added many contributors within the **phase-1**. Checkout [all welcome issues here](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=is%3Aissue+label%3Awelcome+) and get to know each other.
|
|
||||||
2. Now we have an Official [Discord server](https://flipperzero.one/discord) with separate channels for developers and users. There you can chat and join voice channels. [Read more](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Communication) about how it works.
|
|
||||||
3. [Developers blog](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Developer-blog) created. Here you can read project updates in digest format.
|
|
||||||
4. [backlog](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=label%3Abacklog+) label added for tasks that are not a priority at the moment.
|
|
||||||
|
|
||||||
## Environment
|
|
||||||
|
|
||||||
1. Added pipeline to automate Wiki pages building [#63](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/63). Please read (Hot to edit wiki)[https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Contributing#how-to-edit-wiki] in a right way.
|
|
||||||
2. Adding CI workflow has begun: [#70](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/70). Now GitHub pipelines checking that `target_lo` and `target_f1` are successfully compiling.
|
|
||||||
3. Added Rust support into docker image: [#41](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/41) + [#68](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/68). Now you can build Rust code, link it with C and together, using Bindgen and Cbindgen.
|
|
||||||
|
|
||||||
## Core and stuff
|
|
||||||
|
|
||||||
1. Added `target_f1`, now you can build your code for [F1](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F1B1C0.0) board.
|
|
||||||
2. Added implementation of [FURI](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/FURI) (with many issues -- see [#59](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/59))...
|
|
||||||
3. ...and add many examples of how to use FURI, HAL and do some funny things ([List of Application Examples](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Application-examples)):
|
|
||||||
1. [LED Blink](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Blink-app)
|
|
||||||
2. [Writing to UART](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/UART-write)
|
|
||||||
3. [Communication between apps](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/IPC-example)
|
|
||||||
|
|
||||||
## Hardware
|
|
||||||
|
|
||||||
1. We designed and manufactured [F2B0C1.1](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F2B0C1.1)! You can see that these boards already got an SD-card slot! This will be a current Dev Kits.
|
|
||||||
|
|
||||||
<img width="500" src="https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/blog/f2b0c1.1.jpeg" />
|
|
||||||
|
|
||||||
# What are we doing right now
|
|
||||||
|
|
||||||
1. Making UI and display driver [#98](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/98), and implementing dummy display and UI emulator [#97](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/97). With this emulator everyone will be able to develop UI features without a physical FLipper!
|
|
||||||
2. We continue to work on FURI API design and implementations [#59](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/59). If you have proposals or remarks about this component, or you don't understand what we are doing -- read [FURI and FURI AC description](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/FURI), look at the [examples](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Application-examples) and feel free to comment this issue or discuss it in [discord](https://flipperzero.one/discord).
|
|
||||||
3. We started a big work of dynamic loading and linking applications. Flipper is different from many embedded systems because we want to run user applications, load it by USB, Bluetooth, SD-card and other ways, so we need to implement it on a small limited system without MMU. You can see progress and discuss it here [#73](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/73)
|
|
||||||
4. We got an interesting proposal about Zephyr OS [comment in #17](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/17#issuecomment-683929900) and porting it on our new WB55 board [№89](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/89).
|
|
||||||
5. Working on new Flipper's PCB design based on STM32WB55RB MCU and new PMIC (we're using AXP173).
|
|
||||||
6. Creating a unit test environment and pipelines for CI [#40](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/40). if you want to see how building and testing is working right now, check out [Environment](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Environment) page.
|
|
||||||
7. Very soon we will have a remote testing and debugging bench! I think it's a very funny idea! It will be useful for developers who haven't real hardware and also for running CI on physical hardware: [#96](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/96)
|
|
||||||
8. In the next week we will start to blow off magic smoke and breathe life in new F2B0C1.1 boards, stay tuned!
|
|
||||||
|
|
||||||
# We need help
|
|
||||||
|
|
||||||
1. Linting and control code style [#12](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/12) is stuck
|
|
||||||
2. We have a big discussion about integration with IDE. If you feel pain with our current development environment and want to use your favorite IDE, welcome to [#18](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/18)!
|
|
||||||
3. Please check out and discuss the idea of attaching issues to wiki pages: [#66](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/66)
|
|
||||||
4. We want to make a web interface for UI emulator ([#97](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/97)) and looking for people who want to design the webpage. React/TS is preferred.
|
|
||||||
|
|
||||||
# Our plans
|
|
||||||
|
|
||||||
First of all, we need to completely set up our environment for building, testing and debugging code:
|
|
||||||
|
|
||||||
1. Make UI emulator
|
|
||||||
2. Make remote debug/test bench
|
|
||||||
3. Test F2B0C1.1 and send it to contributors
|
|
||||||
4. Make automatic code style checking, unit testing and overall CI.
|
|
||||||
|
|
||||||
Then, we need to make a build system (including dynamic linking specificity), toolset for loading apps on Flipper and run hardware tests, IDE integrations.
|
|
||||||
|
|
||||||
And we should concentrate on core API and architecture: improving FURI features, making examples and porting old Flipper's prototype code to check that our API is usable. Also I want to design core API so that changing HAL/OS will not very painful for app developers.
|
|
||||||
|
|
||||||
After we make UI emulator and deliver real hardware to UI developers we can start UI architecture: interface guidelines, GUI toolkit.
|
|
||||||
|
|
||||||
Also you can analyse features right now, design and propose how Flipper's user features can work. It also helps us to design core API and requirement for core, test bench and build system.
|
|
||||||
|
|
||||||
--
|
|
||||||
Best,
|
|
||||||
Andrew Strokov @glitchcore
|
|
||||||
|
|
||||||
_________________
|
|
||||||
|
|
||||||
# [[18 aug 2020] Initial state of project](Initial-state-of-project)
|
|
||||||
|
|
||||||
## Hardware release: F1B1C0.0
|
|
||||||
|
|
||||||
Current Flipper Zero prototype is based on board [Version 0 (F1B1C0.0)](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F1B1C0.0) that have a lot of bugs.
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/hw-F1B1C0.0.jpg)
|
|
||||||
|
|
||||||
## Firmware
|
|
||||||
|
|
||||||
During the early prototyping stages of Flipper Zero, we have used a lot of 3rd-party code, sketches, and dirty demos just as proof of concept, and didn't think too much about architecture. This code splits into many incompatible pieces of code, and some of them don’t even have an UI. This repo is cleaned from all the dirty demos and prepared for contributors, so we will start porting all the legacy code here, following the new architecture.
|
|
||||||
|
|
||||||
### Release 0.1
|
|
||||||
|
|
||||||
**[Download release](https://github.com/Flipper-Zero/flipperzero-firmware-community/releases/tag/0.1.0)**
|
|
||||||
|
|
||||||
You can run firmware locally (with HAL stub).
|
|
||||||
|
|
||||||
* `docker-compose exec dev make -C target_lo` for build
|
|
||||||
* `docker-compose exec dev target_lo/build/target_lo` for run
|
|
||||||
|
|
||||||
Read more in [building instructions](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Firmware#building).
|
|
||||||
|
|
||||||
# To do
|
|
||||||
|
|
||||||
## Flipper developement roadmap
|
|
||||||
|
|
||||||
* ~~**Phase 0** (compelete) Preparing for Kickstarter, prototyping UI, checkng hardware, prototype protocol sniffer, tag readers, etc.~~
|
|
||||||
* **Phase 1.** (Current) Set up developing routines for massive contributors activity, architecture and documentation. Building hardware rig for remote testing.
|
|
||||||
* **Phase 2.** Start massive contributors program. Preparing Developments Kits for sending to few developers.
|
|
||||||
* **Phase 3.** Next PCB release [Version 1 (F2B0C1)](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F2B0C1.1) and sending it to more contributos.
|
|
||||||
* **Phase 4.** Release PCB based on STM32WB55RB and sending it to developers.
|
|
||||||
* **Phase 5.** Making all repositories publicly open.
|
|
||||||
|
|
||||||
## Tasks for phase 1: (Doing right now)
|
|
||||||
|
|
||||||
Right now we are working on clean architecture and documentation for contributors.
|
|
||||||
|
|
||||||
* Finalize firmware core architecture and document it for contributors onboarding. You can see progress in [Core project](https://github.com/Flipper-Zero/flipperzero-firmware-community/projects/3)
|
|
||||||
* Set up a test environment and CI. You can see progress in [Environment project](https://github.com/Flipper-Zero/flipperzero-firmware-community/projects/2)
|
|
||||||
* Create Flipper Zero software emulator with display and buttons [Task #22](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/22)
|
|
||||||
* Set up integration between wiki and issues, configure wiki generator from doc files: [Task #16](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/16)
|
|
||||||
* Finish the basic wiki pages: create feature description, UI sketches, links to related project/code, documentation for protocols/
|
|
||||||
* Make basic code examples [Task #15](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/15)
|
|
||||||
* Transfer old code to new architecture
|
|
||||||
|
|
||||||
## Next hardware release
|
|
||||||
|
|
||||||
We have finished the next version of PCB, where a lot of bugs are fixed, and now waiting for its manufacturing. This new board will be used as Developer Kit for early firmware development and will be sent to developers.
|
|
|
@ -1,68 +0,0 @@
|
||||||
# What is done
|
|
||||||
|
|
||||||
## Peoples and management
|
|
||||||
|
|
||||||
1. We have added many contributors within the **phase-1**. Checkout [all welcome issues here](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=is%3Aissue+label%3Awelcome+) and get to know each other.
|
|
||||||
2. Now we have an Official [Discord server](https://flipperzero.one/discord) with separate channels for developers and users. There you can chat and join voice channels. [Read more](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Communication) about how it works.
|
|
||||||
3. [Developers blog](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Developer-blog) created. Here you can read project updates in digest format.
|
|
||||||
4. [backlog](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues?q=label%3Abacklog+) label added for tasks that are not a priority at the moment.
|
|
||||||
|
|
||||||
## Environment
|
|
||||||
|
|
||||||
1. Added pipeline to automate Wiki pages building [#63](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/63). Please read (Hot to edit wiki)[https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Contributing#how-to-edit-wiki] in a right way.
|
|
||||||
2. Adding CI workflow has begun: [#70](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/70). Now GitHub pipelines checking that `target_lo` and `target_f1` are successfully compiling.
|
|
||||||
3. Added Rust support into docker image: [#41](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/41) + [#68](https://github.com/Flipper-Zero/flipperzero-firmware-community/pull/68). Now you can build Rust code, link it with C and together, using Bindgen and Cbindgen.
|
|
||||||
|
|
||||||
## Core and stuff
|
|
||||||
|
|
||||||
1. Added `target_f1`, now you can build your code for [F1](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F1B1C0.0) board.
|
|
||||||
2. Added implementation of [FURI](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/FURI) (with many issues -- see [#59](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/59))...
|
|
||||||
3. ...and add many examples of how to use FURI, HAL and do some funny things ([List of Application Examples](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Application-examples)):
|
|
||||||
1. [LED Blink](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Blink-app)
|
|
||||||
2. [Writing to UART](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/UART-write)
|
|
||||||
3. [Communication between apps](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/IPC-example)
|
|
||||||
|
|
||||||
## Hardware
|
|
||||||
|
|
||||||
1. We designed and manufactured [F2B0C1.1](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F2B0C1.1)! You can see that these boards already got an SD-card slot! This will be a current Dev Kits.
|
|
||||||
|
|
||||||
<img width="500" src="https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/blog/f2b0c1.1.jpeg" />
|
|
||||||
|
|
||||||
# What are we doing right now
|
|
||||||
|
|
||||||
1. Making UI and display driver [#98](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/98), and implementing dummy display and UI emulator [#97](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/97). With this emulator everyone will be able to develop UI features without a physical FLipper!
|
|
||||||
2. We continue to work on FURI API design and implementations [#59](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/59). If you have proposals or remarks about this component, or you don't understand what we are doing -- read [FURI and FURI AC description](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/FURI), look at the [examples](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Application-examples) and feel free to comment this issue or discuss it in [discord](https://flipperzero.one/discord).
|
|
||||||
3. We started a big work of dynamic loading and linking applications. Flipper is different from many embedded systems because we want to run user applications, load it by USB, Bluetooth, SD-card and other ways, so we need to implement it on a small limited system without MMU. You can see progress and discuss it here [#73](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/73)
|
|
||||||
4. We got an interesting proposal about Zephyr OS [comment in #17](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/17#issuecomment-683929900) and porting it on our new WB55 board [№89](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/89).
|
|
||||||
5. Working on new Flipper's PCB design based on STM32WB55RB MCU and new PMIC (we're using AXP173).
|
|
||||||
6. Creating a unit test environment and pipelines for CI [#40](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/40). if you want to see how building and testing is working right now, check out [Environment](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Environment) page.
|
|
||||||
7. Very soon we will have a remote testing and debugging bench! I think it's a very funny idea! It will be useful for developers who haven't real hardware and also for running CI on physical hardware: [#96](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/96)
|
|
||||||
8. In the next week we will start to blow off magic smoke and breathe life in new F2B0C1.1 boards, stay tuned!
|
|
||||||
|
|
||||||
# We need help
|
|
||||||
|
|
||||||
1. Linting and control code style [#12](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/12) is stuck
|
|
||||||
2. We have a big discussion about integration with IDE. If you feel pain with our current development environment and want to use your favorite IDE, welcome to [#18](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/18)!
|
|
||||||
3. Please check out and discuss the idea of attaching issues to wiki pages: [#66](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/66)
|
|
||||||
4. We want to make a web interface for UI emulator ([#97](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/97)) and looking for people who want to design the webpage. React/TS is preferred.
|
|
||||||
|
|
||||||
# Our plans
|
|
||||||
|
|
||||||
First of all, we need to completely set up our environment for building, testing and debugging code:
|
|
||||||
|
|
||||||
1. Make UI emulator
|
|
||||||
2. Make remote debug/test bench
|
|
||||||
3. Test F2B0C1.1 and send it to contributors
|
|
||||||
4. Make automatic code style checking, unit testing and overall CI.
|
|
||||||
|
|
||||||
Then, we need to make a build system (including dynamic linking specificity), toolset for loading apps on Flipper and run hardware tests, IDE integrations.
|
|
||||||
|
|
||||||
And we should concentrate on core API and architecture: improving FURI features, making examples and porting old Flipper's prototype code to check that our API is usable. Also I want to design core API so that changing HAL/OS will not very painful for app developers.
|
|
||||||
|
|
||||||
After we make UI emulator and deliver real hardware to UI developers we can start UI architecture: interface guidelines, GUI toolkit.
|
|
||||||
|
|
||||||
Also you can analyse features right now, design and propose how Flipper's user features can work. It also helps us to design core API and requirement for core, test bench and build system.
|
|
||||||
|
|
||||||
--
|
|
||||||
Best,
|
|
||||||
Andrew Strokov @glitchcore
|
|
|
@ -1,51 +0,0 @@
|
||||||
_18 aug 2020 by @glitchcore_
|
|
||||||
|
|
||||||
# What is done
|
|
||||||
|
|
||||||
## Hardware release: F1B1C0.0
|
|
||||||
|
|
||||||
Current Flipper Zero prototype is based on board [Version 0 (F1B1C0.0)](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F1B1C0.0) that have a lot of bugs.
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/hw-F1B1C0.0.jpg)
|
|
||||||
|
|
||||||
## Firmware
|
|
||||||
|
|
||||||
During the early prototyping stages of Flipper Zero, we have used a lot of 3rd-party code, sketches, and dirty demos just as proof of concept, and didn't think too much about architecture. This code splits into many incompatible pieces of code, and some of them don’t even have an UI. This repo is cleaned from all the dirty demos and prepared for contributors, so we will start porting all the legacy code here, following the new architecture.
|
|
||||||
|
|
||||||
### Release 0.1
|
|
||||||
|
|
||||||
**[Download release](https://github.com/Flipper-Zero/flipperzero-firmware-community/releases/tag/0.1.0)**
|
|
||||||
|
|
||||||
You can run firmware locally (with HAL stub).
|
|
||||||
|
|
||||||
* `docker-compose exec dev make -C target_lo` for build
|
|
||||||
* `docker-compose exec dev target_lo/build/target_lo` for run
|
|
||||||
|
|
||||||
Read more in [building instructions](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Firmware#building).
|
|
||||||
|
|
||||||
# To do
|
|
||||||
|
|
||||||
## Flipper developement roadmap
|
|
||||||
|
|
||||||
* ~~**Phase 0** (compelete) Preparing for Kickstarter, prototyping UI, checkng hardware, prototype protocol sniffer, tag readers, etc.~~
|
|
||||||
* **Phase 1.** (Current) Set up developing routines for massive contributors activity, architecture and documentation. Building hardware rig for remote testing.
|
|
||||||
* **Phase 2.** Start massive contributors program. Preparing Developments Kits for sending to few developers.
|
|
||||||
* **Phase 3.** Next PCB release [Version 1 (F2B0C1)](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F2B0C1.1) and sending it to more contributos.
|
|
||||||
* **Phase 4.** Release PCB based on STM32WB55RB and sending it to developers.
|
|
||||||
* **Phase 5.** Making all repositories publicly open.
|
|
||||||
|
|
||||||
## Tasks for phase 1: (Doing right now)
|
|
||||||
|
|
||||||
Right now we are working on clean architecture and documentation for contributors.
|
|
||||||
|
|
||||||
* Finalize firmware core architecture and document it for contributors onboarding. You can see progress in [Core project](https://github.com/Flipper-Zero/flipperzero-firmware-community/projects/3)
|
|
||||||
* Set up a test environment and CI. You can see progress in [Environment project](https://github.com/Flipper-Zero/flipperzero-firmware-community/projects/2)
|
|
||||||
* Create Flipper Zero software emulator with display and buttons [Task #22](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/22)
|
|
||||||
* Set up integration between wiki and issues, configure wiki generator from doc files: [Task #16](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/16)
|
|
||||||
* Finish the basic wiki pages: create feature description, UI sketches, links to related project/code, documentation for protocols/
|
|
||||||
* Make basic code examples [Task #15](https://github.com/Flipper-Zero/flipperzero-firmware-community/issues/15)
|
|
||||||
* Transfer old code to new architecture
|
|
||||||
|
|
||||||
## Next hardware release
|
|
||||||
|
|
||||||
We have finished the next version of PCB, where a lot of bugs are fixed, and now waiting for its manufacturing. This new board will be used as Developer Kit for early firmware development and will be sent to developers.
|
|
|
@ -1,98 +0,0 @@
|
||||||
First, let's create a simple led blinking application.
|
|
||||||
|
|
||||||
## Preparing for launch
|
|
||||||
|
|
||||||
We will use integrated LED. Look at the schematic:
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/leds.png)
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/gpio_pa8.png)
|
|
||||||
|
|
||||||
This LED is connected between power rail and GPIO PA8, and we should configure this pin as an open drain to properly control the LED behaviour.
|
|
||||||
|
|
||||||
You can find GPIO API in `target_*/flipper_hal.h`. Or if you prefer to use Arduino API, you can find the bindings in `core/flipper.h`.
|
|
||||||
|
|
||||||
To work with the pin we should:
|
|
||||||
|
|
||||||
1. Create `GpioPin` instance and specify pin and port.
|
|
||||||
2. Configure mode of pin by `pinMode` function.
|
|
||||||
3. Control state of pin by `digitalWrite` function.
|
|
||||||
|
|
||||||
## Creating application
|
|
||||||
|
|
||||||
1. Create a new file (for example, `blink.c`) in `applications` folder.
|
|
||||||
2. Create code like this:
|
|
||||||
|
|
||||||
```C
|
|
||||||
#include "flipper.h"
|
|
||||||
|
|
||||||
void application_blink(void* p) {
|
|
||||||
// create pin
|
|
||||||
GpioPin led = {.pin = GPIO_PIN_8, .port = GPIOA};
|
|
||||||
|
|
||||||
// configure pin
|
|
||||||
pinMode(led, GpioModeOpenDrain);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
digitalWrite(led, HIGH);
|
|
||||||
delay(500);
|
|
||||||
digitalWrite(led, LOW);
|
|
||||||
delay(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
3. To start your application on Flipper startup, add it to the autorun:
|
|
||||||
* in `applications/startup.h` add prototype of main application function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
void application_blink(void* p);
|
|
||||||
```
|
|
||||||
|
|
||||||
* add entry to `FLIPPER_STARTUP` array (pointer to application function and application name):
|
|
||||||
|
|
||||||
```C
|
|
||||||
const FlipperStartupApp FLIPPER_STARTUP[] = {
|
|
||||||
#ifdef TEST
|
|
||||||
{.app = flipper_test_app, .name = "test app"}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// user applications:
|
|
||||||
|
|
||||||
, {.app = application_blink, .name = "blink"}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Add your application file to Makefile (for each target, `target_lo/Makefile` and `target_f1/Makefile`, we'll add one common makefile later):
|
|
||||||
|
|
||||||
```
|
|
||||||
# User application
|
|
||||||
|
|
||||||
C_SOURCES += ../applications/blink.c
|
|
||||||
```
|
|
||||||
|
|
||||||
Build and run for linux (target_lo):
|
|
||||||
|
|
||||||
`docker-compose exec dev make -C target_lo`
|
|
||||||
|
|
||||||
Run:
|
|
||||||
|
|
||||||
`docker-compose exec dev target_lo/build/target_lo`.
|
|
||||||
|
|
||||||
Linux version has no LED or GPIO, but we can see debug messages of how state of GPIO is changing:
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/example_blink.gif)
|
|
||||||
|
|
||||||
_You can also find source of this example in `applications/examples/blink.c` and run it by `docker-compose exec dev make -C target_lo example_blink`_
|
|
||||||
|
|
||||||
Build for Flipper (board F1):
|
|
||||||
|
|
||||||
`docker-compose exec dev make -C target_f1`
|
|
||||||
|
|
||||||
Upload to microcontroller:
|
|
||||||
|
|
||||||
`./target_f1/deploy.sh`
|
|
||||||
|
|
||||||
Blink!
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/example_blink_hw.gif)
|
|
||||||
|
|
||||||
_You can also compile by `docker-compose exec dev make -C target_f1 example_blink`_
|
|
|
@ -1,145 +0,0 @@
|
||||||
In this example we show how to interact data between different applications.
|
|
||||||
As we already know, we can use FURI Record for this purpose: one application create named record and other application opens it by name.
|
|
||||||
|
|
||||||
We will simulate the display. The first application (called `application_ipc_display`) will be display driver, and the second app (called `application_ipc_widget`) will be draw such simple demo on the screen.
|
|
||||||
|
|
||||||
# Dsiplay definition
|
|
||||||
|
|
||||||
For work with the display we create simple framebuffer and write some "pixels" into it.
|
|
||||||
|
|
||||||
```C
|
|
||||||
#define FB_WIDTH 10
|
|
||||||
#define FB_HEIGHT 3
|
|
||||||
#define FB_SIZE (FB_WIDTH * FB_HEIGHT)
|
|
||||||
|
|
||||||
char _framebuffer[FB_SIZE];
|
|
||||||
|
|
||||||
for(size_t i = 0; i < FB_SIZE; i++) {
|
|
||||||
_framebuffer[i] = ' ';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
On local target we just draw framebuffer content like this:
|
|
||||||
```
|
|
||||||
+==========+
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
| |
|
|
||||||
+==========+
|
|
||||||
```
|
|
||||||
|
|
||||||
```C
|
|
||||||
fuprintf(log, "+==========+\n");
|
|
||||||
for(uint8_t i = 0; i < FB_HEIGHT; i++) {
|
|
||||||
strncpy(row_buffer, &fb[FB_WIDTH * i], FB_WIDTH);
|
|
||||||
fuprintf(log, "|%s|\n", row_buffer);
|
|
||||||
}
|
|
||||||
fuprintf(log, "+==========+\n");
|
|
||||||
```
|
|
||||||
|
|
||||||
_Notice: after creating display emulator this example should be changed to work with real 128×64 display using u8g2_
|
|
||||||
|
|
||||||
# Demo "widget" application
|
|
||||||
|
|
||||||
The application opens record with framebuffer:
|
|
||||||
|
|
||||||
```C
|
|
||||||
FuriRecordSubscriber* fb_record = furi_open(
|
|
||||||
"test_fb", false, false, NULL, NULL, NULL
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
Then it clear display and draw "pixel" every 120 ms, and pixel move across the screen.
|
|
||||||
|
|
||||||
For do that we should tale framebuffer:
|
|
||||||
|
|
||||||
`char* fb = (char*)furi_take(fb_record);`
|
|
||||||
|
|
||||||
Write some data:
|
|
||||||
|
|
||||||
```C
|
|
||||||
if(fb == NULL) furiac_exit(NULL);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < FB_SIZE; i++) {
|
|
||||||
fb[i] = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
fb[counter % FB_SIZE] = '#';
|
|
||||||
```
|
|
||||||
And give framebuffer (use `furi_commit` to notify another apps that record was changed):
|
|
||||||
|
|
||||||
`furi_commit(fb_record);`
|
|
||||||
|
|
||||||
`counter` is increasing on every iteration to make "pixel" moving.
|
|
||||||
|
|
||||||
# Display driver
|
|
||||||
|
|
||||||
The driver application creates framebuffer after start (see [Display definition](#Display-definition)) and creates new FURI record with framebuffer pointer:
|
|
||||||
|
|
||||||
`furi_create("test_fb", (void*)_framebuffer, FB_SIZE)`
|
|
||||||
|
|
||||||
Next it opens this record and subscribe to its changing:
|
|
||||||
|
|
||||||
```
|
|
||||||
FuriRecordSubscriber* fb_record = furi_open(
|
|
||||||
"test_fb", false, false, handle_fb_change, NULL, &ctx
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
The handler is called any time when some app writes to framebuffer record (by calling `furi_commit`):
|
|
||||||
|
|
||||||
```C
|
|
||||||
static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) {
|
|
||||||
IpcCtx* ctx = (IpcCtx*)raw_ctx; // make right type
|
|
||||||
|
|
||||||
fuprintf(ctx->log, "[cb] framebuffer updated\n");
|
|
||||||
|
|
||||||
// send event to app thread
|
|
||||||
xSemaphoreGive(ctx->events);
|
|
||||||
|
|
||||||
// Attention! Please, do not make blocking operation like IO and waits inside callback
|
|
||||||
// Remember that callback execute in calling thread/context
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
That callback execute in calling thread/context, so handler pass control flow to app thread by semaphore. App thread wait for semaphore and then do the "rendering":
|
|
||||||
|
|
||||||
```C
|
|
||||||
if(xSemaphoreTake(events, portMAX_DELAY) == pdTRUE) {
|
|
||||||
fuprintf(log, "[display] get fb update\n\n");
|
|
||||||
|
|
||||||
#ifdef HW_DISPLAY
|
|
||||||
// on Flipper target draw the screen
|
|
||||||
#else
|
|
||||||
// on local target just print
|
|
||||||
{
|
|
||||||
void* fb = furi_take(fb_record);
|
|
||||||
print_fb((char*)fb, log);
|
|
||||||
furi_give(fb_record);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A structure containing the context is used so that the callback can access the semaphore. This structure is passed as an argument to `furi_open` and goes to the handler:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
SemaphoreHandle_t events; // queue to pass events from callback to app thread
|
|
||||||
FuriRecordSubscriber* log; // app logger
|
|
||||||
} IpcCtx;
|
|
||||||
```
|
|
||||||
|
|
||||||
We just have to create a semaphore and define a context:
|
|
||||||
|
|
||||||
```C
|
|
||||||
StaticSemaphore_t event_descriptor;
|
|
||||||
// create stack-based counting semaphore
|
|
||||||
SemaphoreHandle_t events = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
|
|
||||||
|
|
||||||
IpcCtx ctx = {.events = events, .log = log};
|
|
||||||
```
|
|
||||||
|
|
||||||
You can find full example code in `applications/examples/ipc.c`, and run it by `docker-compose exec dev make -C target_lo example_ipc`.
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/example_ipc.gif)
|
|
|
@ -1,71 +0,0 @@
|
||||||
In this example we try to use FURI for interacting between user application and core subsystem.
|
|
||||||
|
|
||||||
First of all, we open FURI record by name "tty". This record is used for send some debug/logging info and interact with user by kind-of-TTY (like UART or USB CDC). By default on Flipper target all writes to tty record handled by debug UART (configured by `DEBUG_UART` define). On local target all writes simply prints to stdout.
|
|
||||||
|
|
||||||
Open record:
|
|
||||||
|
|
||||||
```C
|
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
|
||||||
```
|
|
||||||
|
|
||||||
This is just wrapper on common FURI method:
|
|
||||||
|
|
||||||
```C
|
|
||||||
furi_open("tty", false, false, NULL, NULL);
|
|
||||||
```
|
|
||||||
|
|
||||||
"tty" is FURI pipe record. It means that there is no "data" hold in record, it only manage callbacks: when you call `furi_write`, all subscriber's callback is called. You can find default implementation in `core/tty_uart.c`.
|
|
||||||
|
|
||||||
Let's get a look at full example code:
|
|
||||||
|
|
||||||
```C
|
|
||||||
#include "flipper.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
void application_uart_write(void* p) {
|
|
||||||
// Red led for showing progress
|
|
||||||
GpioPin led = {.pin = GPIO_PIN_8, .port = GPIOA};
|
|
||||||
pinMode(led, GpioModeOpenDrain);
|
|
||||||
|
|
||||||
// get_default_log open "tty" record
|
|
||||||
FuriRecordSubscriber* log = get_default_log();
|
|
||||||
|
|
||||||
// create buffer
|
|
||||||
const char test_string[] = "test\n";
|
|
||||||
furi_write(log, test_string, strlen(test_string));
|
|
||||||
|
|
||||||
// for example, create counter and show its value
|
|
||||||
uint8_t counter = 0;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
// continously write it to UART
|
|
||||||
fuprintf(log, "counter: %d\n", counter);
|
|
||||||
counter++;
|
|
||||||
|
|
||||||
// flash at every send
|
|
||||||
digitalWrite(led, LOW);
|
|
||||||
delay(50);
|
|
||||||
digitalWrite(led, HIGH);
|
|
||||||
|
|
||||||
// delay with overall perion of 1s
|
|
||||||
delay(950);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This code demonstrates two way to work with record:
|
|
||||||
|
|
||||||
1. Directly writes some data by `furi_write`
|
|
||||||
2. Uses `fuprintf` wrapper on `printf`.
|
|
||||||
|
|
||||||
For creating application and set it to autorun, read [Blink example](Blink-app).
|
|
||||||
|
|
||||||
_You can also find source of this example in `applications/examples/uart_write.c` and run it by `docker-compose exec dev make -C target_lo example_uart_write`_
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/example_uart_write.gif)
|
|
||||||
|
|
||||||
_Code for target F1 can be compiled by `docker-compose exec dev make -C target_f1 example_uart_write`_
|
|
||||||
|
|
||||||
![](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/application_examples/example_uart_write_hw.gif)
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
In this article we create few application, interact between apps, use OS functions and interact with HAL.
|
|
||||||
|
|
||||||
# General agreements
|
|
||||||
|
|
||||||
Flipper application is just a function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
void application_name(void* p) {
|
|
||||||
// Setup
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
// Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
1. `void* p` is arbitrary pointer that may be used for pass parameters to application at launch (like argc/argv in POSIX).
|
|
||||||
2. Application must never attempt to return or exit from their implementing function.
|
|
||||||
3. Avoid long cycles without any "waits" or "blocking" like `delay` or `xQueueReceive`, otherwise your app will blocking overall Flipper work.
|
|
||||||
4. Do not create static variables inside function or global variables. Use only local variables. We plan to add virual in-RAM filesystem to save any persistent data.
|
|
||||||
|
|
||||||
# Application examples
|
|
||||||
|
|
||||||
* **[Blink](Blink-app)** show how to create app and control GPIO
|
|
||||||
* **[UART write](UART-write)** operate with FURI pipe and print some messages
|
|
||||||
* **[Inter-process communication](IPC-example)** describes how to interact between application through FURI
|
|
|
@ -1 +0,0 @@
|
||||||
../../bootloader/ReadMe.md
|
|
|
@ -1,49 +0,0 @@
|
||||||
# [Basic concepts](Basic-API)
|
|
||||||
|
|
||||||
* ValueMutex
|
|
||||||
* PubSub
|
|
||||||
* ValueManager
|
|
||||||
* ValueComposer
|
|
||||||
|
|
||||||
# [HAL and devices](HAL-API)
|
|
||||||
|
|
||||||
* GPIO
|
|
||||||
* PWM
|
|
||||||
* ADC
|
|
||||||
* I2C
|
|
||||||
|
|
||||||
* IR RX (unimplemented)
|
|
||||||
* Comparator RX (touch key and RFID 125 kHz RX) (unimplemented)
|
|
||||||
|
|
||||||
# [SPI Devices](SPI-Devices-API.md)
|
|
||||||
|
|
||||||
* Sub-GHz chip
|
|
||||||
* NFC
|
|
||||||
* SD card
|
|
||||||
* display
|
|
||||||
* external SPI
|
|
||||||
|
|
||||||
# OS
|
|
||||||
|
|
||||||
We use [CMSIS OS v2](https://www.keil.com/pack/doc/CMSIS_Dev/RTOS2/html/group__CMSIS__RTOS.html) for thread management and IPC.
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
* **[Input](Input-API)**
|
|
||||||
|
|
||||||
* **[Display](Display-API)**
|
|
||||||
|
|
||||||
* **[LED](LED-API)**
|
|
||||||
|
|
||||||
* **[Backlight](Backlight-API)** (unimplemented)
|
|
||||||
|
|
||||||
# [Power](Power-API)
|
|
||||||
|
|
||||||
* batt voltage
|
|
||||||
* batt charge
|
|
||||||
|
|
||||||
# [UART](Serial-API)
|
|
||||||
|
|
||||||
# USB
|
|
||||||
|
|
||||||
# BLE
|
|
|
@ -1,67 +0,0 @@
|
||||||
# Building/debugging/emulating
|
|
||||||
|
|
||||||
## Preparing for build
|
|
||||||
|
|
||||||
1. Install [docker compose](https://docs.docker.com/compose/install/)
|
|
||||||
2. After startup you should run `docker-compose up -d` to run the container.
|
|
||||||
3. Then you can run `docker-compose exec dev make -C <target_dir>` to build application.
|
|
||||||
|
|
||||||
If Dockerfile is changed you should run `docker-compose down` and `docker-compose build` for rebuild the image.
|
|
||||||
|
|
||||||
## Local build
|
|
||||||
|
|
||||||
For simple case as unit tests or integration test that no require hardware we mock HW and replace RTOS syscalls to POSIX syscalls. We get simple linux app that easy to debug and get flexible control on hardware stubs.
|
|
||||||
|
|
||||||
You can run firmware locally (with HAL stub).
|
|
||||||
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_TEST=1 run` for running tests
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_*=1 run` for running examples (see `applications/applications.mk` for list of applications/examples)
|
|
||||||
|
|
||||||
For UI we do "UI emulator" (not implemented)
|
|
||||||
|
|
||||||
1. Web page with display and other UI elements, controls
|
|
||||||
2. Local (linux) version of firmware. All calls, writing data to UI like display or LED, redirects to unix socket writes, and messages from unix socket redirect to firmware (emulates button press, change batt level, insert/remove USB, etc.)
|
|
||||||
3. Webserver that run linux version fw, pass events from webpage to unixsocket and vice versa.
|
|
||||||
|
|
||||||
## F2 build
|
|
||||||
|
|
||||||
`docker-compose exec dev make -C firmware TARGET=f2 APP_*=1 flash` for build and flash dev board (see `applications/applications.mk` for list of applications/examples)
|
|
||||||
|
|
||||||
## Firmware emulation (not implemented)
|
|
||||||
|
|
||||||
For more HW- and RTOS- specific checks we run real FW in [Renode](https://interrupt.memfault.com/blog/intro-to-renode)
|
|
||||||
|
|
||||||
## Running on remote Debug/test bench
|
|
||||||
|
|
||||||
Eventually we run real FW on remote debug/test bench (#26): flipper board + RPi + some stuff to control and check real hardware.
|
|
||||||
|
|
||||||
# Debug/test bench (in progress)
|
|
||||||
|
|
||||||
* 24×7 connected target Flipper device and accessible via Internet. Raspberry PI or some Linux single-board PC can be used as basic high-level control board.
|
|
||||||
* Tool can push/click each user buttons by hardware by "control board" (low level). Usage of optocouples/reed-switch relays is fine for that.
|
|
||||||
* Connect other Flipper peripherals to target:
|
|
||||||
* 433 door bell/barrier controller, to read it status and it's remote control (to sniff it signal by flipper).
|
|
||||||
* Some iButtons and it's reader can be also connected to target.
|
|
||||||
* RFID reader under the target, to paste readed keys from it to out UART.
|
|
||||||
* RFID cards with different IDs. Can changed by servo or carousel from CD-changer
|
|
||||||
* IR-transmitter/receiver.
|
|
||||||
* ...all the peripherals, that we'll can realize...
|
|
||||||
* "Hardware" USB peripherals (SWD programmer tool, etc?) reconnection and control of PWR, RST, BOOTx internal service lines, etc also need. This can be made by some software hacks or by relays.
|
|
||||||
* Image from target display will be translated by webcam to web page.
|
|
||||||
* WEB page, accessed to all developers (or maybe for everyone to view is better?) with these things:
|
|
||||||
* Target status area, Flipper control buttons, "connected" to real target. Power and service line switches.
|
|
||||||
* Ability to upload custom firmware binary to target. Take firmware build from CI/CD. Button to flash.
|
|
||||||
* Test tool UART with Flipper peripherals status and target device UART log also should be here.
|
|
||||||
* OpenOCD connection from target (can be accessed from developers around the world by VPN or just port forwarding with IP access lists). So this feature allows deep remote debug.
|
|
||||||
* List can be expanded with other good ideas...
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
1. Developers connect to target directly by shedule.
|
|
||||||
2. Run CI tests:
|
|
||||||
* For test automation we can use RobotDemo or simple expect tool/python scripts/etc.
|
|
||||||
* Apply test cases and submit its results.
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
|
|
||||||
You can read about testing in [Testing](Testing) page.
|
|
|
@ -1,61 +0,0 @@
|
||||||
_ (not implemented)_
|
|
||||||
|
|
||||||
List of [FURI](FURI) records for exchange data between applications.
|
|
||||||
|
|
||||||
# Interrupts
|
|
||||||
|
|
||||||
* `/irq/buttons` — raw button press/release events.
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|Button|0 — Up<br/>1 — Down<br/>2 — Right<br/>3 — Left<br/>4 — Ok<br/>5 — Back|1|
|
|
||||||
|State|1 — pressed<br/>0 — released|1|
|
|
||||||
|
|
||||||
* `/irq/charge` — charge state event
|
|
||||||
|
|
||||||
# UI
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|State|1 — charge start<br/>0 — charge stop|1|
|
|
||||||
|
|
||||||
* `/ui/fb` — pointer to current framebuffer
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|Framebuffer pointer|`uint8_t[DISPLAY_WIDTH][DISPAY_HEIGHT]`|4|
|
|
||||||
|
|
||||||
* `/ui/leds` — user led state
|
|
||||||
|
|
||||||
Led state is overrided by charge state (red when charging, green when charged).
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|Red|pwm value (0..255)|1|
|
|
||||||
|Green|pwm value (0..255)|1|
|
|
||||||
|Blue|pwm value (0..255)|1|
|
|
||||||
|Enable|1 — user led enabled<br/>0 — user led disabled (for manual led control)|1|
|
|
||||||
|
|
||||||
* `/ui/buttons_event` — button press/release events after debounce.
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|Button|0 — Up<br/>1 — Down<br/>2 — Right<br/>3 — Left<br/>4 — Ok<br/>5 — Back|1|
|
|
||||||
|State|1 — pressed<br/>0 — released|1|
|
|
||||||
|
|
||||||
* `/ui/buttons_state` — current button state after debounce.
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|Up|1 — pressed<br/>0 — released|1|
|
|
||||||
|Down|1 — pressed<br/>0 — released|1|
|
|
||||||
|Right|1 — pressed<br/>0 — released|1|
|
|
||||||
|Left|1 — pressed<br/>0 — released|1|
|
|
||||||
|Ok|1 — pressed<br/>0 — released|1|
|
|
||||||
|Back|1 — pressed<br/>0 — released|1|
|
|
||||||
|
|
||||||
* `/ui/fullscreen` — fullscreen mode state
|
|
||||||
|
|
||||||
|Name|Type|Size|
|
|
||||||
|---|---|---|
|
|
||||||
|State|1 — fullscreen<br/>0 — no fullscreen|1|
|
|
|
@ -1,54 +0,0 @@
|
||||||
Flipper Universal Registry Implementation or FURI is important part of Flipper firmware. It is used to:
|
|
||||||
|
|
||||||
* application control (start, exit, switch between active)
|
|
||||||
* data exchange between application (create/open channel, subscribe and push messages or read/write values)
|
|
||||||
* non-volatile data storage for application (create/open value and read/write)
|
|
||||||
|
|
||||||
# Application registry and control (FURIAC)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Data exchange
|
|
||||||
|
|
||||||
**`bool furi_create(char* name, void* value, size_t size)`**
|
|
||||||
|
|
||||||
creates named FURI record. Returns NULL if registry have not enough memory for creating. If value is NULL, create FURI Pipe (only callbacks management, no data/mutex).
|
|
||||||
|
|
||||||
**`FuriRecordHandler furi_open(char* name, bool solo, bool no_mute, void(*FlipperRecordCallback)(const void*, size_t), void(*FlipperRecordStateCallback)(FlipperRecordState))`**
|
|
||||||
|
|
||||||
opens existing FURI record by name. Returns NULL if record does not exist. If `solo` is true **another applications handlers set into "muted" state**. When appication has exited or record has closed, all handlers is unmuted. It may be useful for concurrently acces to resources like framebuffer or beeper. If `no_mute` is true, another applications cannot mute this handler.
|
|
||||||
|
|
||||||
**`bool furi_close(FuriRecordHandler* record)`**
|
|
||||||
|
|
||||||
close handler and unmute anothers.
|
|
||||||
|
|
||||||
**`bool furi_read(FuriRecordHandler* record, void* data, size_t size)`**
|
|
||||||
|
|
||||||
read message from record. Returns true if success, false otherwise.
|
|
||||||
|
|
||||||
**`bool furi_write(FuriRecordHandler* record, const void* data, size_t size)`**
|
|
||||||
|
|
||||||
write message to record. Returns true if success, false otherwise (handler gone or muted).
|
|
||||||
|
|
||||||
**`void* furi_take(FuriRecordHandler* record)` works as `furi_read`**
|
|
||||||
|
|
||||||
lock value mutex. It can be useful if records contain pointer to buffer which you want to change. You must call `furi_give` after operation on data and you cannot block executing between `take` and `give` calls
|
|
||||||
|
|
||||||
**`bool furi_give(FuriRecordHandler* record)`**
|
|
||||||
|
|
||||||
unlock value mutex works as `furi_wrte` but unlock global mutex.
|
|
||||||
|
|
||||||
# Usage example
|
|
||||||
_Diagram below describes furi states_
|
|
||||||
|
|
||||||
![FURI states](https://github.com/Flipper-Zero/flipperzero-firmware-community/blob/master/wiki_static/furi_states.png)
|
|
||||||
|
|
||||||
* After start, init code run some applications: in this example there is status bar, a background task and Home screen
|
|
||||||
* Status bar open access to framebuffer by opening "/ui/fb" FURI record
|
|
||||||
* "Home screen" call "Menu" application by `furiac_switch`. "Home screen" application stops and then "Menu" application starts.
|
|
||||||
* "Menu" application call "Your cool app" the same way. It also get access to framebuffer by open "/ui/fb" FURI record
|
|
||||||
* If "Your cool app" needs some backend app, it call this by `furiac_start` and then kill by `furiac_kill`
|
|
||||||
* If background task needs to show popup message (for example "Low battery") it can call new app or simply open "/ui/fb" record.
|
|
||||||
* When "/ui/fb" record is opened by popup message, FURI mute framebuffer handle in "Your cool app". This prevent to overwrite popup message by application drawing.
|
|
||||||
* "Status bar" framebuffer handle not is muted, beacuse open framebuffer with no_mute=true.
|
|
||||||
* After popup message is closed by `furiac_exit` or closing "/ui/fb", FURI unmute previous muted "Your cool app" framebuffer handle.
|
|
|
@ -1 +0,0 @@
|
||||||
../../firmware/ReadMe.md
|
|
|
@ -1,61 +0,0 @@
|
||||||
## Tim1
|
|
||||||
|
|
||||||
~1 kHz, PWM
|
|
||||||
|
|
||||||
* Ch1 -- red led
|
|
||||||
* Ch2 -- green led
|
|
||||||
* Ch3 -- blue led
|
|
||||||
|
|
||||||
## Tim2
|
|
||||||
|
|
||||||
46/48 kHz, interrupt for IR. Ch4 -- IR TX
|
|
||||||
|
|
||||||
## Tim4
|
|
||||||
|
|
||||||
~1 kHz, PWM
|
|
||||||
|
|
||||||
* Ch1 -- backlight
|
|
||||||
|
|
||||||
## Tim5
|
|
||||||
|
|
||||||
Variable freq. PWM. Ch4 -- speaker.
|
|
||||||
|
|
||||||
## Tim8
|
|
||||||
|
|
||||||
* Ch2 -- iButton emulate
|
|
||||||
|
|
||||||
## Tim15
|
|
||||||
|
|
||||||
125 kHz. Square generator and interrupt/RFID pull.
|
|
||||||
|
|
||||||
* Ch1 -- RFID OUT (square generator)
|
|
||||||
* Ch2 -- RFID Pull
|
|
||||||
|
|
||||||
# Devices
|
|
||||||
|
|
||||||
## Speaker
|
|
||||||
Tim5 ch4
|
|
||||||
|
|
||||||
## Blue led
|
|
||||||
Tim1, Tim3, Tim8
|
|
||||||
|
|
||||||
## Red led
|
|
||||||
Tim1
|
|
||||||
|
|
||||||
## Green led
|
|
||||||
Tim15, Tim1, Tim8
|
|
||||||
|
|
||||||
## Backlight
|
|
||||||
Tim16, Tim4
|
|
||||||
|
|
||||||
## IR TX
|
|
||||||
Tim2 ch4
|
|
||||||
|
|
||||||
## RFID out
|
|
||||||
Tim15, Tim1
|
|
||||||
|
|
||||||
## RFID pull
|
|
||||||
Tim15, Tim1, Tim8
|
|
||||||
|
|
||||||
## iButton
|
|
||||||
Tim3, Tim8
|
|
|
@ -1,100 +0,0 @@
|
||||||
Backlight state describes by `uint8_t level;` brightness level.
|
|
||||||
|
|
||||||
LED API provided by struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueComposer* composer; /// every app add its value to compose, <uint8_t*>
|
|
||||||
ValueManager* state; /// value state and changes <uint8_t*>
|
|
||||||
} BacklightApi;
|
|
||||||
```
|
|
||||||
|
|
||||||
You can get API instance by calling `open_backlight`:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// Add new layer to LED:
|
|
||||||
inline BacklightApi* open_backlight(const char* name) {
|
|
||||||
return (BacklightApi*)furi_open(name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Default system led is `/dev/backlight`.
|
|
||||||
|
|
||||||
To read current backlight state you should use `read_backlight` function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// return true if success, false otherwise
|
|
||||||
inline bool read_backlight(BacklightApi* api, uint8_t* value, uint32_t timeout) {
|
|
||||||
return read_mutex(api->state->value, (void*)value, sizeof(uint8_t), timeout);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Also you can subscribe to backlight state changes:
|
|
||||||
|
|
||||||
Use `subscribe_backlight_changes` to register your callback:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// return true if success, false otherwise
|
|
||||||
inline bool subscribe_backlight_changes(LedApi* led, void(*cb)(uint8_t*, void*), void* ctx) {
|
|
||||||
return subscribe_pubsub(led->state->pubsub, void(*)(void*, void*)(cb), ctx);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Userspace helpers
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
uint8_t value;
|
|
||||||
ValueMutex value_mutex;
|
|
||||||
ValueComposerHandle* composer_handle;
|
|
||||||
} Backlight;
|
|
||||||
|
|
||||||
inline bool init_backlight_composer(Backlight* backlight, BacklightApi* api, uint32_t layer) {
|
|
||||||
if(!init_mutex(&backlight->value_mutex, (void*)&backlight->value, sizeof(uint8_t))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
backlight->composer_handle = add_compose_layer(
|
|
||||||
api->composer, COPY_COMPOSE, &backlight->value_mutex, layer
|
|
||||||
); // just copy backlight state on update
|
|
||||||
|
|
||||||
return backlight->composer_handle != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void write_backlight(Backlight* backlight, uint8_t value) {
|
|
||||||
write_mutex(&backlight->value_mutex, (void*)&value, sizeof(uint8_t), OsWaitForever);
|
|
||||||
request_compose(backlight->composer_handle);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
|
|
||||||
void handle_backlight_state(uint8_t* value, void* _ctx) {
|
|
||||||
printf("backlight: %d %%\n", (*value * 100) / 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
void backlight_example(void* p) {
|
|
||||||
BacklightApi* backlight_api = open_backlight("/dev/backlight");
|
|
||||||
if(backlight_api == NULL) return; // backlight not available, critical error
|
|
||||||
|
|
||||||
// subscribe to led state updates
|
|
||||||
subscribe_backlight_changes(backlight_api, handle_backlight_state, NULL);
|
|
||||||
// get current backlight value
|
|
||||||
uint8_t backlight_value;
|
|
||||||
if(read_backlight(backlight_api, &backlight_value, OsWaitForever)) {
|
|
||||||
printf(
|
|
||||||
"initial backlight: %d %%\n",
|
|
||||||
backlight_value * 100 / 256
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create compose to control led
|
|
||||||
Backlight backlight;
|
|
||||||
if(!init_led_composer(&backlight, backlight_api, UiLayerBelowNotify)) return;
|
|
||||||
|
|
||||||
// write RGB value
|
|
||||||
write_backlight(&backlight, 127);
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,402 +0,0 @@
|
||||||
# Flipper universal registry implementation (FURI)
|
|
||||||
|
|
||||||
Create record.
|
|
||||||
|
|
||||||
```C
|
|
||||||
// creates new record in registry and store pointer into it
|
|
||||||
bool furi_create(const char* name, void* ptr);
|
|
||||||
```
|
|
||||||
|
|
||||||
Open record.
|
|
||||||
|
|
||||||
```C
|
|
||||||
// get stored pointer by its name
|
|
||||||
void* furi_open(const char* name);
|
|
||||||
```
|
|
||||||
|
|
||||||
# Flipper Application control (flapp)
|
|
||||||
|
|
||||||
## (in progress. Old verison)
|
|
||||||
|
|
||||||
**`FlappHandler* flapp_start(void(app*)(void*), char* name, void* param)`**
|
|
||||||
|
|
||||||
simply starts application. It call `app` entrypoint with `param` passed as argument. Useful for daemon applications and pop-up.
|
|
||||||
|
|
||||||
|
|
||||||
**`FlappHandler* flapp_switch(void(app*)(void*), char* name, void* param)`**
|
|
||||||
|
|
||||||
swtich to other application. System **stop current app**, call `app` entrypoint with `param` passed as argument and save current application entrypoint to `prev` field in current application registry. Useful for UI or "active" application.
|
|
||||||
|
|
||||||
### Exit application
|
|
||||||
|
|
||||||
**`void flapp_exit(void* param)`**
|
|
||||||
|
|
||||||
stop current application (stop thread and clear application's stack), start application from `prev` entry in current application registry, cleanup current application registry.
|
|
||||||
|
|
||||||
|
|
||||||
**`bool flapp_kill(FlappHandler* app)`**
|
|
||||||
|
|
||||||
stop specified `app` without returning to `prev` application.
|
|
||||||
|
|
||||||
**`void flapp_ready()`**
|
|
||||||
|
|
||||||
If case one app depend on other, notify that app is ready.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
* start daemon app
|
|
||||||
* kill app
|
|
||||||
* start child thread (kill when parent app was killed)
|
|
||||||
* switch between UI apps
|
|
||||||
|
|
||||||
**`bool flapp_on_exit(void(cb*)(void*), void* ctx);`**
|
|
||||||
|
|
||||||
Register on-exit callback. It called before app will be killed. Not recommended to use in user scenario, only for system purpose (unregister callbacks, release mutexes, etc.)
|
|
||||||
|
|
||||||
# ValueMutex
|
|
||||||
|
|
||||||
The most simple concept is ValueMutex. It is wrapper around mutex and value pointer. You can take and give mutex to work with value and read and write value.
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
void* value;
|
|
||||||
size_t size;
|
|
||||||
osMutex mutex;
|
|
||||||
|
|
||||||
osMutexDescriptor __static // some internals;
|
|
||||||
} ValueMutex;
|
|
||||||
```
|
|
||||||
|
|
||||||
Create ValueMutex. Create instance of ValueMutex and call `init_mutex`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool init_mutex(ValueMutex* valuemutex, void* value, size_t size) {
|
|
||||||
valuemutex->mutex = osMutexCreateStatic(valuemutex->__static);
|
|
||||||
if(valuemutex->mutex == NULL) return false;
|
|
||||||
|
|
||||||
valuemutex->value = value;
|
|
||||||
valuemutex->size = size;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For work with data stored in mutex you should call `acquire_mutex`. It return pointer to data if success, NULL otherwise.
|
|
||||||
|
|
||||||
You must release mutex after end of work with data. Call `release_mutex` and pass ValueData instance and pointer to data.
|
|
||||||
|
|
||||||
```C
|
|
||||||
void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout) {
|
|
||||||
if(osMutexTake(valuemutex->mutex, timeout) == osOk) {
|
|
||||||
return valuemutex->value;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// infinitly wait for mutex
|
|
||||||
inline static void* acquire_mutex_block(ValueMutex* valuemutex) {
|
|
||||||
return acquire_mutex(valuemutex, OsWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool release_mutex(ValueMutex* valuemutex, void* value) {
|
|
||||||
if(value != valuemutex->value) return false;
|
|
||||||
|
|
||||||
if(!osMutexGive(valuemutex->mutex)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions. Both functions return true in case of success, false otherwise.
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool read_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) {
|
|
||||||
void* value = acquire_mutex(valuemutex, timeout);
|
|
||||||
if(value == NULL || len > valuemutex->size) return false;
|
|
||||||
memcpy(data, value, len > 0 ? len : valuemutex->size):
|
|
||||||
if(!release_mutex(valuemutex, value)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static bool read_mutex_block(ValueMutex* valuemutex, void* data, size_t len) {
|
|
||||||
return read_mutex(valuemutex, data, len, OsWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write_mutex(ValueMutex* valuemutex, void* data, size_t len, uint32_t timeout) {
|
|
||||||
void* value = acquire_mutex(valuemutex, timeout);
|
|
||||||
if(value == NULL || len > valuemutex->size) return false;
|
|
||||||
memcpy(value, data, len > 0 ? len : valuemutex->size):
|
|
||||||
if(!release_mutex(valuemutex, value)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static bool write_mutex_block(ValueMutex* valuemutex, void* data, size_t len) {
|
|
||||||
return write_mutex(valuemutex, data, len, OsWaitForever);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
/*
|
|
||||||
MANIFEST
|
|
||||||
name="example-provider-app"
|
|
||||||
stack=128
|
|
||||||
*/
|
|
||||||
void provider_app(void* _p) {
|
|
||||||
// create record with mutex
|
|
||||||
uint32_t example_value = 0;
|
|
||||||
ValueMutex example_mutex;
|
|
||||||
if(!init_mutex(&example_mutex, (void*)&example_value, sizeof(uint32_t))) {
|
|
||||||
printf("critical error\n");
|
|
||||||
flapp_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_create("provider/example", (void*)&example_mutex)) {
|
|
||||||
printf("critical error\n");
|
|
||||||
flapp_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we are ready to provide record to other apps
|
|
||||||
flapp_ready();
|
|
||||||
|
|
||||||
// get value and increment it
|
|
||||||
while(1) {
|
|
||||||
uint32_t* value = acquire_mutex(&example_mutex, OsWaitForever);
|
|
||||||
if(value != NULL) {
|
|
||||||
value++;
|
|
||||||
}
|
|
||||||
release_mutex(&example_mutex, value);
|
|
||||||
|
|
||||||
osDelay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
MANIFEST
|
|
||||||
name="example-consumer-app"
|
|
||||||
stack=128
|
|
||||||
require="example-provider-app"
|
|
||||||
*/
|
|
||||||
void consumer_app(void* _p) {
|
|
||||||
// this app run after flapp_ready call in all requirements app
|
|
||||||
|
|
||||||
// open mutex value
|
|
||||||
ValueMutex* counter_mutex = furi_open("provider/example");
|
|
||||||
if(counter_mutex == NULL) {
|
|
||||||
printf("critical error\n");
|
|
||||||
flapp_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// continously read value every 1s
|
|
||||||
uint32_t counter;
|
|
||||||
while(1) {
|
|
||||||
if(read_mutex(counter_mutex, &counter, sizeof(counter), OsWaitForever)) {
|
|
||||||
printf("counter value: %d\n", counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
osDelay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
# PubSub
|
|
||||||
|
|
||||||
PubSub allows users to subscribe on notifies and notify subscribers. Notifier side can pass `void*` arg to subscriber callback, and also subscriber can set `void*` context pointer that pass into callback (you can see callback signature below).
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef void(PubSubCallback*)(void*, void*);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PubSubCallback cb;
|
|
||||||
void* ctx;
|
|
||||||
} PubSubItem;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PubSub* self;
|
|
||||||
PubSubItem* item;
|
|
||||||
} PubSubId;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PubSubItem items[NUM_OF_CALLBACKS];
|
|
||||||
PubSubId ids[NUM_OF_CALLBACKS]; ///< permanent links to item
|
|
||||||
size_t count; ///< count of callbacks
|
|
||||||
} PubSub;
|
|
||||||
```
|
|
||||||
|
|
||||||
To create PubSub you should create PubSub instance and call `init_pubsub`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
void init_pubsub(PubSub* pubsub) {
|
|
||||||
pubsub->count = 0;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < NUM_OF_CALLBACKS; i++) {
|
|
||||||
pubsub->items[i].
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `subscribe_pubsub` to register your callback.
|
|
||||||
|
|
||||||
```C
|
|
||||||
// TODO add mutex to reconfigurate PubSub
|
|
||||||
PubSubId* subscribe_pubsub(PubSub* pubsub, PubSubCallback cb, void* ctx) {
|
|
||||||
if(pubsub->count >= NUM_OF_CALLBACKS) return NULL;
|
|
||||||
|
|
||||||
pubsub->count++;
|
|
||||||
PubSubItem* current = pubsub->items[pubsub->count];
|
|
||||||
|
|
||||||
current->cb = cb;
|
|
||||||
currrnt->ctx = ctx;
|
|
||||||
|
|
||||||
pubsub->ids[pubsub->count].self = pubsub;
|
|
||||||
pubsub->ids[pubsub->count].item = current;
|
|
||||||
|
|
||||||
flapp_on_exit(unsubscribe_pubsub, &(pubsub->ids[pubsub->count]));
|
|
||||||
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `unsubscribe_pubsub` to unregister callback.
|
|
||||||
|
|
||||||
```C
|
|
||||||
void unsubscribe_pubsub(PubSubId* pubsub_id) {
|
|
||||||
// TODO: add, and rearrange all items to keep subscribers item continuous
|
|
||||||
// TODO: keep ids link actual
|
|
||||||
// TODO: also add mutex on every pubsub changes
|
|
||||||
|
|
||||||
// trivial implementation for NUM_OF_CALLBACKS = 1
|
|
||||||
if(NUM_OF_CALLBACKS != 1) return;
|
|
||||||
|
|
||||||
if(pubsub_id != NULL || pubsub_id->self != NULL || pubsub_id->item != NULL) return;
|
|
||||||
|
|
||||||
pubsub_id->self->count = 0;
|
|
||||||
pubsub_id->item = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `notify_pubsub` to notify subscribers.
|
|
||||||
|
|
||||||
```C
|
|
||||||
void notify_pubsub(PubSub* pubsub, void* arg) {
|
|
||||||
// iterate over subscribers
|
|
||||||
for(size_t i = 0; i < pubsub->count; i++) {
|
|
||||||
pubsub->items[i]->cb(arg, pubsub->items[i]->ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
/*
|
|
||||||
MANIFEST
|
|
||||||
name="test"
|
|
||||||
stack=128
|
|
||||||
*/
|
|
||||||
|
|
||||||
void example_pubsub_handler(void* arg, void* ctx) {
|
|
||||||
printf("get %d from %s\n", *(uint32_t*)arg, (const char*)ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pubsub_test() {
|
|
||||||
const char* app_name = "test app";
|
|
||||||
|
|
||||||
PubSub example_pubsub;
|
|
||||||
init_pubsub(&example_pubsub);
|
|
||||||
|
|
||||||
if(!subscribe_pubsub(&example_pubsub, example_pubsub_handler, (void*)app_name)) {
|
|
||||||
printf("critical error\n");
|
|
||||||
flapp_exit(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t counter = 0;
|
|
||||||
while(1) {
|
|
||||||
notify_pubsub(&example_pubsub, (void*)&counter);
|
|
||||||
counter++;
|
|
||||||
|
|
||||||
osDelay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# ValueComposer
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef void(ValueComposerCallback)(void* ctx, void* state);
|
|
||||||
|
|
||||||
void COPY_COMPOSE(void* ctx, void* state) {
|
|
||||||
read_mutex((ValueMutex*)ctx, state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UiLayerBelowNotify
|
|
||||||
UiLayerNotify,
|
|
||||||
UiLayerAboveNotify
|
|
||||||
} UiLayer;
|
|
||||||
```
|
|
||||||
|
|
||||||
```C
|
|
||||||
ValueComposerHandle* add_compose_layer(
|
|
||||||
ValueComposer* composer, ValueComposerCallback cb, void* ctx, uint32_t layer
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool remove_compose_layer(ValueComposerHandle* handle);
|
|
||||||
```
|
|
||||||
|
|
||||||
```C
|
|
||||||
void request_compose(ValueComposerHandle* handle);
|
|
||||||
```
|
|
||||||
|
|
||||||
See [LED](LED-API) or [Display](Display-API) API for examples.
|
|
||||||
|
|
||||||
# ValueManager
|
|
||||||
|
|
||||||
More complicated concept is ValueManager. It is like ValueMutex, but user can subscribe to value updates.
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueMutex value;
|
|
||||||
PubSub pubsub;
|
|
||||||
} ValueManager;
|
|
||||||
```
|
|
||||||
|
|
||||||
First of all you can use value and pubsub part as showing above: aquire/release mutex, read value, subscribe/unsubscribe pubsub. There are two specific methods for ValueManager:
|
|
||||||
|
|
||||||
`write_managed` acquire value, changes it and send notify with current value.
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool write_managed(ValueManager* managed, void* data, size_t len, uint32_t timeout) {
|
|
||||||
void* value = acquire_mutex(managed->mutex, timeout);
|
|
||||||
if(value == NULL) return false;
|
|
||||||
|
|
||||||
memcpy(value, data, len):
|
|
||||||
|
|
||||||
notify_pubsub(&managed->pubsub, value);
|
|
||||||
|
|
||||||
if(!release_mutex(managed->mutex, value)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`commit_managed` works as `release_mutex` but send notify with current value.
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool commit_managed(ValueManager* managed, void* value) {
|
|
||||||
if(value != managed->mutex->value) return false;
|
|
||||||
|
|
||||||
notify_pubsub(&managed->pubsub, value);
|
|
||||||
|
|
||||||
if(!osMutexGive(managed->mutex)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,68 +0,0 @@
|
||||||
All display operations based on [u8g2](https://github.com/olikraus/u8g2) library.
|
|
||||||
|
|
||||||
API available as `ValueComposer`.
|
|
||||||
|
|
||||||
Driver call render callback and pass API contains u8g2 functions, instance and fonts:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
u8g2_t* display;
|
|
||||||
|
|
||||||
void (*u8g2_SetFont)(u8g2_t *u8g2, const uint8_t *font);
|
|
||||||
void (*u8g2_SetDrawColor)(u8g2_t *u8g2, uint8_t color);
|
|
||||||
void (*u8g2_SetFontMode)(u8g2_t *u8g2, uint8_t is_transparent);
|
|
||||||
u8g2_uint_t (*u8g2_DrawStr)(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str);
|
|
||||||
|
|
||||||
Fonts fonts;
|
|
||||||
} DisplayApi;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t* u8g2_font_6x10_mf;
|
|
||||||
} Fonts;
|
|
||||||
```
|
|
||||||
|
|
||||||
First of all you can open display API instance by calling `open_display`
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// Get display instance and API
|
|
||||||
inline Display* open_display(const char* name) {
|
|
||||||
return (Display*)furi_open(name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Default display name is `/dev/display`.
|
|
||||||
|
|
||||||
For draw something to display you need to register new layer in display composer:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef void (RenderCallback*)(void* ctx, DisplayApi* api);
|
|
||||||
|
|
||||||
inline ValueComposerHandle* init_display_composer(
|
|
||||||
Display* api, RenderCallback render, void* ctx, uint32_t layer) {
|
|
||||||
return add_compose_layer(api->composer, (ValueComposerCallback)render, ctx, layer);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And then call `request_compose` every time you need to redraw your image.
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
|
|
||||||
void example_render(void* ctx, DisplayApi* api) {
|
|
||||||
api->u8g2_SetFont(api->display, display_api->fonts.u8g2_font_6x10_mf);
|
|
||||||
api->u8g2_SetDrawColor(api->display, 1);
|
|
||||||
api->u8g2_SetFontMode(api->display, 1);
|
|
||||||
api->u8g2_DrawStr(api->display, 2, 12, (char*)ctx); // ctx contains some static text
|
|
||||||
}
|
|
||||||
|
|
||||||
void u8g2_example(void* p) {
|
|
||||||
Display* display_api = open_display("/dev/display");
|
|
||||||
if(display_api == NULL) return; // display not available, critical error
|
|
||||||
|
|
||||||
ValueComposerHandle display_handler = init_display_composer(
|
|
||||||
display_api, example_render, (void*)"Hello world", UiLayerBelowNotify);
|
|
||||||
|
|
||||||
request_compose(display_handler);
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,158 +0,0 @@
|
||||||
# GPIO
|
|
||||||
|
|
||||||
GPIO defined as struct `GpioPin`.
|
|
||||||
|
|
||||||
GPIO functions:
|
|
||||||
|
|
||||||
```C
|
|
||||||
// Init GPIO
|
|
||||||
void gpio_init(GpioPin* gpio, GpioMode mode);
|
|
||||||
|
|
||||||
typedef enum { GpioModeInput, GpioModeOutput, GpioModeOpenDrain } GpioMode;
|
|
||||||
|
|
||||||
// write value to GPIO
|
|
||||||
void gpio_write(GpioPin* gpio, bool state);
|
|
||||||
|
|
||||||
// read value from GPIO, f = LOW, t = HIGH
|
|
||||||
bool gpio_read(GpioPin* gpio);
|
|
||||||
```
|
|
||||||
|
|
||||||
When application is exited, system place pin to Z-state by calling `gpio_disable`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
// put GPIO to Z-state (used for restore pin state on app exit)
|
|
||||||
void gpio_disable(ValueMutex* gpio_mutex) {
|
|
||||||
GpioPin* gpio = acquire_mutex(gpio_mutex, 0);
|
|
||||||
gpio_init(gpio, GpioModeInput);
|
|
||||||
release_mutex(gpio_mutex, gpio);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Available GPIO stored in FURI as `ValueMutex<GpioPin*>`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
inline static ValueMutex* open_gpio_mutex(const char* name) {
|
|
||||||
ValueMutex* gpio_mutex = (ValueMutex*)furi_open(name);
|
|
||||||
if(gpio_mutex != NULL) flapp_on_exit(gpio_disable, gpio_mutex);
|
|
||||||
|
|
||||||
return gpio_mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper
|
|
||||||
inline static GpioPin* open_gpio(const char* name) {
|
|
||||||
ValueMutex* gpio_mutex = open_gpio(name);
|
|
||||||
return (GpioPin*)acquire_mutex(gpio_mutex, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available GPIO (target F2)
|
|
||||||
|
|
||||||
* PA4
|
|
||||||
* PA5
|
|
||||||
* PA6
|
|
||||||
* PA7
|
|
||||||
* PB2
|
|
||||||
* PC3
|
|
||||||
* PC0
|
|
||||||
* PC1
|
|
||||||
* PB6
|
|
||||||
* PB7
|
|
||||||
* PA13
|
|
||||||
* PA14
|
|
||||||
* RFID_PULL
|
|
||||||
* IR_TX
|
|
||||||
* IBUTTON
|
|
||||||
* VIBRO
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
void gpio_example() {
|
|
||||||
GpioPin* pin = open_gpio("PB6");
|
|
||||||
|
|
||||||
if(pin == NULL) {
|
|
||||||
printf("pin not available\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio_init(pin, GpioModeOutput);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
gpio_write(pin, true);
|
|
||||||
delay(100);
|
|
||||||
gpio_write(pin, false);
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# PWM
|
|
||||||
|
|
||||||
PWM defined as `PwmPin`. To set PWM channel:
|
|
||||||
|
|
||||||
```C
|
|
||||||
void pwm_set(PwmPin* pwm, float value, float freq);
|
|
||||||
```
|
|
||||||
|
|
||||||
When application is exited, system disable pwm by calling `pwm_disable`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
// put GPIO to Z-state (used for restore pin state on app exit)
|
|
||||||
void pwm_disable(ValueMutex* pwm_mutex) {
|
|
||||||
PwmPin* pwm = acquire_mutex(pwm_mutex, 0);
|
|
||||||
pwm_set(pwm, 0., 0.);
|
|
||||||
release_mutex(pwm_mutex, pwm);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Available PWM stored in FURI as `ValueMutex<PwmPin*>`.
|
|
||||||
|
|
||||||
```C
|
|
||||||
inline static ValueMutex* open_pwm_mutex(const char* name) {
|
|
||||||
ValueMutex* pwm_mutex = (ValueMutex*)furi_open(name);
|
|
||||||
if(pwm_mutex != NULL) flapp_on_exit(pwm_disable, pwm_mutex);
|
|
||||||
|
|
||||||
return pwm_mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// helper
|
|
||||||
inline static PwmPin* open_pwm(const char* name) {
|
|
||||||
ValueMutex* pwm_mutex = open_gpio(name);
|
|
||||||
return (PwmPin*)acquire_mutex(pwm_mutex, 0);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available PWM (target F2)
|
|
||||||
|
|
||||||
* SPEAKER
|
|
||||||
* RFID_OUT
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
void sound_example() {
|
|
||||||
PwmPin* speaker = open_pwm("SPEAKER");
|
|
||||||
|
|
||||||
if(speaker == NULL) {
|
|
||||||
printf("speaker not available\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
pwm_set(speaker, 1000., 0.1);
|
|
||||||
delay(2);
|
|
||||||
pwm_set(speaker, 110., 0.5);
|
|
||||||
delay(198);
|
|
||||||
pwm_set(speaker, 330., 0.5);
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# ADC
|
|
||||||
|
|
||||||
Coming soon...
|
|
||||||
|
|
||||||
# I2C
|
|
||||||
|
|
||||||
Coming soon...
|
|
|
@ -1,107 +0,0 @@
|
||||||
All input API available by struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
Subscriber* events; /// debounced keyboards events: press/release, Subscriber<InputEvent*>
|
|
||||||
Subscriber* raw_events; /// raw keyboards events: press/release, Subscriber<InputEvent*>
|
|
||||||
ValueMutex* state; /// current keyboard state, ValueMutex<InputState*>
|
|
||||||
} Input;
|
|
||||||
```
|
|
||||||
|
|
||||||
You can get API instance by calling `open_input`:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// Get input struct
|
|
||||||
inline Input* open_input(const char* name) {
|
|
||||||
return (Input*)furi_open(name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Default (system) input name is `/dev/kb`.
|
|
||||||
|
|
||||||
Buttons state store as struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// Current state of buttons
|
|
||||||
typedef struct {
|
|
||||||
bool up;
|
|
||||||
bool down;
|
|
||||||
bool right;
|
|
||||||
bool left;
|
|
||||||
bool ok;
|
|
||||||
bool back;
|
|
||||||
} InputState;
|
|
||||||
```
|
|
||||||
|
|
||||||
To read buttons state you should use `read_state` function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// read current state of all buttons. Return true if success, false otherwise
|
|
||||||
inline bool read_state(Input* api, InputState* value, uint32_t timeout) {
|
|
||||||
return read_mutex(api->state, (void*)value, sizeof(InputState), timeout);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Also you can subscribe to input events:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// used to pass button press/release evens
|
|
||||||
typedef struct {
|
|
||||||
Inputs input; /// what button
|
|
||||||
bool state; /// true = press, false = release
|
|
||||||
} InputEvent;
|
|
||||||
|
|
||||||
/// List of buttons
|
|
||||||
typedef enum {
|
|
||||||
InputsUp = 0,
|
|
||||||
InputsDown,
|
|
||||||
InputsRight,
|
|
||||||
InputsLeft,
|
|
||||||
InputsOk,
|
|
||||||
InputsBack,
|
|
||||||
InputsSize
|
|
||||||
} Inputs;
|
|
||||||
```
|
|
||||||
|
|
||||||
Use `subscribe_input_events` to register your callback:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// subscribe on button press/release events. Return true if success, false otherwise
|
|
||||||
inline bool subscribe_input_events(Subscriber* events, void(*cb)(InputEvent*, void*), void* ctx) {
|
|
||||||
return subscribe_pubsub(events, void(*)(void*, void*)(cb), ctx);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
// function used to handle keyboard events
|
|
||||||
void handle_keyboard(InputEvent* event, void* _ctx) {
|
|
||||||
if(event->state) {
|
|
||||||
printf("you press %d", event->input);
|
|
||||||
} else {
|
|
||||||
printf("you release %d", event->input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_example(void* p) {
|
|
||||||
Input* input = open_input("/dev/kb");
|
|
||||||
if(input == NULL) return; // keyboard not available, critical error
|
|
||||||
|
|
||||||
// async way
|
|
||||||
subscribe_input_events(input->events, handle_keyboard, NULL);
|
|
||||||
|
|
||||||
// blocking way
|
|
||||||
InputState state;
|
|
||||||
while(1) {
|
|
||||||
if(read_state(input, &state, OsWaitForever)) {
|
|
||||||
if(state.up) {
|
|
||||||
printf("up is pressed");
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,110 +0,0 @@
|
||||||
LED state describes by struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
uint8_t red;
|
|
||||||
uint8_t green;
|
|
||||||
uint8_t blue;
|
|
||||||
} Rgb;
|
|
||||||
```
|
|
||||||
|
|
||||||
LED API provided by struct:
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueComposer* composer; /// every app add its value to compose, <Rgb*>
|
|
||||||
ValueManager* state; /// LED value state and changes <Rgb*>
|
|
||||||
} LedApi;
|
|
||||||
```
|
|
||||||
|
|
||||||
You can get API instance by calling `open_led`:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// Add new layer to LED:
|
|
||||||
inline LedApi* open_led(const char* name) {
|
|
||||||
return (LedApi*)furi_open(name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Default system led is `/dev/led`.
|
|
||||||
|
|
||||||
To read current led state you should use `read_led` function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// return true if success, false otherwise
|
|
||||||
inline bool read_led(LedApi* led, Rgb* value, uint32_t timeout) {
|
|
||||||
return read_mutex(led->state->value, (void*)value, sizeof(Rgb), timeout);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Also you can subscribe to led state changes:
|
|
||||||
|
|
||||||
Use `subscribe_led_changes` to register your callback:
|
|
||||||
|
|
||||||
```C
|
|
||||||
/// return true if success, false otherwise
|
|
||||||
inline bool subscribe_led_changes(LedApi* led, void(*cb)(Rgb*, void*), void* ctx) {
|
|
||||||
return subscribe_pubsub(led->state->pubsub, void(*)(void*, void*)(cb), ctx);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Userspace helpers
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
Rgb value;
|
|
||||||
ValueMutex value_mutex;
|
|
||||||
ValueComposerHandle* composer_handle;
|
|
||||||
} SystemLed;
|
|
||||||
|
|
||||||
inline bool init_led_composer(SystemLed* led, LedApi* api, uint32_t layer) {
|
|
||||||
if(!init_mutex(&led->value_mutex, (void*)&led->value, sizeof(Rgb))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
led->composer_handle = add_compose_layer(
|
|
||||||
api->composer, COPY_COMPOSE, &led->value_mutex, layer
|
|
||||||
); // just copy led state on update
|
|
||||||
|
|
||||||
return led->composer_handle != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void write_led(SystemLed* led, Rgb* value) {
|
|
||||||
write_mutex(&led->value_mutex, (void*)value, sizeof(Rgb), OsWaitForever);
|
|
||||||
request_compose(led->composer_handle);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Usage example
|
|
||||||
|
|
||||||
```C
|
|
||||||
|
|
||||||
void handle_led_state(Rgb* rgb, void* _ctx) {
|
|
||||||
printf("led: #%02X%02X%02X\n", rgb->red, rgb->green, rgb->blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_example(void* p) {
|
|
||||||
LedApi* led_api = open_led("/dev/led");
|
|
||||||
if(led_api == NULL) return; // led not available, critical error
|
|
||||||
|
|
||||||
// subscribe to led state updates
|
|
||||||
subscribe_led_changes(led_api, handle_led_state, NULL);
|
|
||||||
// get current led value
|
|
||||||
Rgb led_value;
|
|
||||||
if(read_led(led_api, &led_value, OsWaitForever)) {
|
|
||||||
printf(
|
|
||||||
"initial led: #%02X%02X%02X\n",
|
|
||||||
led_value->red,
|
|
||||||
led_value->green,
|
|
||||||
led_value->blue
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create compose to control led
|
|
||||||
SystemLed system_led;
|
|
||||||
if(!init_led_composer(&system_led, led_api, UiLayerBelowNotify)) return;
|
|
||||||
|
|
||||||
// write RGB value
|
|
||||||
write_led(&system_led, &(Rgb{.red = 0xFA, green = 0xCE, .blue = 0x8D}));
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,130 +0,0 @@
|
||||||
# SPI
|
|
||||||
|
|
||||||
HAL struct `SPI_HandleTypeDef*` used for handling SPI info.
|
|
||||||
|
|
||||||
For transmit/receive data use `spi_xfer` function:
|
|
||||||
|
|
||||||
```C
|
|
||||||
bool spi_xfer(
|
|
||||||
SPI_HandleTypeDef* spi,
|
|
||||||
uint8_t* tx_data, uint8_t* rx_data, size_t len,
|
|
||||||
PubSubCallback cb, void* ctx);
|
|
||||||
```
|
|
||||||
|
|
||||||
* `tx_data` and `rx_data` size must be equal (and equal `len`)
|
|
||||||
* `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback.
|
|
||||||
|
|
||||||
Blocking verison:
|
|
||||||
|
|
||||||
```C
|
|
||||||
inline static bool spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) {
|
|
||||||
semaphoreInfo s;
|
|
||||||
osSemaphore block = createSemaphoreStatic(s);
|
|
||||||
if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) {
|
|
||||||
osReleaseSemaphore(block);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
osWaitSemaphore(block);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## SPI Bus
|
|
||||||
|
|
||||||
Common implementation of SPI bus: serial interface + CS pin
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
GpioPin* cs; ///< CS pin
|
|
||||||
ValueMutex* spi; ///< <SPI_HandleTypeDef*>
|
|
||||||
} SpiBus;
|
|
||||||
```
|
|
||||||
|
|
||||||
## SPI device
|
|
||||||
|
|
||||||
For dedicated work with one device there is `SpiDevice` entity. It contains ValueMutex around SpiBus: after you acquire device you can acquire spi to work with it (don't forget SPI bus is shared around many device, release it after every transaction as quick as possible).
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueMutex* bus; ///< <SpiBus*>
|
|
||||||
} SpiDevice;
|
|
||||||
```
|
|
||||||
|
|
||||||
## SPI IRQ device
|
|
||||||
|
|
||||||
Many devices (like CC1101 and NFC) present as SPI bus and IRQ line. For work with it there is special entity `SpiIrqDevice`. Use `subscribe_pubsub` for subscribinq to irq events.
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueMutex* bus; ///< <SpiBus*>
|
|
||||||
PubSub* irq;
|
|
||||||
} SpiIrqDevice;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Display device
|
|
||||||
|
|
||||||
Special implementation of SPI bus: serial interface + CS, Res, D/I lines.
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
GpioPin* cs; ///< CS pin
|
|
||||||
GpioPin* res; ///< reset pin
|
|
||||||
GpioPin* di; ///< D/I pin
|
|
||||||
ValueMutex* spi; ///< <SPI_HandleTypeDef*>
|
|
||||||
} DisplayBus;
|
|
||||||
|
|
||||||
```C
|
|
||||||
typedef struct {
|
|
||||||
ValueMutex* bus; ///< <DisplayBus*>
|
|
||||||
} DisplayDevice;
|
|
||||||
```
|
|
||||||
|
|
||||||
# SPI devices (F2)
|
|
||||||
|
|
||||||
* `/dev/sdcard` - SD card SPI, `SpiDevice`
|
|
||||||
* `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice`
|
|
||||||
* `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice`
|
|
||||||
* `/dev/display` - `DisplayDevice`
|
|
||||||
* `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7)
|
|
||||||
|
|
||||||
### Application example
|
|
||||||
|
|
||||||
```C
|
|
||||||
// Be careful, this function called from IRQ context
|
|
||||||
void handle_irq(void* _arg, void* _ctx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void cc1101_example() {
|
|
||||||
SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus");
|
|
||||||
if(cc1101_device == NULL) return; // bus not available, critical error
|
|
||||||
|
|
||||||
subscribe_pubsub(cc1101_device->irq, handle_irq, NULL);
|
|
||||||
|
|
||||||
{
|
|
||||||
// acquire device as device bus
|
|
||||||
SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0);
|
|
||||||
if(spi_bus == NULL) {
|
|
||||||
printf("Device busy\n");
|
|
||||||
// wait for device
|
|
||||||
spi_bus = acquire_mutex_block(cc1101_device->bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make transaction
|
|
||||||
uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF};
|
|
||||||
uint8_t response[4];
|
|
||||||
|
|
||||||
{
|
|
||||||
SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi);
|
|
||||||
|
|
||||||
gpio_write(spi_bus->cs, false);
|
|
||||||
spi_xfer_block(spi, request, response, 4);
|
|
||||||
gpio_write(spi_bus->cs, true);
|
|
||||||
|
|
||||||
release_mutex(cc1101_device->spi, spi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// release device (device bus)
|
|
||||||
release_mutex(cc1101_device->bus, spi_bus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1,90 +0,0 @@
|
||||||
### Display
|
|
||||||
|
|
||||||
* Monochrome LCD
|
|
||||||
* Resolution: 128х64px
|
|
||||||
* Diagonal: 1.4”
|
|
||||||
* Orange LED backlight
|
|
||||||
|
|
||||||
### LED
|
|
||||||
|
|
||||||
RGB LED
|
|
||||||
|
|
||||||
### Control
|
|
||||||
|
|
||||||
* 5-button joystick
|
|
||||||
* Back button
|
|
||||||
* Reboot — Back+Left buttons for 2 seconds
|
|
||||||
|
|
||||||
### MCU
|
|
||||||
|
|
||||||
* ARM® Cortex®-M4
|
|
||||||
* 64 MHz
|
|
||||||
* 1MB (1M x 8) FLASH
|
|
||||||
|
|
||||||
### Sub-1 GHz Range
|
|
||||||
|
|
||||||
* СС1101
|
|
||||||
* TX/RX
|
|
||||||
* Frequency: 433/434/315/868 Mhz
|
|
||||||
* Modulation: ASK/FSK
|
|
||||||
|
|
||||||
### USB
|
|
||||||
|
|
||||||
* 1x USB 2.0 port, type C
|
|
||||||
* USB device
|
|
||||||
* Charging
|
|
||||||
|
|
||||||
### GPIO
|
|
||||||
|
|
||||||
* 0.65mm Female Header Connectors with 2.54 pitch
|
|
||||||
* x12+ — Data pins / 5V tolerant
|
|
||||||
* 2x — GND
|
|
||||||
* 1x — 3.3V
|
|
||||||
* 1x — 5V
|
|
||||||
|
|
||||||
### 125 khz RFID
|
|
||||||
|
|
||||||
* Supported protocols: EM-4100, HID Prox
|
|
||||||
* Operate modes: Reader/Writer/Emulator
|
|
||||||
|
|
||||||
### iButton 1-Wire
|
|
||||||
|
|
||||||
* Supported protocols: Dallas DS1990A, Cyphral, Metakom
|
|
||||||
* Operate modes: Reader/Writer/Emulator
|
|
||||||
|
|
||||||
### InfraRed
|
|
||||||
|
|
||||||
* Supported frequency: 36-40 kHz
|
|
||||||
* Operate modes: Reader/Emulator
|
|
||||||
|
|
||||||
### Bluetooth
|
|
||||||
|
|
||||||
* Bluetooth Low Energy 4.0+
|
|
||||||
* STM32WB55
|
|
||||||
|
|
||||||
### NFC
|
|
||||||
|
|
||||||
* Supported protocols: Mifare
|
|
||||||
* Operate modes: Reader/Emulator/Sniffer
|
|
||||||
|
|
||||||
### Vibro
|
|
||||||
|
|
||||||
* Type: Coin motor
|
|
||||||
* RPM: ≥10000
|
|
||||||
|
|
||||||
### Speaker
|
|
||||||
|
|
||||||
* Type: Coin
|
|
||||||
|
|
||||||
### Power and battery
|
|
||||||
|
|
||||||
* Built-in not removable lithium‑ion battery 2000mAh
|
|
||||||
* USB charging 5V, 500-2000mA
|
|
||||||
* ≥10 days standby
|
|
||||||
|
|
||||||
### Physical
|
|
||||||
|
|
||||||
* Materials: PC
|
|
||||||
* Weight: <200g
|
|
||||||
* Size: ~98х40х22mm
|
|
||||||
* Operating temperature: 0 ~ 50 °C
|
|
|
@ -1,20 +0,0 @@
|
||||||
[Device schematic (pdf)](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/F1B1C0.0.pdf)
|
|
||||||
|
|
||||||
## Errata
|
|
||||||
|
|
||||||
* NAND reset IC drive reset net by push-pull output may cause MCU fault and disable internal MCU reset feature.
|
|
||||||
* System going to boot-loop state when reset by reset circuit
|
|
||||||
* No series resistors on external gpio for protecting MCU
|
|
||||||
* Wrong value LED series resistor
|
|
||||||
* Wrong footprint for CMOS transistors
|
|
||||||
* Wrong value IR TX series resistor
|
|
||||||
* No need capacitor on IR RX
|
|
||||||
* Wrong value IR RX pullup resistor
|
|
||||||
* 125 kHz RFID + iButton wrong schematic
|
|
||||||
* It seems bad to place main VCC on external GPIO pins. Overcurrent can damage main regulator and cause device broken. User can apply wrong voltage on this pin.
|
|
||||||
|
|
||||||
### New RFID + iButton schematic
|
|
||||||
|
|
||||||
after many experiments we found good schematic solution for work with RFID and auxiliary follow iButton level (for non-TTL protocol like Cyphral)
|
|
||||||
|
|
||||||
![new RFID + iButton schematic](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/new-rfid-ibutton-sch.png)
|
|
|
@ -1,84 +0,0 @@
|
||||||
* Firmware target: F2
|
|
||||||
* Body version: no body
|
|
||||||
* Interconnection version: 1
|
|
||||||
|
|
||||||
**[Device schematic (pdf)](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/F2B0C1.1.sch.pdf)**
|
|
||||||
|
|
||||||
# Device layout
|
|
||||||
|
|
||||||
* [main PCB](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/F2B0C1.1.main.pdf)
|
|
||||||
* [NFC PCB](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/F2B0C1.1.NFC.pdf)
|
|
||||||
* [iButton PCB](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/F2B0C1.1.ibtn.pdf)
|
|
||||||
|
|
||||||
# Pinout:
|
|
||||||
| Pin | Mode | Define | Description |
|
|
||||||
|-|-|-|-|
|
|
||||||
| PC13 | EXTI13 | BUTTON_BACK | Button |
|
|
||||||
| PC14 | RCC_OSC32_IN | | 32768 kHz XTAL |
|
|
||||||
| PC15 | RCC_OSC32_OUT | | 32768 kHz XTAL |
|
|
||||||
| PH0 | RCC_OSC_IN | | 16 MHz XTAL |
|
|
||||||
| PH1 | RCC_OSC_OUT | | 16 MHz XTAL |
|
|
||||||
| PC0 | GPIO_Analog | | External GPIO |
|
|
||||||
| PC1 | GPIO_Analog | | External GPIO |
|
|
||||||
| PC2 | EXTI2 | CHRG | Charge state |
|
|
||||||
| PC3 | ADC1_IN4 | BATT_V | Battery voltage |
|
|
||||||
| PA0 | ADC1_IN5 | IR_RX | Infrared receiver |
|
|
||||||
| PA1 | EXTI1 | BUTTON_DOWN | Button |
|
|
||||||
| PA2 | GPIO_Output | DISPLAY_DI | Display |
|
|
||||||
| PA3 | TIM5_CH4 | SPEAKER | |
|
|
||||||
| PA4 | GPIO_Analog | | External GPIO |
|
|
||||||
| PA5 | GPIO_Analog | | External GPIO |
|
|
||||||
| PA6 | GPIO_Analog | | External GPIO |
|
|
||||||
| PA7 | GPIO_Analog | | External GPIO |
|
|
||||||
| PC4 | GPIO_Output | NFC_CS | NFC SPI CS |
|
|
||||||
| PC5 | COMP1_INP | RFID_RF_IN | 125 kHz RFID RX, contact keys analog input (for Cyfral/metakom) |
|
|
||||||
| PB0 | EXTI0 | BUTTON_UP | Button |
|
|
||||||
| PB1 | GPIO_Output | LED_BLUE | Led |
|
|
||||||
| PB2 | GPIO_Analog | | External GPIO |
|
|
||||||
| PB10 | GPIO_Output | DISPLAY_RST | Display |
|
|
||||||
| PB11 | GPIO_Output | IR_TX | Infrared transmit |
|
|
||||||
| PB12 | GPIO_Analog | | External GPIO |
|
|
||||||
| PB13 | TIM15_CH1N | RFID_OUT | RFID 125 kHz read master tone/write TX |
|
|
||||||
| PB14 | GPIO_Output | LED_GREEN | Led |
|
|
||||||
| PB15 | TIM15_CH2 | RFID_PULL | RFID 125 kHz write/emulate pulling | NFC IRQ |
|
|
||||||
| PC6 | GPIO_Output | VIBRO | |
|
|
||||||
| PC7 | TIM8_CH2 | iButton | contact key |
|
|
||||||
| PC8 | GPIO_Output | DISPLAY_CS | Dispay |
|
|
||||||
| PC9 | GPIO_Output | SD_CS | microSD card SD |
|
|
||||||
| PA8 | GPIO_Output | LED_RED | Led |
|
|
||||||
| PA9 | USART1_TX | | External GPIO/USART TX |
|
|
||||||
| PA10 | USART1_RX | | External GPIO/USART RX |
|
|
||||||
| PA11 | USB_OTG_FS_DM | | USB |
|
|
||||||
| PA12 | USB_OTG_FS_DP | | USB |
|
|
||||||
| PA13 | SWDIO | | External GPIO/SWDIO |
|
|
||||||
| PA14 | SWCLK | | External GPIO/SWDCLK |
|
|
||||||
| PA15 | GPIO_Output | CC1101_CS | CC1101 CS |
|
|
||||||
| PC10 | SPI3_SCK | | SD/CC1101/NFC SPI |
|
|
||||||
| PC11 | SPI3_MISO | | SD/CC1101/NFC SPI |
|
|
||||||
| PC12 | SPI3_MOSI | | SD/CC1101/NFC SPI |
|
|
||||||
| PD2 | GPIO_Analog | | External GPIO |
|
|
||||||
| PB3 | SPI1_SCK | | Display |
|
|
||||||
| PB4 | EXTI4 | BUTTON_LEFT | Button |
|
|
||||||
| PB5 | SPI1_MOSI | | Display |
|
|
||||||
| PB6 | GPIO_Output | DISPLAY_BACKLIGHT | |
|
|
||||||
| PB7 | GPIO_Input | CC1101_G0 | |
|
|
||||||
| PB8 | EXTI8 | BUTTON_RIGHT | Button |
|
|
||||||
| PB9 | EXTI9 | BUTTON_OK | Button |
|
|
||||||
|
|
||||||
# External GPIO
|
|
||||||
|
|
||||||
| Pin | | | | | |
|
|
||||||
|-|-|-|-|-|-|
|
|
||||||
| PC0 | GPIO | LPUART RX | ADC1/2/3-1 | I²C SCL | |
|
|
||||||
| PC1 | GPIO | LPUART TX | ADC1/2/3-2 | I²C SDA | |
|
|
||||||
| PA4 | GPIO | DAC1-1 | ADC1/2-9 | SPI1 NSS | |
|
|
||||||
| PA5 | GPIO | DAC1-2 | ADC1/2-10 | SPI1 SCK | TIM2/8 OUT |
|
|
||||||
| PA6 | GPIO | | ADC1/2-11 | SPI1 MISO | TIM3/16 OUT |
|
|
||||||
| PA7 | GPIO | | ADC1/2-12 | SPI1 MOSI | TIM1/2/8/17 OUT |
|
|
||||||
| PB2 | GPIO | | | | RTC Alarm |
|
|
||||||
| PB12 | GPIO | | | | |
|
|
||||||
| PA9 | GPIO | USART1 TX | | | |
|
|
||||||
| PA10 | GPIO | USART1 RX | | | |
|
|
||||||
| PA13 | GPIO | SWDIO | | | |
|
|
||||||
| PA14 | GPIO | SWCLK | | | |
|
|
||||||
| PD2 | GPIO | UART5 RX | | | |
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Hardware
|
|
||||||
|
|
||||||
|
|
||||||
## External GPIO Pinout
|
|
||||||
|
|
||||||
![](./../../wiki_static/hw/gpio-pinout.jpeg)
|
|
||||||
|
|
||||||
| Pin | | | | | |
|
|
||||||
|-|-|-|-|-|-|
|
|
||||||
| PC0 | GPIO | LPUART RX | ADC1/2/3-1 | I²C SCL | |
|
|
||||||
| PC1 | GPIO | LPUART TX | ADC1/2/3-2 | I²C SDA | |
|
|
||||||
| PA4 | GPIO | DAC1-1 | ADC1/2-9 | SPI1 NSS | |
|
|
||||||
| PA5 | GPIO | DAC1-2 | ADC1/2-10 | SPI1 SCK | TIM2/8 OUT |
|
|
||||||
| PA6 | GPIO | | ADC1/2-11 | SPI1 MISO | TIM3/16 OUT |
|
|
||||||
| PA7 | GPIO | | ADC1/2-12 | SPI1 MOSI | TIM1/2/8/17 OUT |
|
|
||||||
| PB2 | GPIO | | | | RTC Alarm |
|
|
||||||
| PB12 | GPIO | | | | |
|
|
||||||
| PA9 | GPIO | USART1 TX | | | |
|
|
||||||
| PA10 | GPIO | USART1 RX | | | |
|
|
||||||
| PA13 | GPIO | SWDIO | | | |
|
|
||||||
| PA14 | GPIO | SWCLK | | | |
|
|
||||||
| PD2 | GPIO | UART5 RX | | | |
|
|
||||||
|
|
||||||
|
|
||||||
## Dev Kit F2B0C1.1
|
|
||||||
|
|
||||||
![](./../../wiki_static/hw/dev-kit-f2b0c1.1.jpeg)
|
|
||||||
|
|
||||||
|
|
||||||
## [Hardware Specification](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-specification)
|
|
||||||
|
|
||||||
## Board releases
|
|
||||||
|
|
||||||
[F1B1C0.0](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F1B1C0.0)
|
|
||||||
[F2B0C1.1](https://github.com/Flipper-Zero/flipperzero-firmware-community/wiki/Hardware-version-F2B0C1.1)
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
1. `# Clean flash`
|
|
||||||
2. `make -C bootloader flash` `# Load bootloader`
|
|
||||||
3. `# reboot device`
|
|
||||||
* Press right
|
|
||||||
* Press left
|
|
||||||
* Wait 0.1 s
|
|
||||||
* Release left
|
|
||||||
* Release right
|
|
||||||
4. Wait 0.5 s
|
|
||||||
5. `# Expect no FW`
|
|
||||||
* Expect: no uart welcome message
|
|
||||||
* Expect: red led on
|
|
||||||
* Expect: no USB
|
|
||||||
6. `# reboot device and go to DFU`
|
|
||||||
* Press left
|
|
||||||
* Press right
|
|
||||||
* Wait 0.1 s
|
|
||||||
* Release left
|
|
||||||
* Wait 0.5 s
|
|
||||||
* Release right
|
|
||||||
7. Wait 0.5 s
|
|
||||||
8. `# Expect DFU`
|
|
||||||
* Expect: blue led on
|
|
||||||
* Expect: USB: DFU
|
|
||||||
9. `target_f2/deploy-dfu.sh` `# load FW`
|
|
||||||
10. `# reboot device`
|
|
||||||
* Press right
|
|
||||||
* Press left
|
|
||||||
* Wait 0.1 s
|
|
||||||
* Release left
|
|
||||||
* Release right
|
|
||||||
11. Wait 0.5 s
|
|
||||||
12. `# Expect FW`
|
|
||||||
* Expect: uart welcome message
|
|
||||||
* Expect: USB Flipper CDC
|
|
|
@ -1,75 +0,0 @@
|
||||||
## Local target
|
|
||||||
|
|
||||||
* APP_TEST
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_TEST=1 clean`
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_TEST=1 run`
|
|
||||||
* check tests pass/fail (by exitcode == 0)
|
|
||||||
|
|
||||||
* APP_EXAMPLE_BLINK
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_BLINK=1 run`
|
|
||||||
* GPIO on and off
|
|
||||||
|
|
||||||
* APP_EXAMPLE_UART_WRITE
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_UART_WRITE=1 run`
|
|
||||||
* GPIO on/off and `counter: %` writes
|
|
||||||
|
|
||||||
* APP_EXAMPLE_IPC
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_IPC=1 run`
|
|
||||||
* ASCII display draw
|
|
||||||
|
|
||||||
* APP_EXAMPLE_INPUT_DUMP
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_INPUT_DUMP=1 run` not implemented
|
|
||||||
|
|
||||||
* APP_EXAMPLE_QRCODE
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_QRCODE=1 run`
|
|
||||||
* Some writes to display
|
|
||||||
|
|
||||||
* APP_EXAMPLE_DISPLAY
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_DISPLAY=1 run`
|
|
||||||
* Some writes to display
|
|
||||||
|
|
||||||
* APP_EXAMPLE_FATFS
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=local APP_EXAMPLE_FATFS=1 flash`
|
|
||||||
* TODO: FatFs emulation and test not implemented
|
|
||||||
|
|
||||||
## F2 target
|
|
||||||
|
|
||||||
* APP_TEST
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_TEST=1 clean`
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_TEST=1 flash`
|
|
||||||
* check UART for test pass/fail
|
|
||||||
* blue led when test is running
|
|
||||||
* green led if test is passed
|
|
||||||
* red led if test is failed
|
|
||||||
|
|
||||||
* APP_EXAMPLE_BLINK
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_BLINK=1 flash`
|
|
||||||
* Red LED blink (1s period)
|
|
||||||
|
|
||||||
* APP_EXAMPLE_UART_WRITE
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_UART_WRITE=1 flash`
|
|
||||||
* Red LED shortly blinking, `counter: %` writes to UART
|
|
||||||
|
|
||||||
* APP_EXAMPLE_IPC
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_IPC=1 flash`
|
|
||||||
* ASCII display draw in UART
|
|
||||||
|
|
||||||
* APP_EXAMPLE_INPUT_DUMP
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_INPUT_DUMP=1 flash`
|
|
||||||
* Press all buttons, `state` and `event` writes to UART
|
|
||||||
|
|
||||||
* APP_EXAMPLE_QRCODE
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_QRCODE=1 flash`
|
|
||||||
* QR code show on the screen
|
|
||||||
|
|
||||||
* APP_EXAMPLE_DISPLAY
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_DISPLAY=1 flash`
|
|
||||||
* `Hello world` show on the screen
|
|
||||||
|
|
||||||
* APP_EXAMPLE_FATFS
|
|
||||||
* `docker-compose exec dev make -C firmware TARGET=f2 APP_EXAMPLE_FATFS=1 flash`
|
|
||||||
* `Init sd card error` on the screen
|
|
||||||
* Insert SD-card
|
|
||||||
* Reboot
|
|
||||||
* Show file list on the screen
|
|
||||||
* Scroll by pressing up and down
|
|
|
@ -1,22 +0,0 @@
|
||||||
1. `docker-compose exec dev make -C target_f2 example_input_dump`
|
|
||||||
2. Flash
|
|
||||||
3. For x in ```
|
|
||||||
[
|
|
||||||
(Up, "00"),
|
|
||||||
(Down, "01"),
|
|
||||||
(Right, "02"),
|
|
||||||
(Left, "03"),
|
|
||||||
(Ok, "04"),
|
|
||||||
(Back, "05"),
|
|
||||||
]
|
|
||||||
```
|
|
||||||
* Press ${x[0]}
|
|
||||||
* wait 0.05
|
|
||||||
* Expect: Uart: "event: ${x[1]} pressed"
|
|
||||||
* wait 0.05
|
|
||||||
* Release ${x[0]}
|
|
||||||
* wait 0.05
|
|
||||||
* Expect: Uart: "event: ${x[1]} released"
|
|
||||||
* wait 0.05
|
|
||||||
|
|
||||||
TODO: add debouncing check (multiple press and check there is no multiple events)
|
|
|
@ -1,27 +0,0 @@
|
||||||
## Check LF RFID
|
|
||||||
|
|
||||||
1. Go to LF RFID workaround app
|
|
||||||
2. See "LF RFID/OFF/125 kHz" on the screen
|
|
||||||
3. Read Flipper by EM4100 reader
|
|
||||||
4. Press ok
|
|
||||||
5. See "ON" on the screen
|
|
||||||
6. Check 125 kHz signal on RFID antenna by oscilloscope
|
|
||||||
7. Take EM4100 tag, place 20 mm from antenna
|
|
||||||
8. Get signal on demodulator output (RFID_IN)
|
|
||||||
9. Exit LF RFID app
|
|
||||||
|
|
||||||
## Check NFC
|
|
||||||
|
|
||||||
1. Go to NFC app
|
|
||||||
2. See "NFC timeout" on the screen
|
|
||||||
3. Place NFC tag directly on the antenna
|
|
||||||
4. See "NFC device found" and check type
|
|
||||||
5. Exit NFC app
|
|
||||||
|
|
||||||
For compatibility check:
|
|
||||||
|
|
||||||
1. make LF RFID test
|
|
||||||
2. make NFC test
|
|
||||||
3. Reboot device (issue with app loader don't allow run many apps)
|
|
||||||
4. make NFC test
|
|
||||||
5. make LF RFID test
|
|
|
@ -1,31 +0,0 @@
|
||||||
We use lightweight VPN to access internal resources. It's just to bypass NAT and keep IP addresses static. Nothing more.
|
|
||||||
|
|
||||||
`⚠️ WARNING ⚠️` There is no security restrictions in VPN network. Use your own secuity tools to protect yourself: firewals, strong password, SSH keys and so on.
|
|
||||||
|
|
||||||
# Zero Tier
|
|
||||||
|
|
||||||
[Zero Tier](https://www.zerotier.com/) — easy to use VPN replacement for all platforms. No configuration required, only one command to join network. Works great behind NAT and firewalls. Each node will keep their IP address static forever after join to network.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Get package for your platform: https://www.zerotier.com/download/ Linux, Windows, macOS and even iOS and Android supported.
|
|
||||||
|
|
||||||
## Join network
|
|
||||||
|
|
||||||
Join our developers network:
|
|
||||||
|
|
||||||
`sudo zerotier-cli join b6079f73c697cbc4`
|
|
||||||
|
|
||||||
## Ask for approve
|
|
||||||
|
|
||||||
Ask @zhovner to approve your node. After few seconds after approve, you will get access to our network:
|
|
||||||
|
|
||||||
```
|
|
||||||
IPv4 network: 172.25.0.0/16
|
|
||||||
IPv6 network: fdb6:079f:73c6:97cb:c499:93__:____:___
|
|
||||||
```
|
|
||||||
|
|
||||||
# Hosts
|
|
||||||
|
|
||||||
`dolphinarium.vpn.flipperzero.one` — Testbench backed on rapsberry pi
|
|
||||||
`lab.flipperzero.one` — testbench frontend
|
|
|
@ -1,19 +0,0 @@
|
||||||
![](./../../wiki_static/tools/st-link-v2.jpg)
|
|
||||||
|
|
||||||
# Install legacy stlink utils v.1.5.1
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
|
|
||||||
```
|
|
||||||
brew tap zhovner/stlink-legacy
|
|
||||||
brew install stlink-legacy
|
|
||||||
```
|
|
||||||
|
|
||||||
# Downgrade ST-Link firmware
|
|
||||||
|
|
||||||
Some Chinese ST-Link clones won't work with latest `stlink` utils and firmware. Download firmware to fix this
|
|
||||||
|
|
||||||
1. Connect St-Link adapter to Windows PC and install driver [ST-Link_Windows_driver.zip](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/tools/en.stsw-link009.zip)
|
|
||||||
2. Run [Firmware upgrade util](https://github.com/Flipper-Zero/flipperzero-firmware-community/raw/master/wiki_static/tools/stlink-V2.J21.S4.zip)
|
|
||||||
|
|
||||||
![](./../../wiki_static/tools/st-link-upgrade-util-windows.jpg)
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:3d17de0d863d935e49be522838f672f67a6b376c5d0188ceb3005fb890b2410f
|
|
||||||
size 1200697
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9c4b431461cbf5f34aec3b690da36da6b9191afb6c4c6c97bcd46e5ac0d821ed
|
|
||||||
size 420433
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:c57fafe62af8ee96b8898584e9d78424d5789f785bd55622ca65947e7066c51f
|
|
||||||
size 12435
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:74af7543e70bb22c8c86fd7b751146d759d343d90a5845266c126fb008fa18f6
|
|
||||||
size 2023661
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:32f267fe1c51ba4e9ad6f78d19fa907d98d00865f654740d53c656ad05972a40
|
|
||||||
size 1630441
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:e386746c69e0685a45f8cd320239e825b23e17f07ab272a764cb08b54796a1e2
|
|
||||||
size 411159
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:0901a507ea047af9945c27549dc1460d5552cfafcff27f646453d129030f23da
|
|
||||||
size 623188
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:af329bb9df3fcf8d74084753c6ab4ef10707a3227cdb3e7224ca76a8e81145e4
|
|
||||||
size 180549
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:818b3ef2a3b10fdade1be9459904f8295f75efd16fb532927d5ef6ff187e60e6
|
|
||||||
size 265769
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:76e5e8205a6cec14f5cc34f9b48a12133e0a8d79347f3286eb4bb28aacde4337
|
|
||||||
size 772608
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:21d591754f159cc9c2e1870cf88fbae2bd69573c4a3b3721e9c2857d6265d44c
|
|
||||||
size 17359
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:3d54ae19be7820c2db4f2d0177ecfee2e3dd16a387df49543876039dbfe92fa2
|
|
||||||
size 14717
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:4717d95c1feba2c0988587ee7806531ea4af920682dbf03bed1bf70ec992fb4c
|
|
||||||
size 178813
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:e6ca0439abf8148e5b20c9199a8146c2e1cb1c570f7fa7990581b79a331c9fab
|
|
||||||
size 252943
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:cf3b36cb3db6c3552d241e7639f3a2b6858979f00ad8fda25bf7bfaa65bf317d
|
|
||||||
size 537771
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:ab566f4ad1ef282e038e1a982937228edf5e52fcbaa2f0a18d90b96ea4d6e493
|
|
||||||
size 148325
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:2af09e099308abf2d61ea0d3dc4326d30a2134c9b87b4aeb4678eadac96d17b5
|
|
||||||
size 46060
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:35627515ecf8e96d5d28b5469fdf569b993981cda1240b921ca62f997e6ec099
|
|
||||||
size 338558
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:8764367c15252a9ff37514451af086a6c4d0adca7ec5b423643b730151388d53
|
|
||||||
size 88079
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:370ec74cbd8e37a5760ed03f19cf31bd135f021a88c4669a68f0705e7ecf0902
|
|
||||||
size 95362
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a597f75658b80373afa8017d40e37d1725c2f2df275c0f311afdec2e5fee1b45
|
|
||||||
size 317865
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b1010e3cc9836cbebdca23ec83c5faf181a0d716ac4a6639c64fed865bc9e326
|
|
||||||
size 101529
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b24900e262b8dfd213797f2834dbb1c9a4b43991534f74d1ce4433743e39af23
|
|
||||||
size 103994
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:ad8828548bf9afd6d1cd6f2faf7c9fd7c80b686b6a6e93b673923503e6c15799
|
|
||||||
size 107441
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a225f89987da7c5b503f7fa795de267dd3e1d648b24baebdaa66f0e27706037a
|
|
||||||
size 87387
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:11ee366535cd1039c755c6682a8f49d65774216394d687441b232e267630d81d
|
|
||||||
size 82107
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:987ef78e80e1c15df9c7e662122396999a0b55946e939dc32dae271312cbd2ff
|
|
||||||
size 80059
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:104772cc4c0c19c8df7076035a731f97e95d633c0681acfb0ec99ddb48e1ab0d
|
|
||||||
size 105156
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a4df9170fa0aeb92c191c9953cb5cafe3aed673bea726229f00e789d35781045
|
|
||||||
size 253591
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:5a2f94c209ba82437a15972e329a1362586cfb51f77f1189c3cd9aed47204702
|
|
||||||
size 8740004
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:069338c973f835fb0286df1eb19b37582496830d412db3e64f103c3bc6ac8b28
|
|
||||||
size 2461
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:b2605c5f49ce0bc32055ae74b32fe09b386ff7df2684af7ee26ec0f1a84768b9
|
|
||||||
size 17303
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:710ff3e1a8ca48424f29bd7417b0d3024c3694d088b1f21e47a8c8e3b2e60f43
|
|
||||||
size 46689
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:41e98d45f897f43110a2b881a60c6579fc65b667e4db9e9ef39074d7dae4d459
|
|
||||||
size 168847
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9b8453a08fb9dc7510e887c749d28a8aadac7b96db91ec95efe0581f434650fb
|
|
||||||
size 369440
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:931cc6c1d5206745ee9dff78cb92b35fd8659cb33d19fcb0a5ac440e6bed6a13
|
|
||||||
size 134904
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:66b74fb331f821038b933729b3621e92a617b62a8a9667b69b19a7b38e7261c3
|
|
||||||
size 151241
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9ea84b7168b553f09ecdfe769d0a87d339d034b6aa54babb8b0ce01da25f03b2
|
|
||||||
size 859
|
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a68c79c43e5fdc37e64419e529878103212f402e66e67ef6c7ce0eaeb5c58a35
|
|
||||||
size 89557
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:020ddb67fb2e27f65a44c652e78c80fd3e31f83fad5bdf0a957913f5f5c808cc
|
|
||||||
size 85744
|
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:1d240d7faa5e964e283af37d8935bca61eda4c795260ae5a3ad75358e9a6ca41
|
|
||||||
size 8954
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:dc3241041f10e814bebc4b7f558e4b91b67f1f2939c40a6d0a072e70bf4f4648
|
|
||||||
size 59073
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:7982aa0ffaae260e2d3500e6e441d8f556080744ba9c7947546063130b2653f5
|
|
||||||
size 59132
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:86c12e179bd7eeec6483e021be62d610234dd80ee72194459797a89bb50bfbb9
|
|
||||||
size 122388
|
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:8fad2e0263fce7091ce80467a68bd050e440fb9300cfd03edee0b68ec8b76677
|
|
||||||
size 6831
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue