|
| 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