[FL-3152] Screen streaming improvements (#2498)
* Rpc: reserve some bandwidth when screen streaming * Move furi_hal_compress to toolbox/comporess * Lib: heatshrink as external submodule, compile warnings fixes, better buffer management * Lib: cleanup compressor definitions * Rpc: add canvas orientation support * Format Sources
This commit is contained in:
@@ -62,7 +62,6 @@ Header,+,firmware/targets/furi_hal_include/furi_hal.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_compress.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,,
|
||||
Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,,
|
||||
@@ -1057,12 +1056,6 @@ Function,-,furi_hal_clock_resume_tick,void,
|
||||
Function,-,furi_hal_clock_suspend_tick,void,
|
||||
Function,-,furi_hal_clock_switch_to_hsi,void,
|
||||
Function,-,furi_hal_clock_switch_to_pll,void,
|
||||
Function,-,furi_hal_compress_alloc,FuriHalCompress*,uint16_t
|
||||
Function,-,furi_hal_compress_decode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
|
||||
Function,-,furi_hal_compress_encode,_Bool,"FuriHalCompress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
|
||||
Function,-,furi_hal_compress_free,void,FuriHalCompress*
|
||||
Function,-,furi_hal_compress_icon_decode,void,"const uint8_t*, uint8_t**"
|
||||
Function,-,furi_hal_compress_icon_init,void,
|
||||
Function,+,furi_hal_console_disable,void,
|
||||
Function,+,furi_hal_console_enable,void,
|
||||
Function,+,furi_hal_console_init,void,
|
||||
|
|
@@ -8,29 +8,20 @@
|
||||
|
||||
void furi_hal_init_early() {
|
||||
furi_hal_cortex_init_early();
|
||||
|
||||
furi_hal_clock_init_early();
|
||||
|
||||
furi_hal_resources_init_early();
|
||||
|
||||
furi_hal_os_init();
|
||||
|
||||
furi_hal_spi_config_init_early();
|
||||
|
||||
furi_hal_i2c_init_early();
|
||||
furi_hal_light_init();
|
||||
|
||||
furi_hal_rtc_init_early();
|
||||
}
|
||||
|
||||
void furi_hal_deinit_early() {
|
||||
furi_hal_rtc_deinit_early();
|
||||
|
||||
furi_hal_i2c_deinit_early();
|
||||
furi_hal_spi_config_deinit_early();
|
||||
|
||||
furi_hal_resources_deinit_early();
|
||||
|
||||
furi_hal_clock_deinit_early();
|
||||
}
|
||||
|
||||
@@ -39,41 +30,24 @@ void furi_hal_init() {
|
||||
furi_hal_clock_init();
|
||||
furi_hal_console_init();
|
||||
furi_hal_rtc_init();
|
||||
|
||||
furi_hal_interrupt_init();
|
||||
|
||||
furi_hal_flash_init();
|
||||
|
||||
furi_hal_resources_init();
|
||||
FURI_LOG_I(TAG, "GPIO OK");
|
||||
|
||||
furi_hal_version_init();
|
||||
furi_hal_region_init();
|
||||
|
||||
furi_hal_spi_config_init();
|
||||
furi_hal_spi_dma_init();
|
||||
|
||||
furi_hal_ibutton_init();
|
||||
FURI_LOG_I(TAG, "iButton OK");
|
||||
furi_hal_speaker_init();
|
||||
FURI_LOG_I(TAG, "Speaker OK");
|
||||
|
||||
furi_hal_crypto_init();
|
||||
|
||||
furi_hal_i2c_init();
|
||||
|
||||
// High Level
|
||||
furi_hal_power_init();
|
||||
furi_hal_light_init();
|
||||
|
||||
furi_hal_bt_init();
|
||||
furi_hal_memory_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
#ifndef FURI_RAM_EXEC
|
||||
// USB
|
||||
furi_hal_usb_init();
|
||||
FURI_LOG_I(TAG, "USB OK");
|
||||
furi_hal_vibro_init();
|
||||
furi_hal_subghz_init();
|
||||
furi_hal_nfc_init();
|
||||
|
@@ -1,264 +0,0 @@
|
||||
#include <furi_hal_compress.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/heatshrink/heatshrink_encoder.h>
|
||||
#include <lib/heatshrink/heatshrink_decoder.h>
|
||||
|
||||
#define TAG "FuriHalCompress"
|
||||
|
||||
#define FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE (2 * 512)
|
||||
#define FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE (1024)
|
||||
|
||||
#define FURI_HAL_COMPRESS_EXP_BUFF_SIZE (1 << FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG)
|
||||
|
||||
typedef struct {
|
||||
uint8_t is_compressed;
|
||||
uint8_t reserved;
|
||||
uint16_t compressed_buff_size;
|
||||
} FuriHalCompressHeader;
|
||||
|
||||
typedef struct {
|
||||
heatshrink_decoder* decoder;
|
||||
uint8_t
|
||||
compress_buff[FURI_HAL_COMPRESS_EXP_BUFF_SIZE + FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE];
|
||||
uint8_t decoded_buff[FURI_HAL_COMPRESS_ICON_DECODED_BUFF_SIZE];
|
||||
} FuriHalCompressIcon;
|
||||
|
||||
struct FuriHalCompress {
|
||||
heatshrink_encoder* encoder;
|
||||
heatshrink_decoder* decoder;
|
||||
uint8_t* compress_buff;
|
||||
uint16_t compress_buff_size;
|
||||
};
|
||||
|
||||
static FuriHalCompressIcon* icon_decoder;
|
||||
|
||||
static void furi_hal_compress_reset(FuriHalCompress* compress) {
|
||||
furi_assert(compress);
|
||||
heatshrink_encoder_reset(compress->encoder);
|
||||
heatshrink_decoder_reset(compress->decoder);
|
||||
memset(compress->compress_buff, 0, compress->compress_buff_size);
|
||||
}
|
||||
|
||||
void furi_hal_compress_icon_init() {
|
||||
icon_decoder = malloc(sizeof(FuriHalCompressIcon));
|
||||
icon_decoder->decoder = heatshrink_decoder_alloc(
|
||||
icon_decoder->compress_buff,
|
||||
FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE,
|
||||
FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG,
|
||||
FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
|
||||
heatshrink_decoder_reset(icon_decoder->decoder);
|
||||
memset(icon_decoder->decoded_buff, 0, sizeof(icon_decoder->decoded_buff));
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_compress_icon_decode(const uint8_t* icon_data, uint8_t** decoded_buff) {
|
||||
furi_assert(icon_data);
|
||||
furi_assert(decoded_buff);
|
||||
|
||||
FuriHalCompressHeader* header = (FuriHalCompressHeader*)icon_data;
|
||||
if(header->is_compressed) {
|
||||
size_t data_processed = 0;
|
||||
heatshrink_decoder_sink(
|
||||
icon_decoder->decoder,
|
||||
(uint8_t*)&icon_data[4],
|
||||
header->compressed_buff_size,
|
||||
&data_processed);
|
||||
while(1) {
|
||||
HSD_poll_res res = heatshrink_decoder_poll(
|
||||
icon_decoder->decoder,
|
||||
icon_decoder->decoded_buff,
|
||||
sizeof(icon_decoder->decoded_buff),
|
||||
&data_processed);
|
||||
furi_assert((res == HSDR_POLL_EMPTY) || (res == HSDR_POLL_MORE));
|
||||
if(res != HSDR_POLL_MORE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
heatshrink_decoder_reset(icon_decoder->decoder);
|
||||
memset(icon_decoder->compress_buff, 0, sizeof(icon_decoder->compress_buff));
|
||||
*decoded_buff = icon_decoder->decoded_buff;
|
||||
} else {
|
||||
*decoded_buff = (uint8_t*)&icon_data[1];
|
||||
}
|
||||
}
|
||||
|
||||
FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size) {
|
||||
FuriHalCompress* compress = malloc(sizeof(FuriHalCompress));
|
||||
compress->compress_buff = malloc(compress_buff_size + FURI_HAL_COMPRESS_EXP_BUFF_SIZE);
|
||||
compress->encoder = heatshrink_encoder_alloc(
|
||||
compress->compress_buff,
|
||||
FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG,
|
||||
FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
|
||||
compress->decoder = heatshrink_decoder_alloc(
|
||||
compress->compress_buff,
|
||||
compress_buff_size,
|
||||
FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG,
|
||||
FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
|
||||
|
||||
return compress;
|
||||
}
|
||||
|
||||
void furi_hal_compress_free(FuriHalCompress* compress) {
|
||||
furi_assert(compress);
|
||||
|
||||
heatshrink_encoder_free(compress->encoder);
|
||||
heatshrink_decoder_free(compress->decoder);
|
||||
free(compress->compress_buff);
|
||||
free(compress);
|
||||
}
|
||||
|
||||
bool furi_hal_compress_encode(
|
||||
FuriHalCompress* compress,
|
||||
uint8_t* data_in,
|
||||
size_t data_in_size,
|
||||
uint8_t* data_out,
|
||||
size_t data_out_size,
|
||||
size_t* data_res_size) {
|
||||
furi_assert(compress);
|
||||
furi_assert(data_in);
|
||||
furi_assert(data_in_size);
|
||||
|
||||
size_t sink_size = 0;
|
||||
size_t poll_size = 0;
|
||||
HSE_sink_res sink_res;
|
||||
HSE_poll_res poll_res;
|
||||
HSE_finish_res finish_res;
|
||||
bool encode_failed = false;
|
||||
size_t sunk = 0;
|
||||
size_t res_buff_size = sizeof(FuriHalCompressHeader);
|
||||
|
||||
// Sink data to encoding buffer
|
||||
while((sunk < data_in_size) && !encode_failed) {
|
||||
sink_res = heatshrink_encoder_sink(
|
||||
compress->encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
|
||||
if(sink_res != HSER_SINK_OK) {
|
||||
encode_failed = true;
|
||||
break;
|
||||
}
|
||||
sunk += sink_size;
|
||||
do {
|
||||
poll_res = heatshrink_encoder_poll(
|
||||
compress->encoder,
|
||||
&data_out[res_buff_size],
|
||||
data_out_size - res_buff_size,
|
||||
&poll_size);
|
||||
if(poll_res < 0) {
|
||||
encode_failed = true;
|
||||
break;
|
||||
}
|
||||
res_buff_size += poll_size;
|
||||
} while(poll_res == HSER_POLL_MORE);
|
||||
}
|
||||
|
||||
// Notify sinking complete and poll encoded data
|
||||
finish_res = heatshrink_encoder_finish(compress->encoder);
|
||||
if(finish_res < 0) {
|
||||
encode_failed = true;
|
||||
} else {
|
||||
do {
|
||||
poll_res = heatshrink_encoder_poll(
|
||||
compress->encoder,
|
||||
&data_out[res_buff_size],
|
||||
data_out_size - 4 - res_buff_size,
|
||||
&poll_size);
|
||||
if(poll_res < 0) {
|
||||
encode_failed = true;
|
||||
break;
|
||||
}
|
||||
res_buff_size += poll_size;
|
||||
finish_res = heatshrink_encoder_finish(compress->encoder);
|
||||
} while(finish_res != HSER_FINISH_DONE);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
// Write encoded data to output buffer if compression is efficient. Else - write header and original data
|
||||
if(!encode_failed && (res_buff_size < data_in_size + 1)) {
|
||||
FuriHalCompressHeader header = {
|
||||
.is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size};
|
||||
memcpy(data_out, &header, sizeof(header));
|
||||
*data_res_size = res_buff_size;
|
||||
} else if(data_out_size > data_in_size) {
|
||||
data_out[0] = 0x00;
|
||||
memcpy(&data_out[1], data_in, data_in_size);
|
||||
*data_res_size = data_in_size + 1;
|
||||
} else {
|
||||
*data_res_size = 0;
|
||||
result = false;
|
||||
}
|
||||
furi_hal_compress_reset(compress);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool furi_hal_compress_decode(
|
||||
FuriHalCompress* compress,
|
||||
uint8_t* data_in,
|
||||
size_t data_in_size,
|
||||
uint8_t* data_out,
|
||||
size_t data_out_size,
|
||||
size_t* data_res_size) {
|
||||
furi_assert(compress);
|
||||
furi_assert(data_in);
|
||||
furi_assert(data_out);
|
||||
furi_assert(data_res_size);
|
||||
|
||||
bool result = false;
|
||||
bool decode_failed = false;
|
||||
HSD_sink_res sink_res;
|
||||
HSD_poll_res poll_res;
|
||||
HSD_finish_res finish_res;
|
||||
size_t sink_size = 0;
|
||||
size_t res_buff_size = 0;
|
||||
size_t poll_size = 0;
|
||||
|
||||
FuriHalCompressHeader* header = (FuriHalCompressHeader*)data_in;
|
||||
if(header->is_compressed) {
|
||||
// Sink data to decoding buffer
|
||||
size_t compressed_size = header->compressed_buff_size;
|
||||
size_t sunk = sizeof(FuriHalCompressHeader);
|
||||
while(sunk < compressed_size && !decode_failed) {
|
||||
sink_res = heatshrink_decoder_sink(
|
||||
compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size);
|
||||
if(sink_res < 0) {
|
||||
decode_failed = true;
|
||||
break;
|
||||
}
|
||||
sunk += sink_size;
|
||||
do {
|
||||
poll_res = heatshrink_decoder_poll(
|
||||
compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
|
||||
if(poll_res < 0) {
|
||||
decode_failed = true;
|
||||
break;
|
||||
}
|
||||
res_buff_size += poll_size;
|
||||
} while(poll_res == HSDR_POLL_MORE);
|
||||
}
|
||||
// Notify sinking complete and poll decoded data
|
||||
if(!decode_failed) {
|
||||
finish_res = heatshrink_decoder_finish(compress->decoder);
|
||||
if(finish_res < 0) {
|
||||
decode_failed = true;
|
||||
} else {
|
||||
do {
|
||||
poll_res = heatshrink_decoder_poll(
|
||||
compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
|
||||
res_buff_size += poll_size;
|
||||
finish_res = heatshrink_decoder_finish(compress->decoder);
|
||||
} while(finish_res != HSDR_FINISH_DONE);
|
||||
}
|
||||
}
|
||||
*data_res_size = res_buff_size;
|
||||
result = !decode_failed;
|
||||
} else if(data_out_size >= data_in_size - 1) {
|
||||
memcpy(data_out, &data_in[1], data_in_size);
|
||||
*data_res_size = data_in_size - 1;
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
furi_hal_compress_reset(compress);
|
||||
|
||||
return result;
|
||||
}
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "FuriHalIbutton"
|
||||
#define FURI_HAL_IBUTTON_TIMER TIM1
|
||||
#define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16
|
||||
|
||||
@@ -33,6 +34,8 @@ static void furi_hal_ibutton_emulate_isr() {
|
||||
void furi_hal_ibutton_init() {
|
||||
furi_hal_ibutton = malloc(sizeof(FuriHalIbutton));
|
||||
furi_hal_ibutton->state = FuriHalIbuttonStateIdle;
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_emulate_start(
|
||||
|
@@ -4,6 +4,8 @@
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
|
||||
#define TAG "FuriHalResources"
|
||||
|
||||
const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
|
||||
@@ -190,6 +192,8 @@ void furi_hal_resources_init() {
|
||||
|
||||
NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
NVIC_EnableIRQ(EXTI15_10_IRQn);
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) {
|
||||
|
@@ -4,10 +4,11 @@
|
||||
#include <alt_boot.h>
|
||||
#include <u8g2_glue.h>
|
||||
#include <assets_icons.h>
|
||||
#include <toolbox/compress.h>
|
||||
|
||||
void flipper_boot_dfu_show_splash() {
|
||||
// Initialize
|
||||
furi_hal_compress_icon_init();
|
||||
CompressIcon* compress_icon = compress_icon_alloc();
|
||||
|
||||
u8g2_t* fb = malloc(sizeof(u8g2_t));
|
||||
memset(fb, 0, sizeof(u8g2_t));
|
||||
@@ -15,13 +16,15 @@ void flipper_boot_dfu_show_splash() {
|
||||
u8g2_InitDisplay(fb);
|
||||
u8g2_SetDrawColor(fb, 0x01);
|
||||
uint8_t* splash_data = NULL;
|
||||
furi_hal_compress_icon_decode(icon_get_data(&I_DFU_128x50), &splash_data);
|
||||
compress_icon_decode(compress_icon, icon_get_data(&I_DFU_128x50), &splash_data);
|
||||
u8g2_DrawXBM(fb, 0, 64 - 50, 128, 50, splash_data);
|
||||
u8g2_SetFont(fb, u8g2_font_helvB08_tr);
|
||||
u8g2_DrawStr(fb, 2, 8, "Update & Recovery Mode");
|
||||
u8g2_DrawStr(fb, 2, 21, "DFU Started");
|
||||
u8g2_SetPowerSave(fb, 0);
|
||||
u8g2_SendBuffer(fb);
|
||||
|
||||
compress_icon_free(compress_icon);
|
||||
}
|
||||
|
||||
void flipper_boot_dfu_exec() {
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <alt_boot.h>
|
||||
#include <u8g2_glue.h>
|
||||
#include <assets_icons.h>
|
||||
#include <toolbox/compress.h>
|
||||
|
||||
#define COUNTER_VALUE (136U)
|
||||
|
||||
@@ -27,9 +28,9 @@ void flipper_boot_recovery_exec() {
|
||||
u8g2_Setup_st756x_flipper(fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32);
|
||||
u8g2_InitDisplay(fb);
|
||||
|
||||
furi_hal_compress_icon_init();
|
||||
CompressIcon* compress_icon = compress_icon_alloc();
|
||||
uint8_t* splash_data = NULL;
|
||||
furi_hal_compress_icon_decode(icon_get_data(&I_Erase_pin_128x64), &splash_data);
|
||||
compress_icon_decode(compress_icon, icon_get_data(&I_Erase_pin_128x64), &splash_data);
|
||||
|
||||
u8g2_ClearBuffer(fb);
|
||||
u8g2_SetDrawColor(fb, 0x01);
|
||||
@@ -38,6 +39,7 @@ void flipper_boot_recovery_exec() {
|
||||
u8g2_DrawXBM(fb, 0, 0, 128, 64, splash_data);
|
||||
u8g2_SendBuffer(fb);
|
||||
u8g2_SetPowerSave(fb, 0);
|
||||
compress_icon_free(compress_icon);
|
||||
|
||||
size_t counter = COUNTER_VALUE;
|
||||
while(counter) {
|
||||
|
Reference in New Issue
Block a user