mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
adaptation to the new build system + fixes
This commit is contained in:
parent
aaeede7793
commit
1c55a55ddd
28 changed files with 173 additions and 868 deletions
15
.drone.yml
15
.drone.yml
|
@ -11,23 +11,15 @@ steps:
|
|||
- git submodule foreach git config --local gc.auto 0
|
||||
- git log -1 --format='%H'
|
||||
|
||||
- name: 'Rebuild Assets'
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_TAG}
|
||||
- export WORKFLOW_BRANCH_OR_TAG=${DRONE_TAG}
|
||||
- make assets_rebuild assets_manifest
|
||||
|
||||
- name: 'Build default fw'
|
||||
image: hfdj/fztools
|
||||
pull: never
|
||||
commands:
|
||||
- export DIST_SUFFIX=${DRONE_TAG}
|
||||
- export WORKFLOW_BRANCH_OR_TAG=${DRONE_TAG}
|
||||
- make updater_package TARGET=f7 DEBUG=0 COMPACT=1
|
||||
- export WORKFLOW_BRANCH_OR_TAG=dev-cfw
|
||||
- ./fbt --with-updater COMPACT=1 DEBUG=0 updater_package
|
||||
- mkdir artifacts-default
|
||||
- mv dist/f7/* artifacts-default/
|
||||
- mv dist/f7-C/* artifacts-default/
|
||||
- ls -laS artifacts-default
|
||||
- ls -laS artifacts-default/f7-update-${DRONE_TAG}
|
||||
|
||||
|
@ -36,7 +28,6 @@ steps:
|
|||
commands:
|
||||
- tar czpf artifacts-default/flipper-z-any-resources-${DRONE_TAG}.tgz -C assets resources
|
||||
- mkdir sd-card
|
||||
- mkdir -p sd-card/wav_player
|
||||
- mkdir -p sd-card/subghz/assets
|
||||
- mkdir -p sd-card/nfc/assets
|
||||
- cp assets/resources/subghz/assets/universal_rf_map sd-card/subghz/assets/universal_rf_map
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
### New Update
|
||||
* Merged latest ofw changes - scons build system
|
||||
* Removed WAV Player - it's not bad as a concept but has a lot of problems
|
||||
* Some small fixes
|
||||
#### Previous changes
|
||||
* Spectrum Analyzer - show current mode on screen when changing modes
|
||||
* Spectrum Analyzer - Ultra Narrow mode
|
||||
* Desktop autolock more time options
|
||||
* Merged latest ofw dev changes:
|
||||
SubGhz: PowerSmart protocol, Infrared app fixes
|
||||
#### Previous changes
|
||||
* Merged latest ofw dev changes:
|
||||
Infrared app C port, nfc: NTAG21x complete emulation, nfc: DESFire fixes
|
||||
SubGhz: frequency analyzer combined frequency detection method, etc...
|
||||
|
|
21
ReadMe.md
21
ReadMe.md
|
@ -67,7 +67,7 @@ then select **`flipper-z-f7-full-(CURRENT VERSION).dfu`**
|
|||
|
||||
- And wait, if all flashed successfully - you can manually upload IR libs and other stuff to sd card
|
||||
|
||||
- If you doing install for first time or migrating from official fw, unpack 3 folders from archive `sd-card-(CURRENT VERSION).zip` onto your microSD card
|
||||
- If you doing install for first time or migrating from official fw, unpack 2 folders from archive `sd-card-(CURRENT VERSION).zip` onto your microSD card
|
||||
|
||||
|
||||
<br>
|
||||
|
@ -85,13 +85,13 @@ then select **`flipper-z-f7-full-(CURRENT VERSION).dfu`**
|
|||
### **Replace (CURRENT VERSION) with version that you downloaded from releases**
|
||||
3. Run `dfu-util -D flipper-z-f7-full-(CURRENT VERSION).dfu -a 0`
|
||||
|
||||
4. If you doing install for first time or migrating from official fw, unpack 3 folders from archive `sd-card-(CURRENT VERSION).zip` to your microSD card
|
||||
4. If you doing install for first time or migrating from official fw, unpack 2 folders from archive `sd-card-(CURRENT VERSION).zip` to your microSD card
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
# After install:
|
||||
- ### If you installed using .dfu - unpack 3 folders from archive `sd-card-(CURRENT VERSION).zip` to your microSD card
|
||||
- ### If you installed using .dfu - unpack 2 folders from archive `sd-card-(CURRENT VERSION).zip` to your microSD card
|
||||
<br>
|
||||
|
||||
- ## [How To: Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md)
|
||||
|
@ -128,13 +128,13 @@ $ git clone --recursive https://github.com/Eng1n33r/flipperzero-firmware.git
|
|||
### Compile everything for development
|
||||
|
||||
```sh
|
||||
docker-compose exec dev make
|
||||
docker-compose exec dev ./fbt
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
|
||||
```sh
|
||||
docker-compose exec dev make updater_package TARGET=f7 DEBUG=0 COMPACT=1
|
||||
docker-compose exec dev ./fbt --with-updater COMPACT=1 DEBUG=0 updater_package
|
||||
```
|
||||
|
||||
Check `dist/` for build outputs.
|
||||
|
@ -145,6 +145,8 @@ If compilation fails, make sure all submodules are all initialized. Either clone
|
|||
|
||||
# Build on macOS
|
||||
|
||||
Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
## macOS Prerequisites
|
||||
|
||||
Make sure you have [brew](https://brew.sh) and install all the dependencies:
|
||||
|
@ -152,18 +154,18 @@ Make sure you have [brew](https://brew.sh) and install all the dependencies:
|
|||
brew bundle --verbose
|
||||
```
|
||||
|
||||
**P.S. Brewfile has been fixed, so build works now**
|
||||
Install Python packages required by assets build scripts: `pip3 install -r scripts/requirements.txt`
|
||||
|
||||
### Compile everything for development
|
||||
|
||||
```sh
|
||||
make
|
||||
./fbt
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
|
||||
```sh
|
||||
make updater_package TARGET=f7 DEBUG=0 COMPACT=1
|
||||
./fbt --with-updater COMPACT=1 DEBUG=0 updater_package
|
||||
```
|
||||
|
||||
Check `dist/` for build outputs.
|
||||
|
@ -174,7 +176,6 @@ Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device.
|
|||
|
||||
- [Clock/Stopwatch (By CompaqDisc, Stopwatch & Sound Alert By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/unleashed/applications/clock_app/clock_app.c)
|
||||
- [UniversalRF Remix (By ESurge)(Original UniversalRF By jimilinuxguy)](https://github.com/ESurge/flipperzero-firmware-unirfremix)
|
||||
- [WAV Player (By DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) With Fix From [Atmanos](https://github.com/at-manos)
|
||||
- [Tetris (By jeffplang)](https://github.com/jeffplang/flipperzero-firmware/tree/tetris_game/applications/tetris_game)
|
||||
- [Spectrum Analyzer (By jolcese)](https://github.com/jolcese/flipperzero-firmware/tree/spectrum/applications/spectrum_analyzer) - [Ultra Narrow mode & scan channels non-consecutively](https://github.com/theY4Kman/flipperzero-firmware/commits?author=theY4Kman)
|
||||
- [Arkanoid (By gotnull)](https://github.com/gotnull/flipperzero-firmware-wPlugins)
|
||||
|
@ -198,7 +199,7 @@ Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device.
|
|||
- `documentation` - Documentation generation system configs and input files
|
||||
- `firmware` - Firmware source code
|
||||
- `lib` - Our and 3rd party libraries, drivers and etc...
|
||||
- `make` - Make helpers
|
||||
- `site_scons` - Build helpers
|
||||
- `scripts` - Supplementary scripts and python libraries home
|
||||
|
||||
Also pay attention to `ReadMe.md` files inside of those directories.
|
||||
|
|
10
applications/arkanoid/application.fam
Normal file
10
applications/arkanoid/application.fam
Normal file
|
@ -0,0 +1,10 @@
|
|||
App(
|
||||
appid="arkanoid_game",
|
||||
name="Arkanoid",
|
||||
apptype=FlipperAppType.GAME,
|
||||
entry_point="arkanoid_game_app",
|
||||
cdefines=["APP_ARKANOID_GAME"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=30,
|
||||
)
|
|
@ -2,7 +2,6 @@
|
|||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
#define TAG "Arkanoid"
|
||||
|
@ -154,8 +153,8 @@ void move_ball(Canvas* canvas) {
|
|||
}
|
||||
|
||||
//Bounce off Bricks
|
||||
for(int row = 0; row < ROWS; row++) {
|
||||
for(int column = 0; column < COLUMNS; column++) {
|
||||
for(unsigned int row = 0; row < ROWS; row++) {
|
||||
for(unsigned int column = 0; column < COLUMNS; column++) {
|
||||
if(!isHit[row][column]) {
|
||||
//Sets Brick bounds
|
||||
leftBrick = 10 * column;
|
||||
|
@ -244,8 +243,8 @@ void reset_level(Canvas* canvas) {
|
|||
released = false;
|
||||
|
||||
// Reset all brick hit states
|
||||
for(int row = 0; row < ROWS; row++) {
|
||||
for(int column = 0; column < COLUMNS; column++) {
|
||||
for(unsigned int row = 0; row < ROWS; row++) {
|
||||
for(unsigned int column = 0; column < COLUMNS; column++) {
|
||||
isHit[row][column] = false;
|
||||
}
|
||||
}
|
||||
|
@ -277,8 +276,8 @@ static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
|
|||
}
|
||||
|
||||
//Draws new bricks and resets their values
|
||||
for(int row = 0; row < ROWS; row++) {
|
||||
for(int column = 0; column < COLUMNS; column++) {
|
||||
for(unsigned int row = 0; row < ROWS; row++) {
|
||||
for(unsigned int column = 0; column < COLUMNS; column++) {
|
||||
if(!isHit[row][column]) {
|
||||
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
|
||||
}
|
||||
|
@ -320,6 +319,10 @@ static void arkanoid_update_timer_callback(osMessageQueueId_t event_queue) {
|
|||
}
|
||||
|
||||
int32_t arkanoid_game_app(void* p) {
|
||||
UNUSED(p);
|
||||
// Set random seed from interrupts
|
||||
srand(DWT->CYCCNT);
|
||||
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(GameEvent), NULL);
|
||||
|
||||
ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState));
|
||||
|
@ -404,7 +407,6 @@ int32_t arkanoid_game_app(void* p) {
|
|||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
furi_record_close("notification");
|
||||
|
||||
return 0;
|
||||
}
|
11
applications/clock_app/application.fam
Normal file
11
applications/clock_app/application.fam
Normal file
|
@ -0,0 +1,11 @@
|
|||
App(
|
||||
appid="clock",
|
||||
name="Clock",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="clock_app",
|
||||
cdefines=["APP_CLOCK"],
|
||||
requires=["gui"],
|
||||
icon="A_Clock_14",
|
||||
stack_size=2 * 1024,
|
||||
order=9,
|
||||
)
|
|
@ -35,7 +35,29 @@ App(
|
|||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"music_player",
|
||||
"snake_game",
|
||||
"bt_hid",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="custom_games",
|
||||
name="Custom applications for games menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"snake_game",
|
||||
"tetris_game",
|
||||
"arkanoid_game",
|
||||
"tictactoe_game",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="custom_apps",
|
||||
name="Custom applications for main menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"clock",
|
||||
"spectrum_analyzer",
|
||||
"unirfremix",
|
||||
],
|
||||
)
|
|
@ -1,11 +1,10 @@
|
|||
App(
|
||||
appid="snake_game",
|
||||
name="Snake Game",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
apptype=FlipperAppType.GAME,
|
||||
entry_point="snake_game_app",
|
||||
cdefines=["APP_SNAKE_GAME"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
icon="A_Plugins_14",
|
||||
order=30,
|
||||
order=10,
|
||||
)
|
||||
|
|
11
applications/spectrum_analyzer/application.fam
Normal file
11
applications/spectrum_analyzer/application.fam
Normal file
|
@ -0,0 +1,11 @@
|
|||
App(
|
||||
appid="spectrum_analyzer",
|
||||
name="Spectrum Analyzer",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="spectrum_analyzer_app",
|
||||
cdefines=["APP_SPECTRUM_ANALYZER"],
|
||||
requires=["gui"],
|
||||
icon="A_SpectrumAnalyzer_14",
|
||||
stack_size=1 * 1024,
|
||||
order=12,
|
||||
)
|
|
@ -17,35 +17,26 @@
|
|||
static const uint32_t subghz_frequency_list[] = {
|
||||
/* 300 - 348 */
|
||||
300000000,
|
||||
302757000, /* FCC ID N6U303NTX */
|
||||
303875000,
|
||||
304250000, /* Ceiling Fan - Harbor Breeze*/
|
||||
304250000,
|
||||
310000000,
|
||||
313850000, /* 2007 Honda Key */
|
||||
315000000,
|
||||
318000000,
|
||||
348000000,
|
||||
387000000,
|
||||
|
||||
/* 387 - 464 */
|
||||
390000000,
|
||||
418000000,
|
||||
433075000, /* LPD433 first */
|
||||
433220000, /* 2016-2020 Honda */
|
||||
433420000,
|
||||
433889000, /* ROGUE? */
|
||||
433920000 | FREQUENCY_FLAG_DEFAULT, /* LPD433 mid */
|
||||
434420000,
|
||||
434775000, /* LPD433 last channels */
|
||||
438900000,
|
||||
464000000,
|
||||
|
||||
/* 779 - 928 */
|
||||
779000000,
|
||||
868350000,
|
||||
915000000,
|
||||
925000000,
|
||||
928000000,
|
||||
0,
|
||||
};
|
||||
|
||||
|
|
10
applications/tetris_game/application.fam
Normal file
10
applications/tetris_game/application.fam
Normal file
|
@ -0,0 +1,10 @@
|
|||
App(
|
||||
appid="tetris_game",
|
||||
name="Tetris",
|
||||
apptype=FlipperAppType.GAME,
|
||||
entry_point="tetris_game_app",
|
||||
cdefines=["APP_TETRIS_GAME"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
)
|
10
applications/tictactoe_game/application.fam
Normal file
10
applications/tictactoe_game/application.fam
Normal file
|
@ -0,0 +1,10 @@
|
|||
App(
|
||||
appid="tictactoe_game",
|
||||
name="Tic Tac Toe",
|
||||
apptype=FlipperAppType.GAME,
|
||||
entry_point="tictactoe_game_app",
|
||||
cdefines=["APP_TICTACTOE_GAME"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=40,
|
||||
)
|
|
@ -2,7 +2,6 @@
|
|||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/view.h>
|
||||
|
||||
#define TAG "TicTacToe"
|
||||
|
@ -269,6 +268,7 @@ static void tictactoe_update_timer_callback(osMessageQueueId_t event_queue) {
|
|||
}
|
||||
|
||||
int32_t tictactoe_game_app(void* p) {
|
||||
UNUSED(p);
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(GameEvent), NULL);
|
||||
|
||||
TicTacToeState* tictactoe_state = malloc(sizeof(TicTacToeState));
|
||||
|
@ -277,6 +277,7 @@ int32_t tictactoe_game_app(void* p) {
|
|||
if(!init_mutex(&state_mutex, tictactoe_state, sizeof(TicTacToeState))) {
|
||||
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
|
||||
free(tictactoe_state);
|
||||
osMessageQueueDelete(event_queue);
|
||||
return 255;
|
||||
}
|
||||
|
||||
|
@ -341,7 +342,6 @@ int32_t tictactoe_game_app(void* p) {
|
|||
furi_record_close("gui");
|
||||
view_port_free(view_port);
|
||||
osMessageQueueDelete(event_queue);
|
||||
furi_record_close("notification");
|
||||
delete_mutex(&state_mutex);
|
||||
free(tictactoe_state);
|
||||
|
||||
|
|
11
applications/unirfremix/application.fam
Normal file
11
applications/unirfremix/application.fam
Normal file
|
@ -0,0 +1,11 @@
|
|||
App(
|
||||
appid="unirfremix",
|
||||
name="UniRF Remix",
|
||||
apptype=FlipperAppType.APP,
|
||||
entry_point="unirfremix_app",
|
||||
cdefines=["APP_UNIRFREMIX"],
|
||||
requires=["gui"],
|
||||
icon="A_UniRFRemix_14",
|
||||
stack_size=2 * 1024,
|
||||
order=11,
|
||||
)
|
|
@ -1,84 +0,0 @@
|
|||
#include "wav_parser.h"
|
||||
|
||||
#define TAG "WavParser"
|
||||
|
||||
const char* format_text(FormatTag tag) {
|
||||
switch(tag) {
|
||||
case FormatTagPCM:
|
||||
return "PCM";
|
||||
case FormatTagIEEE_FLOAT:
|
||||
return "IEEE FLOAT";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
struct WavParser {
|
||||
WavHeaderChunk header;
|
||||
WavFormatChunk format;
|
||||
WavDataChunk data;
|
||||
size_t wav_data_start;
|
||||
size_t wav_data_end;
|
||||
};
|
||||
|
||||
WavParser* wav_parser_alloc() {
|
||||
return malloc(sizeof(WavParser));
|
||||
}
|
||||
|
||||
void wav_parser_free(WavParser* parser) {
|
||||
free(parser);
|
||||
}
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream) {
|
||||
stream_read(stream, (uint8_t*)&parser->header, sizeof(WavHeaderChunk));
|
||||
stream_read(stream, (uint8_t*)&parser->format, sizeof(WavFormatChunk));
|
||||
stream_read(stream, (uint8_t*)&parser->data, sizeof(WavDataChunk));
|
||||
|
||||
if(memcmp(parser->header.riff, "RIFF", 4) != 0 ||
|
||||
memcmp(parser->header.wave, "WAVE", 4) != 0) {
|
||||
FURI_LOG_E(TAG, "WAV: wrong header");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(memcmp(parser->format.fmt, "fmt ", 4) != 0) {
|
||||
FURI_LOG_E(TAG, "WAV: wrong format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(parser->format.tag != FormatTagPCM || memcmp(parser->data.data, "data", 4) != 0) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"WAV: non-PCM format %u, next '%lu'",
|
||||
parser->format.tag,
|
||||
(uint32_t)parser->data.data);
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_I(
|
||||
TAG,
|
||||
"Format tag: %s, ch: %u, smplrate: %lu, bps: %lu, bits: %u",
|
||||
format_text(parser->format.tag),
|
||||
parser->format.channels,
|
||||
parser->format.sample_rate,
|
||||
parser->format.byte_per_sec,
|
||||
parser->format.bits_per_sample);
|
||||
|
||||
parser->wav_data_start = stream_tell(stream);
|
||||
parser->wav_data_end = parser->wav_data_start + parser->data.size;
|
||||
|
||||
FURI_LOG_I(TAG, "data: %u - %u", parser->wav_data_start, parser->wav_data_end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_start(WavParser* parser) {
|
||||
return parser->wav_data_start;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_end(WavParser* parser) {
|
||||
return parser->wav_data_end;
|
||||
}
|
||||
|
||||
size_t wav_parser_get_data_len(WavParser* parser) {
|
||||
return parser->wav_data_end - parser->wav_data_start;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
#include <toolbox/stream/stream.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
FormatTagPCM = 0x0001,
|
||||
FormatTagIEEE_FLOAT = 0x0003,
|
||||
} FormatTag;
|
||||
|
||||
typedef struct {
|
||||
uint8_t riff[4];
|
||||
uint32_t size;
|
||||
uint8_t wave[4];
|
||||
} WavHeaderChunk;
|
||||
|
||||
typedef struct {
|
||||
uint8_t fmt[4];
|
||||
uint32_t size;
|
||||
uint16_t tag;
|
||||
uint16_t channels;
|
||||
uint32_t sample_rate;
|
||||
uint32_t byte_per_sec;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
} WavFormatChunk;
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[4];
|
||||
uint32_t size;
|
||||
} WavDataChunk;
|
||||
|
||||
typedef struct WavParser WavParser;
|
||||
|
||||
WavParser* wav_parser_alloc();
|
||||
|
||||
void wav_parser_free(WavParser* parser);
|
||||
|
||||
bool wav_parser_parse(WavParser* parser, Stream* stream);
|
||||
|
||||
size_t wav_parser_get_data_start(WavParser* parser);
|
||||
|
||||
size_t wav_parser_get_data_end(WavParser* parser);
|
||||
|
||||
size_t wav_parser_get_data_len(WavParser* parser);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,297 +0,0 @@
|
|||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <cli/cli.h>
|
||||
#include <gui/gui.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include "wav_player_hal.h"
|
||||
#include "wav_parser.h"
|
||||
#include "wav_player_view.h"
|
||||
|
||||
#define TAG "WavPlayer"
|
||||
|
||||
static bool open_wav_stream(Storage* storage, Stream* stream) {
|
||||
DialogsApp* dialogs = furi_record_open("dialogs");
|
||||
bool result = false;
|
||||
string_t path;
|
||||
string_init(path);
|
||||
string_set_str(path, "/ext/wav_player");
|
||||
bool ret = dialog_file_browser_show(dialogs, path, path, ".wav", true, &I_music_10px, false);
|
||||
|
||||
furi_record_close("dialogs");
|
||||
if(ret) {
|
||||
if(!file_stream_open(stream, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
FURI_LOG_E(TAG, "Cannot open file \"%s\"", string_get_cstr(path));
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
string_clear(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
WavPlayerEventHalfTransfer,
|
||||
WavPlayerEventFullTransfer,
|
||||
WavPlayerEventCtrlVolUp,
|
||||
WavPlayerEventCtrlVolDn,
|
||||
WavPlayerEventCtrlMoveL,
|
||||
WavPlayerEventCtrlMoveR,
|
||||
WavPlayerEventCtrlOk,
|
||||
WavPlayerEventCtrlBack,
|
||||
} WavPlayerEventType;
|
||||
|
||||
typedef struct {
|
||||
WavPlayerEventType type;
|
||||
} WavPlayerEvent;
|
||||
|
||||
static void wav_player_dma_isr(void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
// half of transfer
|
||||
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
|
||||
LL_DMA_ClearFlag_HT1(DMA1);
|
||||
// fill first half of buffer
|
||||
WavPlayerEvent event = {.type = WavPlayerEventHalfTransfer};
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
// transfer complete
|
||||
if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
|
||||
LL_DMA_ClearFlag_TC1(DMA1);
|
||||
// fill second half of buffer
|
||||
WavPlayerEvent event = {.type = WavPlayerEventFullTransfer};
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Storage* storage;
|
||||
Stream* stream;
|
||||
WavParser* parser;
|
||||
uint16_t* sample_buffer;
|
||||
uint8_t* tmp_buffer;
|
||||
|
||||
size_t samples_count_half;
|
||||
size_t samples_count;
|
||||
|
||||
osMessageQueueId_t queue;
|
||||
|
||||
float volume;
|
||||
bool play;
|
||||
|
||||
WavPlayerView* view;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
} WavPlayerApp;
|
||||
|
||||
static WavPlayerApp* app_alloc() {
|
||||
WavPlayerApp* app = malloc(sizeof(WavPlayerApp));
|
||||
app->samples_count_half = 1024 * 4;
|
||||
app->samples_count = app->samples_count_half * 2;
|
||||
app->storage = furi_record_open("storage");
|
||||
app->stream = file_stream_alloc(app->storage);
|
||||
app->parser = wav_parser_alloc();
|
||||
app->sample_buffer = malloc(sizeof(uint16_t) * app->samples_count);
|
||||
app->tmp_buffer = malloc(sizeof(uint8_t) * app->samples_count);
|
||||
app->queue = osMessageQueueNew(10, sizeof(WavPlayerEvent), NULL);
|
||||
|
||||
app->volume = 10.0f;
|
||||
app->play = true;
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->view = wav_player_view_alloc();
|
||||
|
||||
view_dispatcher_add_view(app->view_dispatcher, 0, wav_player_view_get_view(app->view));
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
||||
|
||||
app->notification = furi_record_open("notification");
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void app_free(WavPlayerApp* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
wav_player_view_free(app->view);
|
||||
furi_record_close("gui");
|
||||
|
||||
osMessageQueueDelete(app->queue);
|
||||
free(app->tmp_buffer);
|
||||
free(app->sample_buffer);
|
||||
wav_parser_free(app->parser);
|
||||
stream_free(app->stream);
|
||||
furi_record_close("storage");
|
||||
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
|
||||
furi_record_close("notification");
|
||||
free(app);
|
||||
}
|
||||
|
||||
// TODO: that works only with 8-bit 2ch audio
|
||||
static bool fill_data(WavPlayerApp* app, size_t index) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
for(size_t i = count; i < app->samples_count; i++) {
|
||||
app->tmp_buffer[i] = 0;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < app->samples_count; i += 2) {
|
||||
float data = app->tmp_buffer[i];
|
||||
data -= UINT8_MAX / 2; // to signed
|
||||
data /= UINT8_MAX / 2; // scale -1..1
|
||||
|
||||
data *= app->volume; // volume
|
||||
data = tanhf(data); // hyperbolic tangent limiter
|
||||
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i / 2] = data;
|
||||
}
|
||||
|
||||
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
|
||||
|
||||
return count != app->samples_count;
|
||||
}
|
||||
|
||||
static void ctrl_callback(WavPlayerCtrl ctrl, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
WavPlayerEvent event;
|
||||
|
||||
switch(ctrl) {
|
||||
case WavPlayerCtrlVolUp:
|
||||
event.type = WavPlayerEventCtrlVolUp;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlVolDn:
|
||||
event.type = WavPlayerEventCtrlVolDn;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlMoveL:
|
||||
event.type = WavPlayerEventCtrlMoveL;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlMoveR:
|
||||
event.type = WavPlayerEventCtrlMoveR;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlOk:
|
||||
event.type = WavPlayerEventCtrlOk;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
case WavPlayerCtrlBack:
|
||||
event.type = WavPlayerEventCtrlBack;
|
||||
osMessageQueuePut(event_queue, &event, 0, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void app_run(WavPlayerApp* app) {
|
||||
if(!open_wav_stream(app->storage, app->stream)) return;
|
||||
if(!wav_parser_parse(app->parser, app->stream)) return;
|
||||
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
wav_player_view_set_start(app->view, wav_parser_get_data_start(app->parser));
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
wav_player_view_set_end(app->view, wav_parser_get_data_end(app->parser));
|
||||
wav_player_view_set_play(app->view, app->play);
|
||||
|
||||
wav_player_view_set_context(app->view, app->queue);
|
||||
wav_player_view_set_ctrl_callback(app->view, ctrl_callback);
|
||||
|
||||
bool eof = fill_data(app, 0);
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
|
||||
wav_player_speaker_init();
|
||||
wav_player_dma_init((uint32_t)app->sample_buffer, app->samples_count);
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, wav_player_dma_isr, app->queue);
|
||||
|
||||
wav_player_dma_start();
|
||||
wav_player_speaker_start();
|
||||
|
||||
WavPlayerEvent event;
|
||||
|
||||
while(1) {
|
||||
if(osMessageQueueGet(app->queue, &event, NULL, osWaitForever) == osOK) {
|
||||
if(event.type == WavPlayerEventHalfTransfer) {
|
||||
eof = fill_data(app, 0);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
stream_seek(
|
||||
app->stream,
|
||||
wav_parser_get_data_start(app->parser),
|
||||
StreamOffsetFromStart);
|
||||
}
|
||||
|
||||
} else if(event.type == WavPlayerEventFullTransfer) {
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
stream_seek(
|
||||
app->stream,
|
||||
wav_parser_get_data_start(app->parser),
|
||||
StreamOffsetFromStart);
|
||||
}
|
||||
} else if(event.type == WavPlayerEventCtrlVolUp) {
|
||||
if(app->volume < 9.9) app->volume += 0.2;
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
} else if(event.type == WavPlayerEventCtrlVolDn) {
|
||||
if(app->volume > 0.01) app->volume -= 0.2;
|
||||
wav_player_view_set_volume(app->view, app->volume);
|
||||
} else if(event.type == WavPlayerEventCtrlMoveL) {
|
||||
int32_t seek = stream_tell(app->stream) - wav_parser_get_data_start(app->parser);
|
||||
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
|
||||
stream_seek(app->stream, -seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlMoveR) {
|
||||
int32_t seek = wav_parser_get_data_end(app->parser) - stream_tell(app->stream);
|
||||
seek = MIN(seek, wav_parser_get_data_len(app->parser) / 100);
|
||||
stream_seek(app->stream, seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlOk) {
|
||||
app->play = !app->play;
|
||||
wav_player_view_set_play(app->view, app->play);
|
||||
|
||||
if(!app->play) {
|
||||
wav_player_speaker_stop();
|
||||
} else {
|
||||
wav_player_speaker_start();
|
||||
}
|
||||
} else if(event.type == WavPlayerEventCtrlBack) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wav_player_speaker_stop();
|
||||
wav_player_dma_stop();
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
|
||||
}
|
||||
|
||||
int32_t wav_player_app(void* p) {
|
||||
WavPlayerApp* app = app_alloc();
|
||||
app_run(app);
|
||||
app_free(app);
|
||||
return 0;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#include "wav_player_hal.h"
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
|
||||
#define FURI_HAL_SPEAKER_TIMER TIM16
|
||||
#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
|
||||
#define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1
|
||||
|
||||
void wav_player_speaker_init() {
|
||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||
TIM_InitStruct.Prescaler = 4;
|
||||
TIM_InitStruct.Autoreload = 255;
|
||||
LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct);
|
||||
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 127;
|
||||
LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct);
|
||||
}
|
||||
|
||||
void wav_player_speaker_start() {
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_speaker_stop() {
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_init(uint32_t address, size_t size) {
|
||||
uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1);
|
||||
|
||||
LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetDataLength(DMA_INSTANCE, size);
|
||||
|
||||
LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP);
|
||||
LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH);
|
||||
LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR);
|
||||
LL_DMA_SetPeriphIncMode(DMA_INSTANCE, LL_DMA_PERIPH_NOINCREMENT);
|
||||
LL_DMA_SetMemoryIncMode(DMA_INSTANCE, LL_DMA_MEMORY_INCREMENT);
|
||||
LL_DMA_SetPeriphSize(DMA_INSTANCE, LL_DMA_PDATAALIGN_HALFWORD);
|
||||
LL_DMA_SetMemorySize(DMA_INSTANCE, LL_DMA_MDATAALIGN_HALFWORD);
|
||||
|
||||
LL_DMA_EnableIT_TC(DMA_INSTANCE);
|
||||
LL_DMA_EnableIT_HT(DMA_INSTANCE);
|
||||
}
|
||||
|
||||
void wav_player_dma_start() {
|
||||
LL_DMA_EnableChannel(DMA_INSTANCE);
|
||||
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void wav_player_dma_stop() {
|
||||
LL_DMA_DisableChannel(DMA_INSTANCE);
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void wav_player_speaker_init();
|
||||
|
||||
void wav_player_speaker_start();
|
||||
|
||||
void wav_player_speaker_stop();
|
||||
|
||||
void wav_player_dma_init(uint32_t address, size_t size);
|
||||
|
||||
void wav_player_dma_start();
|
||||
|
||||
void wav_player_dma_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,214 +0,0 @@
|
|||
#include "wav_player_view.h"
|
||||
|
||||
#define DATA_COUNT 116
|
||||
|
||||
struct WavPlayerView {
|
||||
View* view;
|
||||
WavPlayerCtrlCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool play;
|
||||
float volume;
|
||||
size_t start;
|
||||
size_t end;
|
||||
size_t current;
|
||||
uint8_t data[DATA_COUNT];
|
||||
} WavPlayerViewModel;
|
||||
|
||||
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min;
|
||||
}
|
||||
|
||||
static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
WavPlayerViewModel* model = _model;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
uint8_t x_pos = 0;
|
||||
uint8_t y_pos = 0;
|
||||
|
||||
// volume
|
||||
x_pos = 124;
|
||||
y_pos = 0;
|
||||
const float volume = (64 / 10.0f) * model->volume;
|
||||
canvas_draw_frame(canvas, x_pos, y_pos, 4, 64);
|
||||
canvas_draw_box(canvas, x_pos, y_pos + (64 - volume), 4, volume);
|
||||
|
||||
// play / pause
|
||||
x_pos = 58;
|
||||
y_pos = 55;
|
||||
if(model->play) {
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 8, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 8, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
} else {
|
||||
canvas_draw_box(canvas, x_pos, y_pos, 3, 9);
|
||||
canvas_draw_box(canvas, x_pos + 4, y_pos, 3, 9);
|
||||
}
|
||||
|
||||
x_pos = 78;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 82;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 40;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
x_pos = 44;
|
||||
y_pos = 55;
|
||||
canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4);
|
||||
canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos);
|
||||
|
||||
// len
|
||||
x_pos = 4;
|
||||
y_pos = 47;
|
||||
const uint8_t play_len = 116;
|
||||
uint8_t play_pos = map(model->current, model->start, model->end, 0, play_len - 4);
|
||||
|
||||
canvas_draw_frame(canvas, x_pos, y_pos, play_len, 4);
|
||||
canvas_draw_box(canvas, x_pos + play_pos, y_pos - 2, 4, 8);
|
||||
canvas_draw_box(canvas, x_pos, y_pos, play_pos, 4);
|
||||
|
||||
// osc
|
||||
x_pos = 4;
|
||||
y_pos = 0;
|
||||
for(size_t i = 1; i < DATA_COUNT; i++) {
|
||||
canvas_draw_line(canvas, x_pos + i - 1, model->data[i - 1], x_pos + i, model->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool wav_player_view_input_callback(InputEvent* event, void* context) {
|
||||
WavPlayerView* wav_player_view = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(wav_player_view->callback) {
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
if(event->key == InputKeyUp) {
|
||||
wav_player_view->callback(WavPlayerCtrlVolUp, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
wav_player_view->callback(WavPlayerCtrlVolDn, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
wav_player_view->callback(WavPlayerCtrlMoveL, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyRight) {
|
||||
wav_player_view->callback(WavPlayerCtrlMoveR, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
wav_player_view->callback(WavPlayerCtrlOk, wav_player_view->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
wav_player_view->callback(WavPlayerCtrlBack, wav_player_view->context);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
WavPlayerView* wav_player_view_alloc() {
|
||||
WavPlayerView* wav_view = malloc(sizeof(WavPlayerView));
|
||||
wav_view->view = view_alloc();
|
||||
view_set_context(wav_view->view, wav_view);
|
||||
view_allocate_model(wav_view->view, ViewModelTypeLocking, sizeof(WavPlayerViewModel));
|
||||
view_set_draw_callback(wav_view->view, wav_player_view_draw_callback);
|
||||
view_set_input_callback(wav_view->view, wav_player_view_input_callback);
|
||||
|
||||
return wav_view;
|
||||
}
|
||||
|
||||
void wav_player_view_free(WavPlayerView* wav_view) {
|
||||
furi_assert(wav_view);
|
||||
view_free(wav_view->view);
|
||||
free(wav_view);
|
||||
}
|
||||
|
||||
View* wav_player_view_get_view(WavPlayerView* wav_view) {
|
||||
furi_assert(wav_view);
|
||||
return wav_view->view;
|
||||
}
|
||||
|
||||
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->volume = volume;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->start = start;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->end = end;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->current = current;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
model->play = play;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, (WavPlayerViewModel * model) {
|
||||
size_t inc = (data_count / DATA_COUNT) - 1;
|
||||
|
||||
for(size_t i = 0; i < DATA_COUNT; i++) {
|
||||
model->data[i] = *data / 6;
|
||||
if(model->data[i] > 42) model->data[i] = 42;
|
||||
data += inc;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) {
|
||||
furi_assert(wav_view);
|
||||
wav_view->callback = callback;
|
||||
}
|
||||
|
||||
void wav_player_view_set_context(WavPlayerView* wav_view, void* context) {
|
||||
furi_assert(wav_view);
|
||||
wav_view->context = context;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct WavPlayerView WavPlayerView;
|
||||
|
||||
typedef enum {
|
||||
WavPlayerCtrlVolUp,
|
||||
WavPlayerCtrlVolDn,
|
||||
WavPlayerCtrlMoveL,
|
||||
WavPlayerCtrlMoveR,
|
||||
WavPlayerCtrlOk,
|
||||
WavPlayerCtrlBack,
|
||||
} WavPlayerCtrl;
|
||||
|
||||
typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context);
|
||||
|
||||
WavPlayerView* wav_player_view_alloc();
|
||||
|
||||
void wav_player_view_free(WavPlayerView* wav_view);
|
||||
|
||||
View* wav_player_view_get_view(WavPlayerView* wav_view);
|
||||
|
||||
void wav_player_view_set_volume(WavPlayerView* wav_view, float volume);
|
||||
|
||||
void wav_player_view_set_start(WavPlayerView* wav_view, size_t start);
|
||||
|
||||
void wav_player_view_set_end(WavPlayerView* wav_view, size_t end);
|
||||
|
||||
void wav_player_view_set_current(WavPlayerView* wav_view, size_t current);
|
||||
|
||||
void wav_player_view_set_play(WavPlayerView* wav_view, bool play);
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count);
|
||||
|
||||
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);
|
||||
|
||||
void wav_player_view_set_context(WavPlayerView* wav_view, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,53 +1,29 @@
|
|||
Filetype: Flipper SubGhz Setting File
|
||||
Version: 1
|
||||
|
||||
# Add Standard frequencies for your region
|
||||
# Add All Standard frequencies
|
||||
#add_standard_frequencies: true
|
||||
|
||||
# Default Frequency: used as default for "Read" and "Read Raw"
|
||||
#default_frequency: 433920000
|
||||
|
||||
# Frequencies used for "Read", "Read Raw" and "Frequency Analyzer"
|
||||
frequency: 300000000
|
||||
# Frequencies used for "Read", "Read Raw" and "Frequency Analyzer" + default ones if enabled in add_standard_frequencies
|
||||
frequency: 302757000
|
||||
frequency: 303875000
|
||||
frequency: 304250000
|
||||
frequency: 310000000
|
||||
frequency: 312000000
|
||||
frequency: 312100000
|
||||
frequency: 313850000
|
||||
frequency: 314000000
|
||||
frequency: 314350000
|
||||
frequency: 315000000
|
||||
frequency: 318000000
|
||||
frequency: 345000000
|
||||
frequency: 348000000
|
||||
frequency: 387000000
|
||||
frequency: 390000000
|
||||
frequency: 418000000
|
||||
frequency: 433075000
|
||||
frequency: 433220000
|
||||
frequency: 433420000
|
||||
frequency: 433889000
|
||||
frequency: 433920000
|
||||
frequency: 434420000
|
||||
frequency: 434775000
|
||||
frequency: 438900000
|
||||
frequency: 464000000
|
||||
frequency: 779000000
|
||||
frequency: 868350000
|
||||
frequency: 915000000
|
||||
frequency: 925000000
|
||||
frequency: 928000000
|
||||
|
||||
# Frequencies used for hopping mode (keep this list small or flipper will miss signal)
|
||||
hopper_frequency: 300000000
|
||||
# Frequencies used for hopping mode (keep this list small or flipper will miss signal) + default ones if enabled in add_standard_frequencies
|
||||
#hopper_frequency: 300000000
|
||||
hopper_frequency: 345000000
|
||||
#hopper_frequency: 310000000
|
||||
#hopper_frequency: 312000000
|
||||
#hopper_frequency: 314000000
|
||||
#hopper_frequency: 315000000
|
||||
#hopper_frequency: 318000000
|
||||
#hopper_frequency: 390000000
|
||||
#hopper_frequency: 433920000
|
||||
#hopper_frequency: 868350000
|
||||
hopper_frequency: 434420000
|
||||
|
|
|
@ -54,12 +54,16 @@ FIRMWARE_APPS = {
|
|||
"basic_apps",
|
||||
"updater_app",
|
||||
"archive",
|
||||
# Custom Apps
|
||||
"custom_apps",
|
||||
# Settings
|
||||
"passport",
|
||||
"system_settings",
|
||||
"about",
|
||||
# Plugins
|
||||
"basic_plugins",
|
||||
# Custom Games
|
||||
"custom_games",
|
||||
# Debug
|
||||
"debug_apps",
|
||||
),
|
||||
|
|
|
@ -277,6 +277,7 @@ LevelDuration subghz_protocol_encoder_came_atomo_yield(void* context) {
|
|||
}
|
||||
|
||||
void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment) {
|
||||
UNUSED(environment);
|
||||
SubGhzProtocolDecoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolDecoderCameAtomo));
|
||||
instance->base.protocol = &subghz_protocol_came_atomo;
|
||||
instance->generic.protocol_name = instance->base.protocol->name;
|
||||
|
|
|
@ -3,20 +3,41 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
void set_random_name(char* name, uint8_t max_name_size) {
|
||||
FuriHalRtcDateTime datetime;
|
||||
furi_hal_rtc_get_datetime(&datetime);
|
||||
char strings[1][25];
|
||||
sprintf(
|
||||
strings[0],
|
||||
"%s%.4d%.2d%.2d%.2d%.2d",
|
||||
"s",
|
||||
datetime.year,
|
||||
datetime.month,
|
||||
datetime.day,
|
||||
datetime.hour,
|
||||
datetime.minute);
|
||||
sniprintf(name, max_name_size, "%s", strings[0]);
|
||||
}
|
||||
static bool rand_generator_inited = false;
|
||||
|
||||
if(!rand_generator_inited) {
|
||||
srand(DWT->CYCCNT);
|
||||
rand_generator_inited = true;
|
||||
}
|
||||
const char* prefix[] = {
|
||||
"super",
|
||||
"big",
|
||||
"little",
|
||||
"liquid",
|
||||
"unknown",
|
||||
"thin",
|
||||
"thick",
|
||||
"great",
|
||||
"my",
|
||||
};
|
||||
|
||||
const char* suffix[] = {
|
||||
"maslina",
|
||||
"sus",
|
||||
"anomalija",
|
||||
"artefact",
|
||||
"monolit",
|
||||
"burer",
|
||||
"sidorovich",
|
||||
"habar",
|
||||
};
|
||||
// sus is not (sus)pect - this is about super sus
|
||||
uint8_t prefix_i = rand() % COUNT_OF(prefix);
|
||||
uint8_t suffix_i = rand() % COUNT_OF(suffix);
|
||||
|
||||
sniprintf(name, max_name_size, "%s_%s", prefix[prefix_i], suffix[suffix_i]);
|
||||
// Set first symbol to upper case
|
||||
name[0] = name[0] - 0x20;
|
||||
}
|
|
@ -14,4 +14,4 @@ void set_random_name(char* name, uint8_t max_name_size);
|
|||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -32,10 +32,10 @@ class GitVersion:
|
|||
|
||||
branch_num = self._exec_git("rev-list --count HEAD") or "n/a"
|
||||
|
||||
try:
|
||||
version = self._exec_git("describe --tags --abbrev=0 --exact-match")
|
||||
except subprocess.CalledProcessError:
|
||||
version = "unknown"
|
||||
version = (
|
||||
os.environ.get("DIST_SUFFIX", None)
|
||||
or "unknown"
|
||||
)
|
||||
|
||||
return {
|
||||
"GIT_COMMIT": commit,
|
||||
|
|
|
@ -19,6 +19,7 @@ class FlipperAppType(Enum):
|
|||
STARTUP = "StartupHook"
|
||||
EXTERNAL = "External"
|
||||
METAPACKAGE = "Package"
|
||||
GAME = "Game"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -98,6 +99,7 @@ class AppBuildset:
|
|||
FlipperAppType.ARCHIVE,
|
||||
FlipperAppType.SETTINGS,
|
||||
FlipperAppType.STARTUP,
|
||||
FlipperAppType.GAME,
|
||||
)
|
||||
|
||||
def __init__(self, appmgr: AppManager, appnames: List[str]):
|
||||
|
@ -190,6 +192,7 @@ class ApplicationsCGenerator:
|
|||
FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"),
|
||||
FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"),
|
||||
FlipperAppType.PLUGIN: ("FlipperApplication", "FLIPPER_PLUGINS"),
|
||||
FlipperAppType.GAME: ("FlipperApplication", "FLIPPER_GAMES"),
|
||||
FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"),
|
||||
FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"),
|
||||
FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"),
|
||||
|
|
Loading…
Reference in a new issue