An advanced OBD-II emissions monitoring simulator for Teensy 4.0 with comprehensive vehicle diagnostics support, dynamic driving simulation, and real Mercedes-Benz data.
Important Context: OBD-II is fundamentally an emissions control program, not a general diagnostic system. Mandated by the EPA and CARB since January 1, 1996, OBD-II focuses exclusively on emissions-related functions:
- Covered Systems: Engine, transmission, and drivetrain components that affect emissions
- Not Covered: Body controls, ABS, airbags, lighting (manufacturer-specific, not OBD-II)
- Primary Purpose: Monitor and ensure vehicles maintain emissions compliance throughout their operational life
- Standards: Based on SAE J1979 recommendations, adopted by EPA for emissions monitoring
This simulator accurately reproduces the emissions monitoring aspects of OBD-II, providing realistic data that matches real-world emissions testing scenarios.
This simulator implements 5 of the 10 OBD-II modes, focusing on the emissions-critical modes:
Purpose: Provide access to current LIVE emissions-related data values. These must be actual sensor readings, not defaults or substitutes.
- Engine Performance: RPM, speed, coolant temp (affects cold-start emissions), intake temp
- Fuel System: Fuel trims (STFT/LTFT) for maintaining stoichiometric ratio (14.7:1)
- Emission Controls: O2 sensors (primary feedback), catalyst temps, EVAP system
- Throttle/Load: Engine load calculations for emissions optimization
- Environmental: Ambient temp, barometric pressure (altitude compensation)
- Diagnostic: Monitor status (shows which emissions tests have run)
Purpose: Access emissions-related data stored at the moment a DTC was set. Critical for diagnosing intermittent emissions problems.
- Captures exact conditions when emissions fault occurred
- Stores 2 independent freeze frames for multiple DTCs
- Preserves data for technician diagnosis even after fault clears
Purpose: Retrieve stored emissions-related "P" codes that have "matured" and triggered the MIL.
- Returns P0118 (Coolant sensor - affects emissions at cold start)
- Returns P0130 (O2 sensor - critical for emissions feedback loop)
- Only shows DTCs that affect emissions compliance
Purpose: Comprehensive reset of ALL emissions-related diagnostic data.
- Clears emissions DTCs and turns off MIL
- Erases freeze frame data
- Resets all emissions monitors to "not ready" status
- Monitors must complete drive cycles to become ready again
Purpose: Access vehicle identification and calibration data for emissions compliance verification.
- VIN: Links vehicle to its emissions certification (4JGDA5HB7JB158144)
- Calibration ID: Identifies emissions software version (2769011200190170)
- CVN: Checksum prevents tampering with emissions tune (EB854939)
- ECU Name: Identifies responding emissions module (ECM-EngineControl)
- Performance Tracking: Monitors how often emissions tests run
- ISO-TP Protocol: Multi-frame support for long messages
- Mode 05: O2 sensor test results (legacy, replaced by Mode 06 on CAN systems)
- Mode 06: On-board monitoring test results (manufacturer-specific format)
- Mode 07: Pending codes (first drive cycle after ECM reset)
- Mode 08: Bidirectional control (mainly EVAP system testing)
- Mode 10: Permanent codes (only module can clear after passing self-test)
The simulator cycles through realistic driving states that affect emissions:
-
IDLE (800 RPM, 0 km/h)
- Warmed-up engine at optimal temperature for catalytic converter (95°C)
- Closed-loop fuel control using O2 sensor feedback
- Low emissions state with minimal NOx and HC production
-
CITY (1800 RPM, 45 km/h)
- Simulates EPA FTP-75 urban driving cycle conditions
- Moderate NOx production, catalyst at working temperature
- Fuel trims actively adjusting for emissions compliance
-
ACCELERATING (3500 RPM, 90 km/h)
- Higher emissions during power enrichment phase
- Tests catalyst efficiency under load conditions
- Temporary open-loop operation during WOT (wide-open throttle)
-
HIGHWAY (2500 RPM, 120 km/h)
- Steady-state emissions (HWFET cycle conditions)
- Optimal fuel efficiency and lowest emissions
- Lean cruise for reduced fuel consumption and CO2
-
BRAKING (1200 RPM, 30 km/h)
- Deceleration fuel cut-off (DFCO) reduces emissions
- O2 sensor shows lean condition (>0.8V)
- Zero fuel consumption during engine braking
Emissions Control Features:
- Automatic state transitions every 10 seconds (simulates EPA test cycles)
- Smooth value interpolation prevents emissions spikes
- Correlated parameters maintain proper stoichiometric air/fuel ratio
- O2 sensor oscillation (0.35-0.45V) indicates proper closed-loop control
- 100ms update rate matches real ECU scan frequency for emissions monitoring
The codebase uses a plugin-based architecture where each OBD-II mode is implemented in its own file and automatically registered at compile time.
File Structure:
Teensy40_OBDII_simulator/
├── ecu_sim.cpp # Core ECU logic (291 lines, down from 1,133)
├── ecu_sim.h # Type definitions and declarations
├── mode_registry.h # Mode registration system
├── mode_registry.cpp # Registry implementation
├── mode_includes.h # Auto-includes all modes
└── modes/ # Mode implementations
├── mode_01.cpp # Current Data (44 PIDs, 590 lines)
├── mode_02.cpp # Freeze Frame (206 lines)
├── mode_03.cpp # DTCs (88 lines)
├── mode_04.cpp # Clear DTCs (79 lines)
└── mode_09.cpp # Vehicle Info (348 lines)
To add a new OBD mode (e.g., Mode 06 - Test Results):
- Create
modes/mode_06.cpp:
#include "mode_registry.h"
#include <FlexCAN_T4.h>
extern FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
extern ecu_t ecu;
bool handle_mode_06(CAN_message_t& can_MsgRx,
CAN_message_t& can_MsgTx,
ecu_simClass* ecu_sim) {
if (can_MsgRx.buf[1] != MODE6) return false;
// Your Mode 06 implementation here
return true;
}
static ModeRegistrar mode_06_registrar(MODE6, handle_mode_06, "Test Results");- Add to
mode_includes.h:
#include "modes/mode_06.cpp"- Done! The mode automatically registers and is available.
- Separation of Concerns: Each mode is self-contained
- Easy Testing: Test modes independently
- Code Clarity: Main file reduced by 74% (842 lines)
- Extensibility: Add modes without modifying core code
- Automatic Registration: No manual dispatcher updates needed
Comprehensive technical documentation is available in the docs/ directory:
Each OBD-II mode has detailed documentation with protocol specifications, formulas, and usage examples:
-
MODE_01.md - Current Powertrain Data (45 PIDs)
- Complete SAE J1979 formula reference
- All 45 PIDs with data ranges and examples
- Dynamic driving simulation states
- Multi-ECU response behavior
-
MODE_02.md - Freeze Frame Data
- Fault condition capture mechanism
- 2 independent freeze frame storage
- DTC association (P0100, P0200)
- Data persistence until Mode 04 clear
-
MODE_03.md - Request Emissions DTCs
- Emissions diagnostic trouble codes
- DTC format and encoding
- MIL (Check Engine Light) relationship
-
MODE_04.md - Clear Diagnostic Information
- Comprehensive emissions data reset
- What gets cleared and implications
- Post-repair verification workflow
-
MODE_09.md - Vehicle Information
- VIN, Calibration ID, CVN retrieval
- ISO-TP multi-frame protocol
- Real Mercedes-Benz data integration
- Compliance verification
- MODE_01_AUDIT.md - Initial protocol audit findings
- MODE_01_FIXES_SUMMARY.md - Complete fix documentation
- Teensy 4.0 microcontroller
- CAN Bus transceiver (MCP2562 or similar)
- OBD-II connector wiring
- Optional: Status LEDs (red/green)
Teensy 4.0 -> CAN Transceiver
Pin 22 (CTX1) -> TXD
Pin 23 (CRX1) -> RXD
GND -> GND
3.3V -> VCC
Status LEDs:
Pin 13 -> Built-in LED
Pin 19 -> Red LED (optional)
Pin 20 -> Green LED (optional)
- Install Teensyduino for Arduino IDE
- Install required library:
- FlexCAN_T4 (via Library Manager)
- Install Teensy Loader (choose one):
- Teensy Loader GUI - Graphical application
- Teensy Loader CLI - Command-line tool
# macOS brew install teensy_loader_cli # Linux sudo apt-get install teensy-loader-cli # From source git clone https://github.com/PaulStoffregen/teensy_loader_cli cd teensy_loader_cli make
-
Clone this repository:
git clone https://github.com/Wal33D/Teensy40_OBDII_simulator.git cd Teensy40_OBDII_simulator -
Option A: Arduino IDE
- Open
Teensy40_OBDII_simulator.inoin Arduino IDE - Select Tools > Board > Teensy 4.0
- Select Tools > USB Type > Serial
- Click Upload
- Open
-
Option B: Command Line (Recommended)
# Compile arduino-cli compile --fqbn teensy:avr:teensy40 . # Upload with CLI loader teensy_loader_cli --mcu=TEENSY40 -w -v build/Teensy40_OBDII_simulator.ino.hex
Flashing Method: Graphical User Interface Estimated Time: 5-10 seconds Difficulty: Beginner-friendly
| Step | Action | Duration |
|---|---|---|
| 1 | Press program button | Instant |
| 2 | Select HEX file | ~1 second |
| 3 | Verify configuration | ~1 second |
| 4 | Automatic flashing | 3-5 seconds |
| 5 | Reboot and run | 1-2 seconds |
Press the program button on your Teensy 4.0 device to put it into bootloader mode. The Teensy Loader application will automatically detect the device and show it as ready to program.
Click "Open HEX File" in the Teensy Loader and navigate to your compiled firmware:
build/Teensy40_OBDII_simulator.ino.hex
Before flashing, confirm the following settings:
- ✅ Correct board type (Teensy 4.0) is selected
- ✅ HEX file path displays correctly
- ✅ Device shows as connected (green indicator)
The Teensy Loader will automatically begin the flashing sequence:
| Phase | Description | Status |
|---|---|---|
| Erase | Clearing existing firmware | In progress... |
| Write | Programming new firmware | In progress... |
| Verify | Confirming successful flash | Completed ✓ |
Once flashing completes, the Teensy will automatically reboot and begin running your OBD-II simulator firmware. The status LEDs should activate with their normal operating patterns.
| Safety Precautions | |
|---|---|
| ⏱️ | The entire process takes approximately 5-10 seconds |
| 🔌 | Do not disconnect the device during flashing |
| 🔄 | If flashing fails, press the program button again and retry |
| 💾 | The Teensy will remember the last HEX file loaded for quick re-flashing |
| 📍 | Ensure you're in the correct project directory when selecting the HEX file |
- Connect the Teensy to your vehicle's OBD-II port or diagnostic tool
- Power on the device (via USB or OBD-II connector)
- The simulator automatically starts broadcasting responses
- LEDs indicate status:
- Green flash: Normal operation
- Red flash: CAN message received
- Built-in LED: Heartbeat (500ms interval)
Compatible with any OBD-II scanner or software:
- Torque Pro (Android)
- OBD Fusion (iOS/Android)
- ScanTool.net OBDLink
- ELM327 based tools
- Custom diagnostic software
All simulated values are based on real vehicle data:
- Source Vehicle: Mercedes-Benz
- Data Points: 7,510+ logged OBD responses
- Driving Conditions: Real-world idle, city, highway, and braking scenarios
- Protocol Compliance: ISO 15765-4 CAN (11-bit, 500kbps)
- Original Code: 199 lines (basic 8 PIDs)
- Enhanced Code v2.0: 1,085+ lines (44 PIDs + modes)
- Modular Refactor v3.0: 1,711 lines across modular files
- Growth Factor: 8.6x from original
- Code Reduction: Main file reduced 74% (842 lines) via modularization
- New Features: 81 additional switch cases
- Protocol Support: ISO-TP multi-frame handling
Teensy40_OBDII_simulator/
├── Teensy40_OBDII_simulator.ino # Main sketch (72 lines)
├── ecu_sim.cpp # Core ECU logic (291 lines)
├── ecu_sim.h # Type definitions (284 lines)
├── mode_registry.h # Mode registration system (122 lines)
├── mode_registry.cpp # Registry implementation (3 lines)
├── mode_includes.h # Auto-include all modes (21 lines)
├── modes/
│ ├── mode_01.cpp # Current Data - 44 PIDs (590 lines)
│ ├── mode_02.cpp # Freeze Frame (206 lines)
│ ├── mode_03.cpp # DTCs (88 lines)
│ ├── mode_04.cpp # Clear DTCs (79 lines)
│ └── mode_09.cpp # Vehicle Info (348 lines)
├── CHANGELOG.md # Detailed change history
└── README.md # This file
| Metric | v1.0 (Original) | v2.0 (Enhanced) | v3.0 (Modular) | v3.1 (Protocol) |
|---|---|---|---|---|
| Total Lines | 337 | 1,485 | 1,711 | 1,719 |
| OBD Modes | 3 | 5 | 5 | 5 |
| Mode 01 PIDs | 8 | 44 | 44 | 45 |
| Files | 3 | 3 | 12 | 17 |
| Largest File | 199 lines | 1,133 lines | 590 lines | 598 lines |
| Modularity | None | None | Full | Full |
| Protocol Compliance | Partial | Partial | Partial | 100% |
- Critical Protocol Fixes: 23 bugs corrected for 100% SAE J1979 compliance
- Fixed 20 missing CAN IDs (PIDs 0x31-0x58)
- Corrected O2 voltage range (0.35V-0.55V per spec)
- Fixed fuel rail pressure formula (400 kPa realistic value)
- Added missing PID 0x14 (O2 Voltage) handler
- Updated supported PID bitmasks for accuracy
- Comprehensive Documentation: 5 detailed mode guides in docs/
- MODE_01.md: All 45 PIDs with SAE J1979 formulas
- MODE_02.md: Freeze frame data capture and storage
- MODE_03.md: Emissions DTC retrieval
- MODE_04.md: Diagnostic data clearing
- MODE_09.md: Vehicle information and ISO-TP protocol
- Build Verified: Successful compilation and flash to Teensy 4.0
- Real-World Testing: Confirmed working with Bluetooth OBD dongles
- Complete architectural refactoring to modular plugin system
- Each OBD mode in separate file (modes/mode_XX.cpp)
- Automatic mode registration system
- Main file reduced by 74% (842 lines)
- Easy extensibility - add modes without modifying core
- Improved code organization and maintainability
- Added comprehensive architecture documentation
- Added 36 new Mode 01 PIDs
- Implemented Mode 02 (Freeze Frame)
- Implemented Mode 09 (Vehicle Information)
- Dynamic driving state simulation
- ISO-TP multi-frame protocol support
- Real Mercedes-Benz data integration
- Basic Mode 01 (8 PIDs)
- Mode 03/04 DTC support
- Static potentiometer-based values
- Baud Rate: 500kbps (standard OBD-II)
- CAN ID Request: 0x7DF (broadcast) or 0x7E0 (ECU specific)
- CAN ID Response: 0x7E8
- Protocol: ISO 15765-4
Standard Response: [Mode+0x40] [PID] [Data...]
Example Mode 01: 41 0C XX XX (RPM response)
Example Mode 09: 49 02 01 [VIN data...] (VIN response)
For responses > 8 bytes (like VIN):
- First Frame:
10 [length] [data...] - Flow Control: Wait for
30 00 00 - Consecutive Frames:
21 [data...],22 [data...]
Contributions are welcome! Please ensure:
- Code follows existing style
- Comments explain complex logic
- Test with real OBD-II scanners
- Update CHANGELOG.md
This project is based on original work by skpang.co.uk (2022) with significant enhancements.
Enhanced Version (v2.0.0)
- Waleed Judah (Wal33D)
- Email: aquataze@yahoo.com
- GitHub: @Wal33D
Original Version (v1.0.0)
- skpang.co.uk
- Product Page
- Original simulator framework by skpang.co.uk
- FlexCAN_T4 library by tonton81
- Real vehicle data from Mercedes-Benz diagnostics
- OBD-II PID documentation from Wikipedia
Note: This simulator is for educational and development purposes. Always comply with local regulations when working with vehicle systems.




