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.