diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 728e087..9eab86b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,8 @@ on: branches: [ main, master, develop ] jobs: - build-and-test: - name: Build and Test + build-and-test-core: + name: Build and Test dmsai (core) runs-on: ubuntu-latest permissions: contents: read @@ -19,12 +19,16 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Build dmsai + - name: Build dmsai core module run: | mkdir -p build cd build - cmake .. -DDMOD_MODE=DMOD_MODULE - cmake --build . + # dmsai links against dmsai_port_if (headers only), + # not dmsai_port itself, so building only these two targets + # never touches src/port/*/port.c - safe to build natively here + # regardless of which CPU family the port defaults to. + cmake .. -DDMOD_MODE=DMOD_MODULE -DDMOD_TOOLS_NAME=arch/x86_64 + cmake --build . --target dmsai test_dmsai - name: Verify module files run: | @@ -38,5 +42,66 @@ jobs: - name: Run tests with dmod_loader run: | export DMOD_DMF_DIR=$(pwd)/build/dmf - dmf-get install -d ${DMOD_DMF_DIR}/test_dmsai-local.dmd -y dmod_loader build/dmf/test_dmsai.dmf + + discover-cpu-families: + name: Discover CPU Families + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + cpu_families: ${{ steps.list-families.outputs.cpu_families }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: List available CPU families + id: list-families + run: | + # Find all CPU families by looking for directories containing port.c + CPU_FAMILIES=$(find src/port -mindepth 2 -maxdepth 2 -name "port.c" -type f -printf '%h\n' | \ + xargs -n1 basename | \ + sort | \ + jq -R -s -c 'split("\n") | map(select(length > 0))') + + echo "Found CPU families: $CPU_FAMILIES" + echo "cpu_families=$CPU_FAMILIES" >> $GITHUB_OUTPUT + + build-dmsai: + name: Build dmsai for ${{ matrix.cpu_family }} + needs: discover-cpu-families + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + matrix: + cpu_family: ${{ fromJson(needs.discover-cpu-families.outputs.cpu_families) }} + + container: + image: chocotechnologies/dmod:1.0.4 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Build dmsai for ${{ matrix.cpu_family }} + run: | + set -e + CPU_FAMILY="${{ matrix.cpu_family }}" + mkdir -p build_$CPU_FAMILY + cd build_$CPU_FAMILY + + cmake .. -DDMOD_CPU_FAMILY="${CPU_FAMILY}" + cmake --build . + + echo "Build completed for CPU family: ${CPU_FAMILY}" + ls -lh dmf/ + + - name: Verify dmsai_port module files + run: | + CPU_FAMILY="${{ matrix.cpu_family }}" + echo "Checking for dmsai_port module files for ${CPU_FAMILY}..." + ls -lh build_$CPU_FAMILY/dmf/ + test -f build_$CPU_FAMILY/dmf/dmsai_port.dmf + test -f build_$CPU_FAMILY/dmf/dmsai_port_version.txt + echo "Module files present for ${CPU_FAMILY}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b64c435..8203659 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,52 +5,37 @@ on: types: [created] jobs: - discover-architectures: - name: Discover Architectures + discover-cpu-families: + name: Discover CPU Families runs-on: ubuntu-latest permissions: contents: read - container: - image: chocotechnologies/dmod:1.0.4 outputs: - architectures: ${{ steps.list-archs.outputs.architectures }} + cpu_families: ${{ steps.list-families.outputs.cpu_families }} steps: - name: Checkout code uses: actions/checkout@v4 - - name: Fetch dmod to discover architectures - run: | - # A plain `git clone` here (rather than configuring dmsai's - # own CMakeLists.txt via FetchContent, as before) so this step only - # ever depends on dmod itself - not on dmsai's - # dmod_link_modules() fetches of other modules, which this step has - # no business needing just to list dmod's supported architectures, - # and which previously made this discovery job (and therefore the - # whole release) fail outright whenever any of those unrelated - # external fetches hiccuped. - git clone --depth 1 https://github.com/choco-technologies/dmod.git dmod_discovery - - - name: List available architectures - id: list-archs + - name: List available CPU families + id: list-families run: | - # create JSON array - ARCHS=$(find dmod_discovery/configs/arch -name "tools-cfg.cmake" | \ - sed "s|dmod_discovery/configs/arch/||g" | \ - sed 's|/tools-cfg.cmake||g' | \ + CPU_FAMILIES=$(find src/port -mindepth 2 -maxdepth 2 -name "port.c" -type f -printf '%h\n' | \ + xargs -n1 basename | \ + sort | \ jq -R -s -c 'split("\n") | map(select(length > 0))') - echo "Found architectures: $ARCHS" - echo "architectures=$ARCHS" >> $GITHUB_OUTPUT + echo "Found CPU families: $CPU_FAMILIES" + echo "cpu_families=$CPU_FAMILIES" >> $GITHUB_OUTPUT - build-release: - name: Build Release for ${{ matrix.arch_name }} - needs: discover-architectures + build-dmsai: + name: Build dmsai for ${{ matrix.cpu_family }} + needs: discover-cpu-families runs-on: ubuntu-latest permissions: contents: write strategy: matrix: - arch_name: ${{ fromJson(needs.discover-architectures.outputs.architectures) }} + cpu_family: ${{ fromJson(needs.discover-cpu-families.outputs.cpu_families) }} container: image: chocotechnologies/dmod:1.0.4 @@ -62,36 +47,41 @@ jobs: - name: Extract version from tag id: get_version run: | - # Extract version from tag (e.g., v1.2 -> 1.2) VERSION="${{ github.event.release.tag_name }}" - VERSION="${VERSION#v}" # Remove 'v' prefix if present + VERSION="${VERSION#v}" echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Extracted version: $VERSION" - - name: Build dmsai for ${{ matrix.arch_name }} + - name: Build dmsai for ${{ matrix.cpu_family }} run: | set -e - ARCH_DIR_NAME=$(echo "${{ matrix.arch_name }}" | sed 's|/|-|') - echo "ARCH_DIR_NAME=$ARCH_DIR_NAME" >> $GITHUB_ENV - echo "ARTIFACT_NAME=release-$ARCH_DIR_NAME" >> $GITHUB_ENV - mkdir -p build_$ARCH_DIR_NAME - cd build_$ARCH_DIR_NAME - - # DMOD_DMR_PATH is already set in CMakeLists.txt, so this build also - # assembles build_$ARCH_DIR_NAME/packages// for every module - # defined in this repo's CMake config - nothing left to do here but - # discover whatever got packaged, add release notes, and zip it. - cmake .. -DDMOD_TOOLS_NAME=arch/${{ matrix.arch_name }} -DDMOD_MODULE_VERSION="${{ steps.get_version.outputs.version }}" + CPU_FAMILY="${{ matrix.cpu_family }}" + BUILD_NAME="port-${CPU_FAMILY}" + echo "BUILD_NAME=$BUILD_NAME" >> $GITHUB_ENV + echo "ARTIFACT_NAME=release-$BUILD_NAME" >> $GITHUB_ENV + mkdir -p build_$BUILD_NAME + cd build_$BUILD_NAME + + # DMOD_DMR_PATH is already set for both dmsai and + # dmsai_port in their respective CMakeLists.txt, so this + # build also assembles packages// for every module defined + # in this repo (normally dmsai and dmsai_port, but + # this discovers whatever is actually there). + cmake .. \ + -DDMOD_MODULE_VERSION="${{ steps.get_version.outputs.version }}" \ + -DDMOD_CPU_FAMILY="${CPU_FAMILY}" + cmake --build . - echo "Build completed for ${{ matrix.arch_name }}" - ls -la packages/ + echo "Build completed for CPU family: ${CPU_FAMILY}" + ls -la packages/ || echo "No packages directory" - name: Add release notes and create release archives run: | set -e - BUILD_DIR="build_$ARCH_DIR_NAME" + BUILD_DIR="build_$BUILD_NAME" TAG="${{ github.event.release.tag_name }}" + CPU="${{ matrix.cpu_family }}" PACKAGES_DIR="$BUILD_DIR/packages" if [ ! -d "$PACKAGES_DIR" ] || [ -z "$(ls -A "$PACKAGES_DIR")" ]; then @@ -99,24 +89,21 @@ jobs: exit 1 fi - # A repo may define more than one module (e.g. a core + port split, - # or several independent modules) - package every subdirectory - # found under packages/, not just dmsai. : > package-names.txt for pkg_dir in "$PACKAGES_DIR"/*/; do pkg=$(basename "$pkg_dir") echo "$pkg" >> package-names.txt echo "${{ github.event.release.body }}" > "${pkg_dir}RELEASE_NOTES.txt" - (cd "$pkg_dir" && zip -r "${OLDPWD}/${pkg}-${TAG}-${ARCH_DIR_NAME}.zip" .) + (cd "$pkg_dir" && zip -r "${OLDPWD}/${pkg}-${TAG}-${CPU}.zip" .) done echo "Created archives:" - ls -lh *-"${TAG}"-"${ARCH_DIR_NAME}".zip + ls -lh *-"${TAG}"-"${CPU}".zip echo "Packages found:" cat package-names.txt - - name: Upload artifact + - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: ${{ env.ARTIFACT_NAME }} @@ -127,7 +114,7 @@ jobs: generate-versions-manifest: name: Generate versions.dmm - needs: [discover-architectures, build-release] + needs: [discover-cpu-families, build-dmsai] runs-on: ubuntu-latest permissions: contents: read @@ -136,7 +123,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - fetch-depth: 0 # Fetch all history to get all tags + fetch-depth: 0 - name: Download release artifacts uses: actions/download-artifact@v4 @@ -150,10 +137,7 @@ jobs: echo "# Generated automatically by CI" >> versions.dmm echo "" >> versions.dmm - # Get all version tags (starting with 'v') and extract version numbers VERSIONS=$(git tag -l 'v*' | sed 's/^v//' | sort -V | tr '\n' ' ' | sed 's/ $//') - - # Remove vlatest from the list if present VERSIONS=$(echo $VERSIONS | sed 's/\blatest\b//g' | xargs) if [ -z "$VERSIONS" ]; then @@ -164,9 +148,6 @@ jobs: echo "Found versions: $VERSIONS" - # Union of package names discovered across every architecture build - # (the same set is expected everywhere, but union is safe even if - # some packages only exist for a subset of architectures). PACKAGES=$(cat artifacts/release-*/package-names.txt | sort -u) echo "Found packages: $PACKAGES" @@ -186,7 +167,7 @@ jobs: upload-release-assets: name: Upload Release Assets - needs: [build-release, generate-versions-manifest] + needs: [build-dmsai, generate-versions-manifest] runs-on: ubuntu-latest permissions: contents: write diff --git a/.vscode/settings.json b/.vscode/settings.json index 9fb722c..1cc929a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,8 @@ { + "files.associations": { + "dmsai.h": "c", + "dmsai_port.h": "c" + }, "C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json", "C_Cpp.intelliSenseEngine": "default", "C_Cpp.errorSquiggles": "enabled" diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a448d4..9bebc00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.18) +set(DMOD_CPU_FAMILY "stm32f7" CACHE STRING "Target CPU family") +include(${CMAKE_CURRENT_SOURCE_DIR}/src/port/${DMOD_CPU_FAMILY}/config.cmake) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(NOT DEFINED DMOD_MODULE_VERSION) @@ -27,7 +30,7 @@ set(DMOD_BUILD_TEMPLATES OFF CACHE BOOL "Build templates") FetchContent_MakeAvailable(dmod) project(dmsai VERSION ${DMOD_MODULE_VERSION} - DESCRIPTION "dmsai DMOD application module" + DESCRIPTION "dmsai DMOD library module" LANGUAGES C CXX) set(DMOD_DIR ${dmod_SOURCE_DIR} CACHE PATH "DMOD source directory") @@ -42,10 +45,7 @@ set(DMOD_MODULE_NAME dmsai) set(DMOD_AUTHOR_NAME "Patryk Kubiak") # Stack size for the module (should be integer) -set(DMOD_STACK_SIZE 4096) - -# Priority for the thread of the module (should be integer) -set(DMOD_PRIORITY 0) +set(DMOD_STACK_SIZE 1024) # Path to the .dmr file - enables release package creation in build/packages/ set(DMOD_DMR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/dmsai.dmr) @@ -53,21 +53,36 @@ set(DMOD_DMR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/dmsai.dmr) # List of MAL interfaces implemented by this module (leave empty if none) set(DMOD_MAL_IMPLS ) +# List of DIF interfaces implemented by this module (leave empty if none) +set(DMOD_DIF_IMPLS ) + # -# dmod_add_executable - create an executable module -# it has the same signature as add_executable, +# dmod_add_library - create a library module +# it has the same signature as add_library # and can be used in the same way after the creation # (for example, to link libraries) # -dmod_add_executable(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} +dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} # List of source files - can include C and C++ files src/dmsai.c + src/dmsai_private.c +) + +target_include_directories(${DMOD_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +target_include_directories(${DMOD_MODULE_NAME}_if INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/include ) # To depend on another module's headers, use: -# dmod_link_modules(${DMOD_MODULE_NAME} -# other_module@1.0 -# ) +dmod_link_modules(${DMOD_MODULE_NAME} + dmini + dmdrvi +) +add_subdirectory(src/port) +target_link_libraries(${DMOD_MODULE_NAME} ${DMOD_MODULE_NAME}_port_if) enable_testing() add_subdirectory(tests) diff --git a/Makefile b/Makefile index 8d94a38..2225b91 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # ############################################################################# # -# This is an example of a simple application module. +# This is an example of a simple library module. # # ############################################################################# DMOD_DIR=@DMOD_DIR@ @@ -30,7 +30,7 @@ DMOD_CSOURCES=src/dmsai.c DMOD_CXXSOURCES= # The list of include directories -DMOD_INC_DIRS= +DMOD_INC_DIRS=include # The list of libraries to link DMOD_LIBS= @@ -43,7 +43,12 @@ DMOD_DEFINITIONS= # ----------------------------------------------------------------------------- DMOD_MAL_IMPLS= +# ----------------------------------------------------------------------------- +# List of DIF interfaces implemented by the module +# ----------------------------------------------------------------------------- +DMOD_DIF_IMPLS= + # ----------------------------------------------------------------------------- # Include the dmod app makefile # ----------------------------------------------------------------------------- -include $(DMOD_DMF_APP_FILE_PATH) +include $(DMOD_DMF_LIB_FILE_PATH) diff --git a/README.md b/README.md index cd1346c..4ad85d2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/choco-technologies/dmsai/actions/workflows/ci.yml/badge.svg)](https://github.com/choco-technologies/dmsai/actions/workflows/ci.yml) -dmsai DMOD application module. +dmsai DMOD library module. ## Description @@ -52,32 +52,62 @@ dmod_loader build/dmf/test_dmsai.dmf -This application module can be loaded and executed using the DMOD loader: +This library module provides functions that can be used by other modules: -```bash -dmod_loader /path/to/dmsai.dmf +```c +#include "dmsai.h" ``` ## API -`dmsai` is loaded and executed through the DMOD loader - it does not -expose a callable module API of its own. See -[docs/api-reference.md](docs/api-reference.md) for its command-line -arguments and exit codes. +| Function | Description | +|----------|-------------| +| `dmsai_create()` | Create a new `dmsai_t` instance. | +| `dmsai_destroy()` | Destroy an instance created by `_create()`. | +| `dmsai_is_valid()` | Check whether a handle is a valid instance. | + +See [include/dmsai.h](include/dmsai.h) for the full +declarations and [docs/api-reference.md](docs/api-reference.md) for the +complete reference. ## Documentation See the `docs/` directory: -- **[api-reference.md](docs/api-reference.md)** - Command-line usage +- **[api-reference.md](docs/api-reference.md)** - Complete API documentation View documentation using `dmf-man dmsai`. +## Hardware Port + +This module ships two DMOD modules: the architecture-independent +`dmsai` and `dmsai_port`, which contains the +architecture-specific implementation. The active architecture is selected via +`DMOD_CPU_FAMILY` (default: `stm32f7`): + +```bash +cmake .. -DDMOD_CPU_FAMILY=stm32f7 +``` + +See [docs/port-implementation.md](docs/port-implementation.md) for how to add +another architecture. Port-specific files: + +``` +├── include/dmsai_port.h +├── src/port/ +│ ├── CMakeLists.txt +│ └── stm32f7/ +│ ├── config.cmake +│ └── port.c +└── dmsai_port.dmr +``` ## Project Structure ``` dmsai/ ├── docs/ # Documentation (markdown format) +├── include/ # Public headers +│ └── dmsai.h ├── src/ │ └── dmsai.c ├── tests/ diff --git a/dmsai_port.dmr b/dmsai_port.dmr new file mode 100644 index 0000000..609061d --- /dev/null +++ b/dmsai_port.dmr @@ -0,0 +1,22 @@ +# DMOD Resource File for dmsai_port +# This file specifies where resources should be installed + +# === Core Module === +# Main module file - always installed +dmf=./${module}.dmf => ${destination}/${module}.dmf [origin=${dmf_dir}/${module}.dmf] + +# Compressed module +dmfc=./${module}.dmfc => ${destination}/${module}.dmfc [origin=${build_dir}/dmfc/${module}.dmfc] + +# Dependencies file (if exists) +dmd=./${module}.dmd => ${destination}/${module}.dmd [origin=${dmf_dir}/${module}.dmd] + +# Version information +version=./${module}_version.txt => ${destination}/${module}_version.txt [origin=${dmf_dir}/${module}_version.txt] + +# === Header Files === +# Full include directory with all headers and generated platform definitions header +inc=./include => ${destination}/${module}/include [origin=${repo_dir}/include] [origin=${build_dir}/src/port/${module}_defs.h] + +# === License === +license=./LICENSE => ${destination}/${module}/LICENSE [origin=${repo_dir}/LICENSE] diff --git a/docs/README.md b/docs/README.md index 4dc536c..336a287 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,13 @@ Welcome to the dmsai module documentation. ## Contents -- **[api-reference.md](api-reference.md)** - Command-line usage and behavior +- **[api-reference.md](api-reference.md)** - Complete API documentation + +## Quick Reference + +```c +#include "dmsai.h" +``` View documentation using `dmf-man`: diff --git a/docs/api-reference.md b/docs/api-reference.md index 21f90b5..dfcc8e2 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -1,13 +1,12 @@ # dmsai API Reference -Document command-line usage, arguments, and exit codes here. +Document the module's public types and functions here as you add them to +`include/dmsai.h`. -## Usage +## Types -```bash -dmod_loader dmsai.dmf [args...] -``` +_(none yet)_ -## Arguments +## Functions _(none yet)_ diff --git a/docs/port-implementation.md b/docs/port-implementation.md new file mode 100644 index 0000000..b8c0faa --- /dev/null +++ b/docs/port-implementation.md @@ -0,0 +1,24 @@ +# Adding a New MCU Port to dmsai + +`dmsai_port` currently supports `stm32f7`. The port is split from +the core `dmsai` module so a new architecture can be added without +touching architecture-independent logic. + +## Steps to add another architecture + +1. Create `src/port//config.cmake`, setting `DMOD_TOOLS_NAME` for the + target architecture (see `src/port/stm32f7/config.cmake` for the pattern - + it must match a directory under `dmod/configs/arch/...`). +2. Create `src/port//port.c` implementing the + `dmod_dmsai_port_api_declaration(...)` functions declared in + `include/dmsai_port.h`, plus `dmod_init`/`dmod_deinit` and any + `DMOD_IRQ_HANDLER(...)` needed. +3. If the underlying peripheral IP is identical across families, factor the + shared logic into `src/port/_common/` and keep each + `src/port//port.c` a thin wrapper (lifecycle + IRQ only) - see + `dmfmc/src/port/stm32_common/` for a real example of this split. +4. Build by selecting the new family: + `cmake .. -DDMOD_CPU_FAMILY=`. +5. Do not introduce a module-specific variable (e.g. `_MCU_SERIES`) for + this - `DMOD_CPU_FAMILY` is the ecosystem-wide convention, already wired + into `dmf-get` package resolution. diff --git a/include/dmsai.h b/include/dmsai.h new file mode 100644 index 0000000..4590b59 --- /dev/null +++ b/include/dmsai.h @@ -0,0 +1,10 @@ +#ifndef DMSAI_H +#define DMSAI_H + +#include +#include +#include +#include "dmod_types.h" +#include "dmsai_defs.h" + +#endif // DMSAI_H diff --git a/include/dmsai_port.h b/include/dmsai_port.h new file mode 100644 index 0000000..ae2ebb2 --- /dev/null +++ b/include/dmsai_port.h @@ -0,0 +1,33 @@ +#ifndef DMSAI_PORT_H +#define DMSAI_PORT_H + +#include "dmod_types.h" +#include "dmsai_port_defs.h" + +/* + * Declare architecture-independent port API functions here, following the + * dmod_dmsai_port_api(version, return_type, _suffix, (args)) pattern, + * e.g.: + * + * dmod_dmsai_port_api(1.0, int, _configure, ( int some_arg ) ); + * + * Each declaration here must have a matching *definition* in + * src/port//port.c (or a shared src/port/_common/ file), written + * with the dmod_dmsai_port_api_declaration(...) macro instead: + * + * dmod_dmsai_port_api_declaration(1.0, int, _configure, ( int some_arg ) ) + * { + * ... + * } + * + * Note this is a *different* mechanism from the dmod_init()/dmod_deinit() + * module lifecycle hooks already defined in port.c - don't declare `_init`/ + * `_deinit` here too, that name collides with the lifecycle hooks and (unlike + * them) requires an explicit dmod_dmsai_port_api_declaration(...) + * definition to avoid an undefined-reference link error. + * + * See dmfmc/include/dmfmc_port.h and dmfmc/src/port/stm32_common/stm32_common.c + * for a fully worked example. + */ + +#endif // DMSAI_PORT_H diff --git a/manifest.dmm b/manifest.dmm index a0647d8..bb7d149 100644 --- a/manifest.dmm +++ b/manifest.dmm @@ -1,5 +1,10 @@ # Include dynamically generated versions list from latest release $include https://github.com/choco-technologies/dmsai/releases/download/vlatest/versions.dmm -# Module entry with version placeholder - expanded by $version-available -dmsai https://github.com/choco-technologies/dmsai/releases/download/v/dmsai-v-.zip +# Module entries with version placeholder - expanded by $version-available. +# Both the core module and the port use here, not : +# the release workflow packages this repo per DMOD_CPU_FAMILY, not per full +# architecture (see dmfmc/manifest.dmm or dmuart/manifest.dmm for the +# real-world reference). +dmsai https://github.com/choco-technologies/dmsai/releases/download/v/dmsai-v-.zip +dmsai_port https://github.com/choco-technologies/dmsai/releases/download/v/dmsai_port-v-.zip diff --git a/src/dmsai.c b/src/dmsai.c index 5195268..6aed528 100644 --- a/src/dmsai.c +++ b/src/dmsai.c @@ -1,35 +1,147 @@ +#define DMOD_ENABLE_REGISTRATION ON #include "dmod.h" +#include "dmsai.h" +#include "dmdrvi.h" +#include "dmsai_private.h" +#include /** - * @brief Pre-initialization function for the module. + * @brief Initialization function for the module. + * + * This function is called when the module is enabled. + * Please use this function to initialize the module, for instance: + * - initialize the module variables + * - initialize the module hardware + * - allocate memory + */ +int dmod_init(const Dmod_Config_t *Config) +{ + return 0; +} + +/** + * @brief De-initialization function for the module. + * + * This function is called when the module is disabled. + * Please use this function to de-initialize the module, for instance: + * - free memory + * - de-initialize the module hardware + * - de-initialize the module variables + */ +int dmod_deinit(void) +{ + return 0; +} + + +/** + * @brief Create a DMDRVI context + * + * The driver will assign device numbers based on the configuration and return them + * via the dev_num parameter. The driver also sets flags to indicate which numbering + * scheme it uses (none, major only, or major+minor). + * + * @param config Pointer to dmini_context object with configuration parameters (dmini module required to parse them) + * @param dev_num Output pointer to device number structure - driver fills in major, minor, and flags (must not be NULL) * - * @note This function is optional. You can remove it if you don't need it. + * @return dmdrvi_context_t Created DMDRVI context + */ +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, dmdrvi_context_t, _create, ( dmini_context_t config, dmdrvi_dev_num_t* dev_num )) +{ + Dmod_Printf("Hello world!\n"); + return NULL; +} + + +/** + * @brief Close a device + * + * @param context DMDRVI context + * @param handle Device handle + */ +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, void, _close, ( dmdrvi_context_t context, void* handle )) +{ + +} + +/** + * @brief Read from a device + * + * @param context DMDRVI context + * @param handle Device handle + * @param buffer Buffer to read data into + * @param size Number of bytes to read; values greater than INT64_MAX must fail + * with -EOVERFLOW because they cannot be represented by dmdrvi_ssize_t + * @param offset Non-negative byte offset from the beginning of the device + * + * @return Number of bytes read, zero at end of device, or a negative + * errno-compatible error. A zero-length request returns zero. + */ +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, dmdrvi_ssize_t, _read, ( dmdrvi_context_t context, void* handle, void* buffer, size_t size, dmdrvi_offset_t offset )) +{ + return -ENOTSUP; +} + +/** + * @brief Write to a device + * + * @param context DMDRVI context + * @param handle Device handle + * @param buffer Buffer with data to write + * @param size Number of bytes to write; values greater than INT64_MAX must fail + * with -EOVERFLOW because they cannot be represented by dmdrvi_ssize_t + * @param offset Non-negative byte offset from the beginning of the device * - * This function is called when the module enabling is in progress. + * @return Number of bytes written or a negative errno-compatible error. A + * zero-length request returns zero. + */ +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, dmdrvi_ssize_t, _write, ( dmdrvi_context_t context, void* handle, const void* buffer, size_t size, dmdrvi_offset_t offset )) +{ + return -ENOTSUP; +} + +/** + * @brief Ioctl operation on a device + * + * @param context DMDRVI context + * @param handle Device handle + * @param command Ioctl command + * @param arg Argument for the ioctl command * - * You can use this function to load the required dependencies, such as - * other modules. Please be aware that the module is not fully initialized, - * so not all the API functions are available - you can check if the API - * is connected by calling the Dmod_IsFunctionConnected() function. + * @return int Result of the ioctl operation (errno) */ -void dmod_preinit(void) +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, int, _ioctl, ( dmdrvi_context_t context, void* handle, int command, void* arg )) { - if(Dmod_IsFunctionConnected( Dmod_Printf )) - { - Dmod_Printf("API is connected!\n"); - } + return -ENOTSUP; } /** - * @brief Main function of the application + * @brief Flush device buffers + * + * @param context DMDRVI context + * @param handle Device handle * - * @param argc Number of arguments - * @param argv Array of arguments + * @return int Result of the flush operation (errno) + */ +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, int, _flush, ( dmdrvi_context_t context, void* handle )) +{ + return -ENOTSUP; +} + +/** + * @brief Get device status + * + * Gets status information for the specified device path without requiring + * the device to be opened first (similar to POSIX stat() which works with + * a path without requiring fopen()). + * + * @param context DMDRVI context + * @param path Device path (e.g., "/dev/dmuart0", "/dev/dmspi0/0") + * @param stat Pointer to dmdrvi_stat_t structure to fill with status information * - * @return 0 if success, error code otherwise + * @return int Result of the stat operation (errno) */ -int main(int argc, char *argv[]) +dmod_dmdrvi_dif_api_declaration(2.0, dmsai, int, _stat, ( dmdrvi_context_t context, const char* path, dmdrvi_stat_t* stat )) { - Dmod_Printf("Hello, World!\n"); - return 0; + return -ENOTSUP; } diff --git a/src/dmsai_private.c b/src/dmsai_private.c new file mode 100644 index 0000000..829271d --- /dev/null +++ b/src/dmsai_private.c @@ -0,0 +1,19 @@ +#include "dmsai_private.h" + +// ======================================================================================= +// FUNCTIONS +// ======================================================================================= + +/** + * @brief checks if the context is valid + * + * The function checks if the given context is valid. + * + * @param context context of the driver + * + * @return true if the context is valid + */ +bool is_context_valid( const dmsai_t* context ) +{ + return context != NULL && context->magic == DMSAI_MAGIC; +} \ No newline at end of file diff --git a/src/dmsai_private.h b/src/dmsai_private.h new file mode 100644 index 0000000..77e8642 --- /dev/null +++ b/src/dmsai_private.h @@ -0,0 +1,27 @@ +#ifndef DMSAI_PRIVATE_H +#define DMSAI_PRIVATE_H + +#include "dmsai.h" + +// ======================================================================================= +// DEFINITIONS +// ======================================================================================= +#define DMSAI_MAGIC 0x646D7361 + +// ======================================================================================= +// TYPES +// ======================================================================================= + +/* Example internal state - replace with your module's real fields. */ +typedef struct dmdrvi_context +{ + uint32_t magic; //!< MAGIC number for verification of the structure +} dmsai_t; + +// ======================================================================================= +// FUNCTIONS +// ======================================================================================= + +extern bool is_context_valid( const dmsai_t* context ); + +#endif // DMSAI_PRIVATE_H \ No newline at end of file diff --git a/src/port/CMakeLists.txt b/src/port/CMakeLists.txt new file mode 100644 index 0000000..6e28405 --- /dev/null +++ b/src/port/CMakeLists.txt @@ -0,0 +1,49 @@ +# ====================================================================== +# dmsai_port Module Configuration +# ====================================================================== + +# Name of the module +set(DMOD_MODULE_NAME dmsai_port) + +# Version is already set above and used in project() + +# Author (should be string) +set(DMOD_AUTHOR_NAME "Patryk Kubiak") + +# Stack size for the module (should be integer) +set(DMOD_STACK_SIZE 1024) + +# Path to the DMR file for this module +set(DMOD_DMR_PATH ${CMAKE_SOURCE_DIR}/dmsai_port.dmr) + +# Adding sources common for the families +set(COMMON_SOURCES "") +if(DMOD_CPU_FAMILY MATCHES "^stm32") + set(COMMON_SOURCES stm32_common/stm32_common.c) +endif() + +# +# dmod_add_library - create a library module +# it has the same signature as add_library +# and can be used in the same way after the creation +# (for example, to link libraries) +# +dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} + # List of source files - can include C and C++ files + ${DMOD_CPU_FAMILY}/port.c + ${COMMON_SOURCES} +) + +# To depend on another module's headers, use: +# dmod_link_modules(${DMOD_MODULE_NAME} +# other_module@1.0 +# ) + +target_include_directories(${DMOD_MODULE_NAME} BEFORE PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_include_directories(${DMOD_MODULE_NAME}_if INTERFACE + ${CMAKE_SOURCE_DIR}/include +) diff --git a/src/port/stm32_common/stm32_common.c b/src/port/stm32_common/stm32_common.c new file mode 100644 index 0000000..e69de29 diff --git a/src/port/stm32f7/config.cmake b/src/port/stm32f7/config.cmake new file mode 100644 index 0000000..05a32b2 --- /dev/null +++ b/src/port/stm32f7/config.cmake @@ -0,0 +1,6 @@ +# DMOD_TOOLS_NAME must match a directory under dmod/configs/arch/... +# Known mappings used elsewhere in the ecosystem: +# stm32f7 -> arch/armv7/cortex-m7 +# stm32f4 -> arch/armv7/cortex-m4 +# x86_64 -> arch/x86_64 +set(DMOD_TOOLS_NAME "arch/armv7/cortex-m7" CACHE STRING "Name of the tools configuration") diff --git a/src/port/stm32f7/port.c b/src/port/stm32f7/port.c new file mode 100644 index 0000000..778e068 --- /dev/null +++ b/src/port/stm32f7/port.c @@ -0,0 +1,29 @@ +#define DMOD_ENABLE_REGISTRATION ON +#include "dmsai_port.h" +#include "dmod.h" + +/* ---- DMOD lifecycle ---- */ + +int dmod_init(const Dmod_Config_t *Config) +{ + Dmod_Printf("dmsai port module initialized (stm32f7)\n"); + return 0; +} + +int dmod_deinit(void) +{ + Dmod_Printf("dmsai port module deinitialized (stm32f7)\n"); + return 0; +} + +/* ---- API implementation ---- + * + * Implement the dmod_dmsai_port_api_declaration(...) functions + * declared in include/dmsai_port.h here. Register an interrupt + * handler if needed, e.g.: + * + * DMOD_IRQ_HANDLER(SOME_IRQn) + * { + * // handle interrupt + * } + */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9c8c6dd..5b106e0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,12 @@ dmod_add_test(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION} dmsai_test.c ) +target_include_directories(${DMOD_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../include +) + +target_link_libraries(${DMOD_MODULE_NAME} dmsai_if) + # Register the test module with ctest - this replays the same two steps CI # runs (see .github/templates/ci.yml.template): install the test module's # dependencies with dmf-get, then execute it through dmod_loader. The test's diff --git a/tests/dmsai_test.c b/tests/dmsai_test.c index d5ac9c1..1088a57 100644 --- a/tests/dmsai_test.c +++ b/tests/dmsai_test.c @@ -1,12 +1,29 @@ #define DMOD_ENABLE_REGISTRATION ON #include "dmod_test.h" +#include "dmsai.h" -/* Optional lifecycle hooks */ -// void dmod_test_setup(void) { /* reset state */ } -// void dmod_test_teardown(void) { /* cleanup */ } +void dmod_test_setup(void) +{ + // g_handle = dmsai_create(); +} -DMOD_TEST_STEP(example) +void dmod_test_teardown(void) { - /* Replace with real assertions once the module has behavior to test. */ - DMOD_TEST_EXPECT_TRUE(1); + // g_handle = NULL; } + +// DMOD_TEST_STEP(dmsai_create) +// { +// DMOD_TEST_EXPECT_NOT_NULL(g_handle); +// } + +// DMOD_TEST_STEP(dmsai_is_valid) +// { +// DMOD_TEST_EXPECT_TRUE(dmsai_is_valid(g_handle)); +// } + +// DMOD_TEST_STEP(dmsai_destroy_null) +// { +// /* Destroying NULL must not crash. */ +// dmsai_destroy(NULL); +// }