Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 69 additions & 13 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ name: Code Quality

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
quality:
Expand All @@ -22,28 +24,65 @@ jobs:
- name: Run Cppcheck
run: |
echo "Running cppcheck static analysis..."
SRC_DIRS=()
for d in core imgproc board device wrapper; do
[ -d "$d" ] && SRC_DIRS+=("$d")
done
if [ ${#SRC_DIRS[@]} -eq 0 ]; then
echo "No source directories found for cppcheck"
exit 1
fi

INCLUDE_ARGS=()
for d in "${SRC_DIRS[@]}"; do
INCLUDE_ARGS+=("-I" "$d")
done

cppcheck \
--enable=warning,style,performance,portability \
--enable=warning,performance,portability \
--error-exitcode=1 \
--inline-suppr \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--std=c11 \
--force \
-I embedDIP/core \
-I embedDIP/imgproc \
-I embedDIP/board \
-I embedDIP/device \
-I embedDIP/wrapper \
-I Drivers/STM32F7xx_HAL_Driver/Inc \
-I Drivers/CMSIS/Device/ST/STM32F7xx/Include \
-I Drivers/CMSIS/Core/Include \
-I Core/Inc \
embedDIP/ Core/ \
"${INCLUDE_ARGS[@]}" \
"${SRC_DIRS[@]}" \
--xml \
2> cppcheck-report.xml

- name: Run Cppcheck Style Report
continue-on-error: true
run: |
echo "Running cppcheck style analysis (non-blocking)..."
SRC_DIRS=()
for d in core imgproc board device wrapper; do
[ -d "$d" ] && SRC_DIRS+=("$d")
done
if [ ${#SRC_DIRS[@]} -eq 0 ]; then
echo "No source directories found for cppcheck style scan"
exit 0
fi

INCLUDE_ARGS=()
for d in "${SRC_DIRS[@]}"; do
INCLUDE_ARGS+=("-I" "$d")
done

cppcheck \
--enable=style \
--inline-suppr \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--std=c11 \
--force \
"${INCLUDE_ARGS[@]}" \
"${SRC_DIRS[@]}" \
--xml \
2> cppcheck-style-report.xml || true

- name: Check Code Formatting
run: |
echo "Checking code formatting..."
Expand All @@ -63,8 +102,16 @@ jobs:
fi

# Fail if any file is not properly formatted
find embedDIP Core \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) \
-not -path "*/Drivers/*" \
SRC_DIRS=()
for d in core imgproc board device wrapper; do
[ -d "$d" ] && SRC_DIRS+=("$d")
done
if [ ${#SRC_DIRS[@]} -eq 0 ]; then
echo "No source directories found for format check"
exit 1
fi

find "${SRC_DIRS[@]}" \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" \) \
-print0 | xargs -0 clang-format --dry-run --Werror

- name: Upload Cppcheck Report
Expand All @@ -75,3 +122,12 @@ jobs:
path: cppcheck-report.xml
retention-days: 30
if-no-files-found: warn

- name: Upload Cppcheck Style Report
if: always()
uses: actions/upload-artifact@v4
with:
name: cppcheck-style-report
path: cppcheck-style-report.xml
retention-days: 30
if-no-files-found: warn
4 changes: 2 additions & 2 deletions .github/workflows/doxygen-gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- '**/*.hpp'
- '**/*.c'
- '**/*.cpp'
- 'Doxyfile'
- 'docs/Doxyfile'
- '.github/workflows/doxygen-gh-pages.yml'
workflow_dispatch: # Allow manual trigger

Expand Down Expand Up @@ -46,7 +46,7 @@ jobs:

- name: Generate Doxygen documentation
run: |
doxygen Doxyfile
doxygen docs/Doxyfile

- name: Check generated documentation
run: |
Expand Down
18 changes: 8 additions & 10 deletions board/esp32/board_esp32_fft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ static bool isValidFFTSize(int w, int h)

embeddip_status_t fft(const Image *inImg, Image *outImg)
{
if (!inImg || !outImg || !inImg->pixels) {
return EMBEDDIP_ERROR_NULL_PTR;
}

int N = inImg->width;
if (!isValidFFTSize(N, N)) {
// Serial.println("[ERROR] Invalid FFT size. Only powers of 2 are supported.");
Expand All @@ -35,12 +39,6 @@ embeddip_status_t fft(const Image *inImg, Image *outImg)
// Serial.println("[ERROR] 1pixels are null.");
float *buf0 = outImg->chals->ch[0];
float *buf1 = outImg->chals->ch[1];
// Serial.println("[ERROR] 2or pixels are null.");
if (!inImg || !inImg->pixels) {
// Serial.println("[ERROR]3 or pixels are null.");
return EMBEDDIP_ERROR_NULL_PTR;
}

uint8_t *input = static_cast<uint8_t *>(inImg->pixels);
for (int i = 0; i < N * N; i++) {
buf0[2 * i] = (float)input[i]; // real part
Expand Down Expand Up @@ -233,13 +231,13 @@ embeddip_status_t fftshift(Image *img)

embeddip_status_t _abs_(const Image *fftImg, Image *magImg)
{
int size = fftImg->width * fftImg->height;

if (!fftImg || !fftImg->chals) {
if (!fftImg || !fftImg->chals || !magImg) {
// Serial.println("[ERROR] Input FFT image or its channels are null.");
return EMBEDDIP_ERROR_NULL_PTR;
}

int size = fftImg->width * fftImg->height;

float *fft = (fftImg->log == IMAGE_DATA_COMPLEX) ? fftImg->chals->ch[1] : fftImg->chals->ch[0];

if (!fft) {
Expand Down Expand Up @@ -614,4 +612,4 @@ embeddip_status_t ffilter2D(const Image *fftImg, const Image *filterMask, Image
polarToCart(magImg, phaseImg, outImg);
return EMBEDDIP_OK;
}
#endif
#endif
17 changes: 13 additions & 4 deletions board/stm32f7/board_stm32f7_fft.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,20 @@ embeddip_status_t fourierInv(const Image *inImg, Image *outImg)
*/
embeddip_status_t polarToCart(const Image *mag_img, const Image *phase_img, Image *dst)
{
if (!mag_img || !phase_img || !dst)
return EMBEDDIP_ERROR_NULL_PTR;

int size = mag_img->width * mag_img->height;

if (isChalsEmpty(dst)) {
createChalsComplex(dst, 1); // Complex channel for interleaved (Re, Im)
dst->is_chals = 1;
if (!isChalsEmpty(dst) && dst->chals && dst->chals->ch[0]) {
// Ensure output buffer has complex capacity (2*N floats).
memory_free(dst->chals->ch[0]);
dst->chals->ch[0] = NULL;
}

embeddip_status_t status = createChalsComplex(dst, 1);
if (status != EMBEDDIP_OK) {
return status;
}

float *mag = mag_img->chals->ch[0];
Expand Down Expand Up @@ -553,7 +562,7 @@ embeddip_status_t ifft__(const Image *inImg, Image *outImg)
float *buf0;

if (isChalsEmpty(outImg)) {
createChals(outImg, 2);
createChalsComplex(outImg, 1);
outImg->is_chals = 1;
buf0 = outImg->chals->ch[0];
} else {
Expand Down
63 changes: 56 additions & 7 deletions board/stm32f7/board_stm32f7_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,51 @@
static uint8_t *memory_pool = ((uint8_t *)SDRAM_BANK_ADDR + CAMERA_LCD_FRAMEBUFFER_SIZE);

typedef struct MemoryBlock {
uint32_t magic;
size_t size;
struct MemoryBlock *next;
int is_free;
} MemoryBlock;

#define ALIGN4(s) (((s) + 3) & ~3)
#define BLOCK_SIZE sizeof(MemoryBlock)
#define MEMBLOCK_MAGIC 0xB10C4EADu

static MemoryBlock *free_list = NULL;
static int initialized = 0;

static inline uintptr_t pool_start_addr(void)
{
return (uintptr_t)memory_pool;
}

static inline uintptr_t pool_end_addr(void)
{
return (uintptr_t)memory_pool + MEMORY_POOL_SIZE;
}

static inline int ptr_in_pool(const void *p)
{
uintptr_t a = (uintptr_t)p;
return a >= pool_start_addr() && a < pool_end_addr();
}

static inline int block_header_valid(const MemoryBlock *b)
{
if (!b || !ptr_in_pool(b))
return 0;
if ((uintptr_t)b + BLOCK_SIZE > pool_end_addr())
return 0;
return (b->magic == MEMBLOCK_MAGIC);
}

void memory_init()
{
if (initialized)
return;

free_list = (MemoryBlock *)memory_pool;
free_list->magic = MEMBLOCK_MAGIC;
free_list->size = MEMORY_POOL_SIZE - BLOCK_SIZE;
free_list->next = NULL;
free_list->is_free = 1;
Expand All @@ -54,14 +82,15 @@ void *memory_alloc(size_t size)

MemoryBlock *curr = free_list;

while (curr) {
while (curr && block_header_valid(curr)) {
if (curr->is_free && curr->size >= size) {
uintptr_t curr_addr = (uintptr_t)curr;
uintptr_t pool_end = (uintptr_t)memory_pool + MEMORY_POOL_SIZE;
uintptr_t pool_end = pool_end_addr();
uintptr_t next_block_addr = curr_addr + BLOCK_SIZE + size;

if (curr->size >= size + BLOCK_SIZE + 4 && next_block_addr + BLOCK_SIZE < pool_end) {
MemoryBlock *new_block = (MemoryBlock *)(next_block_addr);
new_block->magic = MEMBLOCK_MAGIC;
new_block->size = curr->size - size - BLOCK_SIZE;
new_block->next = curr->next;
new_block->is_free = 1;
Expand All @@ -85,8 +114,8 @@ void memory_free(void *ptr)
if (!ptr)
return;

uintptr_t pool_start = (uintptr_t)memory_pool;
uintptr_t pool_end = pool_start + MEMORY_POOL_SIZE;
uintptr_t pool_start = pool_start_addr();
uintptr_t pool_end = pool_end_addr();
uintptr_t addr = (uintptr_t)ptr;

if (addr < pool_start || addr >= pool_end)
Expand All @@ -96,12 +125,28 @@ void memory_free(void *ptr)
memory_init();

MemoryBlock *block = (MemoryBlock *)((uint8_t *)ptr - BLOCK_SIZE);

if (!block_header_valid(block))
return;

// Ignore double free.
if (block->is_free)
return;

// Ensure the pointer corresponds exactly to block payload start.
if ((void *)((uint8_t *)block + BLOCK_SIZE) != ptr)
return;

block->is_free = 1;

// Merge adjacent free blocks
// Merge only physically adjacent free blocks.
MemoryBlock *curr = free_list;
while (curr && curr->next) {
if (curr->is_free && curr->next->is_free) {
while (curr && block_header_valid(curr) && curr->next) {
if (!block_header_valid(curr->next)) {
break;
}
uintptr_t curr_end = (uintptr_t)curr + BLOCK_SIZE + curr->size;
if (curr->is_free && curr->next->is_free && curr_end == (uintptr_t)curr->next) {
curr->size += BLOCK_SIZE + curr->next->size;
curr->next = curr->next->next;
} else {
Expand All @@ -119,6 +164,10 @@ void *memory_realloc(void *ptr, size_t new_size)
memory_init();

MemoryBlock *block = (MemoryBlock *)((uint8_t *)ptr - BLOCK_SIZE);
if (!block_header_valid(block))
return NULL;

new_size = ALIGN4(new_size);

if (block->size >= new_size)
return ptr;
Expand Down
1 change: 1 addition & 0 deletions device/camera/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define CAMERA_H

#include "core/image.h"

#include <stddef.h>
#include <stdint.h>

Expand Down
Loading
Loading