Merge branch 'dev' into release-candidate

This commit is contained in:
Aleksandr Kutuzov 2021-12-08 18:03:54 +03:00
commit 3a70d3b7f6
281 changed files with 9275 additions and 3794 deletions

View File

@ -73,6 +73,11 @@ jobs:
echo "::set-output name=short-hash::${SHA}"
echo "::set-output name=default-target::${DEFAULT_TARGET}"
- name: 'Bundle scripts'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts
- name: 'Build the firmware in docker'
uses: ./.github/actions/docker
with:
@ -92,6 +97,12 @@ jobs:
mv dist/${TARGET}/* artifacts/
done
- name: 'Bundle resources'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
./scripts/assets.py manifest assets/resources
tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources
- name: 'Bundle core2 firmware'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
@ -100,17 +111,6 @@ jobs:
./scripts/assets.py copro lib/STM32CubeWB core2_firmware STM32WB5x
tar czpf artifacts/flipper-z-any-core2_firmware-${{steps.names.outputs.suffix}}.tgz core2_firmware
- name: 'Bundle scripts'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
tar czpf artifacts/flipper-z-any-scripts-${{steps.names.outputs.suffix}}.tgz scripts
- name: 'Bundle resources'
if: ${{ !github.event.pull_request.head.repo.fork }}
run: |
./scripts/assets.py manifest assets/resources
tar czpf artifacts/flipper-z-any-resources-${{steps.names.outputs.suffix}}.tgz -C assets resources
- name: 'Upload artifacts to update server'
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: burnett01/rsync-deployments@5.1

View File

@ -14,24 +14,14 @@ Our goal is to create nice and clean code with good documentation, to make it a
Flipper Zero's firmware consists of three components:
- Core2 firmware set - proprietary components by ST: FUS + radio stack.
- Core1 Bootloader - controls basic hardware initialization and loads firmware
- Core1 Firmware - HAL + OS + Drivers + Applications
- Core2 firmware set - proprietary components by ST: FUS + radio stack. FUS is flashed at factory and you should never update it.
- Core1 Bootloader - controls basic hardware initialization and loads firmware.
- Core1 Firmware - HAL + OS + Drivers + Applications.
All 3 of them must be flashed in order described.
## With STLink
### Core2 flashing procedures
Prerequisites:
- Linux / macOS
- Terminal
- STM32_Programmer_CLI added to $PATH
One liner: `./flash_core2_ble.sh`
### Core1 Bootloader + Firmware
Prerequisites:
@ -41,13 +31,23 @@ Prerequisites:
- [arm-gcc-none-eabi](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)
- openocd
One liner: `./flash_core1_main.sh`
One liner: `make flash`
### Core2 flashing procedures
Prerequisites:
- Linux / macOS
- Terminal
- STM32_Programmer_CLI (v2.5.0) added to $PATH
One liner: `make flash_radio`
## With USB DFU
1. Download latest [Firmware](https://update.flipperzero.one)
2. Reboot Flipper to Bootloader
2. Reboot Flipper to Bootloader
- Press and hold `← Left` + `↩ Back` for reset
- Release `↩ Back` and keep holding `← Left` until blue LED lights up
- Release `← Left`
@ -61,9 +61,10 @@ One liner: `./flash_core1_main.sh`
1. Install [Docker Engine and Docker Compose](https://www.docker.com/get-started)
2. Prepare the container:
```sh
docker-compose up -d
```
```sh
docker-compose up -d
```
## Compile everything
@ -148,7 +149,7 @@ make whole
* cli - Console service
* debug_tools - different tools that we use on factory and for debug
* dialogs - service for showing GUI dialogs
* dolphin - dolphin service and supplientary apps
* dolphin - dolphin service and supplementary apps
* gpio-tester - GPIO control application
* gui - GUI service
* ibutton - ibutton application, onewire keys and more
@ -187,7 +188,7 @@ make whole
* app-scened-template - scened template app library
* app-template - template app library
* callback-connector - callback connector library
* common-api - common api delaration library
* common-api - common api declaration library
* cyfral - cyfral library
* drivers - drivers that we wrote
* fatfs - external storage file system

View File

@ -33,12 +33,14 @@ extern int32_t keypad_test_app(void* p);
extern int32_t lfrfid_app(void* p);
extern int32_t lfrfid_debug_app(void* p);
extern int32_t nfc_app(void* p);
extern int32_t passport_app(void* p);
extern int32_t scened_app(void* p);
extern int32_t storage_test_app(void* p);
extern int32_t subghz_app(void* p);
extern int32_t usb_mouse_app(void* p);
extern int32_t usb_test_app(void* p);
extern int32_t vibro_test_app(void* p);
extern int32_t ble_keyboard_app(void* p);
// Plugins
extern int32_t music_player_app(void* p);
@ -151,7 +153,6 @@ const FlipperApplication FLIPPER_APPS[] = {
#ifdef APP_BAD_USB
{.app = bad_usb_app, .name = "Bad USB", .stack_size = 2048, .icon = &A_BadUsb_14},
#endif
};
const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication);
@ -218,6 +219,10 @@ const size_t FLIPPER_PLUGINS_COUNT = sizeof(FLIPPER_PLUGINS) / sizeof(FlipperApp
// Plugin menu
const FlipperApplication FLIPPER_DEBUG_APPS[] = {
#ifdef APP_BLE_KEYBOARD
{.app = ble_keyboard_app, .name = "BLE keyboard demo", .stack_size = 1024, .icon = NULL},
#endif
#ifdef APP_BLINK
{.app = blink_test_app, .name = "Blink Test", .stack_size = 1024, .icon = NULL},
#endif
@ -303,6 +308,10 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = {
{.app = desktop_settings_app, .name = "Desktop", .stack_size = 1024, .icon = NULL},
#endif
#ifdef APP_PASSPORT
{.app = passport_app, .name = "Passport", .stack_size = 1024, .icon = NULL},
#endif
#ifdef APP_ABOUT
{.app = about_settings_app, .name = "About", .stack_size = 1024, .icon = NULL},
#endif

View File

@ -32,6 +32,7 @@ APP_LF_RFID = 1
APP_NFC = 1
APP_SUBGHZ = 1
APP_ABOUT = 1
APP_PASSPORT = 1
# Plugins
APP_MUSIC_PLAYER = 1
@ -46,7 +47,7 @@ APP_SD_TEST = 1
APP_VIBRO_TEST = 1
APP_USB_TEST = 1
APP_DISPLAY_TEST = 1
APP_BLE_KEYBOARD = 1
APP_USB_MOUSE = 1
APP_BAD_USB = 1
APP_UART_ECHO = 1
@ -100,6 +101,13 @@ SRV_GUI = 1
endif
APP_PASSPORT ?= 0
ifeq ($(APP_PASSPORT), 1)
CFLAGS += -DAPP_PASSPORT
SRV_GUI = 1
endif
APP_LF_RFID ?= 0
ifeq ($(APP_LF_RFID), 1)
CFLAGS += -DAPP_LF_RFID
@ -159,6 +167,12 @@ CFLAGS += -DAPP_BAD_USB
SRV_GUI = 1
endif
APP_BLE_KEYBOARD ?=0
ifeq ($(APP_BLE_KEYBOARD), 1)
CFLAGS += -DAPP_BLE_KEYBOARD
SRV_GUI = 1
endif
APP_KEYPAD_TEST ?= 0
ifeq ($(APP_KEYPAD_TEST), 1)
CFLAGS += -DAPP_KEYPAD_TEST
@ -223,6 +237,10 @@ endif
SRV_DOLPHIN ?= 0
ifeq ($(SRV_DOLPHIN), 1)
CFLAGS += -DSRV_DOLPHIN
SRV_DOLPHIN_STATE_DEBUG ?= 0
ifeq ($(SRV_DOLPHIN_STATE_DEBUG), 1)
CFLAGS += -DSRV_DOLPHIN_STATE_DEBUG
endif
endif

View File

@ -39,6 +39,19 @@ static void bt_pin_code_show_event_handler(Bt* bt, uint32_t pin) {
string_clear(pin_str);
}
static bool bt_pin_code_verify_event_handler(Bt* bt, uint32_t pin) {
furi_assert(bt);
string_t pin_str;
dialog_message_set_icon(bt->dialog_message, &I_BLE_Pairing_128x64, 0, 0);
string_init_printf(pin_str, "Verify code\n%06d", pin);
dialog_message_set_text(
bt->dialog_message, string_get_cstr(pin_str), 64, 4, AlignCenter, AlignTop);
dialog_message_set_buttons(bt->dialog_message, "Cancel", "Ok", NULL);
DialogMessageButton button = dialog_message_show(bt->dialogs, bt->dialog_message);
string_clear(pin_str);
return button == DialogMessageButtonCenter;
}
static void bt_battery_level_changed_callback(const void* _event, void* context) {
furi_assert(_event);
furi_assert(context);
@ -56,7 +69,8 @@ static void bt_battery_level_changed_callback(const void* _event, void* context)
Bt* bt_alloc() {
Bt* bt = furi_alloc(sizeof(Bt));
// Init default maximum packet size
bt->max_packet_size = FURI_HAL_BT_PACKET_SIZE_MAX;
bt->max_packet_size = FURI_HAL_BT_SERIAL_PACKET_SIZE_MAX;
bt->profile = BtProfileSerial;
// Load settings
if(!bt_settings_load(&bt->bt_settings)) {
bt_settings_save(&bt->bt_settings);
@ -83,27 +97,30 @@ Bt* bt_alloc() {
bt->rpc = furi_record_open("rpc");
bt->rpc_event = osEventFlagsNew(NULL);
// API evnent
bt->api_event = osEventFlagsNew(NULL);
return bt;
}
// Called from GAP thread from Serial service
static uint16_t bt_on_data_received_callback(uint8_t* data, uint16_t size, void* context) {
static uint16_t bt_serial_event_callback(SerialServiceEvent event, void* context) {
furi_assert(context);
Bt* bt = context;
uint16_t ret = 0;
size_t bytes_processed = rpc_session_feed(bt->rpc_session, data, size, 1000);
if(bytes_processed != size) {
FURI_LOG_E(TAG, "Only %d of %d bytes processed by RPC", bytes_processed, size);
if(event.event == SerialServiceEventTypeDataReceived) {
size_t bytes_processed =
rpc_session_feed(bt->rpc_session, event.data.buffer, event.data.size, 1000);
if(bytes_processed != event.data.size) {
FURI_LOG_E(
TAG, "Only %d of %d bytes processed by RPC", bytes_processed, event.data.size);
}
ret = rpc_session_get_available_size(bt->rpc_session);
} else if(event.event == SerialServiceEventTypeDataSent) {
osEventFlagsSet(bt->rpc_event, BT_RPC_EVENT_BUFF_SENT);
}
return rpc_session_get_available_size(bt->rpc_session);
}
// Called from GAP thread from Serial service
static void bt_on_data_sent_callback(void* context) {
furi_assert(context);
Bt* bt = context;
osEventFlagsSet(bt->rpc_event, BT_RPC_EVENT_BUFF_SENT);
return ret;
}
// Called from RPC thread
@ -116,10 +133,10 @@ static void bt_rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t byt
while(bytes_sent < bytes_len) {
size_t bytes_remain = bytes_len - bytes_sent;
if(bytes_remain > bt->max_packet_size) {
furi_hal_bt_tx(&bytes[bytes_sent], bt->max_packet_size);
furi_hal_bt_serial_tx(&bytes[bytes_sent], bt->max_packet_size);
bytes_sent += bt->max_packet_size;
} else {
furi_hal_bt_tx(&bytes[bytes_sent], bytes_remain);
furi_hal_bt_serial_tx(&bytes[bytes_sent], bytes_remain);
bytes_sent += bytes_remain;
}
uint32_t event_flag =
@ -130,58 +147,65 @@ static void bt_rpc_send_bytes_callback(void* context, uint8_t* bytes, size_t byt
}
}
static void bt_rpc_buffer_is_empty_callback(void* context) {
furi_assert(context);
furi_hal_bt_notify_buffer_is_empty();
}
// Called from GAP thread
static void bt_on_gap_event_callback(BleEvent event, void* context) {
static bool bt_on_gap_event_callback(BleEvent event, void* context) {
furi_assert(context);
Bt* bt = context;
bool ret = false;
if(event.type == BleEventTypeConnected) {
// Update status bar
bt->status = BtStatusConnected;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
// Open RPC session
FURI_LOG_I(TAG, "Open RPC connection");
bt->rpc_session = rpc_session_open(bt->rpc);
rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback);
rpc_session_set_buffer_is_empty_callback(bt->rpc_session, bt_rpc_buffer_is_empty_callback);
rpc_session_set_context(bt->rpc_session, bt);
furi_hal_bt_set_data_event_callbacks(
RPC_BUFFER_SIZE, bt_on_data_received_callback, bt_on_data_sent_callback, bt);
if(bt->profile == BtProfileSerial) {
// Open RPC session
FURI_LOG_I(TAG, "Open RPC connection");
bt->rpc_session = rpc_session_open(bt->rpc);
rpc_session_set_send_bytes_callback(bt->rpc_session, bt_rpc_send_bytes_callback);
rpc_session_set_buffer_is_empty_callback(
bt->rpc_session, furi_hal_bt_serial_notify_buffer_is_empty);
rpc_session_set_context(bt->rpc_session, bt);
furi_hal_bt_serial_set_event_callback(RPC_BUFFER_SIZE, bt_serial_event_callback, bt);
}
// Update battery level
PowerInfo info;
power_get_info(bt->power, &info);
message.type = BtMessageTypeUpdateBatteryLevel;
message.data.battery_level = info.charge;
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == BleEventTypeDisconnected) {
if(bt->rpc_session) {
if(bt->profile == BtProfileSerial && bt->rpc_session) {
FURI_LOG_I(TAG, "Close RPC connection");
osEventFlagsSet(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED);
rpc_session_close(bt->rpc_session);
furi_hal_bt_set_data_event_callbacks(0, NULL, NULL, NULL);
furi_hal_bt_serial_set_event_callback(0, NULL, NULL);
bt->rpc_session = NULL;
}
ret = true;
} else if(event.type == BleEventTypeStartAdvertising) {
bt->status = BtStatusAdvertising;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == BleEventTypeStopAdvertising) {
bt->status = BtStatusOff;
BtMessage message = {.type = BtMessageTypeUpdateStatusbar};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == BleEventTypePinCodeShow) {
BtMessage message = {
.type = BtMessageTypePinCodeShow, .data.pin_code = event.data.pin_code};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
ret = true;
} else if(event.type == BleEventTypePinCodeVerify) {
ret = bt_pin_code_verify_event_handler(bt, event.data.pin_code);
} else if(event.type == BleEventTypeUpdateMTU) {
bt->max_packet_size = event.data.max_packet_size;
ret = true;
}
return ret;
}
static void bt_on_key_storage_change_callback(uint8_t* addr, uint16_t size, void* context) {
@ -204,29 +228,56 @@ static void bt_statusbar_update(Bt* bt) {
}
}
static void bt_change_profile(Bt* bt, BtMessage* message) {
if(bt->profile == BtProfileSerial && bt->rpc_session) {
FURI_LOG_I(TAG, "Close RPC connection");
osEventFlagsSet(bt->rpc_event, BT_RPC_EVENT_DISCONNECTED);
rpc_session_close(bt->rpc_session);
furi_hal_bt_serial_set_event_callback(0, NULL, NULL);
bt->rpc_session = NULL;
}
FuriHalBtProfile furi_profile;
if(message->data.profile == BtProfileHidKeyboard) {
furi_profile = FuriHalBtProfileHidKeyboard;
} else {
furi_profile = FuriHalBtProfileSerial;
}
if(furi_hal_bt_change_app(furi_profile, bt_on_gap_event_callback, bt)) {
FURI_LOG_I(TAG, "Bt App started");
if(bt->bt_settings.enabled) {
furi_hal_bt_start_advertising();
}
furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt);
bt->profile = message->data.profile;
*message->result = true;
} else {
FURI_LOG_E(TAG, "Failed to start Bt App");
*message->result = false;
}
osEventFlagsSet(bt->api_event, BT_API_UNLOCK_EVENT);
}
int32_t bt_srv() {
Bt* bt = bt_alloc();
furi_record_create("bt", bt);
// Read keys
if(!bt_load_key_storage(bt)) {
FURI_LOG_W(TAG, "Failed to load saved bonding keys");
FURI_LOG_W(TAG, "Failed to load bonding keys");
}
// Start 2nd core
if(!furi_hal_bt_start_core2()) {
FURI_LOG_E(TAG, "Core2 startup failed");
} else {
view_port_enabled_set(bt->statusbar_view_port, true);
if(furi_hal_bt_init_app(bt_on_gap_event_callback, bt)) {
FURI_LOG_I(TAG, "BLE stack started");
if(bt->bt_settings.enabled) {
furi_hal_bt_start_advertising();
}
} else {
FURI_LOG_E(TAG, "BT App start failed");
// Start BLE stack
if(furi_hal_bt_start_app(FuriHalBtProfileSerial, bt_on_gap_event_callback, bt)) {
FURI_LOG_I(TAG, "BLE stack started");
if(bt->bt_settings.enabled) {
furi_hal_bt_start_advertising();
}
furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt);
} else {
FURI_LOG_E(TAG, "BT App start failed");
}
furi_hal_bt_set_key_storage_change_callback(bt_on_key_storage_change_callback, bt);
// Update statusbar
bt_statusbar_update(bt);
@ -239,14 +290,14 @@ int32_t bt_srv() {
bt_statusbar_update(bt);
} else if(message.type == BtMessageTypeUpdateBatteryLevel) {
// Update battery level
if(furi_hal_bt_is_active()) {
battery_svc_update_level(message.data.battery_level);
}
furi_hal_bt_update_battery_level(message.data.battery_level);
} else if(message.type == BtMessageTypePinCodeShow) {
// Display PIN code
bt_pin_code_show_event_handler(bt, message.data.pin_code);
} else if(message.type == BtMessageTypeKeysStorageUpdated) {
bt_save_key_storage(bt);
} else if(message.type == BtMessageTypeSetProfile) {
bt_change_profile(bt, &message);
}
}
return 0;

View File

@ -9,6 +9,22 @@ extern "C" {
typedef struct Bt Bt;
typedef enum {
BtProfileSerial,
BtProfileHidKeyboard,
} BtProfile;
/**
* Change BLE Profile
* @note Call of this function leads to 2nd core restart
*
* @param bt Bt instance
* @param profile BtProfile
*
* @return true on success
*/
bool bt_set_profile(Bt* bt, BtProfile profile);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,15 @@
#include "bt_i.h"
bool bt_set_profile(Bt* bt, BtProfile profile) {
furi_assert(bt);
// Send message
bool result = false;
BtMessage message = {
.type = BtMessageTypeSetProfile, .data.profile = profile, .result = &result};
furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
// Wait for unlock
osEventFlagsWait(bt->api_event, BT_API_UNLOCK_EVENT, osFlagsWaitAny, osWaitForever);
return result;
}

View File

@ -15,6 +15,8 @@
#include "../bt_settings.h"
#define BT_API_UNLOCK_EVENT (1UL << 0)
typedef enum {
BtStatusOff,
BtStatusAdvertising,
@ -26,16 +28,19 @@ typedef enum {
BtMessageTypeUpdateBatteryLevel,
BtMessageTypePinCodeShow,
BtMessageTypeKeysStorageUpdated,
BtMessageTypeSetProfile,
} BtMessageType;
typedef union {
uint32_t pin_code;
uint8_t battery_level;
BtProfile profile;
} BtMessageData;
typedef struct {
BtMessageType type;
BtMessageData data;
bool* result;
} BtMessage;
struct Bt {
@ -44,6 +49,7 @@ struct Bt {
uint16_t max_packet_size;
BtSettings bt_settings;
BtStatus status;
BtProfile profile;
osMessageQueueId_t message_queue;
Gui* gui;
ViewPort* statusbar_view_port;
@ -53,4 +59,5 @@ struct Bt {
Rpc* rpc;
RpcSession* rpc_session;
osEventFlagsId_t rpc_event;
osEventFlagsId_t api_event;
};

View File

@ -113,7 +113,9 @@ void cli_prompt(Cli* cli) {
}
void cli_reset(Cli* cli) {
// cli->last_line is cleared and cli->line's buffer moved to cli->last_line
string_move(cli->last_line, cli->line);
// Reiniting cli->line
string_init(cli->line);
cli->cursor_position = 0;
}
@ -129,7 +131,11 @@ static void cli_handle_backspace(Cli* cli) {
string_reserve(temp, string_size(cli->line) - 1);
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position - 1);
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
// cli->line is cleared and temp's buffer moved to cli->line
string_move(cli->line, temp);
// NO MEMORY LEAK, STOP REPORTING IT
cli->cursor_position--;
} else {
cli_putc(CliSymbolAsciiBell);
@ -332,7 +338,11 @@ void cli_process_input(Cli* cli) {
string_set_strn(temp, string_get_cstr(cli->line), cli->cursor_position);
string_push_back(temp, c);
string_cat_str(temp, string_get_cstr(cli->line) + cli->cursor_position);
// cli->line is cleared and temp's buffer moved to cli->line
string_move(cli->line, temp);
// NO MEMORY LEAK, STOP REPORTING IT
// Print character in replace mode
printf("\e[4h%c\e[4l", c);
fflush(stdout);

View File

@ -18,6 +18,7 @@ typedef enum {
CliSymbolAsciiBell = 0x07,
CliSymbolAsciiBackspace = 0x08,
CliSymbolAsciiTab = 0x09,
CliSymbolAsciiLF = 0x0A,
CliSymbolAsciiCR = 0x0D,
CliSymbolAsciiEsc = 0x1B,
CliSymbolAsciiUS = 0x1F,

View File

@ -1,166 +1,22 @@
#include "cli_commands.h"
#include <furi-hal.h>
#include <furi-hal-gpio.h>
#include <furi-hal-info.h>
#include <rtc.h>
#include <task-control-block.h>
#include <time.h>
#include <notification/notification-messages.h>
#include <shci.h>
#define ENCLAVE_SIGNATURE_KEY_SLOTS 10
#define ENCLAVE_SIGNATURE_SIZE 16
static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = {
{0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a},
{0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf},
{0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd},
{0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9},
{0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7},
{0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44},
{0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d},
{0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b},
{0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8},
{0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e},
};
static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = {
{0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde},
{0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54},
{0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75},
{0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf},
{0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b},
{0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18},
{0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f},
{0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b},
{0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a},
{0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90},
};
static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = {
{0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67},
{0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e},
{0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd},
{0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0},
{0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb},
{0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41},
{0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b},
{0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b},
{0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31},
{0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32},
};
void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) {
printf("%-24s: %s\r\n", key, value);
}
/*
* Device Info Command
* This command is intended to be used by humans and machines
* Keys and values format MUST NOT BE changed
* This command is intended to be used by humans
*/
void cli_command_device_info(Cli* cli, string_t args, void* context) {
// Device Info version
printf("device_info_major : %d\r\n", 2);
printf("device_info_minor : %d\r\n", 0);
// Model name
printf("hardware_model : %s\r\n", furi_hal_version_get_model_name());
// Unique ID
printf("hardware_uid : ");
const uint8_t* uid = furi_hal_version_uid();
for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
printf("%02X", uid[i]);
}
printf("\r\n");
// OTP Revision
printf("hardware_otp_ver : %d\r\n", furi_hal_version_get_otp_version());
printf("hardware_timestamp : %lu\r\n", furi_hal_version_get_hw_timestamp());
// Board Revision
printf("hardware_ver : %d\r\n", furi_hal_version_get_hw_version());
printf("hardware_target : %d\r\n", furi_hal_version_get_hw_target());
printf("hardware_body : %d\r\n", furi_hal_version_get_hw_body());
printf("hardware_connect : %d\r\n", furi_hal_version_get_hw_connect());
printf("hardware_display : %d\r\n", furi_hal_version_get_hw_display());
// Board Personification
printf("hardware_color : %d\r\n", furi_hal_version_get_hw_color());
printf("hardware_region : %d\r\n", furi_hal_version_get_hw_region());
const char* name = furi_hal_version_get_name_ptr();
if(name) {
printf("hardware_name : %s\r\n", name);
}
// Bootloader Version
const Version* bootloader_version = furi_hal_version_get_bootloader_version();
if(bootloader_version) {
printf("bootloader_commit : %s\r\n", version_get_githash(bootloader_version));
printf("bootloader_branch : %s\r\n", version_get_gitbranch(bootloader_version));
printf("bootloader_branch_num : %s\r\n", version_get_gitbranchnum(bootloader_version));
printf("bootloader_version : %s\r\n", version_get_version(bootloader_version));
printf("bootloader_build_date : %s\r\n", version_get_builddate(bootloader_version));
printf("bootloader_target : %d\r\n", version_get_target(bootloader_version));
}
// Firmware version
const Version* firmware_version = furi_hal_version_get_firmware_version();
if(firmware_version) {
printf("firmware_commit : %s\r\n", version_get_githash(firmware_version));
printf("firmware_branch : %s\r\n", version_get_gitbranch(firmware_version));
printf("firmware_branch_num : %s\r\n", version_get_gitbranchnum(firmware_version));
printf("firmware_version : %s\r\n", version_get_version(firmware_version));
printf("firmware_build_date : %s\r\n", version_get_builddate(firmware_version));
printf("firmware_target : %d\r\n", version_get_target(firmware_version));
}
WirelessFwInfo_t pWirelessInfo;
if(furi_hal_bt_is_alive() && SHCI_GetWirelessFwInfo(&pWirelessInfo) == SHCI_Success) {
printf("radio_alive : true\r\n");
// FUS Info
printf("radio_fus_major : %d\r\n", pWirelessInfo.FusVersionMajor);
printf("radio_fus_minor : %d\r\n", pWirelessInfo.FusVersionMinor);
printf("radio_fus_sub : %d\r\n", pWirelessInfo.FusVersionSub);
printf("radio_fus_sram2b : %dK\r\n", pWirelessInfo.FusMemorySizeSram2B);
printf("radio_fus_sram2a : %dK\r\n", pWirelessInfo.FusMemorySizeSram2A);
printf("radio_fus_flash : %dK\r\n", pWirelessInfo.FusMemorySizeFlash * 4);
// Stack Info
printf("radio_stack_type : %d\r\n", pWirelessInfo.StackType);
printf("radio_stack_major : %d\r\n", pWirelessInfo.VersionMajor);
printf("radio_stack_minor : %d\r\n", pWirelessInfo.VersionMinor);
printf("radio_stack_sub : %d\r\n", pWirelessInfo.VersionSub);
printf("radio_stack_branch : %d\r\n", pWirelessInfo.VersionBranch);
printf("radio_stack_release : %d\r\n", pWirelessInfo.VersionReleaseType);
printf("radio_stack_sram2b : %dK\r\n", pWirelessInfo.MemorySizeSram2B);
printf("radio_stack_sram2a : %dK\r\n", pWirelessInfo.MemorySizeSram2A);
printf("radio_stack_sram1 : %dK\r\n", pWirelessInfo.MemorySizeSram1);
printf("radio_stack_flash : %dK\r\n", pWirelessInfo.MemorySizeFlash * 4);
// Mac address
printf("radio_ble_mac : ");
const uint8_t* ble_mac = furi_hal_version_get_ble_mac();
for(size_t i = 0; i < 6; i++) {
printf("%02X", ble_mac[i]);
}
printf("\r\n");
// Signature verification
uint8_t buffer[ENCLAVE_SIGNATURE_SIZE];
size_t enclave_valid_keys = 0;
for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) {
if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) {
if(furi_hal_crypto_encrypt(
enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) {
enclave_valid_keys += memcmp(
buffer,
enclave_signature_expected[key_slot],
ENCLAVE_SIGNATURE_SIZE) == 0;
}
furi_hal_crypto_store_unload_key(key_slot + 1);
}
}
printf("enclave_valid_keys : %d\r\n", enclave_valid_keys);
printf(
"enclave_valid : %s\r\n",
(enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false");
} else {
printf("radio_alive : false\r\n");
}
furi_hal_info_get(cli_command_device_info_callback, context);
}
void cli_command_help(Cli* cli, string_t args, void* context) {
@ -461,6 +317,26 @@ void cli_command_free_blocks(Cli* cli, string_t args, void* context) {
memmgr_heap_printf_free_blocks();
}
void cli_command_i2c(Cli* cli, string_t args, void* context) {
furi_hal_i2c_acquire(&furi_hal_i2c_handle_external);
uint8_t test = 0;
printf("Scanning external i2c on PC0(SCL)/PC1(SDA)\r\n"
"Clock: 100khz, 7bit address\r\n"
"\r\n");
printf(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n");
printf("--+--------------------------------\r\n");
for(uint8_t row = 0; row < 0x8; row++) {
printf("%x | ", row);
for(uint8_t column = 0; column <= 0xF; column++) {
bool ret = furi_hal_i2c_rx(
&furi_hal_i2c_handle_external, ((row << 4) + column) << 1, &test, 1, 2);
printf("%c ", ret ? '#' : '-');
}
printf("\r\n");
}
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
}
void cli_commands_init(Cli* cli) {
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_device_info, NULL);
cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_device_info, NULL);
@ -477,4 +353,5 @@ void cli_commands_init(Cli* cli) {
cli_add_command(cli, "vibro", CliCommandFlagDefault, cli_command_vibro, NULL);
cli_add_command(cli, "led", CliCommandFlagDefault, cli_command_led, NULL);
cli_add_command(cli, "gpio_set", CliCommandFlagDefault, cli_command_gpio_set, NULL);
cli_add_command(cli, "i2c", CliCommandFlagDefault, cli_command_i2c, NULL);
}

View File

@ -0,0 +1,138 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <bt/bt_service/bt.h>
#include <furi-hal-bt.h>
#include <furi-hal-bt-hid.h>
#include <furi-hal-usb-hid.h>
#define TAG "BleKeyboardApp"
typedef enum {
EventTypeInput,
} EventType;
typedef struct {
union {
InputEvent input;
};
EventType type;
} BleKeyboardEvent;
static void ble_keyboard_render_callback(Canvas* canvas, void* ctx) {
canvas_clear(canvas);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 0, 10, "BLE keypad demo");
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 0, 63, "Hold [back] to exit");
}
static void ble_keyboard_input_callback(InputEvent* input_event, void* ctx) {
osMessageQueueId_t event_queue = ctx;
BleKeyboardEvent event;
event.type = EventTypeInput;
event.input = *input_event;
osMessageQueuePut(event_queue, &event, 0, osWaitForever);
}
int32_t ble_keyboard_app(void* p) {
Bt* bt = furi_record_open("bt");
if(!bt_set_profile(bt, BtProfileHidKeyboard)) {
FURI_LOG_E(TAG, "Failed to switch profile");
furi_record_close("bt");
return -1;
}
bool bt_turned_on = furi_hal_bt_is_active();
if(!bt_turned_on) {
furi_hal_bt_start_advertising();
}
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(BleKeyboardEvent), NULL);
furi_check(event_queue);
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, ble_keyboard_render_callback, NULL);
view_port_input_callback_set(view_port, ble_keyboard_input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
BleKeyboardEvent event;
while(1) {
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
if(event_status == osOK) {
if(event.type == EventTypeInput) {
if(event.input.type == InputTypeLong && event.input.key == InputKeyBack) {
furi_hal_bt_hid_kb_release_all();
break;
}
if(event.input.key == InputKeyBack) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_ESC);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_ESC);
}
}
if(event.input.key == InputKeyOk) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_ENTER);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_ENTER);
}
}
if(event.input.key == InputKeyRight) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_RIGHT_ARROW);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_RIGHT_ARROW);
}
}
if(event.input.key == InputKeyLeft) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_LEFT_ARROW);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_LEFT_ARROW);
}
}
if(event.input.key == InputKeyDown) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_DOWN_ARROW);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_DOWN_ARROW);
}
}
if(event.input.key == InputKeyUp) {
if(event.input.type == InputTypePress) {
furi_hal_bt_hid_kb_press(KEY_UP_ARROW);
} else if(event.input.type == InputTypeRelease) {
furi_hal_bt_hid_kb_release(KEY_UP_ARROW);
}
}
}
}
view_port_update(view_port);
}
if(bt_turned_on) {
furi_hal_bt_stop_advertising();
}
// remove & free all stuff created by app
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
osMessageQueueDelete(event_queue);
furi_record_close("gui");
bt_set_profile(bt, BtProfileSerial);
furi_record_close("bt");
return 0;
}

View File

@ -11,6 +11,8 @@
#include <desktop/desktop.h>
#include <dolphin/dolphin.h>
#define KEEP_ONLY_CALM_BASIC_ANIMATIONS 1
LIST_DEF(AnimationList, const PairedAnimation*, M_PTR_OPLIST)
#define M_OPL_AnimationList_t() LIST_OPLIST(AnimationList)
@ -81,14 +83,16 @@ void desktop_start_new_idle_animation(DesktopAnimation* animation) {
furi_record_close("dolphin");
furi_assert((stats.level >= 1) && (stats.level <= 3));
uint8_t level = stats.level;
AnimationList_t animation_list;
AnimationList_init(animation_list);
PUSH_BACK_ANIMATIONS(animation_list, mad_animation, stats.butthurt);
#if KEEP_ONLY_CALM_BASIC_ANIMATIONS
PUSH_BACK_ANIMATIONS(animation_list, calm_animation, 0);
#else
PUSH_BACK_ANIMATIONS(animation_list, calm_animation, stats.butthurt);
switch(level) {
PUSH_BACK_ANIMATIONS(animation_list, mad_animation, stats.butthurt);
switch(stats.level) {
case 1:
PUSH_BACK_ANIMATIONS(animation_list, level_1_animation, stats.butthurt);
break;
@ -119,6 +123,7 @@ void desktop_start_new_idle_animation(DesktopAnimation* animation) {
animation->sd_shown_error_card_bad = false;
animation->sd_shown_error_db = false;
}
#endif
uint32_t whole_weight = 0;
for

View File

@ -6,9 +6,9 @@
// Calm/Mad Basic Idle Animations
#define COMMON_BASIC_DURATION (60 * 60)
#define COMMON_ACTIVE_CYCLES 7
#define COMMON_ACTIVE_COOLDOWN 30
#define COMMON_BASIC_DURATION (2 * 60 * 60)
#define COMMON_ACTIVE_CYCLES 1
#define COMMON_ACTIVE_COOLDOWN 15
#define COMMON_WEIGHT 3
#define BUTTHURT_LEVEL(x) (1UL << (x))
@ -18,7 +18,7 @@
#define COMMON_ACTIVE_DURATION(x) ((x)*COMMON_ACTIVE_CYCLES / 2)
static const BasicAnimation animation_TV = {
.icon = &A_TV_128x51,
.icon = &A_Tv_128x52,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
@ -27,12 +27,12 @@ static const BasicAnimation animation_TV = {
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7)};
static const ActiveAnimation animation_TV_active = {
.icon = &A_TVActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
.icon = &A_TvActive_128x52,
.duration = COMMON_ACTIVE_DURATION(6),
};
static const BasicAnimation animation_sleep = {
.icon = &A_Sleep_128x51,
.icon = &A_Sleep_128x52,
.black_status_bar = true,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
@ -43,9 +43,9 @@ static const BasicAnimation animation_sleep = {
BUTTHURT_LEVEL(9) | BUTTHURT_LEVEL(10)};
static const ActiveAnimation animation_sleep_active = {
.icon = &A_SleepActive_128x51,
.icon = &A_SleepActive_128x52,
.black_status_bar = true,
.duration = COMMON_ACTIVE_DURATION(2),
.duration = COMMON_ACTIVE_DURATION(5),
};
static const BasicAnimation animation_leaving = {
@ -62,7 +62,7 @@ static const ActiveAnimation animation_leaving_active = {
};
static const BasicAnimation animation_laptop = {
.icon = &A_Laptop_128x51,
.icon = &A_Laptop_128x52,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
@ -70,8 +70,8 @@ static const BasicAnimation animation_laptop = {
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5)};
static const ActiveAnimation animation_laptop_active = {
.icon = &A_LaptopActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
.icon = &A_LaptopActive_128x52,
.duration = COMMON_ACTIVE_DURATION(8),
};
static const BasicAnimation animation_knife = {
@ -118,15 +118,15 @@ static const ActiveAnimation animation_box_active = {
};
static const BasicAnimation animation_waves = {
.icon = &A_Waves_128x51,
.icon = &A_Waves_128x52,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2)};
static const ActiveAnimation animation_waves_active = {
.icon = &A_WavesActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
.icon = &A_WavesActive_128x52,
.duration = COMMON_ACTIVE_DURATION(7),
};
// Level Idle Animations

View File

@ -112,12 +112,18 @@ bool desktop_debug_input(InputEvent* event, void* context) {
DesktopViewStatsScreens current = 0;
with_view_model(
debug_view->view, (DesktopDebugViewModel * model) {
#if SRV_DOLPHIN_STATE_DEBUG == 1
if(event->key == InputKeyDown) {
model->screen = (model->screen + 1) % DesktopViewStatsTotalCount;
} else if(event->key == InputKeyUp) {
model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) %
DesktopViewStatsTotalCount;
}
#else
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
model->screen = !model->screen;
}
#endif
current = model->screen;
return true;
});

View File

@ -102,6 +102,18 @@ uint8_t dolphin_get_level(uint32_t icounter) {
}
}
uint32_t dolphin_state_xp_above_last_levelup(uint32_t icounter) {
uint32_t threshold = 0;
if(icounter <= LEVEL2_THRESHOLD) {
threshold = 0;
} else if(icounter <= LEVEL3_THRESHOLD) {
threshold = LEVEL2_THRESHOLD + 1;
} else {
threshold = LEVEL3_THRESHOLD + 1;
}
return icounter - threshold;
}
uint32_t dolphin_state_xp_to_levelup(uint32_t icounter) {
uint32_t threshold = 0;
if(icounter <= LEVEL2_THRESHOLD) {

View File

@ -42,6 +42,8 @@ void dolphin_state_butthurted(DolphinState* dolphin_state);
uint32_t dolphin_state_xp_to_levelup(uint32_t icounter);
uint32_t dolphin_state_xp_above_last_levelup(uint32_t icounter);
bool dolphin_state_is_levelup(uint32_t icounter);
void dolphin_state_increase_level(DolphinState* dolphin_state);

View File

@ -0,0 +1,115 @@
#include "assets_icons.h"
#include "cmsis_os2.h"
#include "dolphin/helpers/dolphin_state.h"
#include "furi/check.h"
#include "furi/record.h"
#include <furi.h>
#include <gui/gui.h>
#include <furi-hal-version.h>
#include "dolphin/dolphin.h"
#include "math.h"
#define MOODS_TOTAL 3
#define BUTTHURT_MAX 3
static const Icon* portrait_happy[BUTTHURT_MAX] = {
&I_passport_happy1_46x49,
&I_passport_happy2_46x49,
&I_passport_happy3_46x49};
static const Icon* portrait_ok[BUTTHURT_MAX] = {
&I_passport_okay1_46x49,
&I_passport_okay2_46x49,
&I_passport_okay3_46x49};
static const Icon* portrait_bad[BUTTHURT_MAX] = {
&I_passport_bad1_46x49,
&I_passport_bad2_46x49,
&I_passport_bad3_46x49};
static const Icon** portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad};
static void input_callback(InputEvent* input, void* ctx) {
osSemaphoreId_t semaphore = ctx;
if((input->type == InputTypeShort) && (input->key == InputKeyBack)) {
osSemaphoreRelease(semaphore);
}
}
static void render_callback(Canvas* canvas, void* ctx) {
DolphinStats* stats = ctx;
char level_str[20];
char mood_str[32];
uint8_t mood = 0;
if(stats->butthurt <= 4) {
mood = 0;
snprintf(mood_str, 20, "Mood: Happy");
} else if(stats->butthurt <= 9) {
mood = 1;
snprintf(mood_str, 20, "Mood: Ok");
} else {
mood = 2;
snprintf(mood_str, 20, "Mood: Angry");
}
uint32_t xp_progress = 0;
uint32_t xp_to_levelup = dolphin_state_xp_to_levelup(stats->icounter);
uint32_t xp_for_current_level =
xp_to_levelup + dolphin_state_xp_above_last_levelup(stats->icounter);
if(stats->level == 3) {
xp_progress = 0;
} else {
xp_progress = xp_to_levelup * 64 / xp_for_current_level;
}
// multipass
canvas_draw_icon(canvas, 0, 0, &I_passport_left_6x46);
canvas_draw_icon(canvas, 0, 46, &I_passport_bottom_128x18);
canvas_draw_line(canvas, 6, 0, 125, 0);
canvas_draw_line(canvas, 127, 2, 127, 47);
canvas_draw_dot(canvas, 126, 1);
// portrait
furi_assert((stats->level > 0) && (stats->level <= 3));
canvas_draw_icon(canvas, 9, 5, portraits[mood][stats->level - 1]);
canvas_draw_line(canvas, 58, 16, 123, 16);
canvas_draw_line(canvas, 58, 30, 123, 30);
canvas_draw_line(canvas, 58, 44, 123, 44);
const char* my_name = furi_hal_version_get_name_ptr();
snprintf(level_str, 20, "Level: %hu", stats->level);
canvas_draw_str(canvas, 58, 12, my_name ? my_name : "Unknown");
canvas_draw_str(canvas, 58, 26, mood_str);
canvas_draw_str(canvas, 58, 40, level_str);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 123 - xp_progress, 47, xp_progress + 1, 6);
canvas_set_color(canvas, ColorBlack);
canvas_draw_line(canvas, 123, 47, 123, 52);
}
int32_t passport_app(void* p) {
osSemaphoreId_t semaphore = osSemaphoreNew(1, 0, NULL);
furi_assert(semaphore);
ViewPort* view_port = view_port_alloc();
Dolphin* dolphin = furi_record_open("dolphin");
DolphinStats stats = dolphin_stats(dolphin);
furi_record_close("dolphin");
view_port_draw_callback_set(view_port, render_callback, &stats);
view_port_input_callback_set(view_port, input_callback, semaphore);
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
view_port_update(view_port);
osStatus_t status = osSemaphoreAcquire(semaphore, osWaitForever);
furi_assert(status == osOK);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_record_close("gui");
osSemaphoreDelete(semaphore);
return 0;
}

View File

@ -13,6 +13,8 @@ IconAnimation* icon_animation_alloc(const Icon* icon) {
void icon_animation_free(IconAnimation* instance) {
furi_assert(instance);
icon_animation_stop(instance);
while(xTimerIsTimerActive(instance->timer) == pdTRUE) osDelay(1);
furi_check(osTimerDelete(instance->timer) == osOK);
free(instance);
}
@ -65,8 +67,9 @@ void icon_animation_start(IconAnimation* instance) {
furi_assert(instance->icon->frame_rate);
furi_check(
xTimerChangePeriod(
instance->timer, (osKernelGetTickFreq() / instance->icon->frame_rate), 0) ==
pdPASS);
instance->timer,
(osKernelGetTickFreq() / instance->icon->frame_rate),
portMAX_DELAY) == pdPASS);
}
}
@ -74,7 +77,7 @@ void icon_animation_stop(IconAnimation* instance) {
furi_assert(instance);
if(instance->animating) {
instance->animating = false;
furi_check(xTimerStop(instance->timer, 0) == pdPASS);
furi_check(xTimerStop(instance->timer, portMAX_DELAY) == pdPASS);
instance->frame = 0;
}
}

View File

@ -255,7 +255,6 @@ void onewire_cli_search(Cli* cli) {
printf("Search finished\r\n");
onewire.reset_search();
done = true;
return;
} else {
printf("Found: ");
for(uint8_t i = 0; i < 8; i++) {

View File

@ -1,7 +1,35 @@
#include "lfrfid-debug-app-scene-tune.h"
#include <furi-hal.h>
extern COMP_HandleTypeDef hcomp1;
static void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
COMP_HandleTypeDef* _hcomp = static_cast<COMP_HandleTypeDef*>(hcomp);
if(hcomp == &hcomp1) {
hal_gpio_write(&gpio_ext_pa7, HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH);
}
}
void LfRfidDebugAppSceneTune::on_enter(LfRfidDebugApp* app, bool need_restore) {
app->view_controller.switch_to<LfRfidViewTuneVM>();
hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this);
hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT;
hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH;
hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING;
if(HAL_COMP_Init(&hcomp1) != HAL_OK) {
Error_Handler();
}
HAL_COMP_Start(&hcomp1);
furi_hal_rfid_pins_read();
furi_hal_rfid_tim_read(125000, 0.5);
@ -22,6 +50,10 @@ bool LfRfidDebugAppSceneTune::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Even
}
void LfRfidDebugAppSceneTune::on_exit(LfRfidDebugApp* app) {
HAL_COMP_Stop(&hcomp1);
api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger);
hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
furi_hal_rfid_tim_read_stop();
furi_hal_rfid_tim_reset();
furi_hal_rfid_pins_reset();

View File

@ -33,7 +33,7 @@ typedef struct {
static RpcSystemCallbacks rpc_systems[] = {
{
.alloc = rpc_system_status_alloc,
.alloc = rpc_system_system_alloc,
.free = NULL,
},
{
@ -203,12 +203,23 @@ void rpc_print_message(const PB_Main* message) {
}
break;
}
case PB_Main_ping_request_tag:
case PB_Main_system_ping_request_tag:
string_cat_printf(str, "\tping_request {\r\n");
break;
case PB_Main_ping_response_tag:
case PB_Main_system_ping_response_tag:
string_cat_printf(str, "\tping_response {\r\n");
break;
case PB_Main_system_device_info_request_tag:
string_cat_printf(str, "\tdevice_info_request {\r\n");
break;
case PB_Main_system_device_info_response_tag:
string_cat_printf(str, "\tdevice_info_response {\r\n");
string_cat_printf(
str,
"\t\t%s: %s\r\n",
message->content.system_device_info_response.key,
message->content.system_device_info_response.value);
break;
case PB_Main_storage_mkdir_request_tag:
string_cat_printf(str, "\tmkdir {\r\n");
break;
@ -223,6 +234,38 @@ void rpc_print_message(const PB_Main* message) {
case PB_Main_empty_tag:
string_cat_printf(str, "\tempty {\r\n");
break;
case PB_Main_storage_info_request_tag: {
string_cat_printf(str, "\tinfo_request {\r\n");
const char* path = message->content.storage_info_request.path;
if(path) {
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_storage_info_response_tag: {
string_cat_printf(str, "\tinfo_response {\r\n");
string_cat_printf(
str, "\t\ttotal_space: %lu\r\n", message->content.storage_info_response.total_space);
string_cat_printf(
str, "\t\tfree_space: %lu\r\n", message->content.storage_info_response.free_space);
break;
}
case PB_Main_storage_stat_request_tag: {
string_cat_printf(str, "\tstat_request {\r\n");
const char* path = message->content.storage_stat_request.path;
if(path) {
string_cat_printf(str, "\t\tpath: %s\r\n", path);
}
break;
}
case PB_Main_storage_stat_response_tag: {
string_cat_printf(str, "\tstat_response {\r\n");
if(message->content.storage_stat_response.has_file) {
const PB_Storage_File* msg_file = &message->content.storage_stat_response.file;
rpc_sprintf_msg_file(str, "\t\t\t", msg_file, 1);
}
break;
}
case PB_Main_storage_list_request_tag: {
string_cat_printf(str, "\tlist_request {\r\n");
const char* path = message->content.storage_list_request.path;
@ -265,6 +308,14 @@ void rpc_print_message(const PB_Main* message) {
rpc_sprintf_msg_file(str, "\t\t", msg_file, msg_file_count);
break;
}
case PB_Main_storage_rename_request_tag: {
string_cat_printf(str, "\trename_request {\r\n");
string_cat_printf(
str, "\t\told_path: %s\r\n", message->content.storage_rename_request.old_path);
string_cat_printf(
str, "\t\tnew_path: %s\r\n", message->content.storage_rename_request.new_path);
break;
}
case PB_Main_gui_start_screen_stream_request_tag:
string_cat_printf(str, "\tstart_screen_stream {\r\n");
break;

View File

@ -21,7 +21,7 @@ void rpc_send_and_release(Rpc* rpc, PB_Main* main_message);
void rpc_send_and_release_empty(Rpc* rpc, uint32_t command_id, PB_CommandStatus status);
void rpc_add_handler(Rpc* rpc, pb_size_t message_tag, RpcHandler* handler);
void* rpc_system_status_alloc(Rpc* rpc);
void* rpc_system_system_alloc(Rpc* rpc);
void* rpc_system_storage_alloc(Rpc* rpc);
void rpc_system_storage_free(void* ctx);
void* rpc_system_app_alloc(Rpc* rpc);

View File

@ -1,39 +0,0 @@
#include "flipper.pb.h"
#include "rpc_i.h"
#include "status.pb.h"
void rpc_system_status_ping_process(const PB_Main* msg_request, void* context) {
if(msg_request->has_next) {
rpc_send_and_release_empty(
context, msg_request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
return;
}
PB_Main msg_response = PB_Main_init_default;
msg_response.has_next = false;
msg_response.command_status = PB_CommandStatus_OK;
msg_response.command_id = msg_request->command_id;
msg_response.which_content = PB_Main_ping_response_tag;
const PB_Status_PingRequest* request = &msg_request->content.ping_request;
PB_Status_PingResponse* response = &msg_response.content.ping_response;
if(request->data && (request->data->size > 0)) {
response->data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(request->data->size));
memcpy(response->data->bytes, request->data->bytes, request->data->size);
response->data->size = request->data->size;
}
rpc_send_and_release(context, &msg_response);
}
void* rpc_system_status_alloc(Rpc* rpc) {
RpcHandler rpc_handler = {
.message_handler = rpc_system_status_ping_process,
.decode_submessage = NULL,
.context = rpc,
};
rpc_add_handler(rpc, PB_Main_ping_request_tag, &rpc_handler);
return NULL;
}

View File

@ -96,6 +96,37 @@ static PB_CommandStatus rpc_system_storage_get_file_error(File* file) {
return rpc_system_storage_get_error(storage_file_get_error(file));
}
static void rpc_system_storage_info_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
furi_assert(request->which_content == PB_Main_storage_info_request_tag);
RpcStorageSystem* rpc_storage = context;
rpc_system_storage_reset_state(rpc_storage, true);
PB_Main* response = furi_alloc(sizeof(PB_Main));
response->command_id = request->command_id;
Storage* fs_api = furi_record_open("storage");
FS_Error error = storage_common_fs_info(
fs_api,
request->content.storage_info_request.path,
&response->content.storage_info_response.total_space,
&response->content.storage_info_response.free_space);
response->command_status = rpc_system_storage_get_error(error);
if(error == FSE_OK) {
response->which_content = PB_Main_storage_info_response_tag;
} else {
response->which_content = PB_Main_empty_tag;
}
rpc_send_and_release(rpc_storage->rpc, response);
free(response);
furi_record_close("storage");
}
static void rpc_system_storage_stat_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(context);
@ -388,6 +419,7 @@ static void rpc_system_storage_mkdir_process(const PB_Main* request, void* conte
} else {
status = PB_CommandStatus_ERROR_INVALID_PARAMETERS;
}
furi_record_close("storage");
rpc_send_and_release_empty(rpc_storage->rpc, request->command_id, status);
}
@ -453,6 +485,26 @@ static void rpc_system_storage_md5sum_process(const PB_Main* request, void* cont
furi_record_close("storage");
}
static void rpc_system_storage_rename_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(request->which_content == PB_Main_storage_rename_request_tag);
furi_assert(context);
RpcStorageSystem* rpc_storage = context;
PB_CommandStatus status;
rpc_system_storage_reset_state(rpc_storage, true);
Storage* fs_api = furi_record_open("storage");
FS_Error error = storage_common_rename(
fs_api,
request->content.storage_rename_request.old_path,
request->content.storage_rename_request.new_path);
status = rpc_system_storage_get_error(error);
furi_record_close("storage");
rpc_send_and_release_empty(rpc_storage->rpc, request->command_id, status);
}
void* rpc_system_storage_alloc(Rpc* rpc) {
furi_assert(rpc);
@ -467,6 +519,9 @@ void* rpc_system_storage_alloc(Rpc* rpc) {
.context = rpc_storage,
};
rpc_handler.message_handler = rpc_system_storage_info_process;
rpc_add_handler(rpc, PB_Main_storage_info_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_storage_stat_process;
rpc_add_handler(rpc, PB_Main_storage_stat_request_tag, &rpc_handler);
@ -488,6 +543,9 @@ void* rpc_system_storage_alloc(Rpc* rpc) {
rpc_handler.message_handler = rpc_system_storage_md5sum_process;
rpc_add_handler(rpc, PB_Main_storage_md5sum_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_storage_rename_process;
rpc_add_handler(rpc, PB_Main_storage_rename_request_tag, &rpc_handler);
return rpc_storage;
}

View File

@ -0,0 +1,118 @@
#include "flipper.pb.h"
#include "rpc_i.h"
#include "status.pb.h"
#include <furi-hal-info.h>
#include <power/power_service/power.h>
void rpc_system_system_ping_process(const PB_Main* msg_request, void* context) {
furi_assert(msg_request);
furi_assert(msg_request->which_content == PB_Main_system_ping_request_tag);
furi_assert(context);
Rpc* rpc = context;
if(msg_request->has_next) {
rpc_send_and_release_empty(
rpc, msg_request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
return;
}
PB_Main msg_response = PB_Main_init_default;
msg_response.has_next = false;
msg_response.command_status = PB_CommandStatus_OK;
msg_response.command_id = msg_request->command_id;
msg_response.which_content = PB_Main_system_ping_response_tag;
const PB_System_PingRequest* request = &msg_request->content.system_ping_request;
PB_System_PingResponse* response = &msg_response.content.system_ping_response;
if(request->data && (request->data->size > 0)) {
response->data = furi_alloc(PB_BYTES_ARRAY_T_ALLOCSIZE(request->data->size));
memcpy(response->data->bytes, request->data->bytes, request->data->size);
response->data->size = request->data->size;
}
rpc_send_and_release(rpc, &msg_response);
}
void rpc_system_system_reboot_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(request->which_content == PB_Main_system_reboot_request_tag);
furi_assert(context);
Rpc* rpc = context;
const int mode = request->content.system_reboot_request.mode;
if(mode == PB_System_RebootRequest_RebootMode_OS) {
power_reboot(PowerBootModeNormal);
} else if(mode == PB_System_RebootRequest_RebootMode_DFU) {
power_reboot(PowerBootModeDfu);
} else {
rpc_send_and_release_empty(
rpc, request->command_id, PB_CommandStatus_ERROR_INVALID_PARAMETERS);
}
}
typedef struct {
Rpc* rpc;
PB_Main* response;
} RpcSystemSystemDeviceInfoContext;
void rpc_system_system_device_info_callback(
const char* key,
const char* value,
bool last,
void* context) {
furi_assert(key);
furi_assert(value);
furi_assert(context);
RpcSystemSystemDeviceInfoContext* ctx = context;
char* str_key = strdup(key);
char* str_value = strdup(value);
ctx->response->has_next = !last;
ctx->response->content.system_device_info_response.key = str_key;
ctx->response->content.system_device_info_response.value = str_value;
rpc_send_and_release(ctx->rpc, ctx->response);
}
void rpc_system_system_device_info_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(request->which_content == PB_Main_system_device_info_request_tag);
furi_assert(context);
Rpc* rpc = context;
PB_Main* response = furi_alloc(sizeof(PB_Main));
response->command_id = request->command_id;
response->which_content = PB_Main_system_device_info_response_tag;
response->command_status = PB_CommandStatus_OK;
RpcSystemSystemDeviceInfoContext device_info_context = {
.rpc = rpc,
.response = response,
};
furi_hal_info_get(rpc_system_system_device_info_callback, &device_info_context);
free(response);
}
void* rpc_system_system_alloc(Rpc* rpc) {
RpcHandler rpc_handler = {
.message_handler = NULL,
.decode_submessage = NULL,
.context = rpc,
};
rpc_handler.message_handler = rpc_system_system_ping_process;
rpc_add_handler(rpc, PB_Main_system_ping_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_system_reboot_process;
rpc_add_handler(rpc, PB_Main_system_reboot_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_system_device_info_process;
rpc_add_handler(rpc, PB_Main_system_device_info_request_tag, &rpc_handler);
return NULL;
}

View File

@ -427,7 +427,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
string_init_printf(fullname, "%s/%s", string_get_cstr(cur_dir), name);
FS_Error error = storage_common_remove(storage, string_get_cstr(fullname));
furi_assert(error == FSE_OK);
furi_check(error == FSE_OK);
string_clear(fullname);
}
storage_dir_close(dir);
@ -438,7 +438,7 @@ bool storage_simply_remove_recursive(Storage* storage, const char* path) {
}
FS_Error error = storage_common_remove(storage, string_get_cstr(cur_dir));
furi_assert(error == FSE_OK);
furi_check(error == FSE_OK);
if(string_cmp(cur_dir, path)) {
size_t last_char = string_search_rchar(cur_dir, '/');

View File

@ -377,7 +377,7 @@ static FS_Error storage_process_common_rename(Storage* app, const char* old, con
StorageType type_old = storage_get_type_by_path(old);
StorageType type_new = storage_get_type_by_path(new);
if(storage_type_is_not_valid(type_old) || storage_type_is_not_valid(type_old)) {
if(storage_type_is_not_valid(type_old) || storage_type_is_not_valid(type_new)) {
ret = FSE_INVALID_NAME;
} else {
if(type_old != type_new) {

View File

@ -512,7 +512,7 @@ static FS_Error storage_ext_common_fs_info(
/******************* Init Storage *******************/
void storage_ext_init(StorageData* storage) {
SDData* sd_data = malloc(sizeof(SDData));
SDData* sd_data = furi_alloc(sizeof(SDData));
sd_data->fs = &USERFatFS;
sd_data->path = "0:/";
sd_data->sd_was_present = true;

View File

@ -0,0 +1,141 @@
#include "subghz_chat.h"
#include <lib/subghz/subghz_tx_rx_worker.h>
#define TAG "SubGhzChat"
#define SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES 500
struct SubGhzChatWorker {
FuriThread* thread;
SubGhzTxRxWorker* subghz_txrx;
volatile bool worker_running;
volatile bool worker_stoping;
osMessageQueueId_t event_queue;
uint32_t last_time_rx_data;
};
/** Worker thread
*
* @param context
* @return exit code
*/
static int32_t subghz_chat_worker_thread(void* context) {
SubGhzChatWorker* instance = context;
FURI_LOG_I(TAG, "Worker start");
char c;
SubghzChatEvent event;
event.event = SubghzChatEventUserEntrance;
osMessageQueuePut(instance->event_queue, &event, 0, 0);
while(instance->worker_running) {
if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) {
event.event = SubghzChatEventInputData;
event.c = c;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
}
FURI_LOG_I(TAG, "Worker stop");
return 0;
}
static void subghz_chat_worker_update_rx_event_chat(void* context) {
furi_assert(context);
SubGhzChatWorker* instance = context;
SubghzChatEvent event;
if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
event.event = SubghzChatEventNewMessage;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
instance->last_time_rx_data = millis();
event.event = SubghzChatEventRXData;
osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
}
SubGhzChatWorker* subghz_chat_worker_alloc() {
SubGhzChatWorker* instance = furi_alloc(sizeof(SubGhzChatWorker));
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "SubghzChat");
furi_thread_set_stack_size(instance->thread, 2048);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL);
return instance;
}
void subghz_chat_worker_free(SubGhzChatWorker* instance) {
furi_assert(instance);
furi_assert(!instance->worker_running);
osMessageQueueDelete(instance->event_queue);
subghz_tx_rx_worker_free(instance->subghz_txrx);
furi_thread_free(instance->thread);
free(instance);
}
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) {
furi_assert(instance);
furi_assert(!instance->worker_running);
bool res = false;
if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) {
osMessageQueueReset(instance->event_queue);
subghz_tx_rx_worker_set_callback_have_read(
instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance);
instance->worker_running = true;
instance->last_time_rx_data = 0;
res = furi_thread_start(instance->thread);
}
return res;
}
void subghz_chat_worker_stop(SubGhzChatWorker* instance) {
furi_assert(instance);
furi_assert(instance->worker_running);
if(subghz_tx_rx_worker_is_running(instance->subghz_txrx)) {
subghz_tx_rx_worker_stop(instance->subghz_txrx);
}
instance->worker_running = false;
furi_thread_join(instance->thread);
}
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) {
furi_assert(instance);
return instance->worker_running;
}
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
furi_assert(instance);
SubghzChatEvent event;
if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
return event;
} else {
event.event = SubghzChatEventNoEvent;
return event;
}
}
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) {
furi_assert(instance);
osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
}
size_t subghz_chat_worker_available(SubGhzChatWorker* instance) {
furi_assert(instance);
return subghz_tx_rx_worker_available(instance->subghz_txrx);
}
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
furi_assert(instance);
return subghz_tx_rx_worker_read(instance->subghz_txrx, data, size);
}
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size) {
furi_assert(instance);
return subghz_tx_rx_worker_write(instance->subghz_txrx, data, size);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "../subghz_i.h"
typedef struct SubGhzChatWorker SubGhzChatWorker;
typedef enum {
SubghzChatEventNoEvent,
SubghzChatEventUserEntrance,
SubghzChatEventUserExit,
SubghzChatEventInputData,
SubghzChatEventRXData,
SubghzChatEventNewMessage,
} SubghzChatEventType;
typedef struct {
SubghzChatEventType event;
char c;
} SubghzChatEvent;
SubGhzChatWorker* subghz_chat_worker_alloc();
void subghz_chat_worker_free(SubGhzChatWorker* instance);
bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
void subghz_chat_worker_stop(SubGhzChatWorker* instance);
bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event);
size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);

View File

@ -41,9 +41,13 @@ void subghz_scene_read_raw_on_enter(void* context) {
SubGhz* subghz = context;
if(subghz->txrx->rx_key_state == SubGhzRxKeyStateBack) {
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE);
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE, "");
} else if(subghz->txrx->rx_key_state == SubGhzRxKeyStateRAWLoad) {
subghz_read_raw_set_status(
subghz->subghz_read_raw, SubghzReadRAWStatusTX, subghz->file_name);
subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
} else {
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart);
subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart, "");
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
}

View File

@ -4,7 +4,12 @@ void subghz_scene_saved_on_enter(void* context) {
SubGhz* subghz = context;
if(subghz_load_protocol_from_file(subghz)) {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
if((!strcmp(subghz->txrx->protocol_result->name, "RAW"))) {
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
} else {
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);
}
} else {
scene_manager_search_and_switch_to_previous_scene(subghz->scene_manager, SubGhzSceneStart);
}

View File

@ -10,10 +10,14 @@
#include <lib/subghz/protocols/subghz_protocol_common.h>
#include <lib/subghz/protocols/subghz_protocol_princeton.h>
#include "helpers/subghz_chat.h"
#include <notification/notification-messages.h>
#define SUBGHZ_FREQUENCY_RANGE_STR \
"299999755...348000000 or 386999938...464000000 or 778999847...928000000"
void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
static void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
uint32_t frequency = 433920000;
if(string_size(args)) {
@ -56,7 +60,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
furi_hal_power_suppress_charge_exit();
}
void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
static void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
uint32_t frequency = 433920000;
if(string_size(args)) {
@ -96,16 +100,16 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
furi_hal_subghz_sleep();
}
void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
static void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
uint32_t frequency = 433920000;
uint32_t key = 0x0074BADE;
size_t repeat = 10;
uint32_t repeat = 10;
if(string_size(args)) {
int ret = sscanf(string_get_cstr(args), "%lx %lu %u", &key, &frequency, &repeat);
int ret = sscanf(string_get_cstr(args), "%lx %lu %lu", &key, &frequency, &repeat);
if(ret != 3) {
printf(
"sscanf returned %d, key: %lx, frequency: %lu, repeat: %u\r\n",
"sscanf returned %d, key: %lx, frequency: %lu, repeat: %lu\r\n",
ret,
key,
frequency,
@ -125,7 +129,7 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
}
printf(
"Transmitting at %lu, key %lx, repeat %u. Press CTRL+C to stop\r\n",
"Transmitting at %lu, key %lx, repeat %lu. Press CTRL+C to stop\r\n",
frequency,
key,
repeat);
@ -187,7 +191,7 @@ static void subghz_cli_command_rx_text_callback(string_t text, void* context) {
printf("%s", string_get_cstr(text));
}
void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
static void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
uint32_t frequency = 433920000;
if(string_size(args)) {
@ -260,7 +264,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
free(instance);
}
void subghz_cli_command_print_usage() {
static void subghz_cli_command_print_usage() {
printf("Usage:\r\n");
printf("subghz <cmd> <args>\r\n");
printf("Cmd list:\r\n");
@ -268,9 +272,10 @@ void subghz_cli_command_print_usage() {
"\tencrypt_keeloq <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt keeloq manufacture keys\r\n");
printf(
"\tencrypt_raw <path_decrypted_file> <path_encrypted_file> <IV:16 bytes in hex>\t - Encrypt RAW data\r\n");
printf("\tchat <frequency:in Herz>\t - Chat with other Flippers\r\n");
}
void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
static void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
uint8_t iv[16];
string_t source;
@ -312,7 +317,7 @@ void subghz_cli_command_encrypt_keeloq(Cli* cli, string_t args) {
string_clear(source);
}
void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
static void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
uint8_t iv[16];
string_t source;
@ -348,7 +353,184 @@ void subghz_cli_command_encrypt_raw(Cli* cli, string_t args) {
string_clear(source);
}
void subghz_cli_command(Cli* cli, string_t args, void* context) {
static void subghz_cli_command_chat(Cli* cli, string_t args) {
uint32_t frequency = 433920000;
if(string_size(args)) {
int ret = sscanf(string_get_cstr(args), "%lu", &frequency);
if(ret != 1) {
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
cli_print_usage("subghz_txrx", "<Frequency in HZ>", string_get_cstr(args));
return;
}
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
printf(
"Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n",
frequency);
return;
}
}
if(!furi_hal_subghz_is_tx_allowed(frequency)) {
printf(
"In your region, only reception on this frequency (%lu) is allowed,\r\n"
"the actual operation of the application is not possible\r\n ",
frequency);
return;
}
SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc();
if(!subghz_chat_worker_start(subghz_chat, frequency)) {
printf("Startup error SubGhzChatWorker\r\n");
if(subghz_chat_worker_is_running(subghz_chat)) {
subghz_chat_worker_stop(subghz_chat);
subghz_chat_worker_free(subghz_chat);
}
return;
}
printf("Receiving at frequency %lu Hz\r\n", frequency);
printf("Press CTRL+C to stop\r\n");
furi_hal_power_suppress_charge_enter();
size_t message_max_len = 64;
uint8_t message[64] = {0};
string_t input;
string_init(input);
string_t name;
string_init(name);
string_t output;
string_init(output);
string_t sysmsg;
string_init(sysmsg);
bool exit = false;
SubghzChatEvent chat_event;
NotificationApp* notification = furi_record_open("notification");
string_printf(name, "\033[0;33m%s\033[0m: ", furi_hal_version_get_name_ptr());
string_set(input, name);
printf("%s", string_get_cstr(input));
fflush(stdout);
while(!exit) {
chat_event = subghz_chat_worker_get_event_chat(subghz_chat);
switch(chat_event.event) {
case SubghzChatEventInputData:
if(chat_event.c == CliSymbolAsciiETX) {
printf("\r\n");
chat_event.event = SubghzChatEventUserExit;
subghz_chat_worker_put_event_chat(subghz_chat, &chat_event);
break;
} else if(
(chat_event.c == CliSymbolAsciiBackspace) || (chat_event.c == CliSymbolAsciiDel)) {
size_t len = string_length_u(input);
if(len > string_length_u(name)) {
printf("%s", "\e[D\e[1P");
fflush(stdout);
//delete 1 char UTF
const char* str = string_get_cstr(input);
size_t size = 0;
m_str1ng_utf8_state_e s = M_STRING_UTF8_STARTING;
string_unicode_t u = 0;
string_reset(sysmsg);
while(*str) {
m_str1ng_utf8_decode(*str, &s, &u);
if((s == M_STRING_UTF8_ERROR) || s == M_STRING_UTF8_STARTING) {
string_push_u(sysmsg, u);
if(++size >= len - 1) break;
s = M_STRING_UTF8_STARTING;
}
str++;
}
string_set(input, sysmsg);
}
} else if(chat_event.c == CliSymbolAsciiCR) {
printf("\r\n");
string_push_back(input, '\r');
string_push_back(input, '\n');
while(!subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(input),
strlen(string_get_cstr(input)))) {
delay(10);
}
string_printf(input, "%s", string_get_cstr(name));
printf("%s", string_get_cstr(input));
fflush(stdout);
} else if(chat_event.c == CliSymbolAsciiLF) {
//cut out the symbol \n
} else {
putc(chat_event.c, stdout);
fflush(stdout);
string_push_back(input, chat_event.c);
break;
case SubghzChatEventRXData:
do {
memset(message, 0x00, message_max_len);
size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len);
for(size_t i = 0; i < len; i++) {
string_push_back(output, message[i]);
if(message[i] == '\n') {
printf("\r");
for(uint8_t i = 0; i < 80; i++) {
printf(" ");
}
printf("\r %s", string_get_cstr(output));
printf("%s", string_get_cstr(input));
fflush(stdout);
string_reset(output);
}
}
} while(subghz_chat_worker_available(subghz_chat));
break;
case SubghzChatEventNewMessage:
notification_message(notification, &sequence_single_vibro);
break;
case SubghzChatEventUserEntrance:
string_printf(
sysmsg,
"\033[0;34m%s joined chat.\033[0m\r\n",
furi_hal_version_get_name_ptr());
subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(sysmsg),
strlen(string_get_cstr(sysmsg)));
break;
case SubghzChatEventUserExit:
string_printf(
sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr());
subghz_chat_worker_write(
subghz_chat,
(uint8_t*)string_get_cstr(sysmsg),
strlen(string_get_cstr(sysmsg)));
delay(10);
exit = true;
break;
default:
FURI_LOG_W("SubGhzChat", "Error event");
break;
}
}
}
string_clear(input);
string_clear(name);
string_clear(output);
string_clear(sysmsg);
furi_hal_power_suppress_charge_exit();
furi_record_close("notification");
if(subghz_chat_worker_is_running(subghz_chat)) {
subghz_chat_worker_stop(subghz_chat);
subghz_chat_worker_free(subghz_chat);
}
printf("\r\nExit chat\r\n");
}
static void subghz_cli_command(Cli* cli, string_t args, void* context) {
string_t cmd;
string_init(cmd);
@ -368,6 +550,11 @@ void subghz_cli_command(Cli* cli, string_t args, void* context) {
break;
}
if(string_cmp_str(cmd, "chat") == 0) {
subghz_cli_command_chat(cli, args);
break;
}
subghz_cli_command_print_usage();
} while(false);

View File

@ -41,8 +41,8 @@ bool subghz_get_preset_name(SubGhz* subghz, string_t preset) {
case FuriHalSubGhzPreset2FSKDev476Async:
preset_name = "FuriHalSubGhzPreset2FSKDev476Async";
break;
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset");
default:
FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset");
return false;
break;
}
@ -320,7 +320,7 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) {
break;
}
// Create saved directory if necessary
if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) {
if(!storage_simply_mkdir(storage, SUBGHZ_APP_PATH_FOLDER)) {
dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
break;
}

View File

@ -73,6 +73,7 @@ typedef enum {
SubGhzRxKeyStateBack,
SubGhzRxKeyStateAddKey,
SubGhzRxKeyStateExit,
SubGhzRxKeyStateRAWLoad,
} SubGhzRxKeyState;
struct SubGhzTxRx {

View File

@ -21,6 +21,7 @@ typedef struct {
string_t frequency_str;
string_t preset_str;
string_t sample_write;
string_t file_name;
uint8_t* rssi_history;
bool rssi_history_end;
uint8_t ind_write;
@ -224,6 +225,8 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) {
elements_button_left(canvas, "Erase");
elements_button_center(canvas, "Send");
elements_button_right(canvas, "Save");
canvas_draw_str_aligned(
canvas, 58, 28, AlignCenter, AlignTop, string_get_cstr(model->file_name));
} else if(model->satus == SubghzReadRAWStatusStart) {
elements_button_left(canvas, "Config");
elements_button_center(canvas, "REC");
@ -297,6 +300,7 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
model->rssi_history_end = false;
model->ind_write = 0;
string_set(model->sample_write, "0 spl.");
string_reset(model->file_name);
instance->callback(SubghzCustomEventViewReadRAWErase, instance->context);
}
return true;
@ -332,7 +336,10 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
return true;
}
void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus satus) {
void subghz_read_raw_set_status(
SubghzReadRAW* instance,
SubghzReadRAWStatus satus,
const char* file_name) {
furi_assert(instance);
if(satus == SubghzReadRAWStatusStart) {
with_view_model(
@ -340,6 +347,7 @@ void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus sat
model->satus = SubghzReadRAWStatusStart;
model->rssi_history_end = false;
model->ind_write = 0;
string_reset(model->file_name);
string_set(model->sample_write, "0 spl.");
return true;
});
@ -349,6 +357,16 @@ void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus sat
model->satus = SubghzReadRAWStatusIDLE;
return true;
});
} else if(satus == SubghzReadRAWStatusTX) {
with_view_model(
instance->view, (SubghzReadRAWModel * model) {
model->satus = SubghzReadRAWStatusIDLE;
model->rssi_history_end = false;
model->ind_write = 0;
string_set(model->file_name, file_name);
string_set(model->sample_write, "RAW");
return true;
});
}
}
@ -389,6 +407,7 @@ SubghzReadRAW* subghz_read_raw_alloc() {
string_init(model->frequency_str);
string_init(model->preset_str);
string_init(model->sample_write);
string_init(model->file_name);
model->rssi_history = furi_alloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t));
return true;
});
@ -404,6 +423,7 @@ void subghz_read_raw_free(SubghzReadRAW* instance) {
string_clear(model->frequency_str);
string_clear(model->preset_str);
string_clear(model->sample_write);
string_clear(model->file_name);
free(model->rssi_history);
return true;
});

View File

@ -37,6 +37,9 @@ void subghz_read_raw_update_sin(SubghzReadRAW* instance);
void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi);
void subghz_read_raw_set_status(SubghzReadRAW* instance, SubghzReadRAWStatus satus);
void subghz_read_raw_set_status(
SubghzReadRAW* instance,
SubghzReadRAWStatus satus,
const char* file_name);
View* subghz_read_raw_get_view(SubghzReadRAW* subghz_static);

View File

@ -115,7 +115,7 @@ static void clean_directory(Storage* fs_api, const char* clean_dir) {
clean_directory(fs_api, fullname);
}
FS_Error error = storage_common_remove(fs_api, fullname);
furi_assert(error == FSE_OK);
furi_check(error == FSE_OK);
free(fullname);
}
free(name);
@ -196,8 +196,8 @@ static void test_rpc_add_ping_to_list(MsgList_t msg_list, bool request, uint32_t
response->command_status = PB_CommandStatus_OK;
response->cb_content.funcs.encode = NULL;
response->has_next = false;
response->which_content = (request == PING_REQUEST) ? PB_Main_ping_request_tag :
PB_Main_ping_response_tag;
response->which_content = (request == PING_REQUEST) ? PB_Main_system_ping_request_tag :
PB_Main_system_ping_response_tag;
}
static void test_rpc_create_simple_message(
@ -209,8 +209,7 @@ static void test_rpc_create_simple_message(
char* str_copy = NULL;
if(str) {
str_copy = furi_alloc(strlen(str) + 1);
strcpy(str_copy, str);
str_copy = strdup(str);
}
message->command_id = command_id;
message->command_status = PB_CommandStatus_OK;
@ -218,6 +217,9 @@ static void test_rpc_create_simple_message(
message->which_content = tag;
message->has_next = false;
switch(tag) {
case PB_Main_storage_info_request_tag:
message->content.storage_info_request.path = str_copy;
break;
case PB_Main_storage_stat_request_tag:
message->content.storage_stat_request.path = str_copy;
break;
@ -268,9 +270,7 @@ static void test_rpc_add_read_or_write_to_list(
request->command_status = PB_CommandStatus_OK;
if(write == WRITE_REQUEST) {
size_t path_size = strlen(path) + 1;
request->content.storage_write_request.path = furi_alloc(path_size);
strncpy(request->content.storage_write_request.path, path, path_size);
request->content.storage_write_request.path = strdup(path);
request->which_content = PB_Main_storage_write_request_tag;
request->content.storage_write_request.has_file = true;
msg_file = &request->content.storage_write_request.file;
@ -353,10 +353,10 @@ static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) {
switch(result->which_content) {
case PB_Main_empty_tag:
case PB_Main_ping_response_tag:
case PB_Main_system_ping_response_tag:
/* nothing to check */
break;
case PB_Main_ping_request_tag:
case PB_Main_system_ping_request_tag:
case PB_Main_storage_list_request_tag:
case PB_Main_storage_read_request_tag:
case PB_Main_storage_write_request_tag:
@ -372,6 +372,15 @@ static void test_rpc_compare_messages(PB_Main* result, PB_Main* expected) {
mu_check(result_locked == expected_locked);
break;
}
case PB_Main_storage_info_response_tag: {
uint64_t result_total_space = result->content.storage_info_response.total_space;
uint64_t expected_total_space = expected->content.storage_info_response.total_space;
mu_check(result_total_space == expected_total_space);
uint64_t result_free_space = result->content.storage_info_response.free_space;
uint64_t expected_free_space = expected->content.storage_info_response.free_space;
mu_check(result_free_space == expected_free_space);
} break;
case PB_Main_storage_stat_response_tag: {
bool result_has_msg_file = result->content.storage_stat_response.has_file;
bool expected_has_msg_file = expected->content.storage_stat_response.has_file;
@ -701,6 +710,38 @@ static void test_create_file(const char* path, size_t size) {
furi_check(test_is_exists(path));
}
static void test_rpc_storage_info_run(const char* path, uint32_t command_id) {
PB_Main request;
MsgList_t expected_msg_list;
MsgList_init(expected_msg_list);
test_rpc_create_simple_message(&request, PB_Main_storage_info_request_tag, path, command_id);
PB_Main* response = MsgList_push_new(expected_msg_list);
response->command_id = command_id;
Storage* fs_api = furi_record_open("storage");
FS_Error error = storage_common_fs_info(
fs_api,
path,
&response->content.storage_info_response.total_space,
&response->content.storage_info_response.free_space);
response->command_status = rpc_system_storage_get_error(error);
if(error == FSE_OK) {
response->which_content = PB_Main_storage_info_response_tag;
} else {
response->which_content = PB_Main_empty_tag;
}
test_rpc_encode_and_feed_one(&request);
test_rpc_decode_and_compare(expected_msg_list);
pb_release(&PB_Main_msg, &request);
test_rpc_free_msg_list(expected_msg_list);
}
static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
PB_Main request;
MsgList_t expected_msg_list;
@ -735,6 +776,12 @@ static void test_rpc_storage_stat_run(const char* path, uint32_t command_id) {
test_rpc_free_msg_list(expected_msg_list);
}
MU_TEST(test_storage_info) {
test_rpc_storage_info_run("/any", ++command_id);
test_rpc_storage_info_run("/int", ++command_id);
test_rpc_storage_info_run("/ext", ++command_id);
}
#define TEST_DIR_STAT_NAME TEST_DIR "stat_dir"
#define TEST_DIR_STAT TEST_DIR_STAT_NAME "/"
MU_TEST(test_storage_stat) {
@ -928,7 +975,7 @@ MU_TEST(test_storage_interrupt_continuous_another_system) {
.command_status = PB_CommandStatus_OK,
.cb_content.funcs.encode = NULL,
.has_next = false,
.which_content = PB_Main_ping_request_tag,
.which_content = PB_Main_system_ping_request_tag,
};
MsgList_it_t it;
@ -1162,6 +1209,54 @@ MU_TEST(test_storage_md5sum) {
test_storage_md5sum_run(TEST_DIR "file2.txt", ++command_id, md5sum2, PB_CommandStatus_OK);
}
static void test_rpc_storage_rename_run(
const char* old_path,
const char* new_path,
uint32_t command_id,
PB_CommandStatus status) {
PB_Main request;
MsgList_t expected_msg_list;
MsgList_init(expected_msg_list);
char* str_old_path = strdup(old_path);
char* str_new_path = strdup(new_path);
request.command_id = command_id;
request.command_status = PB_CommandStatus_OK;
request.cb_content.funcs.encode = NULL;
request.which_content = PB_Main_storage_rename_request_tag;
request.has_next = false;
request.content.storage_rename_request.old_path = str_old_path;
request.content.storage_rename_request.new_path = str_new_path;
test_rpc_add_empty_to_list(expected_msg_list, status, command_id);
test_rpc_encode_and_feed_one(&request);
test_rpc_decode_and_compare(expected_msg_list);
pb_release(&PB_Main_msg, &request);
test_rpc_free_msg_list(expected_msg_list);
}
MU_TEST(test_storage_rename) {
test_rpc_storage_rename_run(
NULL, NULL, ++command_id, PB_CommandStatus_ERROR_STORAGE_INVALID_NAME);
furi_check(!test_is_exists(TEST_DIR "empty.txt"));
test_create_file(TEST_DIR "empty.txt", 0);
test_rpc_storage_rename_run(
TEST_DIR "empty.txt", TEST_DIR "empty2.txt", ++command_id, PB_CommandStatus_OK);
mu_check(!test_is_exists(TEST_DIR "empty.txt"));
mu_check(test_is_exists(TEST_DIR "empty2.txt"));
furi_check(!test_is_exists(TEST_DIR "dir1"));
test_create_dir(TEST_DIR "dir1");
test_rpc_storage_rename_run(
TEST_DIR "dir1", TEST_DIR "dir2", ++command_id, PB_CommandStatus_OK);
mu_check(!test_is_exists(TEST_DIR "dir1"));
mu_check(test_is_exists(TEST_DIR "dir2"));
}
MU_TEST(test_ping) {
MsgList_t input_msg_list;
MsgList_init(input_msg_list);
@ -1196,7 +1291,7 @@ MU_TEST(test_ping) {
// 3) test for one push of several packets
// 4) test for fill buffer till end (great varint) and close connection
MU_TEST_SUITE(test_rpc_status) {
MU_TEST_SUITE(test_rpc_system) {
MU_SUITE_CONFIGURE(&test_rpc_setup, &test_rpc_teardown);
MU_RUN_TEST(test_ping);
@ -1205,6 +1300,7 @@ MU_TEST_SUITE(test_rpc_status) {
MU_TEST_SUITE(test_rpc_storage) {
MU_SUITE_CONFIGURE(&test_rpc_storage_setup, &test_rpc_storage_teardown);
MU_RUN_TEST(test_storage_info);
MU_RUN_TEST(test_storage_stat);
MU_RUN_TEST(test_storage_list);
MU_RUN_TEST(test_storage_read);
@ -1214,6 +1310,7 @@ MU_TEST_SUITE(test_rpc_storage) {
MU_RUN_TEST(test_storage_delete_recursive);
MU_RUN_TEST(test_storage_mkdir);
MU_RUN_TEST(test_storage_md5sum);
MU_RUN_TEST(test_storage_rename);
MU_RUN_TEST(test_storage_interrupt_continuous_same_system);
MU_RUN_TEST(test_storage_interrupt_continuous_another_system);
}
@ -1230,16 +1327,14 @@ static void test_app_create_request(
request->has_next = false;
if(app_name) {
char* msg_app_name = furi_alloc(strlen(app_name) + 1);
strcpy(msg_app_name, app_name);
char* msg_app_name = strdup(app_name);
request->content.app_start_request.name = msg_app_name;
} else {
request->content.app_start_request.name = NULL;
}
if(app_args) {
char* msg_app_args = furi_alloc(strlen(app_args) + 1);
strcpy(msg_app_args, app_args);
char* msg_app_args = strdup(app_args);
request->content.app_start_request.args = msg_app_args;
} else {
request->content.app_start_request.args = NULL;
@ -1339,7 +1434,7 @@ int run_minunit_test_rpc() {
MU_RUN_SUITE(test_rpc_storage);
}
MU_RUN_SUITE(test_rpc_status);
MU_RUN_SUITE(test_rpc_system);
MU_RUN_SUITE(test_rpc_app);
return MU_EXIT_CODE;

View File

@ -18,12 +18,12 @@ make all
- `NAME` - mandatory - Asset name in CamelCase. [A-Za-z0-9], special symbols not allowed
- `VARIANT` - optional - icon variant: can relate to state or rendering conditions. Examples: active, inactive, inverted.
- `SIZE` - mandatory - size in px. Example squere 10, 20, 24, etc. Example rectangular: 10x8, 19x5, etc.
- `SIZE` - mandatory - size in px. Example square 10, 20, 24, etc. Example rectangular: 10x8, 19x5, etc.
Image names will be automatically prefixed with `I_`, animation names with `A_`.
Icons and Animations will be gathered into `icon.h` and `icon.c`.
# Important notes
Don't include assets that you are not using, compiller is not going to strip unusued assets.
Don't include assets that you are not using, compiler is not going to strip unused assets.

View File

@ -13,7 +13,7 @@ PROTOBUF_SOURCES := $(shell find $(PROTOBUF_SOURCE_DIR) -type f -iname '*.proto
#PROTOBUF_FILENAMES := $(notdir $(PROTOBUF))
PROTOBUF_FILENAMES := $(notdir $(addsuffix .pb.c,$(basename $(PROTOBUF_SOURCES))))
PROTOBUF := $(addprefix $(PROTOBUF_COMPILED_DIR)/,$(PROTOBUF_FILENAMES))
PROTOBUF_CFLAGS += -DPB_ENABLE_MALLOC -DPB_WITHOUT_64BIT
PROTOBUF_CFLAGS += -DPB_ENABLE_MALLOC
CFLAGS += -I$(ASSETS_COMPILED_DIR) $(PROTOBUF_CFLAGS)
C_SOURCES += $(wildcard $(ASSETS_COMPILED_DIR)/*.c)

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
#pragma once
#include <gui/icon.h>
extern const Icon I_Certification2_119x30;
extern const Icon I_Certification1_103x23;
extern const Icon I_Certification2_119x30;
extern const Icon A_BadBattery_128x51;
extern const Icon A_BoxActive_128x51;
extern const Icon A_Box_128x51;
@ -14,8 +14,8 @@ extern const Icon A_CryActive_128x51;
extern const Icon A_Cry_128x51;
extern const Icon A_KnifeActive_128x51;
extern const Icon A_Knife_128x51;
extern const Icon A_LaptopActive_128x51;
extern const Icon A_Laptop_128x51;
extern const Icon A_LaptopActive_128x52;
extern const Icon A_Laptop_128x52;
extern const Icon A_LeavingActive_128x51;
extern const Icon A_Leaving_128x51;
extern const Icon A_Level1FurippaActive_128x51;
@ -36,100 +36,100 @@ extern const Icon A_Level3HijackActive_128x51;
extern const Icon A_Level3Hijack_128x51;
extern const Icon A_Level3LabActive_128x51;
extern const Icon A_Level3Lab_128x51;
extern const Icon I_LevelUp2_03;
extern const Icon I_LevelUp2_02;
extern const Icon I_LevelUp2_05;
extern const Icon I_LevelUp2_04;
extern const Icon I_LevelUp2_01;
extern const Icon I_LevelUp2_06;
extern const Icon I_LevelUp2_07;
extern const Icon I_LevelUp2_06;
extern const Icon I_LevelUp2_04;
extern const Icon I_LevelUp2_05;
extern const Icon I_LevelUp2_01;
extern const Icon I_LevelUp2_02;
extern const Icon I_LevelUp2_03;
extern const Icon I_LevelUp3_05;
extern const Icon I_LevelUp3_06;
extern const Icon I_LevelUp3_02;
extern const Icon I_LevelUp3_07;
extern const Icon I_LevelUp3_04;
extern const Icon I_LevelUp3_06;
extern const Icon I_LevelUp3_07;
extern const Icon I_LevelUp3_03;
extern const Icon I_LevelUp3_02;
extern const Icon I_LevelUp3_01;
extern const Icon A_LevelUpPending_128x51;
extern const Icon A_NoSdCard_128x51;
extern const Icon A_SleepActive_128x51;
extern const Icon A_Sleep_128x51;
extern const Icon A_TVActive_128x51;
extern const Icon A_TV_128x51;
extern const Icon A_WavesActive_128x51;
extern const Icon A_Waves_128x51;
extern const Icon I_ble_10px;
extern const Icon I_ibutt_10px;
extern const Icon I_125_10px;
extern const Icon I_sub1_10px;
extern const Icon A_SleepActive_128x52;
extern const Icon A_Sleep_128x52;
extern const Icon A_TvActive_128x52;
extern const Icon A_Tv_128x52;
extern const Icon A_WavesActive_128x52;
extern const Icon A_Waves_128x52;
extern const Icon I_dir_10px;
extern const Icon I_ir_10px;
extern const Icon I_Nfc_10px;
extern const Icon I_sub1_10px;
extern const Icon I_ir_10px;
extern const Icon I_ibutt_10px;
extern const Icon I_unknown_10px;
extern const Icon I_ble_10px;
extern const Icon I_125_10px;
extern const Icon I_BLE_Pairing_128x64;
extern const Icon I_EviSmile2_18x21;
extern const Icon I_EviSmile1_18x21;
extern const Icon I_UsbTree_48x22;
extern const Icon I_EviWaiting1_18x21;
extern const Icon I_EviWaiting2_18x21;
extern const Icon I_Percent_10x14;
extern const Icon I_Smile_18x18;
extern const Icon I_Error_18x18;
extern const Icon I_Clock_18x18;
extern const Icon I_Smile_18x18;
extern const Icon I_EviSmile1_18x21;
extern const Icon I_Percent_10x14;
extern const Icon I_Error_18x18;
extern const Icon I_EviWaiting1_18x21;
extern const Icon I_EviSmile2_18x21;
extern const Icon I_ButtonRightSmall_3x5;
extern const Icon I_ButtonLeft_4x7;
extern const Icon I_ButtonLeftSmall_3x5;
extern const Icon I_ButtonCenter_7x7;
extern const Icon I_DFU_128x50;
extern const Icon I_Warning_30x23;
extern const Icon I_ButtonDown_7x4;
extern const Icon I_ButtonRight_4x7;
extern const Icon I_DFU_128x50;
extern const Icon I_ButtonCenter_7x7;
extern const Icon I_ButtonUp_7x4;
extern const Icon I_Warning_30x23;
extern const Icon I_ButtonLeft_4x7;
extern const Icon I_DolphinFirstStart7_61x51;
extern const Icon I_DolphinOkay_41x43;
extern const Icon I_DolphinFirstStart5_54x49;
extern const Icon I_Flipper_young_80x60;
extern const Icon I_DolphinFirstStart2_59x51;
extern const Icon I_DolphinFirstStart8_56x51;
extern const Icon I_DolphinFirstStart3_57x48;
extern const Icon I_DolphinFirstStart0_70x53;
extern const Icon I_DolphinFirstStart4_67x53;
extern const Icon I_DolphinFirstStart2_59x51;
extern const Icon I_DolphinFirstStart5_54x49;
extern const Icon I_DolphinFirstStart0_70x53;
extern const Icon I_DolphinFirstStart6_58x54;
extern const Icon I_DolphinFirstStart1_59x53;
extern const Icon I_ArrowDownFilled_14x15;
extern const Icon I_ArrowUpEmpty_14x15;
extern const Icon I_DolphinFirstStart8_56x51;
extern const Icon I_DolphinFirstStart7_61x51;
extern const Icon I_Flipper_young_80x60;
extern const Icon I_DolphinFirstStart3_57x48;
extern const Icon I_ArrowUpFilled_14x15;
extern const Icon I_ArrowUpEmpty_14x15;
extern const Icon I_ArrowDownEmpty_14x15;
extern const Icon I_DoorLocked_10x56;
extern const Icon I_ArrowDownFilled_14x15;
extern const Icon I_PassportBottom_128x17;
extern const Icon I_PassportLeft_6x47;
extern const Icon I_DoorLocked_10x56;
extern const Icon I_DoorLeft_70x55;
extern const Icon I_LockPopup_100x49;
extern const Icon I_PassportLeft_6x47;
extern const Icon I_DoorRight_70x55;
extern const Icon I_IrdaArrowDown_4x8;
extern const Icon I_Power_25x27;
extern const Icon I_LockPopup_100x49;
extern const Icon I_Mute_25x27;
extern const Icon I_Down_hvr_25x27;
extern const Icon I_Vol_up_25x27;
extern const Icon I_IrdaLearnShort_128x31;
extern const Icon I_Up_25x27;
extern const Icon I_Vol_down_hvr_25x27;
extern const Icon I_Vol_down_25x27;
extern const Icon I_Vol_up_hvr_25x27;
extern const Icon I_Fill_marker_7x7;
extern const Icon I_Up_hvr_25x27;
extern const Icon I_IrdaArrowUp_4x8;
extern const Icon I_Down_25x27;
extern const Icon I_Up_hvr_25x27;
extern const Icon I_DolphinReadingSuccess_59x63;
extern const Icon I_IrdaSendShort_128x34;
extern const Icon I_IrdaLearn_128x64;
extern const Icon I_Mute_hvr_25x27;
extern const Icon I_IrdaSend_128x64;
extern const Icon I_Vol_down_25x27;
extern const Icon I_Down_25x27;
extern const Icon I_Power_hvr_25x27;
extern const Icon I_IrdaLearnShort_128x31;
extern const Icon I_IrdaArrowDown_4x8;
extern const Icon I_Vol_down_hvr_25x27;
extern const Icon I_IrdaLearn_128x64;
extern const Icon I_Down_hvr_25x27;
extern const Icon I_Fill_marker_7x7;
extern const Icon I_Power_25x27;
extern const Icon I_Vol_up_25x27;
extern const Icon I_Up_25x27;
extern const Icon I_Back_15x10;
extern const Icon I_KeySaveSelected_24x11;
extern const Icon I_IrdaSend_128x64;
extern const Icon I_IrdaSendShort_128x34;
extern const Icon I_Vol_up_hvr_25x27;
extern const Icon I_KeySave_24x11;
extern const Icon I_KeyBackspaceSelected_16x9;
extern const Icon I_KeySaveSelected_24x11;
extern const Icon I_KeyBackspace_16x9;
extern const Icon A_125khz_14;
extern const Icon A_BadUsb_14;
@ -148,45 +148,56 @@ extern const Icon A_Sub1ghz_14;
extern const Icon A_Tamagotchi_14;
extern const Icon A_U2F_14;
extern const Icon A_iButton_14;
extern const Icon I_Medium_chip_22x21;
extern const Icon I_Detailed_chip_17x13;
extern const Icon I_Medium_chip_22x21;
extern const Icon I_passport_happy1_46x49;
extern const Icon I_passport_bad3_46x49;
extern const Icon I_passport_okay2_46x49;
extern const Icon I_passport_bad2_46x49;
extern const Icon I_passport_okay3_46x49;
extern const Icon I_passport_bottom_128x18;
extern const Icon I_passport_bad1_46x49;
extern const Icon I_passport_happy3_46x49;
extern const Icon I_passport_happy2_46x49;
extern const Icon I_passport_okay1_46x49;
extern const Icon I_passport_left_6x46;
extern const Icon I_Health_16x16;
extern const Icon I_Voltage_16x16;
extern const Icon I_BatteryBody_52x28;
extern const Icon I_FaceNormal_29x14;
extern const Icon I_FaceCharging_29x14;
extern const Icon I_Battery_16x16;
extern const Icon I_FaceConfused_29x14;
extern const Icon I_BatteryBody_52x28;
extern const Icon I_Voltage_16x16;
extern const Icon I_Temperature_16x16;
extern const Icon I_FaceNopower_29x14;
extern const Icon I_FaceNormal_29x14;
extern const Icon I_Battery_16x16;
extern const Icon I_FaceConfused_29x14;
extern const Icon I_RFIDDolphinSuccess_108x57;
extern const Icon I_RFIDBigChip_37x36;
extern const Icon I_RFIDDolphinReceive_97x61;
extern const Icon I_RFIDDolphinSend_97x61;
extern const Icon I_SDError_43x35;
extern const Icon I_RFIDDolphinReceive_97x61;
extern const Icon I_SDQuestion_35x43;
extern const Icon I_SDError_43x35;
extern const Icon I_Cry_dolph_55x52;
extern const Icon I_Battery_19x8;
extern const Icon I_SDcardFail_11x8;
extern const Icon I_Bluetooth_5x8;
extern const Icon I_PlaceholderR_30x13;
extern const Icon I_Battery_26x8;
extern const Icon I_Lock_8x8;
extern const Icon I_SDcardMounted_11x8;
extern const Icon I_BadUsb_9x8;
extern const Icon I_BT_Pair_9x8;
extern const Icon I_PlaceholderR_30x13;
extern const Icon I_Lock_8x8;
extern const Icon I_Battery_26x8;
extern const Icon I_PlaceholderL_11x13;
extern const Icon I_Background_128x11;
extern const Icon I_Battery_19x8;
extern const Icon I_SDcardMounted_11x8;
extern const Icon I_SDcardFail_11x8;
extern const Icon I_USBConnected_15x8;
extern const Icon I_Quest_7x8;
extern const Icon I_MHz_25x11;
extern const Icon I_Bluetooth_5x8;
extern const Icon I_BT_Pair_9x8;
extern const Icon I_Background_128x11;
extern const Icon I_Scanning_123x52;
extern const Icon I_Quest_7x8;
extern const Icon I_Unlock_7x8;
extern const Icon I_MHz_25x11;
extern const Icon I_Lock_7x8;
extern const Icon I_DolphinNice_96x59;
extern const Icon I_iButtonDolphinSuccess_109x60;
extern const Icon I_DolphinExcited_64x63;
extern const Icon I_iButtonKey_49x44;
extern const Icon I_iButtonDolphinVerySuccess_108x52;
extern const Icon I_DolphinWait_61x59;
extern const Icon I_DolphinMafia_115x62;
extern const Icon I_DolphinExcited_64x63;
extern const Icon I_iButtonDolphinSuccess_109x60;
extern const Icon I_iButtonDolphinVerySuccess_108x52;
extern const Icon I_iButtonKey_49x44;
extern const Icon I_DolphinNice_96x59;
extern const Icon I_DolphinWait_61x59;

View File

@ -5,7 +5,7 @@
#define PB_PB_FLIPPER_PB_H_INCLUDED
#include <pb.h>
#include "storage.pb.h"
#include "status.pb.h"
#include "system.pb.h"
#include "application.pb.h"
#include "gui.pb.h"
@ -62,8 +62,8 @@ typedef struct _PB_Main {
pb_size_t which_content;
union {
PB_Empty empty;
PB_Status_PingRequest ping_request;
PB_Status_PingResponse ping_response;
PB_System_PingRequest system_ping_request;
PB_System_PingResponse system_ping_response;
PB_Storage_ListRequest storage_list_request;
PB_Storage_ListResponse storage_list_response;
PB_Storage_ReadRequest storage_read_request;
@ -85,6 +85,12 @@ typedef struct _PB_Main {
PB_Storage_StatResponse storage_stat_response;
PB_Gui_StartVirtualDisplayRequest gui_start_virtual_display_request;
PB_Gui_StopVirtualDisplayRequest gui_stop_virtual_display_request;
PB_Storage_InfoRequest storage_info_request;
PB_Storage_InfoResponse storage_info_response;
PB_Storage_RenameRequest storage_rename_request;
PB_System_RebootRequest system_reboot_request;
PB_System_DeviceInfoRequest system_device_info_request;
PB_System_DeviceInfoResponse system_device_info_response;
} content;
} PB_Main;
@ -112,8 +118,8 @@ extern "C" {
#define PB_Main_command_status_tag 2
#define PB_Main_has_next_tag 3
#define PB_Main_empty_tag 4
#define PB_Main_ping_request_tag 5
#define PB_Main_ping_response_tag 6
#define PB_Main_system_ping_request_tag 5
#define PB_Main_system_ping_response_tag 6
#define PB_Main_storage_list_request_tag 7
#define PB_Main_storage_list_response_tag 8
#define PB_Main_storage_read_request_tag 9
@ -135,6 +141,12 @@ extern "C" {
#define PB_Main_storage_stat_response_tag 25
#define PB_Main_gui_start_virtual_display_request_tag 26
#define PB_Main_gui_stop_virtual_display_request_tag 27
#define PB_Main_storage_info_request_tag 28
#define PB_Main_storage_info_response_tag 29
#define PB_Main_storage_rename_request_tag 30
#define PB_Main_system_reboot_request_tag 31
#define PB_Main_system_device_info_request_tag 32
#define PB_Main_system_device_info_response_tag 33
/* Struct field encoding specification for nanopb */
#define PB_Empty_FIELDLIST(X, a) \
@ -152,8 +164,8 @@ X(a, STATIC, SINGULAR, UINT32, command_id, 1) \
X(a, STATIC, SINGULAR, UENUM, command_status, 2) \
X(a, STATIC, SINGULAR, BOOL, has_next, 3) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,empty,content.empty), 4) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,ping_request,content.ping_request), 5) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,ping_response,content.ping_response), 6) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_ping_request,content.system_ping_request), 5) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_ping_response,content.system_ping_response), 6) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_list_request,content.storage_list_request), 7) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_list_response,content.storage_list_response), 8) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_read_request,content.storage_read_request), 9) \
@ -174,12 +186,18 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_send_input_event_request,content
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_request,content.storage_stat_request), 24) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_stat_response,content.storage_stat_response), 25) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_start_virtual_display_request,content.gui_start_virtual_display_request), 26) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_virtual_display_request,content.gui_stop_virtual_display_request), 27)
X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_virtual_display_request,content.gui_stop_virtual_display_request), 27) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_info_request,content.storage_info_request), 28) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_info_response,content.storage_info_response), 29) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_rename_request,content.storage_rename_request), 30) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_reboot_request,content.system_reboot_request), 31) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_device_info_request,content.system_device_info_request), 32) \
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_device_info_response,content.system_device_info_response), 33)
#define PB_Main_CALLBACK NULL
#define PB_Main_DEFAULT NULL
#define PB_Main_content_empty_MSGTYPE PB_Empty
#define PB_Main_content_ping_request_MSGTYPE PB_Status_PingRequest
#define PB_Main_content_ping_response_MSGTYPE PB_Status_PingResponse
#define PB_Main_content_system_ping_request_MSGTYPE PB_System_PingRequest
#define PB_Main_content_system_ping_response_MSGTYPE PB_System_PingResponse
#define PB_Main_content_storage_list_request_MSGTYPE PB_Storage_ListRequest
#define PB_Main_content_storage_list_response_MSGTYPE PB_Storage_ListResponse
#define PB_Main_content_storage_read_request_MSGTYPE PB_Storage_ReadRequest
@ -201,6 +219,12 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,gui_stop_virtual_display_request,con
#define PB_Main_content_storage_stat_response_MSGTYPE PB_Storage_StatResponse
#define PB_Main_content_gui_start_virtual_display_request_MSGTYPE PB_Gui_StartVirtualDisplayRequest
#define PB_Main_content_gui_stop_virtual_display_request_MSGTYPE PB_Gui_StopVirtualDisplayRequest
#define PB_Main_content_storage_info_request_MSGTYPE PB_Storage_InfoRequest
#define PB_Main_content_storage_info_response_MSGTYPE PB_Storage_InfoResponse
#define PB_Main_content_storage_rename_request_MSGTYPE PB_Storage_RenameRequest
#define PB_Main_content_system_reboot_request_MSGTYPE PB_System_RebootRequest
#define PB_Main_content_system_device_info_request_MSGTYPE PB_System_DeviceInfoRequest
#define PB_Main_content_system_device_info_response_MSGTYPE PB_System_DeviceInfoResponse
extern const pb_msgdesc_t PB_Empty_msg;
extern const pb_msgdesc_t PB_StopSession_msg;
@ -214,9 +238,9 @@ extern const pb_msgdesc_t PB_Main_msg;
/* Maximum encoded size of messages (where known) */
#define PB_Empty_size 0
#define PB_StopSession_size 0
#if defined(PB_Status_PingRequest_size) && defined(PB_Status_PingResponse_size) && defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size)
#if defined(PB_System_PingRequest_size) && defined(PB_System_PingResponse_size) && defined(PB_Storage_ListRequest_size) && defined(PB_Storage_ListResponse_size) && defined(PB_Storage_ReadRequest_size) && defined(PB_Storage_ReadResponse_size) && defined(PB_Storage_WriteRequest_size) && defined(PB_Storage_DeleteRequest_size) && defined(PB_Storage_MkdirRequest_size) && defined(PB_Storage_Md5sumRequest_size) && defined(PB_App_StartRequest_size) && defined(PB_Gui_ScreenFrame_size) && defined(PB_Storage_StatRequest_size) && defined(PB_Storage_StatResponse_size) && defined(PB_Storage_InfoRequest_size) && defined(PB_Storage_RenameRequest_size) && defined(PB_System_DeviceInfoResponse_size)
#define PB_Main_size (10 + sizeof(union PB_Main_content_size_union))
union PB_Main_content_size_union {char f5[(6 + PB_Status_PingRequest_size)]; char f6[(6 + PB_Status_PingResponse_size)]; char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f0[36];};
union PB_Main_content_size_union {char f5[(6 + PB_System_PingRequest_size)]; char f6[(6 + PB_System_PingResponse_size)]; char f7[(6 + PB_Storage_ListRequest_size)]; char f8[(6 + PB_Storage_ListResponse_size)]; char f9[(6 + PB_Storage_ReadRequest_size)]; char f10[(6 + PB_Storage_ReadResponse_size)]; char f11[(6 + PB_Storage_WriteRequest_size)]; char f12[(6 + PB_Storage_DeleteRequest_size)]; char f13[(6 + PB_Storage_MkdirRequest_size)]; char f14[(6 + PB_Storage_Md5sumRequest_size)]; char f16[(7 + PB_App_StartRequest_size)]; char f22[(7 + PB_Gui_ScreenFrame_size)]; char f24[(7 + PB_Storage_StatRequest_size)]; char f25[(7 + PB_Storage_StatResponse_size)]; char f28[(7 + PB_Storage_InfoRequest_size)]; char f30[(7 + PB_Storage_RenameRequest_size)]; char f33[(7 + PB_System_DeviceInfoResponse_size)]; char f0[36];};
#endif
#ifdef __cplusplus

View File

@ -9,6 +9,12 @@
PB_BIND(PB_Storage_File, PB_Storage_File, AUTO)
PB_BIND(PB_Storage_InfoRequest, PB_Storage_InfoRequest, AUTO)
PB_BIND(PB_Storage_InfoResponse, PB_Storage_InfoResponse, AUTO)
PB_BIND(PB_Storage_StatRequest, PB_Storage_StatRequest, AUTO)
@ -42,5 +48,8 @@ PB_BIND(PB_Storage_Md5sumRequest, PB_Storage_Md5sumRequest, AUTO)
PB_BIND(PB_Storage_Md5sumResponse, PB_Storage_Md5sumResponse, AUTO)
PB_BIND(PB_Storage_RenameRequest, PB_Storage_RenameRequest, AUTO)

View File

@ -16,6 +16,10 @@ typedef enum _PB_Storage_File_FileType {
} PB_Storage_File_FileType;
/* Struct definitions */
typedef struct _PB_Storage_InfoRequest {
char *path;
} PB_Storage_InfoRequest;
typedef struct _PB_Storage_ListRequest {
char *path;
} PB_Storage_ListRequest;
@ -32,6 +36,11 @@ typedef struct _PB_Storage_ReadRequest {
char *path;
} PB_Storage_ReadRequest;
typedef struct _PB_Storage_RenameRequest {
char *old_path;
char *new_path;
} PB_Storage_RenameRequest;
typedef struct _PB_Storage_StatRequest {
char *path;
} PB_Storage_StatRequest;
@ -48,6 +57,11 @@ typedef struct _PB_Storage_File {
pb_bytes_array_t *data;
} PB_Storage_File;
typedef struct _PB_Storage_InfoResponse {
uint64_t total_space;
uint64_t free_space;
} PB_Storage_InfoResponse;
typedef struct _PB_Storage_Md5sumResponse {
char md5sum[33];
} PB_Storage_Md5sumResponse;
@ -86,6 +100,8 @@ extern "C" {
/* Initializer values for message structs */
#define PB_Storage_File_init_default {_PB_Storage_File_FileType_MIN, NULL, 0, NULL}
#define PB_Storage_InfoRequest_init_default {NULL}
#define PB_Storage_InfoResponse_init_default {0, 0}
#define PB_Storage_StatRequest_init_default {NULL}
#define PB_Storage_StatResponse_init_default {false, PB_Storage_File_init_default}
#define PB_Storage_ListRequest_init_default {NULL}
@ -97,7 +113,10 @@ extern "C" {
#define PB_Storage_MkdirRequest_init_default {NULL}
#define PB_Storage_Md5sumRequest_init_default {NULL}
#define PB_Storage_Md5sumResponse_init_default {""}
#define PB_Storage_RenameRequest_init_default {NULL, NULL}
#define PB_Storage_File_init_zero {_PB_Storage_File_FileType_MIN, NULL, 0, NULL}
#define PB_Storage_InfoRequest_init_zero {NULL}
#define PB_Storage_InfoResponse_init_zero {0, 0}
#define PB_Storage_StatRequest_init_zero {NULL}
#define PB_Storage_StatResponse_init_zero {false, PB_Storage_File_init_zero}
#define PB_Storage_ListRequest_init_zero {NULL}
@ -109,12 +128,16 @@ extern "C" {
#define PB_Storage_MkdirRequest_init_zero {NULL}
#define PB_Storage_Md5sumRequest_init_zero {NULL}
#define PB_Storage_Md5sumResponse_init_zero {""}
#define PB_Storage_RenameRequest_init_zero {NULL, NULL}
/* Field tags (for use in manual encoding/decoding) */
#define PB_Storage_InfoRequest_path_tag 1
#define PB_Storage_ListRequest_path_tag 1
#define PB_Storage_Md5sumRequest_path_tag 1
#define PB_Storage_MkdirRequest_path_tag 1
#define PB_Storage_ReadRequest_path_tag 1
#define PB_Storage_RenameRequest_old_path_tag 1
#define PB_Storage_RenameRequest_new_path_tag 2
#define PB_Storage_StatRequest_path_tag 1
#define PB_Storage_DeleteRequest_path_tag 1
#define PB_Storage_DeleteRequest_recursive_tag 2
@ -122,6 +145,8 @@ extern "C" {
#define PB_Storage_File_name_tag 2
#define PB_Storage_File_size_tag 3
#define PB_Storage_File_data_tag 4
#define PB_Storage_InfoResponse_total_space_tag 1
#define PB_Storage_InfoResponse_free_space_tag 2
#define PB_Storage_Md5sumResponse_md5sum_tag 1
#define PB_Storage_ListResponse_file_tag 1
#define PB_Storage_ReadResponse_file_tag 1
@ -138,6 +163,17 @@ X(a, POINTER, SINGULAR, BYTES, data, 4)
#define PB_Storage_File_CALLBACK NULL
#define PB_Storage_File_DEFAULT NULL
#define PB_Storage_InfoRequest_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, STRING, path, 1)
#define PB_Storage_InfoRequest_CALLBACK NULL
#define PB_Storage_InfoRequest_DEFAULT NULL
#define PB_Storage_InfoResponse_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT64, total_space, 1) \
X(a, STATIC, SINGULAR, UINT64, free_space, 2)
#define PB_Storage_InfoResponse_CALLBACK NULL
#define PB_Storage_InfoResponse_DEFAULT NULL
#define PB_Storage_StatRequest_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, STRING, path, 1)
#define PB_Storage_StatRequest_CALLBACK NULL
@ -199,7 +235,15 @@ X(a, STATIC, SINGULAR, STRING, md5sum, 1)
#define PB_Storage_Md5sumResponse_CALLBACK NULL
#define PB_Storage_Md5sumResponse_DEFAULT NULL
#define PB_Storage_RenameRequest_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, STRING, old_path, 1) \
X(a, POINTER, SINGULAR, STRING, new_path, 2)
#define PB_Storage_RenameRequest_CALLBACK NULL
#define PB_Storage_RenameRequest_DEFAULT NULL
extern const pb_msgdesc_t PB_Storage_File_msg;
extern const pb_msgdesc_t PB_Storage_InfoRequest_msg;
extern const pb_msgdesc_t PB_Storage_InfoResponse_msg;
extern const pb_msgdesc_t PB_Storage_StatRequest_msg;
extern const pb_msgdesc_t PB_Storage_StatResponse_msg;
extern const pb_msgdesc_t PB_Storage_ListRequest_msg;
@ -211,9 +255,12 @@ extern const pb_msgdesc_t PB_Storage_DeleteRequest_msg;
extern const pb_msgdesc_t PB_Storage_MkdirRequest_msg;
extern const pb_msgdesc_t PB_Storage_Md5sumRequest_msg;
extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg;
extern const pb_msgdesc_t PB_Storage_RenameRequest_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define PB_Storage_File_fields &PB_Storage_File_msg
#define PB_Storage_InfoRequest_fields &PB_Storage_InfoRequest_msg
#define PB_Storage_InfoResponse_fields &PB_Storage_InfoResponse_msg
#define PB_Storage_StatRequest_fields &PB_Storage_StatRequest_msg
#define PB_Storage_StatResponse_fields &PB_Storage_StatResponse_msg
#define PB_Storage_ListRequest_fields &PB_Storage_ListRequest_msg
@ -225,9 +272,11 @@ extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg;
#define PB_Storage_MkdirRequest_fields &PB_Storage_MkdirRequest_msg
#define PB_Storage_Md5sumRequest_fields &PB_Storage_Md5sumRequest_msg
#define PB_Storage_Md5sumResponse_fields &PB_Storage_Md5sumResponse_msg
#define PB_Storage_RenameRequest_fields &PB_Storage_RenameRequest_msg
/* Maximum encoded size of messages (where known) */
/* PB_Storage_File_size depends on runtime parameters */
/* PB_Storage_InfoRequest_size depends on runtime parameters */
/* PB_Storage_StatRequest_size depends on runtime parameters */
/* PB_Storage_StatResponse_size depends on runtime parameters */
/* PB_Storage_ListRequest_size depends on runtime parameters */
@ -238,6 +287,8 @@ extern const pb_msgdesc_t PB_Storage_Md5sumResponse_msg;
/* PB_Storage_DeleteRequest_size depends on runtime parameters */
/* PB_Storage_MkdirRequest_size depends on runtime parameters */
/* PB_Storage_Md5sumRequest_size depends on runtime parameters */
/* PB_Storage_RenameRequest_size depends on runtime parameters */
#define PB_Storage_InfoResponse_size 22
#define PB_Storage_Md5sumResponse_size 34
#ifdef __cplusplus

View File

@ -0,0 +1,25 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5 */
#include "system.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(PB_System_PingRequest, PB_System_PingRequest, AUTO)
PB_BIND(PB_System_PingResponse, PB_System_PingResponse, AUTO)
PB_BIND(PB_System_RebootRequest, PB_System_RebootRequest, AUTO)
PB_BIND(PB_System_DeviceInfoRequest, PB_System_DeviceInfoRequest, AUTO)
PB_BIND(PB_System_DeviceInfoResponse, PB_System_DeviceInfoResponse, AUTO)

121
assets/compiled/system.pb.h Normal file
View File

@ -0,0 +1,121 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5 */
#ifndef PB_PB_SYSTEM_SYSTEM_PB_H_INCLUDED
#define PB_PB_SYSTEM_SYSTEM_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _PB_System_RebootRequest_RebootMode {
PB_System_RebootRequest_RebootMode_OS = 0,
PB_System_RebootRequest_RebootMode_DFU = 1
} PB_System_RebootRequest_RebootMode;
/* Struct definitions */
typedef struct _PB_System_DeviceInfoRequest {
char dummy_field;
} PB_System_DeviceInfoRequest;
typedef struct _PB_System_DeviceInfoResponse {
char *key;
char *value;
} PB_System_DeviceInfoResponse;
typedef struct _PB_System_PingRequest {
pb_bytes_array_t *data;
} PB_System_PingRequest;
typedef struct _PB_System_PingResponse {
pb_bytes_array_t *data;
} PB_System_PingResponse;
typedef struct _PB_System_RebootRequest {
PB_System_RebootRequest_RebootMode mode;
} PB_System_RebootRequest;
/* Helper constants for enums */
#define _PB_System_RebootRequest_RebootMode_MIN PB_System_RebootRequest_RebootMode_OS
#define _PB_System_RebootRequest_RebootMode_MAX PB_System_RebootRequest_RebootMode_DFU
#define _PB_System_RebootRequest_RebootMode_ARRAYSIZE ((PB_System_RebootRequest_RebootMode)(PB_System_RebootRequest_RebootMode_DFU+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define PB_System_PingRequest_init_default {NULL}
#define PB_System_PingResponse_init_default {NULL}
#define PB_System_RebootRequest_init_default {_PB_System_RebootRequest_RebootMode_MIN}
#define PB_System_DeviceInfoRequest_init_default {0}
#define PB_System_DeviceInfoResponse_init_default {NULL, NULL}
#define PB_System_PingRequest_init_zero {NULL}
#define PB_System_PingResponse_init_zero {NULL}
#define PB_System_RebootRequest_init_zero {_PB_System_RebootRequest_RebootMode_MIN}
#define PB_System_DeviceInfoRequest_init_zero {0}
#define PB_System_DeviceInfoResponse_init_zero {NULL, NULL}
/* Field tags (for use in manual encoding/decoding) */
#define PB_System_DeviceInfoResponse_key_tag 1
#define PB_System_DeviceInfoResponse_value_tag 2
#define PB_System_PingRequest_data_tag 1
#define PB_System_PingResponse_data_tag 1
#define PB_System_RebootRequest_mode_tag 1
/* Struct field encoding specification for nanopb */
#define PB_System_PingRequest_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, BYTES, data, 1)
#define PB_System_PingRequest_CALLBACK NULL
#define PB_System_PingRequest_DEFAULT NULL
#define PB_System_PingResponse_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, BYTES, data, 1)
#define PB_System_PingResponse_CALLBACK NULL
#define PB_System_PingResponse_DEFAULT NULL
#define PB_System_RebootRequest_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, mode, 1)
#define PB_System_RebootRequest_CALLBACK NULL
#define PB_System_RebootRequest_DEFAULT NULL
#define PB_System_DeviceInfoRequest_FIELDLIST(X, a) \
#define PB_System_DeviceInfoRequest_CALLBACK NULL
#define PB_System_DeviceInfoRequest_DEFAULT NULL
#define PB_System_DeviceInfoResponse_FIELDLIST(X, a) \
X(a, POINTER, SINGULAR, STRING, key, 1) \
X(a, POINTER, SINGULAR, STRING, value, 2)
#define PB_System_DeviceInfoResponse_CALLBACK NULL
#define PB_System_DeviceInfoResponse_DEFAULT NULL
extern const pb_msgdesc_t PB_System_PingRequest_msg;
extern const pb_msgdesc_t PB_System_PingResponse_msg;
extern const pb_msgdesc_t PB_System_RebootRequest_msg;
extern const pb_msgdesc_t PB_System_DeviceInfoRequest_msg;
extern const pb_msgdesc_t PB_System_DeviceInfoResponse_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define PB_System_PingRequest_fields &PB_System_PingRequest_msg
#define PB_System_PingResponse_fields &PB_System_PingResponse_msg
#define PB_System_RebootRequest_fields &PB_System_RebootRequest_msg
#define PB_System_DeviceInfoRequest_fields &PB_System_DeviceInfoRequest_msg
#define PB_System_DeviceInfoResponse_fields &PB_System_DeviceInfoResponse_msg
/* Maximum encoded size of messages (where known) */
/* PB_System_PingRequest_size depends on runtime parameters */
/* PB_System_PingResponse_size depends on runtime parameters */
/* PB_System_DeviceInfoResponse_size depends on runtime parameters */
#define PB_System_DeviceInfoRequest_size 0
#define PB_System_RebootRequest_size 2
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Some files were not shown because too many files have changed in this diff Show More