Rozdział 3. Architektura oprogramowania

Rozdział 2. Architektura sprzętu | OpenDiag - STM32 CAN Tool | Rozdział 4. Konfiguracja STM32


Rozdział 3. Architektura oprogramowania

3.1 Cel

Architektura oprogramowania ma zapewnić:

  • modułowość,
  • łatwość rozbudowy,
  • niezależność od konkretnego STM32,
  • możliwość ponownego wykorzystania modułów,
  • prostą wymianę sterowników sprzętowych.

3.2 Warstwy oprogramowania

Proponuję następujący podział:

.                   +--------------------------+
                    |        Applications      |
                    +--------------------------+
                    |         Services         |
                    +--------------------------+
                    |        Protocols         |
                    +--------------------------+
                    |        Interfaces        |
                    +--------------------------+
                    |         Drivers          |
                    +--------------------------+
                    |           BSP            |
                    +--------------------------+
                    |          STM32           |
                    +--------------------------+

Każda warstwa może korzystać tylko z warstwy bezpośrednio poniżej.


3.3 BSP (Board Support Package)

Ta warstwa zawiera wszystko, co zależy od płytki.

Przykładowo:

BSP
 ├── bsp_clock
 ├── bsp_gpio
 ├── bsp_uart
 ├── bsp_usb
 ├── bsp_can
 └── bsp_led

Jeżeli kiedyś zmienimy F767 na H723, to właśnie tutaj zajdą największe zmiany.


3.4 Drivers

Sterowniki urządzeń.

Drivers
 ├── CAN
 ├── USB
 ├── UART
 ├── SD
 └── Flash

Tutaj HAL jest dozwolony.

Wyżej już nie.


3.5 Interfaces

To warstwa abstrakcji.

Np.

ICan
IUsb
ILogger
IStorage

Parser ELM nie będzie wiedział, czy pracuje na bxCAN czy FDCAN.

Wywoła tylko:

CAN_Send()

3.6 Protocols

Tutaj znajduje się cała wiedza o protokołach.

Protocols

ELM327

STN

OBD-II

ISO-TP

UDS

Ta warstwa nie wie nic o STM32.


3.7 Services

Łączy kilka protokołów.

Np.

Adapter Service

CAN Monitor

Logger

Configuration

Firmware Update

3.8 Applications

Najwyższa warstwa.

To właściwie gotowe programy.

Przykład:

Adapter

Sniffer

Logger

Bootloader

SelfTest

Dzięki temu z tego samego kodu można zbudować kilka różnych firmware.


3.9 Proponowana struktura katalogów

Firmware/

    App/

    BSP/

    Drivers/

    Interfaces/

    Middleware/

    Protocols/

    Services/

    ThirdParty/

    Tests/

    Docs/

3.10 Zależności

Najważniejsza zasada projektu.

Application

↓

Services

↓

Protocols

↓

Interfaces

↓

Drivers

↓

BSP

Nigdy odwrotnie.

Na przykład:

❌ BSP nie może wywoływać parsera ELM.

❌ Driver CAN nie może znać ISO-TP.


3.11 Moduły

Każdy moduł posiada:

module.c

module.h

Opcjonalnie:

module_cfg.h

module_private.h

3.12 Styl API

Nie chciałbym robić czegoś takiego:

HAL_CAN_AddTxMessage(...)

w dowolnym miejscu projektu.

Lepszy styl:

CAN_Send(...)

CAN_Read(...)

CAN_Filter(...)

A dopiero Driver CAN używa HAL.


3.13 Kolejki komunikacyjne

Już teraz warto założyć, że komunikacja między modułami będzie odbywać się przez kolejki lub bufory pierścieniowe.

Na przykład:

USB RX
      ↓
Parser
      ↓
ELM
      ↓
CAN Queue
      ↓
Driver CAN

Dzięki temu łatwiej będzie później przejść na FreeRTOS lub obsłużyć kilka źródeł danych jednocześnie.


3.14 Logowanie

Od początku przewidujemy wspólny moduł logowania.

Przykładowe poziomy:

ERROR

WARNING

INFO

DEBUG

Na początku logi będą wysyłane przez Virtual COM ST-Link.

Później będzie można dodać:

  • USB,
  • Ethernet,
  • plik na SD.

3.15 Konfiguracja

Projekt powinien mieć jedno miejsce przechowujące konfigurację.

Np.

config.h 

lub

config/

board_cfg.h

adapter_cfg.h

Jedna rzecz, którą chciałbym zmienić

Patrząc na nasz projekt, mam wrażenie, że "Protocols" i "Services" mogą z czasem mocno urosnąć. Dlatego proponuję od razu rozdzielić dwa światy:

Protocols/
    elm327/
    stn/
    isotp/
    uds/

Core/
    can/
    usb/
    cli/
    logger/
    config/

Czyli Core zawiera ogólną infrastrukturę (kolejki, CAN API, USB, konfigurację, logowanie), a Protocols wyłącznie implementacje protokołów diagnostycznych. Dzięki temu dodanie np. protokołu KWP2000 albo J1939 będzie polegało tylko na dopisaniu nowego katalogu w Protocols, bez naruszania reszty projektu.

Moim zdaniem taka architektura będzie bardziej czytelna i lepiej przetrwa rozwój projektu przez kolejne miesiące.