Merge branch 'fz-dev' into dev

This commit is contained in:
MX 2022-08-27 16:17:16 +03:00
commit c714a32ea5
No known key found for this signature in database
GPG key ID: 6C4C311DFD4B4AB5
21 changed files with 522 additions and 63 deletions

View file

@ -281,6 +281,9 @@ void cli_command_free(Cli* cli, string_t args, void* context) {
printf("Total heap size: %d\r\n", memmgr_get_total_heap());
printf("Minimum heap size: %d\r\n", memmgr_get_minimum_free_heap());
printf("Maximum heap block: %d\r\n", memmgr_heap_get_max_free_block());
printf("Pool free: %d\r\n", memmgr_pool_get_free());
printf("Maximum pool block: %d\r\n", memmgr_pool_get_max_block());
}
void cli_command_free_blocks(Cli* cli, string_t args, void* context) {

View file

@ -3,7 +3,7 @@ App(
name="Basic services",
apptype=FlipperAppType.METAPACKAGE,
provides=[
"rpc",
"rpc_start",
"bt",
"desktop",
"loader",

View file

@ -1,12 +1,8 @@
App(
appid="rpc",
name="RpcSrv",
apptype=FlipperAppType.SERVICE,
entry_point="rpc_srv",
appid="rpc_start",
apptype=FlipperAppType.STARTUP,
entry_point="rpc_on_system_start",
cdefines=["SRV_RPC"],
requires=[
"cli",
],
stack_size=4 * 1024,
requires=["cli"],
order=10,
)

View file

@ -395,7 +395,7 @@ void rpc_session_close(RpcSession* session) {
furi_thread_flags_set(furi_thread_get_id(session->thread), RpcEvtDisconnect);
}
int32_t rpc_srv(void* p) {
void rpc_on_system_start(void* p) {
UNUSED(p);
Rpc* rpc = malloc(sizeof(Rpc));
@ -406,8 +406,6 @@ int32_t rpc_srv(void* p) {
cli, "start_rpc_session", CliCommandFlagParallelSafe, rpc_cli_command_start_session, rpc);
furi_record_create(RECORD_RPC, rpc);
return 0;
}
void rpc_add_handler(RpcSession* session, pb_size_t message_tag, RpcHandler* handler) {

View file

@ -14,7 +14,7 @@ extern uint32_t SystemCoreClock;
#define configENABLE_MPU 0
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0

View file

@ -0,0 +1,59 @@
#include "sector_cache.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include <furi_hal_memory.h>
#define SECTOR_SIZE 512
#define N_SECTORS 8
typedef struct {
uint32_t itr;
uint32_t sectors[N_SECTORS];
uint8_t sector_data[N_SECTORS][SECTOR_SIZE];
} SectorCache;
static SectorCache* cache = NULL;
void sector_cache_init() {
if(cache == NULL) {
cache = furi_hal_memory_alloc(sizeof(SectorCache));
}
if(cache != NULL) {
FURI_LOG_I("SectorCache", "Initializing sector cache");
memset(cache, 0, sizeof(SectorCache));
} else {
FURI_LOG_E("SectorCache", "Cannot enable sector cache");
}
}
uint8_t* sector_cache_get(uint32_t n_sector) {
if(cache != NULL && n_sector != 0) {
for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) {
if(cache->sectors[sector_i] == n_sector) {
return cache->sector_data[sector_i];
}
}
}
return NULL;
}
void sector_cache_put(uint32_t n_sector, uint8_t* data) {
if(cache == NULL) return;
cache->sectors[cache->itr % N_SECTORS] = n_sector;
memcpy(cache->sector_data[cache->itr % N_SECTORS], data, SECTOR_SIZE);
cache->itr++;
}
void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) {
if(cache == NULL) return;
for(int sector_i = 0; sector_i < N_SECTORS; ++sector_i) {
if((cache->sectors[sector_i] >= start_sector) &&
(cache->sectors[sector_i] <= end_sector)) {
cache->sectors[sector_i] = 0;
}
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Init sector cache system
*/
void sector_cache_init();
/**
* @brief Get sector data from cache
* @param n_sector Sector number
* @return Pointer to sector data or NULL if not found
*/
uint8_t* sector_cache_get(uint32_t n_sector);
/**
* @brief Put sector data to cache
* @param n_sector Sector number
* @param data Pointer to sector data
*/
void sector_cache_put(uint32_t n_sector, uint8_t* data);
/**
* @brief Invalidate sector cache for given range
* @param start_sector Start sector number
* @param end_sector End sector number
*/
void sector_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector);
#ifdef __cplusplus
}
#endif

View file

@ -92,6 +92,7 @@
#include "string.h"
#include "stdio.h"
#include <furi_hal.h>
#include "sector_cache.h"
/** @addtogroup BSP
* @{
@ -377,6 +378,8 @@ uint8_t BSP_SD_Init(bool reset_card) {
furi_hal_sd_spi_handle = NULL;
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow);
sector_cache_init();
/* SD initialized and set to SPI mode properly */
return res;
}
@ -427,9 +430,15 @@ uint8_t
uint32_t offset = 0;
uint32_t addr;
uint8_t retr = BSP_SD_ERROR;
uint8_t* ptr = NULL;
SD_CmdAnswer_typedef response;
uint16_t BlockSize = 512;
uint8_t* cached_data;
bool single_sector_read = (NumOfBlocks == 1);
if(single_sector_read && (cached_data = sector_cache_get(ReadAddr))) {
memcpy(pData, cached_data, BlockSize);
return BSP_SD_OK;
}
/* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and
Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */
@ -440,12 +449,6 @@ uint8_t
goto error;
}
ptr = malloc(sizeof(uint8_t) * BlockSize);
if(ptr == NULL) {
goto error;
}
memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t) * BlockSize);
/* Initialize the address */
addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize));
@ -461,7 +464,7 @@ uint8_t
/* Now look for the data token to signify the start of the data */
if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) {
/* Read the SD block data : read NumByteToRead data */
SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize);
SD_IO_WriteReadData(NULL, (uint8_t*)pData + offset, BlockSize);
/* Set next read address*/
offset += BlockSize;
@ -479,13 +482,16 @@ uint8_t
SD_IO_WriteByte(SD_DUMMY_BYTE);
}
if(single_sector_read) {
sector_cache_put(ReadAddr, (uint8_t*)pData);
}
retr = BSP_SD_OK;
error:
/* Send dummy byte: 8 Clock pulses of delay */
SD_IO_CSState(1);
SD_IO_WriteByte(SD_DUMMY_BYTE);
if(ptr != NULL) free(ptr);
/* Return the reponse */
return retr;
@ -509,9 +515,9 @@ uint8_t BSP_SD_WriteBlocks(
uint32_t offset = 0;
uint32_t addr;
uint8_t retr = BSP_SD_ERROR;
uint8_t* ptr = NULL;
SD_CmdAnswer_typedef response;
uint16_t BlockSize = 512;
sector_cache_invalidate_range(WriteAddr, WriteAddr + NumOfBlocks);
/* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and
Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */
@ -522,11 +528,6 @@ uint8_t BSP_SD_WriteBlocks(
goto error;
}
ptr = malloc(sizeof(uint8_t) * BlockSize);
if(ptr == NULL) {
goto error;
}
/* Initialize the address */
addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize));
@ -547,7 +548,7 @@ uint8_t BSP_SD_WriteBlocks(
SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE);
/* Write the block data to SD */
SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize);
SD_IO_WriteReadData((uint8_t*)pData + offset, NULL, BlockSize);
/* Set next write address */
offset += BlockSize;
@ -569,7 +570,7 @@ uint8_t BSP_SD_WriteBlocks(
retr = BSP_SD_OK;
error:
if(ptr != NULL) free(ptr);
/* Send dummy byte: 8 Clock pulses of delay */
SD_IO_CSState(1);
SD_IO_WriteByte(SD_DUMMY_BYTE);

View file

@ -1,4 +1,5 @@
#include <furi_hal.h>
#include <furi_hal_memory.h>
#include <stm32wbxx_ll_cortex.h>
@ -75,6 +76,7 @@ void furi_hal_init() {
furi_hal_rfid_init();
#endif
furi_hal_bt_init();
furi_hal_memory_init();
furi_hal_compress_icon_init();
// FatFS driver initialization

View file

@ -0,0 +1,119 @@
#include <furi_hal.h>
#include <furi_hal_memory.h>
#include <furi_hal_rtc.h>
#define TAG "FuriHalMemory"
typedef enum {
SRAM_A,
SRAM_B,
SRAM_MAX,
} SRAM;
typedef struct {
void* start;
uint32_t size;
} FuriHalMemoryRegion;
typedef struct {
FuriHalMemoryRegion region[SRAM_MAX];
} FuriHalMemory;
static FuriHalMemory* furi_hal_memory = NULL;
extern const void __sram2a_start__;
extern const void __sram2a_free__;
extern const void __sram2b_start__;
void furi_hal_memory_init() {
if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) {
return;
}
if(!ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT)) {
FURI_LOG_E(TAG, "C2 start timeout");
return;
}
FuriHalMemory* memory = malloc(sizeof(FuriHalMemory));
const BleGlueC2Info* c2_ver = ble_glue_get_c2_info();
if(c2_ver->mode == BleGlueC2ModeStack) {
uint32_t sram2a_busy_size = (uint32_t)&__sram2a_free__ - (uint32_t)&__sram2a_start__;
uint32_t sram2a_unprotected_size = (32 - c2_ver->MemorySizeSram2A) * 1024;
uint32_t sram2b_unprotected_size = (32 - c2_ver->MemorySizeSram2B) * 1024;
memory->region[SRAM_A].start = (uint8_t*)&__sram2a_free__;
memory->region[SRAM_B].start = (uint8_t*)&__sram2b_start__;
if(sram2a_unprotected_size > sram2a_busy_size) {
memory->region[SRAM_A].size = sram2a_unprotected_size - sram2a_busy_size;
} else {
memory->region[SRAM_A].size = 0;
}
memory->region[SRAM_B].size = sram2b_unprotected_size;
FURI_LOG_I(
TAG, "SRAM2A: 0x%p, %d", memory->region[SRAM_A].start, memory->region[SRAM_A].size);
FURI_LOG_I(
TAG, "SRAM2B: 0x%p, %d", memory->region[SRAM_B].start, memory->region[SRAM_B].size);
if((memory->region[SRAM_A].size > 0) || (memory->region[SRAM_B].size > 0)) {
if((memory->region[SRAM_A].size > 0)) {
FURI_LOG_I(TAG, "SRAM2A clear");
memset(memory->region[SRAM_A].start, 0, memory->region[SRAM_A].size);
}
if((memory->region[SRAM_B].size > 0)) {
FURI_LOG_I(TAG, "SRAM2B clear");
memset(memory->region[SRAM_B].start, 0, memory->region[SRAM_B].size);
}
furi_hal_memory = memory;
FURI_LOG_I(TAG, "Enabled");
} else {
free(memory);
FURI_LOG_E(TAG, "No SRAM2 available");
}
} else {
free(memory);
FURI_LOG_E(TAG, "No Core2 available");
}
}
void* furi_hal_memory_alloc(size_t size) {
if(furi_hal_memory == NULL) {
return NULL;
}
for(int i = 0; i < SRAM_MAX; i++) {
if(furi_hal_memory->region[i].size >= size) {
void* ptr = furi_hal_memory->region[i].start;
furi_hal_memory->region[i].start += size;
furi_hal_memory->region[i].size -= size;
return ptr;
}
}
return NULL;
}
size_t furi_hal_memory_get_free() {
if(furi_hal_memory == NULL) return 0;
size_t free = 0;
for(int i = 0; i < SRAM_MAX; i++) {
free += furi_hal_memory->region[i].size;
}
return free;
}
size_t furi_hal_memory_max_pool_block() {
if(furi_hal_memory == NULL) return 0;
size_t max = 0;
for(int i = 0; i < SRAM_MAX; i++) {
if(furi_hal_memory->region[i].size > max) {
max = furi_hal_memory->region[i].size;
}
}
return max;
}

View file

@ -139,8 +139,6 @@ bool furi_hal_spi_bus_trx(
uint32_t timeout) {
furi_assert(handle);
furi_assert(handle->bus->current_handle == handle);
furi_assert(tx_buffer);
furi_assert(rx_buffer);
furi_assert(size > 0);
bool ret = true;
@ -149,15 +147,23 @@ bool furi_hal_spi_bus_trx(
while(size > 0) {
if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) {
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
tx_buffer++;
if(tx_buffer) {
LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer);
tx_buffer++;
} else {
LL_SPI_TransmitData8(handle->bus->spi, 0xFF);
}
tx_size--;
tx_allowed = false;
}
if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) {
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
rx_buffer++;
if(rx_buffer) {
*rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi);
rx_buffer++;
} else {
LL_SPI_ReceiveData8(handle->bus->spi);
}
size--;
tx_allowed = true;
}

View file

@ -18,6 +18,28 @@
#define TAG "FuriHalSubGhz"
/*
* Uncomment define to enable duplication of
* IO GO0 CC1101 to an external comb.
* Debug pin can be assigned
* gpio_ext_pc0
* gpio_ext_pc1
* gpio_ext_pc3
* gpio_ext_pb2
* gpio_ext_pb3
* gpio_ext_pa4
* gpio_ext_pa6
* gpio_ext_pa7
* Attention this setting switches pin to output.
* Make sure it is not connected directly to power or ground
*/
//#define SUBGHZ_DEBUG_CC1101_PIN gpio_ext_pa7
#ifdef SUBGHZ_DEBUG_CC1101_PIN
uint32_t subghz_debug_gpio_buff[2];
#endif
typedef struct {
volatile SubGhzState state;
volatile SubGhzRegulation regulation;
@ -395,6 +417,9 @@ static void furi_hal_subghz_capture_ISR() {
LL_TIM_ClearFlag_CC1(TIM2);
furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
if(furi_hal_subghz_capture_callback) {
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, false);
#endif
furi_hal_subghz_capture_callback(
true,
furi_hal_subghz_capture_delta_duration,
@ -405,6 +430,9 @@ static void furi_hal_subghz_capture_ISR() {
if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
LL_TIM_ClearFlag_CC2(TIM2);
if(furi_hal_subghz_capture_callback) {
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, true);
#endif
furi_hal_subghz_capture_callback(
false,
LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration,
@ -466,6 +494,11 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(
&SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#endif
// Switch to RX
furi_hal_subghz_rx();
}
@ -479,6 +512,11 @@ void furi_hal_subghz_stop_async_rx() {
FURI_CRITICAL_ENTER();
LL_TIM_DeInit(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#endif
FURI_CRITICAL_EXIT();
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL);
@ -664,6 +702,32 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(
&SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN;
subghz_debug_gpio_buff[0] = gpio->pin;
subghz_debug_gpio_buff[1] = (uint32_t)gpio->pin << GPIO_NUMBER;
dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = 2;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
#endif
return true;
}
@ -695,6 +759,12 @@ void furi_hal_subghz_stop_async_tx() {
// Deinitialize GPIO
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#endif
FURI_CRITICAL_EXIT();
free(furi_hal_subghz_async_tx.buffer);

View file

@ -57,7 +57,8 @@ MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
}
/* Define output sections */
@ -186,9 +187,12 @@ SECTIONS
}
.ARM.attributes 0 : { *(.ARM.attributes) }
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A
._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A
._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B
}

View file

@ -57,7 +57,8 @@ MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM1 (xrw) : ORIGIN = 0x20000000, LENGTH = 0x30000
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
RAM2A (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
RAM2B (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
}
/* Define output sections */
@ -184,9 +185,12 @@ SECTIONS
}
.ARM.attributes 0 : { *(.ARM.attributes) }
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
._sram2a_start : { . = ALIGN(4); __sram2a_start__ = .; } >RAM2A
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM2A
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM2A
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM2A
._sram2a_free : { . = ALIGN(4); __sram2a_free__ = .; } >RAM2A
._sram2b_start : { . = ALIGN(4); __sram2b_start__ = .; } >RAM2B
}

View file

@ -0,0 +1,44 @@
/**
* @file furi_hal_memory.h
* Memory HAL API
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Init memory pool manager
*/
void furi_hal_memory_init();
/**
* @brief Allocate memory from separate memory pool. That memory can't be freed.
*
* @param size
* @return void*
*/
void* furi_hal_memory_alloc(size_t size);
/**
* @brief Get free memory pool size
*
* @return size_t
*/
size_t furi_hal_memory_get_free();
/**
* @brief Get max free block size from memory pool
*
* @return size_t
*/
size_t furi_hal_memory_max_pool_block();
#ifdef __cplusplus
}
#endif

View file

@ -1,6 +1,7 @@
#include "memmgr.h"
#include "common_defines.h"
#include <string.h>
#include <furi_hal_memory.h>
extern void* pvPortMalloc(size_t xSize);
extern void vPortFree(void* pv);
@ -79,3 +80,18 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) {
UNUSED(r);
return realloc(ptr, size);
}
void* memmgr_alloc_from_pool(size_t size) {
void* p = furi_hal_memory_alloc(size);
if(p == NULL) p = malloc(size);
return p;
}
size_t memmgr_pool_get_free(void) {
return furi_hal_memory_get_free();
}
size_t memmgr_pool_get_max_block(void) {
return furi_hal_memory_max_pool_block();
}

View file

@ -35,6 +35,28 @@ size_t memmgr_get_total_heap(void);
*/
size_t memmgr_get_minimum_free_heap(void);
/**
* @brief Allocate memory from separate memory pool. That memory can't be freed.
*
* @param size
* @return void*
*/
void* memmgr_alloc_from_pool(size_t size);
/**
* @brief Get free memory pool size
*
* @return size_t
*/
size_t memmgr_pool_get_free(void);
/**
* @brief Get max free block size from memory pool
*
* @return size_t
*/
size_t memmgr_pool_get_max_block(void);
#ifdef __cplusplus
}
#endif

View file

@ -7,7 +7,9 @@
#include "mutex.h"
#include <task.h>
#include "log.h"
#include <m-string.h>
#include <furi_hal_rtc.h>
#include <furi_hal_console.h>
#define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers
@ -20,6 +22,7 @@ struct FuriThreadStdout {
};
struct FuriThread {
bool is_service;
FuriThreadState state;
int32_t ret;
@ -84,6 +87,11 @@ static void furi_thread_body(void* context) {
furi_assert(thread->state == FuriThreadStateRunning);
furi_thread_set_state(thread, FuriThreadStateStopped);
if(thread->is_service) {
FURI_LOG_E(
"Service", "%s thread exited. Thread memory cannot be reclaimed.", thread->name);
}
// clear thread local storage
__furi_thread_stdout_flush(thread);
furi_assert(pvTaskGetThreadLocalStoragePointer(NULL, 0) != NULL);
@ -96,7 +104,7 @@ static void furi_thread_body(void* context) {
FuriThread* furi_thread_alloc() {
FuriThread* thread = malloc(sizeof(FuriThread));
string_init(thread->output.buffer);
thread->is_service = false;
return thread;
}
@ -117,6 +125,10 @@ void furi_thread_set_name(FuriThread* thread, const char* name) {
thread->name = name ? strdup(name) : NULL;
}
void furi_thread_mark_as_service(FuriThread* thread) {
thread->is_service = true;
}
void furi_thread_set_stack_size(FuriThread* thread, size_t stack_size) {
furi_assert(thread);
furi_assert(thread->state == FuriThreadStateStopped);
@ -168,15 +180,23 @@ void furi_thread_start(FuriThread* thread) {
furi_thread_set_state(thread, FuriThreadStateStarting);
BaseType_t ret = xTaskCreate(
furi_thread_body,
thread->name,
thread->stack_size / 4,
thread,
thread->priority ? thread->priority : FuriThreadPriorityNormal,
&thread->task_handle);
uint32_t stack = thread->stack_size / 4;
UBaseType_t priority = thread->priority ? thread->priority : FuriThreadPriorityNormal;
if(thread->is_service) {
thread->task_handle = xTaskCreateStatic(
furi_thread_body,
thread->name,
stack,
thread,
priority,
memmgr_alloc_from_pool(sizeof(StackType_t) * stack),
memmgr_alloc_from_pool(sizeof(StaticTask_t)));
} else {
BaseType_t ret = xTaskCreate(
furi_thread_body, thread->name, stack, thread, priority, &thread->task_handle);
furi_check(ret == pdPASS);
}
furi_check(ret == pdPASS);
furi_check(thread->task_handle);
}

View file

@ -73,6 +73,13 @@ void furi_thread_free(FuriThread* thread);
*/
void furi_thread_set_name(FuriThread* thread, const char* name);
/** Mark thread as service
* The service cannot be stopped or removed, and cannot exit from the thread body
*
* @param thread
*/
void furi_thread_mark_as_service(FuriThread* thread);
/** Set FuriThread stack size
*
* @param thread FuriThread instance

View file

@ -2,6 +2,7 @@
#include <applications.h>
#include <furi.h>
#include <furi_hal_version.h>
#include <furi_hal_memory.h>
#define TAG "Flipper"
@ -38,9 +39,28 @@ void flipper_init() {
furi_thread_set_name(thread, FLIPPER_SERVICES[i].name);
furi_thread_set_stack_size(thread, FLIPPER_SERVICES[i].stack_size);
furi_thread_set_callback(thread, FLIPPER_SERVICES[i].app);
furi_thread_mark_as_service(thread);
furi_thread_start(thread);
}
FURI_LOG_I(TAG, "services startup complete");
}
void vApplicationGetIdleTaskMemory(
StaticTask_t** tcb_ptr,
StackType_t** stack_ptr,
uint32_t* stack_size) {
*tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t));
*stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configMINIMAL_STACK_SIZE);
*stack_size = configMINIMAL_STACK_SIZE;
}
void vApplicationGetTimerTaskMemory(
StaticTask_t** tcb_ptr,
StackType_t** stack_ptr,
uint32_t* stack_size) {
*tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t));
*stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH);
*stack_size = configTIMER_TASK_STACK_DEPTH;
}

View file

@ -13,6 +13,9 @@ fbtenv_show_usage()
echo "Running this script manually is wrong, please source it";
echo "Example:";
printf "\tsource scripts/toolchain/fbtenv.sh\n";
echo "To restore your enviroment source fbtenv.sh with '--restore'."
echo "Example:";
printf "\tsource scripts/toolchain/fbtenv.sh --restore\n";
}
fbtenv_curl()
@ -25,9 +28,27 @@ fbtenv_wget()
wget --show-progress --progress=bar:force -qO "$1" "$2";
}
fbtenv_restore_env()
{
TOOLCHAIN_ARCH_DIR_SED="$(echo "$TOOLCHAIN_ARCH_DIR" | sed 's/\//\\\//g')"
PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/python\/bin://g")";
PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/bin://g")";
PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/protobuf\/bin://g")";
PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/openocd\/bin://g")";
if [ -n "${PS1:-""}" ]; then
PS1="$(echo "$PS1" | sed 's/\[fbt\]//g')";
elif [ -n "${PROMPT:-""}" ]; then
PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')";
fi
unset SCRIPT_PATH;
unset FBT_TOOLCHAIN_VERSION;
unset FBT_TOOLCHAIN_PATH;
}
fbtenv_check_sourced()
{
case "${ZSH_EVAL_CONTEXT:-""}" in *:file:*)
setopt +o nomatch; # disabling 'no match found' warning in zsh
return 0;;
esac
if [ ${0##*/} = "fbtenv.sh" ]; then # exluding script itself
@ -148,15 +169,17 @@ fbtenv_download_toolchain_tar()
{
echo "Downloading toolchain:";
mkdir -p "$FBT_TOOLCHAIN_PATH/toolchain" || return 1;
"$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL" || return 1;
"$FBT_DOWNLOADER" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$TOOLCHAIN_URL" || return 1;
# restoring oroginal filename if file downloaded successfully
mv "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR.part" "$FBT_TOOLCHAIN_PATH/toolchain/$TOOLCHAIN_TAR"
echo "done";
return 0;
}
fbtenv_remove_old_tooclhain()
{
printf "Removing old toolchain (if exist)..";
rm -rf "${TOOLCHAIN_ARCH_DIR}";
printf "Removing old toolchain..";
rm -rf "${TOOLCHAIN_ARCH_DIR:?}";
echo "done";
}
@ -185,8 +208,12 @@ fbtenv_unpack_toolchain()
fbtenv_clearing()
{
printf "Clearing..";
rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/$TOOLCHAIN_TAR";
if [ -n "${FBT_TOOLCHAIN_PATH:-""}" ]; then
rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.tar.gz;
rm -rf "${FBT_TOOLCHAIN_PATH:?}/toolchain/"*.part;
fi
echo "done";
trap - 2;
return 0;
}
@ -232,12 +259,13 @@ fbtenv_download_toolchain()
fbtenv_check_tar || return 1;
TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")";
TOOLCHAIN_DIR="$(echo "$TOOLCHAIN_TAR" | sed "s/-$FBT_TOOLCHAIN_VERSION.tar.gz//g")";
trap fbtenv_clearing 2; # trap will be restored in fbtenv_clearing
if ! fbtenv_check_downloaded_toolchain; then
fbtenv_curl_wget_check || return 1;
fbtenv_download_toolchain_tar;
fbtenv_download_toolchain_tar || return 1;
fi
fbtenv_remove_old_tooclhain;
fbtenv_unpack_toolchain || { fbtenv_clearing && return 1; };
fbtenv_unpack_toolchain || return 1;
fbtenv_clearing;
return 0;
}
@ -245,15 +273,19 @@ fbtenv_download_toolchain()
fbtenv_main()
{
fbtenv_check_sourced || return 1;
fbtenv_chck_many_source; # many source it's just a warning
fbtenv_set_shell_prompt;
fbtenv_check_script_path || return 1;
fbtenv_get_kernel_type || return 1;
if [ "$1" = "--restore" ]; then
fbtenv_restore_env;
return 0;
fi
fbtenv_chck_many_source; # many source it's just a warning
fbtenv_check_script_path || return 1;
fbtenv_check_download_toolchain || return 1;
fbtenv_set_shell_prompt;
PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH";
PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH";
PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH";
PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH";
}
fbtenv_main;
fbtenv_main "${1:-""}";