Skip to content

Commit 07a7273

Browse files
committed
add simulator
1 parent 6dbc163 commit 07a7273

10 files changed

Lines changed: 633 additions & 40 deletions

File tree

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"files.associations": {
3+
"map": "cpp"
4+
}
5+
}

src/CANHandler.cpp

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -103,31 +103,31 @@ void handleCANCommunication() {
103103
}
104104
}
105105

106-
if (currentTime - lastPrintTime >= 1000) {
107-
Serial.print("RPM: ");
108-
Serial.print(rpm);
109-
Serial.print(" MAP: ");
110-
Serial.print(mapData);
111-
Serial.print(" kPa TPS: ");
112-
Serial.print(tps);
113-
Serial.print(" % ADV:");
114-
Serial.print(adv);
115-
Serial.print(" ° Fuel Pressure: ");
116-
Serial.print(fp);
117-
Serial.print(" kPa AFR: ");
118-
Serial.print(afrConv, 2);
119-
Serial.print(" VSS: ");
120-
Serial.print(vss);
121-
Serial.print(" km/h Voltage: ");
122-
Serial.print(bat, 2);
123-
Serial.print(" V CLT: ");
124-
Serial.print(clt);
125-
Serial.print(" °C IAT: ");
126-
Serial.print(iat);
127-
Serial.print(" °C Trigger Error: ");
128-
Serial.print(triggerError);
129-
Serial.println();
106+
// if (currentTime - lastPrintTime >= 1000) {
107+
// Serial.print("RPM: ");
108+
// Serial.print(rpm);
109+
// Serial.print(" MAP: ");
110+
// Serial.print(mapData);
111+
// Serial.print(" kPa TPS: ");
112+
// Serial.print(tps);
113+
// Serial.print(" % ADV:");
114+
// Serial.print(adv);
115+
// Serial.print(" ° Fuel Pressure: ");
116+
// Serial.print(fp);
117+
// Serial.print(" kPa AFR: ");
118+
// Serial.print(afrConv, 2);
119+
// Serial.print(" VSS: ");
120+
// Serial.print(vss);
121+
// Serial.print(" km/h Voltage: ");
122+
// Serial.print(bat, 2);
123+
// Serial.print(" V CLT: ");
124+
// Serial.print(clt);
125+
// Serial.print(" °C IAT: ");
126+
// Serial.print(iat);
127+
// Serial.print(" °C Trigger Error: ");
128+
// Serial.print(triggerError);
129+
// Serial.println();
130130

131-
lastPrintTime = currentTime;
132-
}
131+
// lastPrintTime = currentTime;
132+
// }
133133
}

src/Config.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ extern const char *password;
2727
// Other constants
2828
#define EEPROM_SIZE 512
2929

30+
// Simulator configuration
31+
#define ENABLE_SIMULATOR 1 // Set to 0 to disable simulator completely
32+
33+
// Debug configuration
34+
#define ENABLE_DEBUG_MODE 1 // Set to 0 to disable debug mode completely
35+
3036
// Font definitions
3137
#define AA_FONT_SMALL NotoSansBold15
3238
#define AA_FONT_LARGE NotoSansBold36

src/DataTypes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,13 @@ extern uint32_t lastClientCheckTimeout;
3434
extern uint32_t wifiTimeout;
3535
extern bool clientConnected;
3636

37+
// Debug variables
38+
extern bool debugMode;
39+
extern float cpuUsage;
40+
extern float fps;
41+
extern uint32_t frameCount;
42+
extern uint32_t lastFpsUpdate;
43+
extern uint32_t lastCpuMeasure;
44+
extern uint32_t loopStartTime;
45+
3746
#endif // DATATYPES_H

src/DisplayManager.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include "NotoSansBold15.h"
66
#include "NotoSansBold36.h"
77
#include <EEPROM.h>
8+
#if ENABLE_SIMULATOR
9+
#include "Simulator.h"
10+
#endif
811

912
TFT_eSPI display = TFT_eSPI();
1013
TFT_eSprite spr = TFT_eSprite(&display);
@@ -137,4 +140,49 @@ void drawData() {
137140
lastRpm = rpm;
138141
}
139142
itemDraw(false);
143+
144+
#if ENABLE_SIMULATOR
145+
// Draw simulator indicator if simulator is active
146+
static uint8_t lastSimMode = SIMULATOR_MODE_OFF;
147+
uint8_t currentSimMode = getSimulatorMode();
148+
149+
if (currentSimMode != SIMULATOR_MODE_OFF) {
150+
display.loadFont(AA_FONT_SMALL);
151+
display.setTextColor(TFT_YELLOW, TFT_BLACK);
152+
display.setTextDatum(TR_DATUM);
153+
display.drawString("SIM", display.width() - 5, 5);
154+
} else if (lastSimMode != SIMULATOR_MODE_OFF) {
155+
// Clear the SIM indicator when simulator is turned off
156+
display.fillRect(display.width() - 30, 5, 25, 15, TFT_BLACK);
157+
}
158+
159+
lastSimMode = currentSimMode;
160+
#endif
161+
162+
#if ENABLE_DEBUG_MODE
163+
// Draw debug information at center top if debug mode is active
164+
static bool lastDebugMode = false;
165+
if (debugMode) {
166+
display.loadFont(AA_FONT_SMALL);
167+
display.setTextColor(TFT_CYAN, TFT_BLACK);
168+
display.setTextDatum(TC_DATUM);
169+
170+
int centerX = display.width() / 2;
171+
172+
// Create debug info string - show only essential info in one line
173+
String debugInfo = "CPU:" + String(cpuUsage, 1) + "% FPS:" + String(fps, 1) + " Heap:" + String(ESP.getFreeHeap()/1024) + "K";
174+
175+
// Draw debug info at center top
176+
display.drawString(debugInfo, centerX, 5);
177+
178+
lastDebugMode = true;
179+
} else {
180+
// Clear debug area when debug mode is turned off
181+
if (lastDebugMode) {
182+
// Clear the top center area where debug info was displayed
183+
display.fillRect(0, 5, display.width(), 20, TFT_BLACK);
184+
lastDebugMode = false;
185+
}
186+
}
187+
#endif
140188
}

src/GlobalVariables.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,12 @@ uint32_t lastClientCheck = 0;
3636
uint32_t lastClientCheckTimeout = 0;
3737
uint32_t wifiTimeout = 30000;
3838
bool clientConnected = true;
39+
40+
// Debug variables
41+
bool debugMode = false;
42+
float cpuUsage = 0.0;
43+
float fps = 0.0;
44+
uint32_t frameCount = 0;
45+
uint32_t lastFpsUpdate = 0;
46+
uint32_t lastCpuMeasure = 0;
47+
uint32_t loopStartTime = 0;

src/Simulator.cpp

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
#include "Simulator.h"
2+
#include "DataTypes.h"
3+
#include "Config.h"
4+
#include "Arduino.h"
5+
6+
static uint8_t simulatorMode = SIMULATOR_MODE_OFF;
7+
static uint32_t lastSimUpdate = 0;
8+
static uint32_t simulatorStep = 0;
9+
static bool rpmIncreasing = true;
10+
11+
void initializeSimulator() {
12+
simulatorMode = SIMULATOR_MODE_OFF;
13+
lastSimUpdate = millis();
14+
simulatorStep = 0;
15+
rpmIncreasing = true;
16+
17+
Serial.println("=== MAZDUINO SIMULATOR INITIALIZED ===");
18+
Serial.println("Simulator starts in OFF mode by default");
19+
Serial.println("Available modes:");
20+
Serial.println("0 = OFF (use real data)");
21+
Serial.println("1 = RPM SWEEP (0-6000 RPM)");
22+
Serial.println("2 = ENGINE IDLE (800-900 RPM)");
23+
Serial.println("3 = DRIVING (1500-4000 RPM)");
24+
Serial.println("4 = REDLINE (5500-6000 RPM)");
25+
Serial.println("Send '1', '2', '3', '4' via Serial to change mode");
26+
Serial.println("Send '0' to turn off simulator");
27+
Serial.println("Send 'h' for help");
28+
Serial.println("======================================");
29+
30+
// Keep simulator OFF by default - user must manually enable
31+
Serial.println("[SIM] Simulator OFF - Using real data from CAN/Serial");
32+
}
33+
34+
void setSimulatorMode(uint8_t mode) {
35+
simulatorMode = mode;
36+
simulatorStep = 0;
37+
rpmIncreasing = true;
38+
39+
// Reset RPM to appropriate starting value for each mode
40+
switch(mode) {
41+
case SIMULATOR_MODE_OFF:
42+
Serial.println("[SIM] Simulator OFF - Using real data");
43+
rpm = 0; // Reset to 0 when turning off
44+
break;
45+
case SIMULATOR_MODE_RPM_SWEEP:
46+
Serial.println("[SIM] RPM SWEEP Mode - 0 to 6000 RPM");
47+
rpm = 0; // Start from 0
48+
break;
49+
case SIMULATOR_MODE_ENGINE_IDLE:
50+
Serial.println("[SIM] ENGINE IDLE Mode - 800-900 RPM");
51+
rpm = 850; // Start at idle
52+
break;
53+
case SIMULATOR_MODE_DRIVING:
54+
Serial.println("[SIM] DRIVING Mode - 1500-4000 RPM");
55+
rpm = 2500; // Start at mid-range
56+
break;
57+
case SIMULATOR_MODE_REDLINE:
58+
Serial.println("[SIM] REDLINE Mode - 5500-6000 RPM");
59+
rpm = 5750; // Start at redline
60+
break;
61+
default:
62+
Serial.println("[SIM] Unknown mode, turning off");
63+
simulatorMode = SIMULATOR_MODE_OFF;
64+
rpm = 0;
65+
break;
66+
}
67+
}
68+
69+
uint8_t getSimulatorMode() {
70+
return simulatorMode;
71+
}
72+
73+
void updateSimulatorData() {
74+
if (simulatorMode == SIMULATOR_MODE_OFF) {
75+
return; // Don't override real data
76+
}
77+
78+
uint32_t currentTime = millis();
79+
if (currentTime - lastSimUpdate < 100) { // Update every 100ms
80+
return;
81+
}
82+
lastSimUpdate = currentTime;
83+
84+
// Generate realistic sensor data based on RPM
85+
switch(simulatorMode) {
86+
case SIMULATOR_MODE_RPM_SWEEP:
87+
// Sweep from 0 to 6000 RPM and back
88+
if (rpmIncreasing) {
89+
rpm = simulatorStep * 50; // Increase by 50 RPM each step
90+
if (rpm >= 6000) {
91+
rpmIncreasing = false;
92+
simulatorStep = 120; // 6000/50 = 120
93+
} else {
94+
simulatorStep++;
95+
}
96+
} else {
97+
rpm = simulatorStep * 50; // Decrease by 50 RPM each step
98+
if (rpm <= 0) {
99+
rpmIncreasing = true;
100+
simulatorStep = 0;
101+
} else {
102+
simulatorStep--;
103+
}
104+
}
105+
break;
106+
107+
case SIMULATOR_MODE_ENGINE_IDLE:
108+
// Realistic idle with small variations
109+
rpm = 850 + (simulatorStep % 10) * 5; // 850-895 RPM
110+
simulatorStep++;
111+
break;
112+
113+
case SIMULATOR_MODE_DRIVING:
114+
// Simulate driving RPM patterns
115+
rpm = 2500 + sin(simulatorStep * 0.1) * 1000; // 1500-3500 RPM sine wave
116+
simulatorStep++;
117+
break;
118+
119+
case SIMULATOR_MODE_REDLINE:
120+
// High RPM simulation
121+
rpm = 5750 + (simulatorStep % 20) * 10; // 5750-5940 RPM
122+
simulatorStep++;
123+
break;
124+
}
125+
126+
// Generate correlated sensor data based on RPM
127+
if (rpm == 0) {
128+
// Engine off
129+
mapData = 30; // Atmospheric pressure
130+
tps = 0; // Throttle closed
131+
adv = 0; // No advance
132+
afrConv = 14.7; // Stoichiometric
133+
fp = 0; // No fuel pressure
134+
triggerError = 0;
135+
vss = 0; // Not moving
136+
137+
// Temperature sensors (engine off values)
138+
clt = 25; // Ambient temp
139+
iat = 25; // Ambient temp
140+
bat = 12.8; // Resting battery voltage
141+
142+
// All indicators off
143+
syncStatus = false;
144+
fan = false;
145+
ase = false;
146+
wue = false;
147+
rev = false;
148+
launch = false;
149+
airCon = false;
150+
dfco = false;
151+
} else {
152+
// Engine running - generate realistic values
153+
mapData = map(rpm, 800, 6000, 35, 95); // 35-95 kPa MAP
154+
tps = map(rpm, 800, 6000, 5, 85); // 5-85% TPS
155+
adv = map(rpm, 800, 6000, 10, 35); // 10-35° advance
156+
157+
// AFR varies with load
158+
if (rpm < 1000) {
159+
afrConv = 14.7; // Idle stoich
160+
} else if (rpm > 4000) {
161+
afrConv = 12.5; // Rich at high RPM
162+
} else {
163+
afrConv = 14.2; // Slightly lean cruise
164+
}
165+
166+
fp = map(rpm, 800, 6000, 250, 350); // 250-350 kPa fuel pressure
167+
triggerError = 0; // No errors in sim
168+
vss = map(rpm, 800, 6000, 0, 120); // 0-120 km/h speed
169+
170+
// Temperature sensors (engine running)
171+
clt = map(rpm, 800, 6000, 85, 95); // 85-95°C coolant
172+
iat = map(rpm, 800, 6000, 30, 45); // 30-45°C intake air
173+
bat = 14.2; // Charging voltage
174+
175+
// Engine indicators based on RPM
176+
syncStatus = true; // Engine synced
177+
fan = (clt > 90); // Fan on when hot
178+
ase = (clt < 60); // After start enrichment when cold
179+
wue = (clt < 80); // Warm up enrichment
180+
rev = (rpm > 5500); // Rev limiter warning
181+
launch = false; // Launch control off
182+
airCon = false; // AC off
183+
dfco = (rpm > 2000 && tps < 10); // DFCO at high RPM, low throttle
184+
}
185+
186+
// Add some realistic noise/variation
187+
if (rpm > 0) {
188+
rpm += random(-10, 10);
189+
mapData += random(-2, 2);
190+
afrConv += (random(-20, 20) / 100.0); // ±0.2 AFR variation
191+
bat += (random(-5, 5) / 100.0); // ±0.05V variation
192+
tps += random(-2, 2); // ±2% TPS variation
193+
adv += random(-1, 1); // ±1° advance variation
194+
195+
// Ensure values stay within realistic bounds
196+
// Don't constrain RPM too tightly in sweep mode to allow proper cycling
197+
if (simulatorMode == SIMULATOR_MODE_RPM_SWEEP) {
198+
rpm = constrain(rpm, 0, 6500); // Allow little headroom for sweep
199+
} else {
200+
rpm = constrain(rpm, 0, 7000);
201+
}
202+
mapData = constrain(mapData, 20, 105);
203+
afrConv = constrain(afrConv, 10.0, 18.0);
204+
bat = constrain(bat, 11.0, 15.0);
205+
tps = constrain(tps, 0, 100);
206+
adv = constrain(adv, -5, 40);
207+
}
208+
209+
// Print current values every 2 seconds
210+
static uint32_t lastPrint = 0;
211+
if (currentTime - lastPrint > 2000) {
212+
Serial.printf("[SIM] RPM:%d MAP:%d TPS:%d AFR:%.1f BAT:%.1f VSS:%d TriggerErr:%d\n",
213+
rpm, mapData, tps, afrConv, bat, vss, triggerError);
214+
215+
// Extra debug for RPM sweep mode
216+
if (simulatorMode == SIMULATOR_MODE_RPM_SWEEP) {
217+
Serial.printf("[SIM] Sweep Debug - Step:%d Direction:%s Target RPM:%d\n",
218+
simulatorStep, rpmIncreasing ? "UP" : "DOWN", simulatorStep * 50);
219+
}
220+
221+
lastPrint = currentTime;
222+
}
223+
}

0 commit comments

Comments
 (0)