Add full automotive RTOS project

Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
This commit is contained in:
root
2026-08-23 03:35:29 -04:00
parent f113bf0a05
commit ca13734bf0
151 changed files with 23945 additions and 0 deletions
+134
View File
@@ -0,0 +1,134 @@
#!/bin/bash
/**
* @file misra_checker.sh
* @brief MISRA C compliance checker
*/
set -e
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# MISRA configuration
MISRA_VERSION="MISRA C:2012"
MISRA_RULES="required" # required, advisory, all
# Source directories
SOURCE_DIRS=(
"${PROJECT_ROOT}/kernel/src"
"${PROJECT_ROOT}/drivers/src"
"${PROJECT_ROOT}/middleware"
"${PROJECT_ROOT}/applications"
)
# Report directory
REPORT_DIR="${PROJECT_ROOT}/build/misra"
mkdir -p "${REPORT_DIR}"
# Print banner
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} MISRA C Compliance Checker${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e " Version: ${YELLOW}${MISRA_VERSION}${NC}"
echo -e " Rules: ${YELLOW}${MISRA_RULES}${NC}"
echo ""
# Check if cppcheck is available
if ! command -v cppcheck >/dev/null 2>&1; then
echo -e "${RED}Error: cppcheck not found${NC}"
echo "Install with: sudo apt-get install cppcheck"
exit 1
fi
# Check if misra addon is available
MISRA_ADDON="/usr/share/cppcheck/addons/misra.py"
if [ ! -f "${MISRA_ADDON}" ]; then
echo -e "${YELLOW}Warning: MISRA addon not found at ${MISRA_ADDON}${NC}"
echo "Will use cppcheck with basic checks"
USE_MISRA_ADDON=false
else
USE_MISRA_ADDON=true
fi
# Function to check directory
check_directory() {
local dir=$1
local report_file="${REPORT_DIR}/$(basename ${dir})_misra.txt"
echo -e "${YELLOW}Checking ${dir}...${NC}"
if [ "${USE_MISRA_ADDON}" = true ]; then
cppcheck \
--enable=all \
--inconclusive \
--std=c11 \
--platform=arm32 \
--addon=misra \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
-I"${PROJECT_ROOT}/kernel/include" \
-I"${PROJECT_ROOT}/drivers/include" \
-I"${PROJECT_ROOT}/middleware" \
-I"${PROJECT_ROOT}/config" \
"${dir}" \
2>&1 | tee "${report_file}"
else
cppcheck \
--enable=all \
--inconclusive \
--std=c11 \
--platform=arm32 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
-I"${PROJECT_ROOT}/kernel/include" \
-I"${PROJECT_ROOT}/drivers/include" \
-I"${PROJECT_ROOT}/middleware" \
-I"${PROJECT_ROOT}/config" \
"${dir}" \
2>&1 | tee "${report_file}"
fi
# Count violations
local violations=$(grep -c "\[" "${report_file}" || true)
echo -e " Found ${violations} potential violations"
echo ""
}
# Check each source directory
TOTAL_VIOLATIONS=0
for dir in "${SOURCE_DIRS[@]}"; do
if [ -d "${dir}" ]; then
check_directory "${dir}"
fi
done
# Generate summary report
SUMMARY_FILE="${REPORT_DIR}/summary.txt"
echo "MISRA C Compliance Summary" > "${SUMMARY_FILE}"
echo "=========================" >> "${SUMMARY_FILE}"
echo "" >> "${SUMMARY_FILE}"
echo "Date: $(date)" >> "${SUMMARY_FILE}"
echo "Version: ${MISRA_VERSION}" >> "${SUMMARY_FILE}"
echo "Rules: ${MISRA_RULES}" >> "${SUMMARY_FILE}"
echo "" >> "${SUMMARY_FILE}"
for report in "${REPORT_DIR}"/*_misra.txt; do
if [ -f "${report}" ]; then
dir_name=$(basename "${report}" _misra.txt)
violations=$(grep -c "\[" "${report}" || true)
echo "${dir_name}: ${violations} violations" >> "${SUMMARY_FILE}"
fi
done
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} MISRA Check Complete${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "Summary: ${BLUE}${SUMMARY_FILE}${NC}"
+204
View File
@@ -0,0 +1,204 @@
#!/usr/bin/env python3
"""
@file stack_usage_analyzer.py
@brief Stack usage analyzer for Automotive RTOS
"""
import os
import re
import sys
import argparse
from collections import defaultdict
from pathlib import Path
class StackUsageAnalyzer:
"""Analyze stack usage from map files and source code"""
def __init__(self, project_root):
self.project_root = Path(project_root)
self.stack_usage = {}
self.function_sizes = {}
self.call_graph = defaultdict(list)
def parse_map_file(self, map_file):
"""Parse linker map file for symbol information"""
print(f"Parsing map file: {map_file}")
symbol_pattern = re.compile(
r'^\s+0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+(\w+)\s+(\w+)$'
)
with open(map_file, 'r') as f:
for line in f:
match = symbol_pattern.match(line)
if match:
address = int(match.group(1), 16)
size = int(match.group(2), 16)
section = match.group(3)
name = match.group(4)
if section in ['.text', '.data', '.bss']:
self.function_sizes[name] = {
'size': size,
'section': section,
'address': address
}
def analyze_source_files(self):
"""Analyze source files for stack allocation"""
print("Analyzing source files for stack usage...")
source_patterns = [
self.project_root / 'kernel' / 'src' / '**' / '*.c',
self.project_root / 'drivers' / 'src' / '**' / '*.c',
self.project_root / 'middleware' / '**' / 'src' / '**' / '*.c',
self.project_root / 'applications' / '**' / 'src' / '**' / '*.c',
]
stack_var_pattern = re.compile(
r'\b(?:uint8_t|uint16_t|uint32_t|int8_t|int16_t|int32_t|'
r'char|short|int|long|float|double|struct|union)\s+'
r'(\w+)\s*\[(\d+)\]'
)
for pattern in source_patterns:
for source_file in self.project_root.glob(str(pattern)):
self._analyze_source_file(source_file, stack_var_pattern)
def _analyze_source_file(self, source_file, pattern):
"""Analyze individual source file"""
try:
with open(source_file, 'r') as f:
content = f.read()
# Find all stack variables
for match in pattern.finditer(content):
var_name = match.group(1)
array_size = int(match.group(2))
# Estimate variable size
var_size = self._estimate_variable_size(match.group(0))
if var_size > 0:
print(f" {source_file.name}: {var_name}[{array_size}] = {var_size} bytes")
except Exception as e:
print(f" Warning: Could not analyze {source_file}: {e}")
def _estimate_variable_size(self, declaration):
"""Estimate variable size from declaration"""
size_map = {
'uint8_t': 1, 'int8_t': 1, 'char': 1,
'uint16_t': 2, 'int16_t': 2, 'short': 2,
'uint32_t': 4, 'int32_t': 4, 'int': 4, 'float': 4,
'uint64_t': 8, 'int64_t': 8, 'double': 8, 'long': 8,
}
for type_name, size in size_map.items():
if type_name in declaration:
# Find array size
array_match = re.search(r'\[(\d+)\]', declaration)
if array_match:
return size * int(array_match.group(1))
return size
return 0
def analyze_task_stacks(self):
"""Analyze task stack configurations"""
print("\nAnalyzing task stack configurations...")
task_config_file = self.project_root / 'config' / 'task_config.h'
if not task_config_file.exists():
print(" Task configuration file not found")
return
with open(task_config_file, 'r') as f:
content = f.read()
# Find stack size definitions
stack_pattern = re.compile(
r'#define\s+TASK_STACK_(\w+)\s+(\d+)'
)
total_stack = 0
task_count = 0
print("\n Task Stack Allocations:")
print(" " + "-" * 40)
for match in stack_pattern.finditer(content):
task_name = match.group(1)
stack_size = int(match.group(2))
total_stack += stack_size
task_count += 1
print(f" {task_name:30s} {stack_size:8d} bytes")
print(" " + "-" * 40)
print(f" Total: {total_stack} bytes across {task_count} tasks")
def generate_report(self, output_file):
"""Generate stack usage report"""
print(f"\nGenerating report: {output_file}")
with open(output_file, 'w') as f:
f.write("=" * 80 + "\n")
f.write("Stack Usage Analysis Report\n")
f.write("=" * 80 + "\n\n")
# Function sizes
f.write("Function Sizes:\n")
f.write("-" * 40 + "\n")
f.write(f"{'Function':30s} {'Size':>8s} {'Section':10s}\n")
f.write("-" * 40 + "\n")
for name, info in sorted(self.function_sizes.items(),
key=lambda x: x[1]['size'], reverse=True):
f.write(f"{name:30s} {info['size']:8d} {info['section']:10s}\n")
f.write("\n\n")
# Recommendations
f.write("Recommendations:\n")
f.write("-" * 40 + "\n")
f.write("1. Review functions with large stack allocations\n")
f.write("2. Consider using static allocation for large buffers\n")
f.write("3. Monitor stack usage during runtime\n")
f.write("4. Ensure stack overflow detection is enabled\n")
def analyze(self, map_file=None):
"""Run complete analysis"""
print("=" * 60)
print("Stack Usage Analyzer")
print("=" * 60)
# Parse map file if provided
if map_file and os.path.exists(map_file):
self.parse_map_file(map_file)
# Analyze source files
self.analyze_source_files()
# Analyze task stacks
self.analyze_task_stacks()
# Generate report
report_file = self.project_root / 'build' / 'stack_usage_report.txt'
report_file.parent.mkdir(parents=True, exist_ok=True)
self.generate_report(report_file)
print(f"\nReport saved to: {report_file}")
def main():
parser = argparse.ArgumentParser(description='Stack usage analyzer')
parser.add_argument('--project', default='.', help='Project root directory')
parser.add_argument('--map-file', help='Linker map file')
parser.add_argument('--output', help='Output report file')
args = parser.parse_args()
analyzer = StackUsageAnalyzer(args.project)
analyzer.analyze(args.map_file)
if __name__ == '__main__':
main()
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""
@file timing_analyzer.py
@brief Timing analyzer for Automotive RTOS
"""
import os
import re
import sys
import argparse
import json
from collections import defaultdict
from pathlib import Path
class TimingAnalyzer:
"""Analyze timing requirements and performance"""
def __init__(self, project_root):
self.project_root = Path(project_root)
self.tasks = {}
self.timing_data = defaultdict(list)
self.violations = []
def analyze_task_configuration(self):
"""Analyze task timing configuration"""
print("Analyzing task configuration...")
task_config_file = self.project_root / 'config' / 'task_config.h'
if not task_config_file.exists():
print("Task configuration file not found")
return
with open(task_config_file, 'r') as f:
content = f.read()
# Parse task priorities and periods
task_pattern = re.compile(
r'\{"([^"]+)",\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(true|false),\s*(true|false)\}'
)
print("\nTask Configuration:")
print("-" * 80)
print(f"{'Task Name':25s} {'Priority':>8s} {'Period':>8s} {'Deadline':>8s}")
print("-" * 80)
for match in task_pattern.finditer(content):
task_name = match.group(1)
priority = int(match.group(2))
period = int(match.group(3))
deadline = int(match.group(5))
self.tasks[task_name] = {
'priority': priority,
'period': period,
'deadline': deadline
}
print(f"{task_name:25s} {priority:8d} {period:8d} {deadline:8d}")
print("-" * 80)
def analyze_schedulability(self):
"""Analyze task schedulability"""
print("\nSchedulability Analysis:")
print("-" * 60)
# Calculate CPU utilization
total_utilization = 0
for task_name, config in self.tasks.items():
if config['period'] > 0:
utilization = config['deadline'] / config['period']
total_utilization += utilization
print(f"{task_name:25s} {utilization*100:6.2f}%")
print("-" * 60)
print(f"Total CPU Utilization: {total_utilization*100:.2f}%")
# Check schedulability
if total_utilization < 0.69: # Liu & Layland bound for RM
print("✓ System is schedulable (Rate Monotonic)")
else:
print("⚠ System may not be schedulable")
self.violations.append("High CPU utilization")
def analyze_timing_logs(self, log_file):
"""Analyze timing logs"""
if not os.path.exists(log_file):
print(f"Timing log not found: {log_file}")
return
print(f"\nAnalyzing timing log: {log_file}")
with open(log_file, 'r') as f:
for line in f:
# Parse timing data
match = re.match(
r'\[(\d+)\]\s+(\w+):\s+start=(\d+)\s+end=(\d+)\s+duration=(\d+)'
, line)
if match:
timestamp = int(match.group(1))
task_name = match.group(2)
duration = int(match.group(5))
self.timing_data[task_name].append({
'timestamp': timestamp,
'duration': duration
})
# Calculate statistics
print("\nTiming Statistics:")
print("-" * 80)
print(f"{'Task Name':25s} {'Count':>6s} {'Min':>8s} {'Max':>8s} {'Avg':>8s} {'Jitter':>8s}")
print("-" * 80)
for task_name, measurements in self.timing_data.items():
if measurements:
durations = [m['duration'] for m in measurements]
count = len(durations)
min_duration = min(durations)
max_duration = max(durations)
avg_duration = sum(durations) / count
jitter = max_duration - min_duration
print(f"{task_name:25s} {count:6d} {min_duration:8d} "
f"{max_duration:8d} {avg_duration:8.1f} {jitter:8d}")
# Check for violations
if task_name in self.tasks:
deadline = self.tasks[task_name]['deadline']
if max_duration > deadline:
self.violations.append(
f"{task_name} exceeds deadline: {max_duration} > {deadline}"
)
def analyze_interrupt_timing(self):
"""Analyze interrupt timing"""
print("\nInterrupt Timing Analysis:")
print("-" * 40)
# Common interrupt latencies
interrupts = {
'SysTick': {'priority': 15, 'typical_latency': 1},
'CAN': {'priority': 5, 'typical_latency': 2},
'UART': {'priority': 6, 'typical_latency': 1},
'SPI': {'priority': 7, 'typical_latency': 1},
'I2C': {'priority': 7, 'typical_latency': 2},
'ADC': {'priority': 8, 'typical_latency': 3},
'Timer': {'priority': 8, 'typical_latency': 1},
}
for irq_name, config in interrupts.items():
print(f"{irq_name:15s} Priority: {config['priority']:2d} "
f"Latency: {config['typical_latency']}ms")
def generate_report(self, output_file):
"""Generate timing analysis report"""
print(f"\nGenerating report: {output_file}")
with open(output_file, 'w') as f:
f.write("=" * 80 + "\n")
f.write("Timing Analysis Report\n")
f.write("=" * 80 + "\n\n")
# Task configuration
f.write("Task Configuration:\n")
f.write("-" * 40 + "\n")
for task_name, config in self.tasks.items():
f.write(f"{task_name}: Priority={config['priority']}, "
f"Period={config['period']}ms, Deadline={config['deadline']}ms\n")
f.write("\n")
# Violations
if self.violations:
f.write("Timing Violations:\n")
f.write("-" * 40 + "\n")
for violation in self.violations:
f.write(f"{violation}\n")
else:
f.write("No timing violations detected.\n")
def analyze(self, timing_log=None):
"""Run complete analysis"""
print("=" * 60)
print("Timing Analyzer")
print("=" * 60)
self.analyze_task_configuration()
self.analyze_schedulability()
self.analyze_interrupt_timing()
if timing_log:
self.analyze_timing_logs(timing_log)
# Generate report
report_file = self.project_root / 'build' / 'timing_report.txt'
report_file.parent.mkdir(parents=True, exist_ok=True)
self.generate_report(report_file)
print(f"\nReport saved to: {report_file}")
def main():
parser = argparse.ArgumentParser(description='Timing analyzer')
parser.add_argument('--project', default='.', help='Project root directory')
parser.add_argument('--timing-log', help='Timing log file')
args = parser.parse_args()
analyzer = TimingAnalyzer(args.project)
analyzer.analyze(args.timing_log)
if __name__ == '__main__':
main()