Carregar ficheiros para "src/core"
This commit is contained in:
1
src/core/__init__.py
Normal file
1
src/core/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
118
src/core/command.py
Normal file
118
src/core/command.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import List, Tuple, Any
|
||||||
|
import numpy as np
|
||||||
|
from .file_handler import MapData
|
||||||
|
|
||||||
|
class Command(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def undo(self) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MapValueCommand(Command):
|
||||||
|
"""Command for single value changes in a map"""
|
||||||
|
def __init__(self, map_data: MapData, x: int, y: int, new_value: float):
|
||||||
|
self.map_data = map_data
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.new_value = new_value
|
||||||
|
self.old_value = map_data.data[x, y]
|
||||||
|
|
||||||
|
def execute(self) -> bool:
|
||||||
|
try:
|
||||||
|
self.map_data.data[self.x, self.y] = self.new_value
|
||||||
|
self.map_data.modified = True
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def undo(self) -> bool:
|
||||||
|
try:
|
||||||
|
self.map_data.data[self.x, self.y] = self.old_value
|
||||||
|
self.map_data.modified = True
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
class RegionCommand(Command):
|
||||||
|
"""Command for region modifications"""
|
||||||
|
def __init__(self, map_data: MapData, x1: int, y1: int, x2: int, y2: int,
|
||||||
|
new_values: np.ndarray):
|
||||||
|
self.map_data = map_data
|
||||||
|
self.x1 = x1
|
||||||
|
self.y1 = y1
|
||||||
|
self.x2 = x2
|
||||||
|
self.y2 = y2
|
||||||
|
self.new_values = new_values
|
||||||
|
self.old_values = map_data.data[x1:x2+1, y1:y2+1].copy()
|
||||||
|
|
||||||
|
def execute(self) -> bool:
|
||||||
|
try:
|
||||||
|
self.map_data.data[self.x1:self.x2+1, self.y1:self.y2+1] = self.new_values
|
||||||
|
self.map_data.modified = True
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def undo(self) -> bool:
|
||||||
|
try:
|
||||||
|
self.map_data.data[self.x1:self.x2+1, self.y1:self.y2+1] = self.old_values
|
||||||
|
self.map_data.modified = True
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
class CommandHistory:
|
||||||
|
def __init__(self, max_history: int = 50):
|
||||||
|
self.max_history = max_history
|
||||||
|
self.history: List[Command] = []
|
||||||
|
self.current: int = -1
|
||||||
|
|
||||||
|
def execute(self, command: Command) -> bool:
|
||||||
|
"""Execute a new command and add it to history"""
|
||||||
|
if command.execute():
|
||||||
|
# Remove any undone commands
|
||||||
|
if self.current < len(self.history) - 1:
|
||||||
|
self.history = self.history[:self.current + 1]
|
||||||
|
|
||||||
|
self.history.append(command)
|
||||||
|
self.current += 1
|
||||||
|
|
||||||
|
# Limit history size
|
||||||
|
if len(self.history) > self.max_history:
|
||||||
|
self.history = self.history[-self.max_history:]
|
||||||
|
self.current = len(self.history) - 1
|
||||||
|
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def undo(self) -> bool:
|
||||||
|
"""Undo the last command"""
|
||||||
|
if self.can_undo():
|
||||||
|
if self.history[self.current].undo():
|
||||||
|
self.current -= 1
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def redo(self) -> bool:
|
||||||
|
"""Redo the last undone command"""
|
||||||
|
if self.can_redo():
|
||||||
|
self.current += 1
|
||||||
|
return self.history[self.current].execute()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def can_undo(self) -> bool:
|
||||||
|
"""Check if undo is possible"""
|
||||||
|
return self.current >= 0
|
||||||
|
|
||||||
|
def can_redo(self) -> bool:
|
||||||
|
"""Check if redo is possible"""
|
||||||
|
return self.current < len(self.history) - 1
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Clear command history"""
|
||||||
|
self.history.clear()
|
||||||
|
self.current = -1
|
||||||
160
src/core/edc15_definitions.py
Normal file
160
src/core/edc15_definitions.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
from typing import Dict, List
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MapAxis:
|
||||||
|
name: str
|
||||||
|
values: List[float]
|
||||||
|
units: str
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class EDC15MapInfo:
|
||||||
|
name: str
|
||||||
|
address: int
|
||||||
|
rows: int
|
||||||
|
cols: int
|
||||||
|
value_type: str
|
||||||
|
description: str
|
||||||
|
x_axis: MapAxis
|
||||||
|
y_axis: MapAxis
|
||||||
|
units: str
|
||||||
|
|
||||||
|
# Common EDC15 map definitions
|
||||||
|
EDC15_MAPS = {
|
||||||
|
# Fuel Maps
|
||||||
|
"MAIN_FUEL_MAP": EDC15MapInfo(
|
||||||
|
name="Mapa Principal de Combustível",
|
||||||
|
address=0x4000, # Example address
|
||||||
|
rows=16,
|
||||||
|
cols=16,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa principal de injeção de combustível",
|
||||||
|
x_axis=MapAxis("RPM", [800, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
|
||||||
|
4500, 5000, 5500, 6000, 6500, 7000, 7500, 8000],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Load", [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
|
||||||
|
110, 120, 130, 140, 150],
|
||||||
|
"%"),
|
||||||
|
units="mg/stroke"
|
||||||
|
),
|
||||||
|
|
||||||
|
"PILOT_INJECTION": EDC15MapInfo(
|
||||||
|
name="Mapa de Pré-Injeção",
|
||||||
|
address=0x4400, # Example address
|
||||||
|
rows=12,
|
||||||
|
cols=12,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa de controle da pré-injeção",
|
||||||
|
x_axis=MapAxis("RPM", [800, 1200, 1600, 2000, 2400, 2800, 3200, 3600,
|
||||||
|
4000, 4400, 4800, 5200],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Load", [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165],
|
||||||
|
"%"),
|
||||||
|
units="mg/stroke"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Boost Maps
|
||||||
|
"BOOST_CONTROL": EDC15MapInfo(
|
||||||
|
name="Mapa de Controle de Boost",
|
||||||
|
address=0x4800, # Example address
|
||||||
|
rows=16,
|
||||||
|
cols=12,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa de controle de pressão do turbo",
|
||||||
|
x_axis=MapAxis("RPM", [1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500,
|
||||||
|
5000, 5500, 6000, 6500],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Load", [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
|
||||||
|
110, 120, 130, 140, 150],
|
||||||
|
"%"),
|
||||||
|
units="mbar"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Timing Maps
|
||||||
|
"INJECTION_TIMING": EDC15MapInfo(
|
||||||
|
name="Mapa de Avanço de Injeção",
|
||||||
|
address=0x4C00, # Example address
|
||||||
|
rows=16,
|
||||||
|
cols=16,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa de avanço do ponto de injeção",
|
||||||
|
x_axis=MapAxis("RPM", [800, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
|
||||||
|
4500, 5000, 5500, 6000, 6500, 7000, 7500, 8000],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Load", [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
|
||||||
|
110, 120, 130, 140, 150],
|
||||||
|
"%"),
|
||||||
|
units="degrees"
|
||||||
|
),
|
||||||
|
|
||||||
|
# EGR Maps
|
||||||
|
"EGR_CONTROL": EDC15MapInfo(
|
||||||
|
name="Mapa de Controle EGR",
|
||||||
|
address=0x5000, # Example address
|
||||||
|
rows=12,
|
||||||
|
cols=12,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa de controle da válvula EGR",
|
||||||
|
x_axis=MapAxis("RPM", [800, 1200, 1600, 2000, 2400, 2800, 3200, 3600,
|
||||||
|
4000, 4400, 4800, 5200],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Load", [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165],
|
||||||
|
"%"),
|
||||||
|
units="%"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Limit Maps
|
||||||
|
"TORQUE_LIMIT": EDC15MapInfo(
|
||||||
|
name="Mapa de Limite de Torque",
|
||||||
|
address=0x5400, # Example address
|
||||||
|
rows=12,
|
||||||
|
cols=16,
|
||||||
|
value_type="float32",
|
||||||
|
description="Mapa de limite de torque do motor",
|
||||||
|
x_axis=MapAxis("RPM", [800, 1000, 1500, 2000, 2500, 3000, 3500, 4000,
|
||||||
|
4500, 5000, 5500, 6000, 6500, 7000, 7500, 8000],
|
||||||
|
"rpm"),
|
||||||
|
y_axis=MapAxis("Temperature", [0, 20, 40, 60, 70, 75, 80, 85, 90, 95,
|
||||||
|
100, 105],
|
||||||
|
"°C"),
|
||||||
|
units="Nm"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checksum regions
|
||||||
|
CHECKSUM_REGIONS = [
|
||||||
|
(0x0000, 0x1000), # Example region 1
|
||||||
|
(0x4000, 0x6000), # Example region 2
|
||||||
|
]
|
||||||
|
|
||||||
|
# Known file signatures
|
||||||
|
EDC15_SIGNATURES = {
|
||||||
|
"EDC15P": bytes([0x55, 0xAA, 0x55, 0xAA]),
|
||||||
|
"EDC15V": bytes([0xAA, 0x55, 0xAA, 0x55]),
|
||||||
|
}
|
||||||
|
|
||||||
|
def calculate_checksum(data: bytes, start: int, end: int) -> int:
|
||||||
|
"""Calculate checksum for a region of data"""
|
||||||
|
checksum = 0
|
||||||
|
for i in range(start, end):
|
||||||
|
if i < len(data):
|
||||||
|
checksum = (checksum + data[i]) & 0xFF
|
||||||
|
return checksum
|
||||||
|
|
||||||
|
def validate_ecu_file(data: bytes) -> bool:
|
||||||
|
"""Validate EDC15 file format and checksums"""
|
||||||
|
if len(data) < 0x8000: # Minimum size check
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check for known signatures
|
||||||
|
for sig_name, signature in EDC15_SIGNATURES.items():
|
||||||
|
if data.startswith(signature):
|
||||||
|
# Verify checksums for each region
|
||||||
|
for start, end in CHECKSUM_REGIONS:
|
||||||
|
stored_checksum = data[end] if end < len(data) else 0
|
||||||
|
calculated = calculate_checksum(data, start, end)
|
||||||
|
if stored_checksum != calculated:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
131
src/core/edc15_maps.py
Normal file
131
src/core/edc15_maps.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
from typing import Dict, List, Tuple
|
||||||
|
import numpy as np
|
||||||
|
from .file_handler import MapData
|
||||||
|
|
||||||
|
class EDC15MapDefinition:
|
||||||
|
def __init__(self, name: str, address: int, rows: int, cols: int,
|
||||||
|
value_type: str, description: str = ""):
|
||||||
|
self.name = name
|
||||||
|
self.address = address
|
||||||
|
self.rows = rows
|
||||||
|
self.cols = cols
|
||||||
|
self.value_type = value_type # 'uint8', 'uint16', 'float'
|
||||||
|
self.description = description
|
||||||
|
|
||||||
|
class EDC15MapDetector:
|
||||||
|
# Common EDC15 map signatures
|
||||||
|
KNOWN_SIGNATURES = {
|
||||||
|
b'\x00\x00\x80\x3F': 'float32', # 1.0f in IEEE 754
|
||||||
|
b'\x00\x00\x00\x40': 'float32', # 2.0f in IEEE 754
|
||||||
|
b'\xCD\xCC\xCC\x3D': 'float32', # 0.1f in IEEE 754
|
||||||
|
}
|
||||||
|
|
||||||
|
# Common map sizes in EDC15
|
||||||
|
COMMON_SIZES = [(8, 8), (16, 16), (12, 12), (16, 12), (12, 16)]
|
||||||
|
|
||||||
|
def __init__(self, data: bytes):
|
||||||
|
self.data = data
|
||||||
|
self.size = len(data)
|
||||||
|
|
||||||
|
def find_potential_maps(self) -> List[EDC15MapDefinition]:
|
||||||
|
"""
|
||||||
|
Find potential maps in the binary data based on known patterns
|
||||||
|
"""
|
||||||
|
potential_maps = []
|
||||||
|
|
||||||
|
# Search for known signatures
|
||||||
|
for signature, value_type in self.KNOWN_SIGNATURES.items():
|
||||||
|
offset = 0
|
||||||
|
while True:
|
||||||
|
offset = self.data.find(signature, offset)
|
||||||
|
if offset == -1:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check for potential map structure around signature
|
||||||
|
for rows, cols in self.COMMON_SIZES:
|
||||||
|
if self._validate_map_structure(offset, rows, cols, value_type):
|
||||||
|
map_def = EDC15MapDefinition(
|
||||||
|
f"Map_0x{offset:X}",
|
||||||
|
offset,
|
||||||
|
rows,
|
||||||
|
cols,
|
||||||
|
value_type
|
||||||
|
)
|
||||||
|
potential_maps.append(map_def)
|
||||||
|
|
||||||
|
offset += len(signature)
|
||||||
|
|
||||||
|
return potential_maps
|
||||||
|
|
||||||
|
def _validate_map_structure(self, offset: int, rows: int, cols: int,
|
||||||
|
value_type: str) -> bool:
|
||||||
|
"""
|
||||||
|
Validate if a potential map structure exists at the given offset
|
||||||
|
"""
|
||||||
|
# Calculate required space for the map
|
||||||
|
bytes_per_value = 4 if value_type == 'float32' else 2
|
||||||
|
required_space = rows * cols * bytes_per_value
|
||||||
|
|
||||||
|
# Check if we have enough space in the file
|
||||||
|
if offset + required_space > self.size:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Validate data consistency
|
||||||
|
try:
|
||||||
|
data = self._extract_map_data(offset, rows, cols, value_type)
|
||||||
|
|
||||||
|
# Check for reasonable value ranges
|
||||||
|
if value_type == 'float32':
|
||||||
|
if not np.all(np.isfinite(data)):
|
||||||
|
return False
|
||||||
|
if np.any(np.abs(data) > 1000000): # Unreasonable values
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check for patterns that suggest this is actually a map
|
||||||
|
# 1. Check if values are somewhat continuous
|
||||||
|
differences = np.abs(np.diff(data.ravel()))
|
||||||
|
if np.max(differences) > 1000: # Too large jumps between values
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 2. Check if there's some variation (not all same value)
|
||||||
|
if np.all(data == data[0, 0]):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _extract_map_data(self, offset: int, rows: int, cols: int,
|
||||||
|
value_type: str) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Extract map data from binary file
|
||||||
|
"""
|
||||||
|
bytes_per_value = 4 if value_type == 'float32' else 2
|
||||||
|
total_bytes = rows * cols * bytes_per_value
|
||||||
|
|
||||||
|
raw_data = self.data[offset:offset + total_bytes]
|
||||||
|
|
||||||
|
if value_type == 'float32':
|
||||||
|
data = np.frombuffer(raw_data, dtype=np.float32)
|
||||||
|
else:
|
||||||
|
data = np.frombuffer(raw_data, dtype=np.uint16)
|
||||||
|
|
||||||
|
return data.reshape((rows, cols))
|
||||||
|
|
||||||
|
def extract_map(self, map_def: EDC15MapDefinition) -> MapData:
|
||||||
|
"""
|
||||||
|
Extract map data based on map definition
|
||||||
|
"""
|
||||||
|
data = self._extract_map_data(
|
||||||
|
map_def.address,
|
||||||
|
map_def.rows,
|
||||||
|
map_def.cols,
|
||||||
|
map_def.value_type
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create axis data (placeholder - should be extracted from actual file)
|
||||||
|
x_axis = np.linspace(0, map_def.cols - 1, map_def.cols)
|
||||||
|
y_axis = np.linspace(0, map_def.rows - 1, map_def.rows)
|
||||||
|
|
||||||
|
return MapData(map_def.name, data, x_axis, y_axis)
|
||||||
504
src/core/edc15p_maps.py
Normal file
504
src/core/edc15p_maps.py
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MapDefinition:
|
||||||
|
name: str
|
||||||
|
address: str # Hex address in the binary
|
||||||
|
rows: int
|
||||||
|
cols: int
|
||||||
|
x_axis: List[float]
|
||||||
|
y_axis: List[float]
|
||||||
|
description: str
|
||||||
|
units: str
|
||||||
|
category: str
|
||||||
|
group: str
|
||||||
|
|
||||||
|
# Map definitions for EDC15P
|
||||||
|
EDC15P_MAPS = {
|
||||||
|
# Drivers Wish [FUEL]
|
||||||
|
"drivers_wish_1": MapDefinition(
|
||||||
|
name="Drivers Wish Map 1",
|
||||||
|
address="04D206",
|
||||||
|
rows=12,
|
||||||
|
cols=8,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70], # Load %
|
||||||
|
description="Drivers Wish Map 1",
|
||||||
|
units="FUEL",
|
||||||
|
category="Fuel",
|
||||||
|
group="Drivers Wish [FUEL]"
|
||||||
|
),
|
||||||
|
"drivers_wish_2": MapDefinition(
|
||||||
|
name="Drivers Wish Map 2",
|
||||||
|
address="06D206",
|
||||||
|
rows=12,
|
||||||
|
cols=8,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70], # Load %
|
||||||
|
description="Drivers Wish Map 2",
|
||||||
|
units="FUEL",
|
||||||
|
category="Fuel",
|
||||||
|
group="Drivers Wish [FUEL]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Torque [FUEL]
|
||||||
|
"torque_1": MapDefinition(
|
||||||
|
name="Torque Map 1",
|
||||||
|
address="04D8D2",
|
||||||
|
rows=3,
|
||||||
|
cols=20,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95], # Load %
|
||||||
|
description="Torque Control Map 1",
|
||||||
|
units="FUEL",
|
||||||
|
category="Torque",
|
||||||
|
group="Torque [FUEL]"
|
||||||
|
),
|
||||||
|
"torque_2": MapDefinition(
|
||||||
|
name="Torque Map 2",
|
||||||
|
address="06D8D2",
|
||||||
|
rows=3,
|
||||||
|
cols=20,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95], # Load %
|
||||||
|
description="Torque Control Map 2",
|
||||||
|
units="FUEL",
|
||||||
|
category="Torque",
|
||||||
|
group="Torque [FUEL]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Smoke Limiter [FUEL]
|
||||||
|
"smoke_limiter_1": MapDefinition(
|
||||||
|
name="Smoke Limiter Map 1",
|
||||||
|
address="04DA04",
|
||||||
|
rows=16,
|
||||||
|
cols=13,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200, 5600], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Smoke Limiter Map 1",
|
||||||
|
units="FUEL",
|
||||||
|
category="Limiters",
|
||||||
|
group="Smoke Limiter [FUEL]"
|
||||||
|
),
|
||||||
|
"smoke_limiter_2": MapDefinition(
|
||||||
|
name="Smoke Limiter Map 2",
|
||||||
|
address="04DBF6",
|
||||||
|
rows=16,
|
||||||
|
cols=13,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200, 5600], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Smoke Limiter Map 2",
|
||||||
|
units="FUEL",
|
||||||
|
category="Limiters",
|
||||||
|
group="Smoke Limiter [FUEL]"
|
||||||
|
),
|
||||||
|
"smoke_limiter_3": MapDefinition(
|
||||||
|
name="Smoke Limiter Map 3",
|
||||||
|
address="06DA04",
|
||||||
|
rows=16,
|
||||||
|
cols=13,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200, 5600], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Smoke Limiter Map 3",
|
||||||
|
units="FUEL",
|
||||||
|
category="Limiters",
|
||||||
|
group="Smoke Limiter [FUEL]"
|
||||||
|
),
|
||||||
|
"smoke_limiter_4": MapDefinition(
|
||||||
|
name="Smoke Limiter Map 4",
|
||||||
|
address="06DBF6",
|
||||||
|
rows=16,
|
||||||
|
cols=13,
|
||||||
|
x_axis=[800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800, 5200, 5600], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Smoke Limiter Map 4",
|
||||||
|
units="FUEL",
|
||||||
|
category="Limiters",
|
||||||
|
group="Smoke Limiter [FUEL]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Speed Limiter Via Temp [ENGINE LOAD]
|
||||||
|
"speed_temp_limiter_1": MapDefinition(
|
||||||
|
name="Speed Temperature Limiter 1",
|
||||||
|
address="04E732",
|
||||||
|
rows=4,
|
||||||
|
cols=4,
|
||||||
|
x_axis=[0, 30, 60, 90], # Temperature
|
||||||
|
y_axis=[0, 25, 50, 75], # Speed %
|
||||||
|
description="Speed Limiter via Temperature Map 1",
|
||||||
|
units="ENGINE LOAD",
|
||||||
|
category="Limiters",
|
||||||
|
group="Speed Limiter Via Temp [ENGINE LOAD]"
|
||||||
|
),
|
||||||
|
"speed_temp_limiter_2": MapDefinition(
|
||||||
|
name="Speed Temperature Limiter 2",
|
||||||
|
address="06E732",
|
||||||
|
rows=4,
|
||||||
|
cols=4,
|
||||||
|
x_axis=[0, 30, 60, 90], # Temperature
|
||||||
|
y_axis=[0, 25, 50, 75], # Speed %
|
||||||
|
description="Speed Limiter via Temperature Map 2",
|
||||||
|
units="ENGINE LOAD",
|
||||||
|
category="Limiters",
|
||||||
|
group="Speed Limiter Via Temp [ENGINE LOAD]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Injection Limiter Via Temp [LOAD]
|
||||||
|
"injection_temp_limiter_1": MapDefinition(
|
||||||
|
name="Injection Temperature Limiter 1",
|
||||||
|
address="04F238",
|
||||||
|
rows=3,
|
||||||
|
cols=3,
|
||||||
|
x_axis=[0, 50, 100], # Temperature
|
||||||
|
y_axis=[0, 50, 100], # Load %
|
||||||
|
description="Injection Limiter via Temperature Map 1",
|
||||||
|
units="LOAD",
|
||||||
|
category="Limiters",
|
||||||
|
group="Injection Limiter Via Temp [LOAD]"
|
||||||
|
),
|
||||||
|
"injection_temp_limiter_2": MapDefinition(
|
||||||
|
name="Injection Temperature Limiter 2",
|
||||||
|
address="06F238",
|
||||||
|
rows=3,
|
||||||
|
cols=3,
|
||||||
|
x_axis=[0, 50, 100], # Temperature
|
||||||
|
y_axis=[0, 50, 100], # Load %
|
||||||
|
description="Injection Limiter via Temperature Map 2",
|
||||||
|
units="LOAD",
|
||||||
|
category="Limiters",
|
||||||
|
group="Injection Limiter Via Temp [LOAD]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Boost Limiter Via Temperature [mBAR]
|
||||||
|
"boost_temp_limiter_1": MapDefinition(
|
||||||
|
name="Boost Temperature Limiter 1",
|
||||||
|
address="051FA0",
|
||||||
|
rows=16,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300], # Temperature
|
||||||
|
description="Boost Limiter via Temperature Map 1",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Boost Limiter Via Temperature [mBAR]"
|
||||||
|
),
|
||||||
|
"boost_temp_limiter_2": MapDefinition(
|
||||||
|
name="Boost Temperature Limiter 2",
|
||||||
|
address="071FA0",
|
||||||
|
rows=16,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300], # Temperature
|
||||||
|
description="Boost Limiter via Temperature Map 2",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Boost Limiter Via Temperature [mBAR]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Spraying Time [DEG]
|
||||||
|
"spraying_time_1": MapDefinition(
|
||||||
|
name="Spraying Time Map 1",
|
||||||
|
address="054548",
|
||||||
|
rows=10,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90], # Load %
|
||||||
|
description="Spraying Time Map 1",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_2": MapDefinition(
|
||||||
|
name="Spraying Time Map 2",
|
||||||
|
address="05465C",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 2",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_3": MapDefinition(
|
||||||
|
name="Spraying Time Map 3",
|
||||||
|
address="0548E2",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 3",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_4": MapDefinition(
|
||||||
|
name="Spraying Time Map 4",
|
||||||
|
address="054B68",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 4",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_5": MapDefinition(
|
||||||
|
name="Spraying Time Map 5",
|
||||||
|
address="074548",
|
||||||
|
rows=10,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90], # Load %
|
||||||
|
description="Spraying Time Map 5",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_6": MapDefinition(
|
||||||
|
name="Spraying Time Map 6",
|
||||||
|
address="07465C",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 6",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_7": MapDefinition(
|
||||||
|
name="Spraying Time Map 7",
|
||||||
|
address="0748E2",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 7",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
"spraying_time_8": MapDefinition(
|
||||||
|
name="Spraying Time Map 8",
|
||||||
|
address="074B68",
|
||||||
|
rows=15,
|
||||||
|
cols=19,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000], # RPM
|
||||||
|
y_axis=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90], # Load %
|
||||||
|
description="Spraying Time Map 8",
|
||||||
|
units="DEG",
|
||||||
|
category="Timing",
|
||||||
|
group="Spraying Time [DEG]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Air Mass Substitutive value [FUEL]
|
||||||
|
"air_mass_sub_1": MapDefinition(
|
||||||
|
name="Air Mass Substitutive Value 1",
|
||||||
|
address="055632",
|
||||||
|
rows=8,
|
||||||
|
cols=8,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70], # Load %
|
||||||
|
description="Air Mass Substitutive Value Map 1",
|
||||||
|
units="FUEL",
|
||||||
|
category="Air Mass",
|
||||||
|
group="Air Mass Substitutive value [FUEL]"
|
||||||
|
),
|
||||||
|
"air_mass_sub_2": MapDefinition(
|
||||||
|
name="Air Mass Substitutive Value 2",
|
||||||
|
address="075632",
|
||||||
|
rows=8,
|
||||||
|
cols=8,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70], # Load %
|
||||||
|
description="Air Mass Substitutive Value Map 2",
|
||||||
|
units="FUEL",
|
||||||
|
category="Air Mass",
|
||||||
|
group="Air Mass Substitutive value [FUEL]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Boost Pressure [mBAR]
|
||||||
|
"boost_pressure_1": MapDefinition(
|
||||||
|
name="Boost Pressure Map 1",
|
||||||
|
address="056926",
|
||||||
|
rows=16,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Boost Pressure Control Map 1",
|
||||||
|
units="mBAR",
|
||||||
|
category="Boost",
|
||||||
|
group="Boost Pressure [mBAR]"
|
||||||
|
),
|
||||||
|
"boost_pressure_2": MapDefinition(
|
||||||
|
name="Boost Pressure Map 2",
|
||||||
|
address="076926",
|
||||||
|
rows=16,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150], # Load %
|
||||||
|
description="Boost Pressure Control Map 2",
|
||||||
|
units="mBAR",
|
||||||
|
category="Boost",
|
||||||
|
group="Boost Pressure [mBAR]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Boost Limiter Via Patm [mBAR]
|
||||||
|
"boost_patm_limiter_1": MapDefinition(
|
||||||
|
name="Boost Patm Limiter 1",
|
||||||
|
address="056F1C",
|
||||||
|
rows=10,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[800, 850, 900, 950, 1000, 1050, 1100, 1150, 1200, 1250], # Atmospheric Pressure
|
||||||
|
description="Boost Limiter via Atmospheric Pressure Map 1",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Boost Limiter Via Patm [mBAR]"
|
||||||
|
),
|
||||||
|
"boost_patm_limiter_2": MapDefinition(
|
||||||
|
name="Boost Patm Limiter 2",
|
||||||
|
address="076F1C",
|
||||||
|
rows=10,
|
||||||
|
cols=10,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500], # RPM
|
||||||
|
y_axis=[800, 850, 900, 950, 1000, 1050, 1100, 1150, 1200, 1250], # Atmospheric Pressure
|
||||||
|
description="Boost Limiter via Atmospheric Pressure Map 2",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Boost Limiter Via Patm [mBAR]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Advance Limiter Via Temp [DEG]
|
||||||
|
"advance_temp_limiter_1": MapDefinition(
|
||||||
|
name="Advance Temperature Limiter 1",
|
||||||
|
address="0581B6",
|
||||||
|
rows=14,
|
||||||
|
cols=11,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130], # Temperature
|
||||||
|
description="Advance Limiter via Temperature Map 1",
|
||||||
|
units="DEG",
|
||||||
|
category="Limiters",
|
||||||
|
group="Advance Limiter Via Temp [DEG]"
|
||||||
|
),
|
||||||
|
"advance_temp_limiter_2": MapDefinition(
|
||||||
|
name="Advance Temperature Limiter 2",
|
||||||
|
address="0781B6",
|
||||||
|
rows=14,
|
||||||
|
cols=11,
|
||||||
|
x_axis=[0, 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000], # RPM
|
||||||
|
y_axis=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130], # Temperature
|
||||||
|
description="Advance Limiter via Temperature Map 2",
|
||||||
|
units="DEG",
|
||||||
|
category="Limiters",
|
||||||
|
group="Advance Limiter Via Temp [DEG]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Idle Speed [RPM]
|
||||||
|
"idle_speed_1": MapDefinition(
|
||||||
|
name="Idle Speed Control 1",
|
||||||
|
address="056FEC",
|
||||||
|
rows=1,
|
||||||
|
cols=2,
|
||||||
|
x_axis=[0], # No X axis (single column)
|
||||||
|
y_axis=[0, 1], # Two states
|
||||||
|
description="Idle Speed Control Map 1",
|
||||||
|
units="RPM",
|
||||||
|
category="Speed",
|
||||||
|
group="Idle Speed [RPM]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Maximum Boost Pressure [mBAR]
|
||||||
|
"max_boost_pressure_1": MapDefinition(
|
||||||
|
name="Maximum Boost Pressure 1",
|
||||||
|
address="051C84",
|
||||||
|
rows=1,
|
||||||
|
cols=1,
|
||||||
|
x_axis=[0], # Single value
|
||||||
|
y_axis=[0], # Single value
|
||||||
|
description="Maximum Boost Pressure Map 1",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Maximum Boost Pressure [mBAR]"
|
||||||
|
),
|
||||||
|
"max_boost_pressure_2": MapDefinition(
|
||||||
|
name="Maximum Boost Pressure 2",
|
||||||
|
address="071C84",
|
||||||
|
rows=1,
|
||||||
|
cols=1,
|
||||||
|
x_axis=[0], # Single value
|
||||||
|
y_axis=[0], # Single value
|
||||||
|
description="Maximum Boost Pressure Map 2",
|
||||||
|
units="mBAR",
|
||||||
|
category="Limiters",
|
||||||
|
group="Maximum Boost Pressure [mBAR]"
|
||||||
|
),
|
||||||
|
|
||||||
|
# Maximum RPM Limiter [RPM]
|
||||||
|
"max_rpm_limiter_1": MapDefinition(
|
||||||
|
name="Maximum RPM Limiter 1",
|
||||||
|
address="0541A3",
|
||||||
|
rows=1,
|
||||||
|
cols=1,
|
||||||
|
x_axis=[0], # Single value
|
||||||
|
y_axis=[0], # Single value
|
||||||
|
description="Maximum RPM Limiter Map 1",
|
||||||
|
units="RPM",
|
||||||
|
category="Limiters",
|
||||||
|
group="Maximum RPM Limiter [RPM]"
|
||||||
|
),
|
||||||
|
"max_rpm_limiter_2": MapDefinition(
|
||||||
|
name="Maximum RPM Limiter 2",
|
||||||
|
address="0741A3",
|
||||||
|
rows=1,
|
||||||
|
cols=1,
|
||||||
|
x_axis=[0], # Single value
|
||||||
|
y_axis=[0], # Single value
|
||||||
|
description="Maximum RPM Limiter Map 2",
|
||||||
|
units="RPM",
|
||||||
|
category="Limiters",
|
||||||
|
group="Maximum RPM Limiter [RPM]"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_map_definition(map_id: str) -> Optional[MapDefinition]:
|
||||||
|
"""Get map definition by ID"""
|
||||||
|
return EDC15P_MAPS.get(map_id)
|
||||||
|
|
||||||
|
def list_maps() -> List[str]:
|
||||||
|
"""List all available map IDs"""
|
||||||
|
return list(EDC15P_MAPS.keys())
|
||||||
|
|
||||||
|
def list_maps_by_group() -> Dict[str, List[MapDefinition]]:
|
||||||
|
"""List maps grouped by their groups"""
|
||||||
|
groups: Dict[str, List[MapDefinition]] = {}
|
||||||
|
|
||||||
|
# First pass: collect all unique groups
|
||||||
|
for map_def in EDC15P_MAPS.values():
|
||||||
|
if map_def.group not in groups:
|
||||||
|
groups[map_def.group] = []
|
||||||
|
|
||||||
|
# Second pass: add maps to their groups
|
||||||
|
for map_id, map_def in EDC15P_MAPS.items():
|
||||||
|
groups[map_def.group].append(map_def)
|
||||||
|
|
||||||
|
return groups
|
||||||
|
|
||||||
|
def list_maps_by_category() -> Dict[str, List[MapDefinition]]:
|
||||||
|
"""List maps grouped by category"""
|
||||||
|
categories: Dict[str, List[MapDefinition]] = {}
|
||||||
|
|
||||||
|
# First pass: collect all unique categories
|
||||||
|
for map_def in EDC15P_MAPS.values():
|
||||||
|
if map_def.category not in categories:
|
||||||
|
categories[map_def.category] = []
|
||||||
|
|
||||||
|
# Second pass: add maps to their categories
|
||||||
|
for map_id, map_def in EDC15P_MAPS.items():
|
||||||
|
categories[map_def.category].append(map_def)
|
||||||
|
|
||||||
|
return categories
|
||||||
Reference in New Issue
Block a user