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()
+212
View File
@@ -0,0 +1,212 @@
#!/bin/bash
/**
* @file build_all.sh
* @brief Build all targets for Automotive RTOS
*/
set -e # Exit on error
# 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'
NC='\033[0m' # No Color
# Build configuration
BUILD_DIR="${PROJECT_ROOT}/build"
LOG_DIR="${BUILD_DIR}/logs"
TARGETS=("stm32f407_discovery" "nxp_s32k144_evb" "custom_ecu")
BUILD_TYPES=("debug" "release")
# Create directories
mkdir -p "${BUILD_DIR}"
mkdir -p "${LOG_DIR}"
# Print banner
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Automotive RTOS Build System${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
# Function to build target
build_target() {
local target=$1
local build_type=$2
echo -e "${YELLOW}Building ${target} (${build_type})...${NC}"
local build_dir="${BUILD_DIR}/${target}/${build_type}"
mkdir -p "${build_dir}"
# Change to build directory
cd "${build_dir}"
# Run CMake
cmake "${PROJECT_ROOT}" \
-DTARGET_BOARD=${target} \
-DCMAKE_BUILD_TYPE=${build_type} \
-DCMAKE_TOOLCHAIN_FILE="${PROJECT_ROOT}/cmake/toolchain-${target}.cmake" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
2>&1 | tee "${LOG_DIR}/${target}_${build_type}_configure.log"
# Build
make -j$(nproc) 2>&1 | tee "${LOG_DIR}/${target}_${build_type}_build.log"
# Check build result
if [ $? -eq 0 ]; then
echo -e "${GREEN}${target} (${build_type}) built successfully${NC}"
else
echo -e "${RED}${target} (${build_type}) build failed${NC}"
return 1
fi
# Generate artifacts
echo -e "${YELLOW}Generating artifacts...${NC}"
# Create hex file
arm-none-eabi-objcopy -O ihex "${build_dir}/automotive_rtos.elf" \
"${build_dir}/automotive_rtos.hex"
# Create binary file
arm-none-eabi-objcopy -O binary "${build_dir}/automotive_rtos.elf" \
"${build_dir}/automotive_rtos.bin"
# Generate size report
arm-none-eabi-size "${build_dir}/automotive_rtos.elf" > \
"${build_dir}/size_report.txt"
# Generate map file
arm-none-eabi-nm -n "${build_dir}/automotive_rtos.elf" > \
"${build_dir}/symbols.txt"
echo -e "${GREEN}✓ Artifacts generated${NC}"
echo ""
return 0
}
# Function to run tests
run_tests() {
echo -e "${YELLOW}Running unit tests...${NC}"
local test_dir="${BUILD_DIR}/tests"
mkdir -p "${test_dir}"
# Run each test
for test_file in "${PROJECT_ROOT}"/tests/unit/test_*.c; do
test_name=$(basename "${test_file}" .c)
echo -e " Testing ${test_name}..."
# Compile test
gcc -I"${PROJECT_ROOT}/kernel/include" \
-I"${PROJECT_ROOT}/tests" \
-I"${PROJECT_ROOT}/third_party/unity" \
"${test_file}" \
"${PROJECT_ROOT}/tests/unity/unity.c" \
-o "${test_dir}/${test_name}" \
-Wall -Wextra -g
# Run test
if "${test_dir}/${test_name}" > "${LOG_DIR}/${test_name}.log" 2>&1; then
echo -e "${GREEN}${test_name} passed${NC}"
else
echo -e "${RED}${test_name} failed${NC}"
cat "${LOG_DIR}/${test_name}.log"
return 1
fi
done
echo -e "${GREEN}✓ All tests passed${NC}"
echo ""
}
# Main build process
main() {
local build_failed=0
# Parse arguments
local clean_build=false
local run_all_tests=false
while [[ $# -gt 0 ]]; do
case $1 in
--clean)
clean_build=true
shift
;;
--test)
run_all_tests=true
shift
;;
--target)
TARGETS=("$2")
shift 2
;;
--type)
BUILD_TYPES=("$2")
shift 2
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Clean build if requested
if [ "${clean_build}" = true ]; then
echo -e "${YELLOW}Cleaning build directory...${NC}"
rm -rf "${BUILD_DIR}"
mkdir -p "${BUILD_DIR}"
echo -e "${GREEN}✓ Clean complete${NC}"
echo ""
fi
# Build all targets
for target in "${TARGETS[@]}"; do
for build_type in "${BUILD_TYPES[@]}"; do
if ! build_target "${target}" "${build_type}"; then
build_failed=1
fi
done
done
# Run tests if requested
if [ "${run_all_tests}" = true ]; then
if ! run_tests; then
build_failed=1
fi
fi
# Print summary
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Build Summary${NC}"
echo -e "${GREEN}========================================${NC}"
if [ ${build_failed} -eq 0 ]; then
echo -e "${GREEN}✓ All builds successful${NC}"
else
echo -e "${RED}✗ Some builds failed${NC}"
exit 1
fi
# Print size reports
echo ""
echo -e "${YELLOW}Size Reports:${NC}"
for target in "${TARGETS[@]}"; do
for build_type in "${BUILD_TYPES[@]}"; do
size_file="${BUILD_DIR}/${target}/${build_type}/size_report.txt"
if [ -f "${size_file}" ]; then
echo -e " ${target} (${build_type}):"
cat "${size_file}" | tail -n 2
fi
done
done
}
# Run main
main "$@"
+219
View File
@@ -0,0 +1,219 @@
#!/bin/bash
/**
* @file build_target.sh
* @brief Build specific target
*/
set -e
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# Default values
TARGET=""
BUILD_TYPE="debug"
CLEAN=false
VERBOSE=false
JOBS=$(nproc)
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Function to print usage
print_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -t, --target <target> Target board (required)"
echo " Available: stm32f407_discovery"
echo " nxp_s32k144_evb"
echo " custom_ecu"
echo " -b, --build-type <type> Build type (default: debug)"
echo " Available: debug, release"
echo " -c, --clean Clean build"
echo " -v, --verbose Verbose output"
echo " -j, --jobs <number> Number of parallel jobs"
echo " -h, --help Show this help"
echo ""
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--target)
TARGET="$2"
shift 2
;;
-b|--build-type)
BUILD_TYPE="$2"
shift 2
;;
-c|--clean)
CLEAN=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-j|--jobs)
JOBS="$2"
shift 2
;;
-h|--help)
print_usage
exit 0
;;
*)
echo "Unknown option: $1"
print_usage
exit 1
;;
esac
done
# Validate target
if [ -z "${TARGET}" ]; then
echo -e "${RED}Error: Target not specified${NC}"
print_usage
exit 1
fi
# Validate build type
case "${BUILD_TYPE}" in
debug|release)
;;
*)
echo -e "${RED}Error: Invalid build type: ${BUILD_TYPE}${NC}"
exit 1
;;
esac
# Build directories
BUILD_DIR="${PROJECT_ROOT}/build/${TARGET}/${BUILD_TYPE}"
LOG_DIR="${PROJECT_ROOT}/build/logs"
# Create directories
mkdir -p "${BUILD_DIR}"
mkdir -p "${LOG_DIR}"
# Print build info
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Building Automotive RTOS${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e " Target: ${YELLOW}${TARGET}${NC}"
echo -e " Build Type: ${YELLOW}${BUILD_TYPE}${NC}"
echo -e " Jobs: ${YELLOW}${JOBS}${NC}"
echo ""
# Clean if requested
if [ "${CLEAN}" = true ]; then
echo -e "${YELLOW}Cleaning build directory...${NC}"
rm -rf "${BUILD_DIR}"/*
echo -e "${GREEN}✓ Clean complete${NC}"
echo ""
fi
# Configure
echo -e "${YELLOW}Configuring build...${NC}"
# Set CMake arguments
CMAKE_ARGS=(
"${PROJECT_ROOT}"
"-DTARGET_BOARD=${TARGET}"
"-DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
"-DCMAKE_TOOLCHAIN_FILE=${PROJECT_ROOT}/cmake/toolchain-${TARGET}.cmake"
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
)
if [ "${VERBOSE}" = true ]; then
CMAKE_ARGS+=("-DCMAKE_VERBOSE_MAKEFILE=ON")
fi
# Run CMake
cd "${BUILD_DIR}"
cmake "${CMAKE_ARGS[@]}" 2>&1 | tee "${LOG_DIR}/${TARGET}_${BUILD_TYPE}_configure.log"
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Configuration failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Configuration complete${NC}"
echo ""
# Build
echo -e "${YELLOW}Building...${NC}"
make -j${JOBS} 2>&1 | tee "${LOG_DIR}/${TARGET}_${BUILD_TYPE}_build.log"
if [ $? -ne 0 ]; then
echo -e "${RED}✗ Build failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Build complete${NC}"
echo ""
# Generate artifacts
echo -e "${YELLOW}Generating artifacts...${NC}"
ELF_FILE="${BUILD_DIR}/automotive_rtos.elf"
HEX_FILE="${BUILD_DIR}/automotive_rtos.hex"
BIN_FILE="${BUILD_DIR}/automotive_rtos.bin"
MAP_FILE="${BUILD_DIR}/automotive_rtos.map"
SIZE_FILE="${BUILD_DIR}/size_report.txt"
# Generate hex file
arm-none-eabi-objcopy -O ihex "${ELF_FILE}" "${HEX_FILE}"
# Generate binary file
arm-none-eabi-objcopy -O binary "${ELF_FILE}" "${BIN_FILE}"
# Generate map file
arm-none-eabi-nm -n "${ELF_FILE}" > "${MAP_FILE}"
# Generate size report
arm-none-eabi-size "${ELF_FILE}" > "${SIZE_FILE}"
echo -e "${GREEN}✓ Artifacts generated:${NC}"
echo -e " ELF: ${BLUE}${ELF_FILE}${NC}"
echo -e " HEX: ${BLUE}${HEX_FILE}${NC}"
echo -e " BIN: ${BLUE}${BIN_FILE}${NC}"
echo -e " MAP: ${BLUE}${MAP_FILE}${NC}"
echo ""
# Print size report
echo -e "${YELLOW}Size Report:${NC}"
cat "${SIZE_FILE}"
echo ""
# Run static analysis if available
if command -v cppcheck >/dev/null 2>&1; then
echo -e "${YELLOW}Running static analysis...${NC}"
cppcheck \
--enable=all \
--inconclusive \
--std=c11 \
--platform=arm32 \
-I"${PROJECT_ROOT}/kernel/include" \
-I"${PROJECT_ROOT}/drivers/include" \
-I"${PROJECT_ROOT}/middleware/include" \
"${PROJECT_ROOT}/kernel/src" \
"${PROJECT_ROOT}/drivers/src" \
"${PROJECT_ROOT}/middleware/src" \
2>&1 | tee "${LOG_DIR}/${TARGET}_${BUILD_TYPE}_cppcheck.log"
echo -e "${GREEN}✓ Static analysis complete${NC}"
echo ""
fi
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Build Successful${NC}"
echo -e "${GREEN}========================================${NC}"
+189
View File
@@ -0,0 +1,189 @@
#!/bin/bash
/**
* @file flash_target.sh
* @brief Flash firmware to target board
*/
set -e
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
# Default values
TARGET=""
BUILD_TYPE="debug"
PROGRAMMER=""
INTERFACE=""
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Function to print usage
print_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -t, --target <target> Target board (required)"
echo " -b, --build-type <type> Build type (default: debug)"
echo " -p, --programmer <prog> Programmer type"
echo " Available: stlink, jlink, openocd"
echo " -i, --interface <iface> Debug interface"
echo " Available: swd, jtag"
echo " -h, --help Show this help"
echo ""
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--target)
TARGET="$2"
shift 2
;;
-b|--build-type)
BUILD_TYPE="$2"
shift 2
;;
-p|--programmer)
PROGRAMMER="$2"
shift 2
;;
-i|--interface)
INTERFACE="$2"
shift 2
;;
-h|--help)
print_usage
exit 0
;;
*)
echo "Unknown option: $1"
print_usage
exit 1
;;
esac
done
# Validate target
if [ -z "${TARGET}" ]; then
echo -e "${RED}Error: Target not specified${NC}"
print_usage
exit 1
fi
# Set default programmer based on target
if [ -z "${PROGRAMMER}" ]; then
case "${TARGET}" in
stm32f407_discovery)
PROGRAMMER="stlink"
INTERFACE="swd"
;;
nxp_s32k144_evb)
PROGRAMMER="jlink"
INTERFACE="swd"
;;
custom_ecu)
PROGRAMMER="openocd"
INTERFACE="swd"
;;
esac
fi
# Firmware file
FIRMWARE_FILE="${PROJECT_ROOT}/build/${TARGET}/${BUILD_TYPE}/automotive_rtos.elf"
HEX_FILE="${PROJECT_ROOT}/build/${TARGET}/${BUILD_TYPE}/automotive_rtos.hex"
# Check if firmware exists
if [ ! -f "${FIRMWARE_FILE}" ]; then
echo -e "${RED}Error: Firmware not found: ${FIRMWARE_FILE}${NC}"
echo -e "${YELLOW}Run build_target.sh first${NC}"
exit 1
fi
# Print flash info
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Flashing Firmware${NC}"
echo -e "${BLUE}========================================${NC}"
echo -e " Target: ${YELLOW}${TARGET}${NC}"
echo -e " Programmer: ${YELLOW}${PROGRAMMER}${NC}"
echo -e " Interface: ${YELLOW}${INTERFACE}${NC}"
echo -e " Firmware: ${YELLOW}${FIRMWARE_FILE}${NC}"
echo ""
# Flash based on programmer
case "${PROGRAMMER}" in
stlink)
echo -e "${YELLOW}Flashing with ST-Link...${NC}"
st-flash --reset write "${HEX_FILE}" 0x08000000
;;
jlink)
echo -e "${YELLOW}Flashing with J-Link...${NC}"
# Create J-Link script
JLINK_SCRIPT="${PROJECT_ROOT}/build/flash.jlink"
cat > "${JLINK_SCRIPT}" << EOF
device ${TARGET}
si ${INTERFACE}
speed 4000
loadfile ${HEX_FILE}
r
g
q
EOF
JLinkExe -CommanderScript "${JLINK_SCRIPT}"
;;
openocd)
echo -e "${YELLOW}Flashing with OpenOCD...${NC}"
# OpenOCD configuration
case "${TARGET}" in
stm32f407_discovery)
OOCD_CFG="board/stm32f4discovery.cfg"
;;
*)
OOCD_CFG="board/${TARGET}.cfg"
;;
esac
openocd \
-f "interface/${INTERFACE}.cfg" \
-f "${OOCD_CFG}" \
-c "program ${FIRMWARE_FILE} verify reset exit"
;;
*)
echo -e "${RED}Error: Unknown programmer: ${PROGRAMMER}${NC}"
exit 1
;;
esac
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Flash successful${NC}"
else
echo -e "${RED}✗ Flash failed${NC}"
exit 1
fi
# Verify flash
echo -e "${YELLOW}Verifying flash...${NC}"
case "${PROGRAMMER}" in
stlink)
st-flash verify "${HEX_FILE}"
;;
*)
echo -e "${YELLOW}Verification not supported for ${PROGRAMMER}${NC}"
;;
esac
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} Flash Complete${NC}"
echo -e "${GREEN}========================================${NC}"
+217
View File
@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""
@file config_generator.py
@brief Configuration file generator for Automotive RTOS
"""
import os
import sys
import argparse
import json
from pathlib import Path
from typing import Dict, List, Any
class ConfigGenerator:
"""Generate RTOS configuration files"""
def __init__(self, project_root):
self.project_root = Path(project_root)
self.config_dir = self.project_root / 'config'
def load_configuration(self, config_file):
"""Load configuration from JSON file"""
with open(config_file, 'r') as f:
return json.load(f)
def generate_kernel_config(self, config: Dict[str, Any]):
"""Generate kernel_config.h"""
print("Generating kernel_config.h...")
kernel = config.get('kernel', {})
content = f"""/**
* @file kernel_config.h
* @brief Kernel configuration (auto-generated)
* @note This file is auto-generated. Do not modify manually.
*/
#ifndef KERNEL_CONFIG_H
#define KERNEL_CONFIG_H
/* ============================================================================
* Basic Kernel Configuration
* ============================================================================ */
#define MAX_TASKS {kernel.get('max_tasks', 32)}
#define MAX_PRIORITY_LEVELS {kernel.get('max_priorities', 16)}
#define TICK_RATE_HZ {kernel.get('tick_rate', 1000)}
#define MAX_TASK_NAME_LENGTH {kernel.get('max_task_name_length', 16)}
/* ============================================================================
* Scheduler Configuration
* ============================================================================ */
#define SCHEDULER_TYPE SCHEDULER_PRIORITY_PREEMPTIVE
#define ENABLE_ROUND_ROBIN {1 if kernel.get('round_robin', True) else 0}
#define ROUND_ROBIN_TIME_SLICE {kernel.get('time_slice', 10)}
#define ENABLE_DEADLINE_MONITORING {1 if kernel.get('deadline_monitoring', True) else 0}
/* ============================================================================
* Synchronization Configuration
* ============================================================================ */
#define MAX_SEMAPHORES {kernel.get('max_semaphores', 32)}
#define MAX_MUTEXES {kernel.get('max_mutexes', 16)}
#define MAX_QUEUES {kernel.get('max_queues', 16)}
#define MAX_TIMERS {kernel.get('max_timers', 16)}
/* ============================================================================
* Memory Configuration
* ============================================================================ */
#define ENABLE_MEMORY_PROTECTION {1 if kernel.get('memory_protection', True) else 0}
#define ENABLE_STACK_CHECK {1 if kernel.get('stack_check', True) else 0}
#define DEFAULT_TASK_STACK_SIZE {kernel.get('default_stack_size', 1024)}
#define HEAP_SIZE {kernel.get('heap_size', 65536)}
#endif /* KERNEL_CONFIG_H */
"""
self._write_file(self.config_dir / 'kernel_config.h', content)
def generate_task_config(self, config: Dict[str, Any]):
"""Generate task_config.h"""
print("Generating task_config.h...")
tasks = config.get('tasks', [])
content = f"""/**
* @file task_config.h
* @brief Task configuration (auto-generated)
* @note This file is auto-generated. Do not modify manually.
*/
#ifndef TASK_CONFIG_H
#define TASK_CONFIG_H
#include "kernel_config.h"
/* ============================================================================
* Task Priority Definitions
* ============================================================================ */
"""
# Generate priority definitions
for task in tasks:
name = task['name'].upper().replace(' ', '_')
priority = task.get('priority', 0)
content += f"#define TASK_PRIORITY_{name:<30s} {priority}\n"
content += "\n/* ============================================================================\n"
content += " * Task Period Definitions (ms)\n"
content += " * ============================================================================ */\n"
# Generate period definitions
for task in tasks:
name = task['name'].upper().replace(' ', '_')
period = task.get('period_ms', 10)
content += f"#define TASK_PERIOD_{name:<30s} {period}\n"
content += "\n/* ============================================================================\n"
content += " * Task Stack Sizes (bytes)\n"
content += " * ============================================================================ */\n"
# Generate stack size definitions
for task in tasks:
name = task['name'].upper().replace(' ', '_')
stack_size = task.get('stack_size', 1024)
content += f"#define TASK_STACK_{name:<30s} {stack_size}\n"
content += "\n/* ============================================================================\n"
content += " * Task Configuration Table\n"
content += " * ============================================================================ */\n\n"
content += "static const TaskConfigEntry_t task_config_table[] = {\n"
content += " /* Name, Priority, Period, Stack, Deadline, Periodic, Critical */\n"
for task in tasks:
name = task['name']
priority = task.get('priority', 0)
period = task.get('period_ms', 10)
stack_size = task.get('stack_size', 1024)
deadline = task.get('deadline_ms', period)
periodic = 'true' if task.get('periodic', True) else 'false'
critical = 'true' if task.get('critical', False) else 'false'
content += f' {{"{name}", {priority}, {period}, {stack_size}, '
content += f'{deadline}, {periodic}, {critical}}},\n'
content += "};\n\n"
content += f"#define TASK_CONFIG_COUNT {len(tasks)}\n\n"
content += "#endif /* TASK_CONFIG_H */\n"
self._write_file(self.config_dir / 'task_config.h', content)
def generate_can_config(self, config: Dict[str, Any]):
"""Generate can_config.h"""
print("Generating can_config.h...")
can_config = config.get('can', {})
content = f"""/**
* @file can_config.h
* @brief CAN configuration (auto-generated)
*/
#ifndef CAN_CONFIG_H
#define CAN_CONFIG_H
/* CAN Baudrate */
#define CAN_BAUDRATE {can_config.get('baudrate', 500000)}
#define CAN_FD_BAUDRATE {can_config.get('fd_baudrate', 2000000)}
#define CAN_FD_ENABLED {1 if can_config.get('fd_enabled', False) else 0}
/* CAN Message IDs */
"""
# Generate message ID definitions
messages = can_config.get('messages', [])
for msg in messages:
name = msg['name'].upper().replace(' ', '_')
msg_id = msg.get('id', 0x100)
content += f"#define CAN_ID_{name:<30s} 0x{msg_id:03X}\n"
content += "\n#endif /* CAN_CONFIG_H */\n"
self._write_file(self.config_dir / 'can_config.h', content)
def _write_file(self, file_path: Path, content: str):
"""Write content to file"""
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, 'w') as f:
f.write(content)
print(f" Generated: {file_path}")
def generate(self, config_file: str):
"""Generate all configuration files"""
print("=" * 60)
print("Configuration Generator")
print("=" * 60)
config = self.load_configuration(config_file)
# Generate configuration files
self.generate_kernel_config(config)
self.generate_task_config(config)
self.generate_can_config(config)
print("\nConfiguration generation complete")
def main():
parser = argparse.ArgumentParser(description='Configuration generator')
parser.add_argument('config_file', help='Configuration JSON file')
parser.add_argument('--project', default='.', help='Project root directory')
args = parser.parse_args()
generator = ConfigGenerator(args.project)
generator.generate(args.config_file)
if __name__ == '__main__':
main()
+205
View File
@@ -0,0 +1,205 @@
#!/usr/bin/env python3
"""
@file task_priority_calculator.py
@brief Task priority calculator for Rate Monotonic Scheduling
"""
import sys
import argparse
from collections import defaultdict
from math import ceil
class TaskPriorityCalculator:
"""Calculate task priorities using RMS/DMS algorithms"""
def __init__(self):
self.tasks = []
def add_task(self, name, period_ms, execution_time_ms, deadline_ms=None):
"""Add task for analysis"""
if deadline_ms is None:
deadline_ms = period_ms
self.tasks.append({
'name': name,
'period': period_ms,
'execution_time': execution_time_ms,
'deadline': deadline_ms
})
def calculate_utilization(self):
"""Calculate CPU utilization"""
total_utilization = 0
for task in self.tasks:
utilization = task['execution_time'] / task['period']
task['utilization'] = utilization
total_utilization += utilization
return total_utilization
def rate_monotonic_priority(self):
"""Assign priorities using Rate Monotonic Scheduling"""
# Sort by period (shortest period = highest priority)
sorted_tasks = sorted(self.tasks, key=lambda x: x['period'])
for i, task in enumerate(sorted_tasks):
task['rms_priority'] = i
return sorted_tasks
def deadline_monotonic_priority(self):
"""Assign priorities using Deadline Monotonic Scheduling"""
# Sort by deadline (shortest deadline = highest priority)
sorted_tasks = sorted(self.tasks, key=lambda x: x['deadline'])
for i, task in enumerate(sorted_tasks):
task['dms_priority'] = i
return sorted_tasks
def check_schedulability(self):
"""Check if task set is schedulable"""
n = len(self.tasks)
total_utilization = self.calculate_utilization()
# Liu & Layland bound for RMS
rms_bound = n * (2 ** (1/n) - 1)
# Exact schedulability test
schedulable = True
for i, task in enumerate(sorted(self.tasks, key=lambda x: x['priority'])):
# Calculate response time
response_time = task['execution_time']
while True:
interference = 0
for j in range(i):
higher_task = self.tasks[j]
interference += ceil(response_time / higher_task['period']) * \
higher_task['execution_time']
new_response = task['execution_time'] + interference
if new_response == response_time:
break
response_time = new_response
if response_time > task['deadline']:
schedulable = False
break
task['response_time'] = response_time
if not schedulable:
break
return schedulable, total_utilization, rms_bound
def generate_report(self):
"""Generate priority assignment report"""
print("=" * 80)
print("Task Priority Calculation Report")
print("=" * 80)
print()
# Calculate utilization
total_utilization = self.calculate_utilization()
print("Task Set:")
print("-" * 80)
print(f"{'Task':20s} {'Period':>8s} {'Exec Time':>10s} {'Deadline':>8s} {'Util':>8s}")
print("-" * 80)
for task in self.tasks:
print(f"{task['name']:20s} {task['period']:8d} "
f"{task['execution_time']:10d} {task['deadline']:8d} "
f"{task['utilization']*100:7.2f}%")
print("-" * 80)
print(f"{'Total':20s} {'':>8s} {'':>10s} {'':>8s} {total_utilization*100:7.2f}%")
print()
# Rate Monotonic
print("Rate Monotonic Priority Assignment:")
print("-" * 40)
rms_tasks = self.rate_monotonic_priority()
for task in rms_tasks:
print(f" Priority {task['rms_priority']}: {task['name']}")
print()
# Deadline Monotonic
print("Deadline Monotonic Priority Assignment:")
print("-" * 40)
dms_tasks = self.deadline_monotonic_priority()
for task in dms_tasks:
print(f" Priority {task['dms_priority']}: {task['name']}")
print()
# Schedulability
schedulable, utilization, bound = self.check_schedulability()
print("Schedulability Analysis:")
print("-" * 40)
print(f"CPU Utilization: {utilization*100:.2f}%")
print(f"Theoretical Bound: {bound*100:.2f}%")
if schedulable:
print("✓ Task set is schedulable")
else:
print("✗ Task set is NOT schedulable")
print()
print("Response Times:")
print("-" * 40)
for task in self.tasks:
if 'response_time' in task:
print(f" {task['name']}: {task['response_time']}ms "
f"(deadline: {task['deadline']}ms)")
def main():
parser = argparse.ArgumentParser(description='Task priority calculator')
parser.add_argument('--tasks', nargs='+', help='Task definitions: name:period:exec[:deadline]')
parser.add_argument('--file', help='Task definition file')
args = parser.parse_args()
calculator = TaskPriorityCalculator()
# Load tasks from file or command line
if args.file:
with open(args.file, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
parts = line.split(':')
if len(parts) >= 3:
name = parts[0]
period = int(parts[1])
exec_time = int(parts[2])
deadline = int(parts[3]) if len(parts) > 3 else period
calculator.add_task(name, period, exec_time, deadline)
elif args.tasks:
for task_def in args.tasks:
parts = task_def.split(':')
if len(parts) >= 3:
name = parts[0]
period = int(parts[1])
exec_time = int(parts[2])
deadline = int(parts[3]) if len(parts) > 3 else period
calculator.add_task(name, period, exec_time, deadline)
else:
# Example tasks
print("Using example task set:")
calculator.add_task("Engine Control", 1, 0.5)
calculator.add_task("Brake Control", 5, 1)
calculator.add_task("CAN Communication", 10, 2)
calculator.add_task("Sensor Reading", 2, 0.3)
calculator.add_task("Display Update", 50, 10)
calculator.generate_report()
if __name__ == '__main__':
main()
+115
View File
@@ -0,0 +1,115 @@
# GDB initialization script for Automotive RTOS debugging
# Set target architecture
set architecture arm
set endian little
# Configure remote target
# target remote localhost:3333
# target remote :2331
# Set program counter
set $pc = Reset_Handler
# Break at main
break main
continue
# RTOS-specific commands
define rtos_tasks
echo === RTOS Tasks ===\n
set $task = task_list_head
while $task != 0
printf "Task: %s\n", $task->name
printf " ID: %d\n", $task->task_id
printf " Priority: %d\n", $task->priority
printf " State: %d\n", $task->state
printf " Stack: 0x%08x\n", $task->stack_pointer
printf " Stack Base: 0x%08x\n", $task->stack_base
printf " Stack Size: %d\n", $task->stack_size
printf "\n"
set $task = $task->next
end
end
define rtos_task_info
if $argc != 1
echo Usage: rtos_task_info <task_name>\n
else
set $task = task_list_head
while $task != 0
if $_streq($task->name, $arg0)
printf "Task Information:\n"
printf " Name: %s\n", $task->name
printf " ID: %d\n", $task->task_id
printf " Priority: %d\n", $task->priority
printf " State: %d\n", $task->state
printf " Stack Pointer: 0x%08x\n", $task->stack_pointer
printf " Stack Base: 0x%08x\n", $task->stack_base
printf " Stack Size: %d\n", $task->stack_size
printf " Stack Used: %d\n", $task->stack_high_water_mark
printf " Execution Count: %d\n", $task->statistics.execution_count
printf " Last Execution: %d\n", $task->statistics.last_execution_time
break
end
set $task = $task->next
end
if $task == 0
echo Task not found\n
end
end
end
define rtos_scheduler_stats
echo === Scheduler Statistics ===\n
printf "Context Switches: %d\n", scheduler_state.statistics.context_switches
printf "Preemptions: %d\n", scheduler_state.statistics.preemptions
printf "Max Latency: %d\n", scheduler_state.statistics.max_scheduling_latency
printf "Total Idle Time: %d\n", scheduler_state.statistics.total_idle_time
end
define rtos_semaphores
echo === Semaphores ===\n
# Iterate through semaphore list
echo Semaphore information not available in this build\n
end
define rtos_mutexes
echo === Mutexes ===\n
# Iterate through mutex list
echo Mutex information not available in this build\n
end
define rtos_queues
echo === Message Queues ===\n
# Iterate through queue list
echo Queue information not available in this build\n
end
define rtos_stack_check
echo === Stack Usage ===\n
set $task = task_list_head
while $task != 0
printf "%s: %d/%d bytes used\n", $task->name, $task->stack_high_water_mark, $task->stack_size
set $task = $task->next
end
end
# Pretty printing
set print pretty on
set print array on
set print elements 20
set print demangle on
# History
set history save on
set history size 1000
set history filename .gdb_history
# Convenience
set pagination off
set confirm off
set verbose off
# Display on stop
display/10i $pc
+213
View File
@@ -0,0 +1,213 @@
#!/usr/bin/env python3
"""
@file trace_analyzer.py
@brief Trace analyzer for Automotive RTOS debugging
"""
import os
import re
import sys
import argparse
import json
from collections import defaultdict
from datetime import datetime
from pathlib import Path
class TraceAnalyzer:
"""Analyze RTOS trace data"""
def __init__(self, trace_file):
self.trace_file = Path(trace_file)
self.events = []
self.task_timeline = defaultdict(list)
self.context_switches = []
self.interrupts = []
def parse_trace_file(self):
"""Parse trace file"""
print(f"Parsing trace file: {self.trace_file}")
if not self.trace_file.exists():
print(f"Error: Trace file not found")
return False
event_pattern = re.compile(
r'\[(\d+\.?\d*)\]\s+(\w+):\s+(.*)'
)
with open(self.trace_file, 'r') as f:
for line in f:
match = event_pattern.match(line)
if match:
timestamp = float(match.group(1))
event_type = match.group(2)
event_data = match.group(3)
event = {
'timestamp': timestamp,
'type': event_type,
'data': event_data
}
self.events.append(event)
# Categorize events
if event_type == 'TASK_SWITCH':
self.context_switches.append(event)
elif event_type == 'IRQ_ENTER':
self.interrupts.append(event)
elif event_type == 'TASK_START':
task_name = event_data.split(':')[0].strip()
self.task_timeline[task_name].append({
'type': 'start',
'timestamp': timestamp
})
elif event_type == 'TASK_END':
task_name = event_data.split(':')[0].strip()
self.task_timeline[task_name].append({
'type': 'end',
'timestamp': timestamp
})
print(f"Parsed {len(self.events)} events")
return True
def analyze_context_switches(self):
"""Analyze context switches"""
print("\nContext Switch Analysis:")
print("-" * 60)
if not self.context_switches:
print("No context switches found")
return
# Calculate intervals
intervals = []
for i in range(1, len(self.context_switches)):
interval = (self.context_switches[i]['timestamp'] -
self.context_switches[i-1]['timestamp'])
intervals.append(interval)
if intervals:
avg_interval = sum(intervals) / len(intervals)
min_interval = min(intervals)
max_interval = max(intervals)
print(f"Total context switches: {len(self.context_switches)}")
print(f"Average interval: {avg_interval:.3f} ms")
print(f"Minimum interval: {min_interval:.3f} ms")
print(f"Maximum interval: {max_interval:.3f} ms")
def analyze_task_execution(self):
"""Analyze task execution times"""
print("\nTask Execution Analysis:")
print("-" * 60)
print(f"{'Task Name':25s} {'Executions':>10s} {'Total Time':>10s} {'Avg Time':>10s}")
print("-" * 60)
for task_name, events in self.task_timeline.items():
executions = 0
total_time = 0
for i in range(0, len(events) - 1, 2):
if i + 1 < len(events):
if events[i]['type'] == 'start' and events[i+1]['type'] == 'end':
duration = events[i+1]['timestamp'] - events[i]['timestamp']
total_time += duration
executions += 1
if executions > 0:
avg_time = total_time / executions
print(f"{task_name:25s} {executions:10d} {total_time:10.3f} {avg_time:10.3f}")
def analyze_interrupts(self):
"""Analyze interrupt handling"""
print("\nInterrupt Analysis:")
print("-" * 40)
if not self.interrupts:
print("No interrupts found")
return
irq_count = defaultdict(int)
for irq in self.interrupts:
irq_name = irq['data'].strip()
irq_count[irq_name] += 1
for irq_name, count in irq_count.items():
print(f"{irq_name:20s} {count:5d} occurrences")
def generate_timeline(self, output_file):
"""Generate task timeline visualization"""
print(f"\nGenerating timeline: {output_file}")
with open(output_file, 'w') as f:
f.write("RTOS Task Timeline\n")
f.write("=" * 80 + "\n\n")
# Find time range
if not self.events:
return
start_time = self.events[0]['timestamp']
end_time = self.events[-1]['timestamp']
duration = end_time - start_time
f.write(f"Time range: {start_time:.3f} to {end_time:.3f} ms\n")
f.write(f"Duration: {duration:.3f} ms\n\n")
# Generate ASCII timeline
timeline_width = 80
time_per_char = duration / timeline_width if duration > 0 else 1
for task_name, events in self.task_timeline.items():
f.write(f"\n{task_name}:\n")
# Create timeline
timeline = [' '] * timeline_width
for i in range(0, len(events) - 1, 2):
if i + 1 < len(events):
start_pos = int((events[i]['timestamp'] - start_time) / time_per_char)
end_pos = int((events[i+1]['timestamp'] - start_time) / time_per_char)
for pos in range(start_pos, min(end_pos, timeline_width)):
if 0 <= pos < timeline_width:
timeline[pos] = '#'
f.write(''.join(timeline) + '\n')
f.write("\nLegend: '#' = task running, ' ' = task not running\n")
def analyze(self):
"""Run complete analysis"""
print("=" * 60)
print("Trace Analyzer")
print("=" * 60)
if not self.parse_trace_file():
return
self.analyze_context_switches()
self.analyze_task_execution()
self.analyze_interrupts()
# Generate timeline
output_dir = self.trace_file.parent
timeline_file = output_dir / 'timeline.txt'
self.generate_timeline(timeline_file)
print(f"\nTimeline saved to: {timeline_file}")
def main():
parser = argparse.ArgumentParser(description='Trace analyzer')
parser.add_argument('trace_file', help='Trace file to analyze')
parser.add_argument('--output', help='Output directory')
args = parser.parse_args()
analyzer = TraceAnalyzer(args.trace_file)
analyzer.analyze()
if __name__ == '__main__':
main()