Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX
2024-05-21 01:34:05 +03:00
78 changed files with 1510 additions and 453 deletions
+1
View File
@@ -34,6 +34,7 @@ env.Append(
File("protocols/mf_ultralight/mf_ultralight_poller.h"),
File("protocols/mf_classic/mf_classic_poller.h"),
File("protocols/mf_desfire/mf_desfire_poller.h"),
File("protocols/slix/slix_poller.h"),
File("protocols/emv/emv_poller.h"),
File("protocols/st25tb/st25tb_poller.h"),
File("protocols/felica/felica_poller.h"),
+1 -1
View File
@@ -660,4 +660,4 @@ NfcError nfc_felica_listener_set_sensf_res_data(
return nfc_process_hal_error(error);
}
#endif // APP_UNIT_TESTS
#endif // FW_CFG_unit_tests
+476
View File
@@ -0,0 +1,476 @@
#ifdef FW_CFG_unit_tests
#include <lib/nfc/nfc.h>
#include <lib/nfc/helpers/iso14443_crc.h>
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a.h>
#include <furi/furi.h>
#define NFC_MAX_BUFFER_SIZE (256)
typedef enum {
NfcTransportLogLevelWarning,
NfcTransportLogLevelInfo,
} NfcTransportLogLevel;
FuriMessageQueue* poller_queue = NULL;
FuriMessageQueue* listener_queue = NULL;
typedef enum {
NfcMessageTypeTx,
NfcMessageTypeTimeout,
NfcMessageTypeAbort,
} NfcMessageType;
typedef struct {
uint16_t data_bits;
uint8_t data[NFC_MAX_BUFFER_SIZE];
} NfcMessageData;
typedef struct {
NfcMessageType type;
NfcMessageData data;
} NfcMessage;
typedef enum {
NfcStateIdle,
NfcStateReady,
NfcStateReset,
} NfcState;
typedef enum {
Iso14443_3aColResStatusIdle,
Iso14443_3aColResStatusInProgress,
Iso14443_3aColResStatusDone,
} Iso14443_3aColResStatus;
typedef struct {
Iso14443_3aSensResp sens_resp;
Iso14443_3aSddResp sdd_resp[2];
Iso14443_3aSelResp sel_resp[2];
} Iso14443_3aColResData;
struct Nfc {
NfcState state;
Iso14443_3aColResStatus col_res_status;
Iso14443_3aColResData col_res_data;
bool software_col_res_required;
NfcEventCallback callback;
void* context;
NfcMode mode;
FuriThread* worker_thread;
};
static void nfc_test_print(
NfcTransportLogLevel log_level,
const char* message,
uint8_t* buffer,
uint16_t bits) {
FuriString* str = furi_string_alloc();
size_t bytes = (bits + 7) / 8;
for(size_t i = 0; i < bytes; i++) {
furi_string_cat_printf(str, " %02X", buffer[i]);
}
if(log_level == NfcTransportLogLevelWarning) {
FURI_LOG_W(message, "%s", furi_string_get_cstr(str));
} else {
FURI_LOG_I(message, "%s", furi_string_get_cstr(str));
}
furi_string_free(str);
}
static void nfc_prepare_col_res_data(
Nfc* instance,
uint8_t* uid,
uint8_t uid_len,
uint8_t* atqa,
uint8_t sak) {
memcpy(instance->col_res_data.sens_resp.sens_resp, atqa, 2);
if(uid_len == 7) {
instance->col_res_data.sdd_resp[0].nfcid[0] = 0x88;
memcpy(&instance->col_res_data.sdd_resp[0].nfcid[1], uid, 3);
uint8_t bss = 0;
for(size_t i = 0; i < 4; i++) {
bss ^= instance->col_res_data.sdd_resp[0].nfcid[i];
}
instance->col_res_data.sdd_resp[0].bss = bss;
instance->col_res_data.sel_resp[0].sak = 0x04;
memcpy(instance->col_res_data.sdd_resp[1].nfcid, &uid[3], 4);
bss = 0;
for(size_t i = 0; i < 4; i++) {
bss ^= instance->col_res_data.sdd_resp[1].nfcid[i];
}
instance->col_res_data.sdd_resp[1].bss = bss;
instance->col_res_data.sel_resp[1].sak = sak;
} else {
furi_crash("Not supporting not 7 bytes");
}
}
Nfc* nfc_alloc(void) {
Nfc* instance = malloc(sizeof(Nfc));
return instance;
}
void nfc_free(Nfc* instance) {
furi_check(instance);
free(instance);
}
void nfc_config(Nfc* instance, NfcMode mode, NfcTech tech) {
UNUSED(instance);
UNUSED(tech);
instance->mode = mode;
}
void nfc_set_fdt_poll_fc(Nfc* instance, uint32_t fdt_poll_fc) {
UNUSED(instance);
UNUSED(fdt_poll_fc);
}
void nfc_set_fdt_listen_fc(Nfc* instance, uint32_t fdt_listen_fc) {
UNUSED(instance);
UNUSED(fdt_listen_fc);
}
void nfc_set_mask_receive_time_fc(Nfc* instance, uint32_t mask_rx_time_fc) {
UNUSED(instance);
UNUSED(mask_rx_time_fc);
}
void nfc_set_fdt_poll_poll_us(Nfc* instance, uint32_t fdt_poll_poll_us) {
UNUSED(instance);
UNUSED(fdt_poll_poll_us);
}
void nfc_set_guard_time_us(Nfc* instance, uint32_t guard_time_us) {
UNUSED(instance);
UNUSED(guard_time_us);
}
NfcError nfc_iso14443a_listener_set_col_res_data(
Nfc* instance,
uint8_t* uid,
uint8_t uid_len,
uint8_t* atqa,
uint8_t sak) {
furi_check(instance);
furi_check(uid);
furi_check(atqa);
nfc_prepare_col_res_data(instance, uid, uid_len, atqa, sak);
instance->software_col_res_required = true;
return NfcErrorNone;
}
static int32_t nfc_worker_poller(void* context) {
Nfc* instance = context;
furi_check(instance->callback);
instance->state = NfcStateReady;
NfcCommand command = NfcCommandContinue;
NfcEvent event = {};
while(true) {
event.type = NfcEventTypePollerReady;
command = instance->callback(event, instance->context);
if(command == NfcCommandStop) {
break;
}
}
instance->state = NfcStateIdle;
return 0;
}
static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, uint16_t rx_bits) {
furi_check(instance->col_res_status != Iso14443_3aColResStatusDone);
BitBuffer* tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
bool processed = false;
if((rx_bits == 7) && (rx_data[0] == 0x52)) {
instance->col_res_status = Iso14443_3aColResStatusInProgress;
bit_buffer_copy_bytes(
tx_buffer,
instance->col_res_data.sens_resp.sens_resp,
sizeof(instance->col_res_data.sens_resp.sens_resp));
nfc_listener_tx(instance, tx_buffer);
processed = true;
} else if(rx_bits == 2 * 8) {
if((rx_data[0] == 0x93) && (rx_data[1] == 0x20)) {
bit_buffer_copy_bytes(
tx_buffer,
(const uint8_t*)&instance->col_res_data.sdd_resp[0],
sizeof(Iso14443_3aSddResp));
nfc_listener_tx(instance, tx_buffer);
processed = true;
} else if((rx_data[0] == 0x95) && (rx_data[1] == 0x20)) {
bit_buffer_copy_bytes(
tx_buffer,
(const uint8_t*)&instance->col_res_data.sdd_resp[1],
sizeof(Iso14443_3aSddResp));
nfc_listener_tx(instance, tx_buffer);
processed = true;
}
} else if(rx_bits == 9 * 8) {
if((rx_data[0] == 0x93) && (rx_data[1] == 0x70)) {
bit_buffer_set_size_bytes(tx_buffer, 1);
bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[0].sak);
iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
nfc_listener_tx(instance, tx_buffer);
processed = true;
} else if((rx_data[0] == 0x95) && (rx_data[1] == 0x70)) {
bit_buffer_set_size_bytes(tx_buffer, 1);
bit_buffer_set_byte(tx_buffer, 0, instance->col_res_data.sel_resp[1].sak);
iso14443_crc_append(Iso14443CrcTypeA, tx_buffer);
nfc_listener_tx(instance, tx_buffer);
instance->col_res_status = Iso14443_3aColResStatusDone;
NfcEvent event = {.type = NfcEventTypeListenerActivated};
instance->callback(event, instance->context);
processed = true;
}
}
if(!processed) {
NfcMessage message = {.type = NfcMessageTypeTimeout};
furi_message_queue_put(poller_queue, &message, FuriWaitForever);
}
bit_buffer_free(tx_buffer);
}
static int32_t nfc_worker_listener(void* context) {
Nfc* instance = context;
furi_check(instance->callback);
NfcMessage message = {};
NfcEventData event_data = {};
event_data.buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE);
NfcEvent nfc_event = {.data = event_data};
while(true) {
furi_message_queue_get(listener_queue, &message, FuriWaitForever);
bit_buffer_copy_bits(event_data.buffer, message.data.data, message.data.data_bits);
if((message.data.data[0] == 0x52) && (message.data.data_bits == 7)) {
instance->col_res_status = Iso14443_3aColResStatusIdle;
}
if(message.type == NfcMessageTypeAbort) {
break;
} else if(message.type == NfcMessageTypeTx) {
nfc_test_print(
NfcTransportLogLevelInfo, "RDR", message.data.data, message.data.data_bits);
if(instance->software_col_res_required &&
(instance->col_res_status != Iso14443_3aColResStatusDone)) {
nfc_worker_listener_pass_col_res(
instance, message.data.data, message.data.data_bits);
} else {
instance->state = NfcStateReady;
nfc_event.type = NfcEventTypeRxEnd;
instance->callback(nfc_event, instance->context);
}
}
}
instance->state = NfcStateIdle;
instance->col_res_status = Iso14443_3aColResStatusIdle;
memset(&instance->col_res_data, 0, sizeof(instance->col_res_data));
bit_buffer_free(nfc_event.data.buffer);
return 0;
}
void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) {
furi_check(instance);
furi_check(instance->worker_thread == NULL);
if(instance->mode == NfcModeListener) {
furi_check(listener_queue == NULL);
// Check that poller didn't start
furi_check(poller_queue == NULL);
} else {
furi_check(poller_queue == NULL);
// Check that poller is started after listener
furi_check(listener_queue);
}
instance->callback = callback;
instance->context = context;
if(instance->mode == NfcModeListener) {
listener_queue = furi_message_queue_alloc(4, sizeof(NfcMessage));
} else {
poller_queue = furi_message_queue_alloc(4, sizeof(NfcMessage));
}
instance->worker_thread = furi_thread_alloc();
furi_thread_set_context(instance->worker_thread, instance);
furi_thread_set_priority(instance->worker_thread, FuriThreadPriorityHigh);
furi_thread_set_stack_size(instance->worker_thread, 8 * 1024);
if(instance->mode == NfcModeListener) {
furi_thread_set_name(instance->worker_thread, "NfcWorkerListener");
furi_thread_set_callback(instance->worker_thread, nfc_worker_listener);
} else {
furi_thread_set_name(instance->worker_thread, "NfcWorkerPoller");
furi_thread_set_callback(instance->worker_thread, nfc_worker_poller);
}
furi_thread_start(instance->worker_thread);
}
void nfc_stop(Nfc* instance) {
furi_check(instance);
furi_check(instance->worker_thread);
if(instance->mode == NfcModeListener) {
NfcMessage message = {.type = NfcMessageTypeAbort};
furi_message_queue_put(listener_queue, &message, FuriWaitForever);
furi_thread_join(instance->worker_thread);
furi_message_queue_free(listener_queue);
listener_queue = NULL;
furi_thread_free(instance->worker_thread);
instance->worker_thread = NULL;
} else {
furi_thread_join(instance->worker_thread);
furi_message_queue_free(poller_queue);
poller_queue = NULL;
furi_thread_free(instance->worker_thread);
instance->worker_thread = NULL;
}
}
// Called from worker thread
NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) {
furi_check(instance);
furi_check(poller_queue);
furi_check(listener_queue);
furi_check(tx_buffer);
NfcMessage message = {};
message.type = NfcMessageTypeTx;
message.data.data_bits = bit_buffer_get_size(tx_buffer);
bit_buffer_write_bytes(tx_buffer, message.data.data, bit_buffer_get_size_bytes(tx_buffer));
furi_message_queue_put(poller_queue, &message, FuriWaitForever);
return NfcErrorNone;
}
NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* tx_buffer) {
return nfc_listener_tx(instance, tx_buffer);
}
NfcError
nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) {
furi_check(instance);
furi_check(tx_buffer);
furi_check(rx_buffer);
furi_check(poller_queue);
furi_check(listener_queue);
UNUSED(fwt);
NfcError error = NfcErrorNone;
NfcMessage message = {};
message.type = NfcMessageTypeTx;
message.data.data_bits = bit_buffer_get_size(tx_buffer);
bit_buffer_write_bytes(tx_buffer, message.data.data, bit_buffer_get_size_bytes(tx_buffer));
// Tx
furi_check(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk);
// Rx
FuriStatus status = furi_message_queue_get(poller_queue, &message, 50);
if(status == FuriStatusErrorTimeout) {
error = NfcErrorTimeout;
} else if(message.type == NfcMessageTypeTx) {
bit_buffer_copy_bits(rx_buffer, message.data.data, message.data.data_bits);
nfc_test_print(
NfcTransportLogLevelWarning, "TAG", message.data.data, message.data.data_bits);
} else if(message.type == NfcMessageTypeTimeout) {
error = NfcErrorTimeout;
}
return error;
}
NfcError nfc_iso14443a_poller_trx_custom_parity(
Nfc* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
return nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt);
}
// Technology specific API
NfcError nfc_iso14443a_poller_trx_short_frame(
Nfc* instance,
NfcIso14443aShortFrame frame,
BitBuffer* rx_buffer,
uint32_t fwt) {
UNUSED(frame);
BitBuffer* tx_buffer = bit_buffer_alloc(32);
bit_buffer_set_size(tx_buffer, 7);
bit_buffer_set_byte(tx_buffer, 0, 0x52);
NfcError error = nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt);
bit_buffer_free(tx_buffer);
return error;
}
NfcError nfc_iso14443a_poller_trx_sdd_frame(
Nfc* instance,
const BitBuffer* tx_buffer,
BitBuffer* rx_buffer,
uint32_t fwt) {
return nfc_poller_trx(instance, tx_buffer, rx_buffer, fwt);
}
NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) {
UNUSED(instance);
return NfcErrorNone;
}
NfcError nfc_felica_listener_set_sensf_res_data(
Nfc* instance,
const uint8_t* idm,
const uint8_t idm_len,
const uint8_t* pmm,
const uint8_t pmm_len) {
furi_assert(instance);
furi_assert(idm);
furi_assert(pmm);
furi_assert(idm_len == 8);
furi_assert(pmm_len == 8);
return NfcErrorNone;
}
#endif
+1
View File
@@ -27,6 +27,7 @@ env.Append(
File("subghz_protocol_registry.h"),
File("devices/cc1101_configs.h"),
File("devices/cc1101_int/cc1101_int_interconnect.h"),
File("subghz_file_encoder_worker.h"),
],
)
+3
View File
@@ -35,6 +35,9 @@ env.Append(
File("simple_array.h"),
File("bit_buffer.h"),
File("keys_dict.h"),
File("pulse_protocols/pulse_glue.h"),
File("md5_calc.h"),
File("varint.h"),
],
)
+97 -74
View File
@@ -3,6 +3,9 @@
#include <furi.h>
#include <lib/heatshrink/heatshrink_encoder.h>
#include <lib/heatshrink/heatshrink_decoder.h>
#include <stdint.h>
#define TAG "Compress"
/** Defines encoder and decoder window size */
#define COMPRESS_EXP_BUFF_SIZE_LOG (8u)
@@ -10,9 +13,16 @@
/** Defines encoder and decoder lookahead buffer size */
#define COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG (4u)
/** Buffer sizes for input and output data */
#define COMPRESS_ICON_ENCODED_BUFF_SIZE (1024u)
#define COMPRESS_ICON_DECODED_BUFF_SIZE (1024u)
/** Buffer size for input data */
#define COMPRESS_ICON_ENCODED_BUFF_SIZE (256u)
static bool compress_decode_internal(
heatshrink_decoder* decoder,
const uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size);
typedef struct {
uint8_t is_compressed;
@@ -24,55 +34,51 @@ _Static_assert(sizeof(CompressHeader) == 4, "Incorrect CompressHeader size");
struct CompressIcon {
heatshrink_decoder* decoder;
uint8_t decoded_buff[COMPRESS_ICON_DECODED_BUFF_SIZE];
uint8_t* buffer;
size_t buffer_size;
};
CompressIcon* compress_icon_alloc(void) {
CompressIcon* compress_icon_alloc(size_t decode_buf_size) {
CompressIcon* instance = malloc(sizeof(CompressIcon));
instance->decoder = heatshrink_decoder_alloc(
COMPRESS_ICON_ENCODED_BUFF_SIZE,
COMPRESS_EXP_BUFF_SIZE_LOG,
COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
heatshrink_decoder_reset(instance->decoder);
memset(instance->decoded_buff, 0, sizeof(instance->decoded_buff));
instance->buffer_size = decode_buf_size + 4; /* To account for heatshrink's poller quirks */
instance->buffer = malloc(instance->buffer_size);
return instance;
}
void compress_icon_free(CompressIcon* instance) {
furi_check(instance);
free(instance->buffer);
heatshrink_decoder_free(instance->decoder);
free(instance);
}
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff) {
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** output) {
furi_check(instance);
furi_check(icon_data);
furi_check(decoded_buff);
furi_check(output);
CompressHeader* header = (CompressHeader*)icon_data;
if(header->is_compressed) {
size_t data_processed = 0;
heatshrink_decoder_sink(
size_t decoded_size = 0;
/* If decompression fails - check that decode_buf_size is large enough */
furi_check(compress_decode_internal(
instance->decoder,
(uint8_t*)&icon_data[sizeof(CompressHeader)],
header->compressed_buff_size,
&data_processed);
while(1) {
HSD_poll_res res = heatshrink_decoder_poll(
instance->decoder,
instance->decoded_buff,
sizeof(instance->decoded_buff),
&data_processed);
furi_check((res == HSDR_POLL_EMPTY) || (res == HSDR_POLL_MORE));
if(res != HSDR_POLL_MORE) {
break;
}
}
heatshrink_decoder_reset(instance->decoder);
*decoded_buff = instance->decoded_buff;
icon_data,
/* Decoder will check/process headers again - need to pass them */
sizeof(CompressHeader) + header->compressed_buff_size,
instance->buffer,
instance->buffer_size,
&decoded_size));
*output = instance->buffer;
} else {
*decoded_buff = (uint8_t*)&icon_data[1];
*output = (uint8_t*)&icon_data[1];
}
}
@@ -81,12 +87,6 @@ struct Compress {
heatshrink_decoder* decoder;
};
static void compress_reset(Compress* compress) {
furi_assert(compress);
heatshrink_encoder_reset(compress->encoder);
heatshrink_decoder_reset(compress->decoder);
}
Compress* compress_alloc(uint16_t compress_buff_size) {
Compress* compress = malloc(sizeof(Compress));
compress->encoder =
@@ -105,16 +105,16 @@ void compress_free(Compress* compress) {
free(compress);
}
bool compress_encode(
Compress* compress,
static bool compress_encode_internal(
heatshrink_encoder* encoder,
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);
furi_check(encoder);
furi_check(data_in);
furi_check(data_in_size);
size_t sink_size = 0;
size_t poll_size = 0;
@@ -125,10 +125,10 @@ bool compress_encode(
size_t sunk = 0;
size_t res_buff_size = sizeof(CompressHeader);
// Sink data to encoding buffer
/* 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);
sink_res =
heatshrink_encoder_sink(encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
if(sink_res != HSER_SINK_OK) {
encode_failed = true;
break;
@@ -136,10 +136,7 @@ bool compress_encode(
sunk += sink_size;
do {
poll_res = heatshrink_encoder_poll(
compress->encoder,
&data_out[res_buff_size],
data_out_size - res_buff_size,
&poll_size);
encoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
if(poll_res < 0) {
encode_failed = true;
break;
@@ -148,31 +145,30 @@ bool compress_encode(
} while(poll_res == HSER_POLL_MORE);
}
// Notify sinking complete and poll encoded data
finish_res = heatshrink_encoder_finish(compress->encoder);
/* Notify sinking complete and poll encoded data */
finish_res = heatshrink_encoder_finish(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);
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;
finish_res = heatshrink_encoder_finish(compress->encoder);
finish_res = heatshrink_encoder_finish(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
/* Write encoded data to output buffer if compression is efficient. Otherwise, write header and original data */
if(!encode_failed && (res_buff_size < data_in_size + 1)) {
CompressHeader header = {
.is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size};
.is_compressed = 0x01,
.reserved = 0x00,
.compressed_buff_size = res_buff_size - sizeof(CompressHeader)};
memcpy(data_out, &header, sizeof(header));
*data_res_size = res_buff_size;
} else if(data_out_size > data_in_size) {
@@ -183,22 +179,21 @@ bool compress_encode(
*data_res_size = 0;
result = false;
}
compress_reset(compress);
heatshrink_encoder_reset(encoder);
return result;
}
bool compress_decode(
Compress* compress,
uint8_t* data_in,
static bool compress_decode_internal(
heatshrink_decoder* decoder,
const 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);
furi_check(decoder);
furi_check(data_in);
furi_check(data_out);
furi_check(data_res_size);
bool result = false;
bool decode_failed = false;
@@ -211,12 +206,15 @@ bool compress_decode(
CompressHeader* header = (CompressHeader*)data_in;
if(header->is_compressed) {
// Sink data to decoding buffer
/* Sink data to decoding buffer */
size_t compressed_size = header->compressed_buff_size;
size_t sunk = sizeof(CompressHeader);
size_t sunk = 0;
while(sunk < compressed_size && !decode_failed) {
sink_res = heatshrink_decoder_sink(
compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size);
decoder,
(uint8_t*)&data_in[sizeof(CompressHeader) + sunk],
compressed_size - sunk,
&sink_size);
if(sink_res < 0) {
decode_failed = true;
break;
@@ -224,25 +222,28 @@ bool compress_decode(
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) {
decoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
if((poll_res < 0) || ((data_out_size - res_buff_size) == 0)) {
decode_failed = true;
break;
}
res_buff_size += poll_size;
} while(poll_res == HSDR_POLL_MORE);
}
// Notify sinking complete and poll decoded data
/* Notify sinking complete and poll decoded data */
if(!decode_failed) {
finish_res = heatshrink_decoder_finish(compress->decoder);
finish_res = heatshrink_decoder_finish(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);
decoder,
&data_out[res_buff_size],
data_out_size - res_buff_size,
&poll_size);
res_buff_size += poll_size;
finish_res = heatshrink_decoder_finish(compress->decoder);
finish_res = heatshrink_decoder_finish(decoder);
} while(finish_res != HSDR_FINISH_DONE);
}
}
@@ -253,9 +254,31 @@ bool compress_decode(
*data_res_size = data_in_size - 1;
result = true;
} else {
/* Not enough space in output buffer */
result = false;
}
compress_reset(compress);
heatshrink_decoder_reset(decoder);
return result;
}
bool compress_encode(
Compress* compress,
uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
return compress_encode_internal(
compress->encoder, data_in, data_in_size, data_out, data_out_size, data_res_size);
}
bool compress_decode(
Compress* compress,
uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
return compress_decode_internal(
compress->decoder, data_in, data_in_size, data_out, data_out_size, data_res_size);
}
+12 -6
View File
@@ -16,10 +16,14 @@ extern "C" {
typedef struct CompressIcon CompressIcon;
/** Initialize icon compressor
*
* @param[in] decode_buf_size The icon buffer size for decoding. Ensure that
* it's big enough for any icons that you are
* planning to decode with it.
*
* @return Compress Icon instance
*/
CompressIcon* compress_icon_alloc(void);
CompressIcon* compress_icon_alloc(size_t decode_buf_size);
/** Free icon compressor
*
@@ -29,14 +33,16 @@ void compress_icon_free(CompressIcon* instance);
/** Decompress icon
*
* @warning decoded_buff pointer set by this function is valid till next
* @warning output pointer set by this function is valid till next
* `compress_icon_decode` or `compress_icon_free` call
*
* @param instance The Compress Icon instance
* @param icon_data pointer to icon data
* @param[in] decoded_buff pointer to decoded buffer pointer
* @param instance The Compress Icon instance
* @param icon_data pointer to icon data.
* @param[in] output pointer to decoded buffer pointer. Data in buffer is
* valid till next call. If icon data was not compressed,
* pointer within icon_data is returned
*/
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff);
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** output);
/** Compress control structure */
typedef struct Compress Compress;