[FL-1922] Assets compression (#773)
* lib: add heatshrink compress library * canvas: new icons format * scripts: add icons compression to assets generation script * assets: update assets * furi-hal: introduce furi-hal-compress * canvas: rework icon drawing with furi-hal-compress * lib: rework heatshrink lib for dynamic buffer allocation API * furi-hal-compress: add encode and decode API * furi-hal-compress: working decode * furi-hal-compress: support f6 target * scripts: format sources * furi-hal-compress: fix incorrect encoder reset * furi-hal: add compress initialization to f6 target Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
221
firmware/targets/f6/furi-hal/furi-hal-compress.c
Normal file
221
firmware/targets/f6/furi-hal/furi-hal-compress.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <furi-hal-compress.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/heatshrink/heatshrink_encoder.h>
|
||||
#include <lib/heatshrink/heatshrink_decoder.h>
|
||||
|
||||
#define FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE (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 = furi_alloc(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("FuriHalCompress", "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(
|
||||
heatshrink_decoder_poll(
|
||||
icon_decoder->decoder,
|
||||
icon_decoder->decoded_buff,
|
||||
sizeof(icon_decoder->decoded_buff),
|
||||
&data_processed) == HSDR_POLL_MORE
|
||||
) {};
|
||||
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 = furi_alloc(sizeof(FuriHalCompress));
|
||||
compress->compress_buff = furi_alloc(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;
|
||||
}
|
@@ -48,6 +48,7 @@ void furi_hal_init() {
|
||||
furi_hal_nfc_init();
|
||||
furi_hal_rfid_init();
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FreeRTOS glue
|
||||
furi_hal_os_init();
|
||||
|
221
firmware/targets/f7/furi-hal/furi-hal-compress.c
Normal file
221
firmware/targets/f7/furi-hal/furi-hal-compress.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <furi-hal-compress.h>
|
||||
|
||||
#include <furi.h>
|
||||
#include <lib/heatshrink/heatshrink_encoder.h>
|
||||
#include <lib/heatshrink/heatshrink_decoder.h>
|
||||
|
||||
#define FURI_HAL_COMPRESS_ICON_ENCODED_BUFF_SIZE (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 = furi_alloc(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("FuriHalCompress", "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(
|
||||
heatshrink_decoder_poll(
|
||||
icon_decoder->decoder,
|
||||
icon_decoder->decoded_buff,
|
||||
sizeof(icon_decoder->decoded_buff),
|
||||
&data_processed) == HSDR_POLL_MORE
|
||||
) {};
|
||||
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 = furi_alloc(sizeof(FuriHalCompress));
|
||||
compress->compress_buff = furi_alloc(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;
|
||||
}
|
@@ -48,6 +48,7 @@ void furi_hal_init() {
|
||||
furi_hal_nfc_init();
|
||||
furi_hal_rfid_init();
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FreeRTOS glue
|
||||
furi_hal_os_init();
|
||||
|
67
firmware/targets/furi-hal-include/furi-hal-compress.h
Normal file
67
firmware/targets/furi-hal-include/furi-hal-compress.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file furi-hal-compress.h
|
||||
* LZSS based compression HAL API
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Defines encoder and decoder window size */
|
||||
#define FURI_HAL_COMPRESS_EXP_BUFF_SIZE_LOG (8)
|
||||
|
||||
/** Defines encoder and decoder lookahead buffer size */
|
||||
#define FURI_HAL_COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG (4)
|
||||
|
||||
/** FuriHalCompress control structure */
|
||||
typedef struct FuriHalCompress FuriHalCompress;
|
||||
|
||||
/** Initialize icon decoder
|
||||
*/
|
||||
void furi_hal_compress_icon_init();
|
||||
|
||||
/** Icon decoder
|
||||
*
|
||||
* @param icon_data pointer to icon data
|
||||
* @param decoded_buff pointer to decoded buffer
|
||||
*/
|
||||
void furi_hal_compress_icon_decode(const uint8_t* icon_data, uint8_t** decoded_buff);
|
||||
|
||||
/** Allocate encoder and decoder
|
||||
*
|
||||
* @param compress_buff_size size of decoder and encoder buffer to allocate
|
||||
*
|
||||
* @return FuriHalCompress instance
|
||||
*/
|
||||
FuriHalCompress* furi_hal_compress_alloc(uint16_t compress_buff_size);
|
||||
|
||||
/** Free encoder and decoder
|
||||
*
|
||||
* @param compress FuriHalCompress instance
|
||||
*/
|
||||
void furi_hal_compress_free(FuriHalCompress* compress);
|
||||
|
||||
/** Encode data
|
||||
*
|
||||
* @param compress FuriHalCompress instance
|
||||
* @param data_in pointer to input data
|
||||
* @param data_in_size size of input data
|
||||
* @param data_out maximum size of output data
|
||||
* @param data_res_size pointer to result output data size
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
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);
|
||||
|
||||
/** Decode data
|
||||
*
|
||||
* @param compress FuriHalCompress instance
|
||||
* @param data_in pointer to input data
|
||||
* @param data_in_size size of input data
|
||||
* @param data_out maximum size of output data
|
||||
* @param data_res_size pointer to result output data size
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
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);
|
@@ -35,6 +35,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
|
||||
#include "furi-hal-nfc.h"
|
||||
#include "furi-hal-usb.h"
|
||||
#include "furi-hal-usb-hid.h"
|
||||
#include "furi-hal-compress.h"
|
||||
|
||||
/** Init furi-hal */
|
||||
void furi_hal_init();
|
||||
|
Reference in New Issue
Block a user