Back to Learn Hub
Log Format Deep-Dive

Gen2 vs Gen3: Log Differences

A technical comparison of Zero Motorcycles log formats across generations, based on reverse-engineering and real-world analysis.

Last updated: February 5, 2026

TL;DR

Gen2 logs (S, SR, FX, DS — 2013-2021) use 256 KB files with periodic snapshots containing all telemetry in text format. Gen3 logs (SR/F, SR/S — 2019+) use 128 KB files with an event-based ring buffer containing binary telemetry payloads. Gen3 requires binary-level decoding and a completely different approach to session detection.

File Format

The most visible difference is the file itself: size, naming convention, and internal structure.

Gen2 (SDS Platform)

Full Support
Models: S, SR, DS, DSR, FX, FXS, FXE
Controller: Sevcon Gen4
File size: 262,144 bytes (256 KB)
MBB filename: VIN_MBB_YYYY-MM-DD.bin
BMS filename: VIN_BMS0_YYYY-MM-DD.bin
Entry structure: Text-based with structured fields
Entries per file: ~6,000 - 8,000

Gen3 (FST / Cypher III)

Full Support
Models: SR/F, SR/S, DSR/X
Controller: Cypher III (proprietary)
MBB size: 131,200 bytes (128 KB)
MBB filename: YYYYMMDD_HH.MM_VIN_6.bin
BMS filename: YYYYMMDD_HH.MM_VIN_10.bin
Entry structure: Binary payloads (75/76/92 bytes) + text events
Entries per file: ~2,000 - 2,500

Note: Gen2 newer firmware uses VIN_MbbD_date.bin naming (lowercase "bb" + "D"). The format remains the same, only the filename convention changed.

Data Logging Approach

Gen2: Periodic Snapshots

Gen2 logs a complete telemetry snapshot every 15-30 seconds during riding, and periodic updates during charging and idle. Each entry contains all available data in human-readable text format.

// Example Gen2 MBB entry

Riding

PackTemp: h 32C, l 28C, PackSOC: 87%,

Vpack:117.3V, MotAmps:23, BattAmps:18,

Mods: 1, MotTemp:45C, CtrlTemp:33C,

AmbTemp:22C, MotRPM:3200, Odo:15234km

Every field is available in every riding entry. Dense, complete data.

Gen3: Event-Based Ring Buffer

Gen3 uses a ring buffer that stores events as they occur. Telemetry is embedded in 75-byte binary payloads, and text events log state changes, faults, and system messages. Entries are not chronologicalin the file — the ring buffer wraps around.

// Example Gen3 MBB entries

75 bytes | state=RUN | SOC=95% V=112.7V I=37A 43km/h T=21C

text | State change: from: STOP, to: RUN

text | Disch limits curr 400 cap 400 pow 111

75 bytes | state=RUN | V=103.2V I=62A RPM=4500

Mixed binary + text. Must sort by timestamp after parsing. Fewer entries per ride.

MBB Telemetry Comparison

What data is available in each generation's MBB (Main Bike Board) log:

Data FieldGen2Gen3
Pack VoltageEvery entry (Vpack, V)Binary [s-21]: uint32 LE (mV) + secondary [s-8]
Battery CurrentEvery entry (BattAmps, A)Binary [s-17]: int32 LE (mA, signed) + secondary [s-4]
SOC (State of Charge)Every entry (PackSOC, %)Binary [s-9]: uint8 (0-100%, dashboard value)
Motor RPMEvery entry (MotRPM)Binary post-state field 3 (uint32 LE)
SpeedDerived from RPMBinary [s-13]: uint32 LE (~cm/s, x0.036=km/h)
OdometerEvery entry (Odo, km)Binary post-state field 5 (uint32 LE, meters)
Motor TemperatureEvery entry (MotTemp, °C)Binary [s+17]: uint32 LE (°C)
Controller TempEvery entry (CtrlTemp, °C)Binary [s+13]: uint32 LE (°C)
Ambient TempEvery entry (AmbTemp, °C)Binary [s+25]: uint32 LE (°C)
Pack TemperatureEvery entry (hi/lo, °C)Binary [s+21]: uint32 LE (°C)
TorqueNot availableBinary post-state field 4 (uint32 LE, Nm)
Motor AmpsEvery entry (MotAmps)Not available (battery current only)
Power (kW)Derived (V × BattAmps)Derived (V × I / 1000)
Discharge LimitNot availableText events (watts, stored as kW)
Charge LimitNot availableText events (watts, stored as kW)
Controller ActiveNot availableByte 11: 0x00=active, 0x6A=standby
Bike StateDerived from event typeASCII [s:s+9]: RUN/STOP/HIB/CHRG/WAIT/PWSU
Error CodesText eventsFault pending/cleared text events
Ride ModeCustom/Eco/Sport/etc.Not in Gen3 logs

Gen2 Advantage

Complete telemetry in every entry. SOC, mode, motor amps, and all temperatures always available. High data density: 6-8K entries per file. Simple text parsing.

Gen3 Advantage

Event-driven means no wasted entries during idle. Captures exact state transitions. Higher precision (millivolts, milliamps, meters). Exclusive: torque (Nm), power limits (kW), cell OCV, dual V/I sensor pairs, controller active flag.

State Machine & Session Detection

Gen2: Mode-Based

Every entry has a clear mode label. Session detection is straightforward:

RidingActive riding with full telemetry
ChargingCharger connected, current flowing
IdleKey on, not riding
ParkedKey off, system monitoring

Gen3: State Machine

Uses a state machine with transitions. Session detection requires pattern matching:

RUNMotor active, riding
CHRGCharger connected
STRTSystem starting up
PWSUPower-up self test
STOPKill switch / key off
HIBHibernation (deep sleep)
WAITWaiting for input

Gen3 Session Detection Signals

Since Gen3 doesn't have clear "Riding" labels, we reconstruct sessions from multiple signals:

RUN state in telemetry (Ride)
Key Sw: ON / Kill Sw: STOP (Ride boundary)
Kickstand Sw: UP/DOWN (Ride start/end)
Time gap > 2 hours (Session split)
CHARGER LSS events (Charge start)
Contactor close/open (Charge boundary)
Voltage increase pattern (Charge detection)
"Saving Stats, Hibernating" (Session end)

BMS Log Differences

Gen2 BMS

Text-based entries with clear labels:

Discharging

PackTemp:h 31C l 27C PackSOC:89%

Vpack:117.2V Cell:H 4105 L 4092 mV

Delta:13mV, BrdTemp:28C

  • Cell voltages (high, low) in every entry
  • SOC (State of Charge) always present
  • Pack and board temperatures
  • Cell balance delta (mV)
  • Charging/Discharging/Balancing modes

Gen3 BMS decoded

Binary entries delimited by 0xB2, with 52-byte telemetry:

0xB2 + 2B header + 4B Unix timestamp (LE) + 1B + 44B payload

Payload[13-14]: CvLow uint16 LE (mV)

Payload[17-18]: CvHigh uint16 LE (mV)

Payload[19]: SOC uint8 (0-100%)

Payload[20-21]: Current int16 LE (mA, neg=charge)

Payload[43]: Temperature uint8 (C)

  • Cell voltages min/max (mV) - CC/CV profile visible
  • SOC 0-100% (0 = BMS sleeping, actual value when active)
  • Current in mA: charging ~-15A CC, taper in CV phase
  • Temperature and pack voltage (derived from cells x28)
  • Charging session detection with power calculation

The Ring Buffer Problem

Gen3 uses a ring buffer (circular buffer) for log storage. This has significant implications for data analysis:

Data Retention: Only 5-7 Days

Gen3 bikes (SR/F, SR/S, DSR/X) can only store approximately 5-7 days of data in their ring buffer. Here's why:

  • 1.The ring buffer holds ~2,300 entries (~131 KB of flash memory)
  • 2.Even when parked, the bike wakes up every ~1 hour for a STRT→PWSU→HIB cycle
  • 3.Each wake-up generates ~15-20 log entries (state changes, BMS checks, stats save)
  • 4.At ~350 entries/day, the buffer fills in ~6.5 days, overwriting all older data

To capture ride history, download your logs within 1-2 days of riding. If you wait longer, the ride data will likely be overwritten by hibernation cycles.

How it works

The log has a fixed capacity (~2,300 entries). When full, new entries overwrite the oldest. This means the file contains entries from different time periods, and they are NOT in chronological order.

// Ring buffer visualization (simplified)

File position: [oldest ... wrap point ... newest]

Timestamps: [Jan 15 ... Dec 3 ... Jan 14]

^ write pointer wraps here

Consequences

  • Entries must be sorted by timestamp before analysis
  • Old riding data gets overwritten by newer hibernation cycles
  • A "stored" bike fills the buffer in 5-7 days, losing all ride history
  • Odometer values from different ring buffer positions may differ significantly
  • Some timestamps may be corrupted (1970 or 2047) — RTC clock issues

MBB vs BMS Data Sources

Gen3 MBB binary telemetry does not contain voltage, current, or speed data. These fields are stored only in the BMS (Battery Management System) log. The MBB records state snapshots (RUN/STOP/HIB), SOC%, temperatures, and an approximate odometer.

MBB provides:

  • State (RUN, STOP, HIB, CHRG...)
  • SOC% (dashboard value)
  • Temperatures (active states only)
  • Odometer (approximate)
  • Text events & fault codes

BMS provides:

  • Cell voltages (min/max)
  • Battery current (mA)
  • Pack SOC%
  • Load state & report mode
  • Temperature

Real-World Example: "Stored" SR/S

An SR/S stored for winter (Oct 2025 – May 2026) showed 0 rides despite having 13,153 km on the odometer. The ring buffer was entirely filled with periodic wake-up cycles (STRT→PWSU→HIB every ~1 hour), which had overwritten all previous ride data. The 9 different odometer readings (12,635 – 13,153 km) are historical snapshots from different ring buffer positions, not actual distance traveled during the logging period.

Charging Detection

Gen2

Simple and reliable:

  1. Entry has mode = "Charging"
  2. SOC increases over time
  3. Charge current visible in BMS
  4. Session ends when SOC stops increasing

Gen3

Requires multi-signal detection:

  1. State = CHRG (explicit)
  2. CHARGER LSS events (charger node registration)
  3. Contactor events (Precharging from module)
  4. Voltage increase during non-RUN periods (fallback)
Gotcha: "Ch limits" entries are BMS capability reports, NOT charging indicators. They appear regardless of charging state.

Known Unknowns

Gen3 log format is not officially documented. Here's what we've decoded so far and what remains unknown:

AreaStatusNotes
MBB Voltagedecoded[s-21]: uint32 LE millivolts. Secondary at [s-8]. Dual sensor pairs confirmed
MBB Currentdecoded[s-17]: signed int32 LE milliamps (+discharge, -regen). Secondary at [s-4]
MBB Speeddecoded[s-13]: uint32 LE (~cm/s, x0.036=km/h). Validated 2-113 km/h range
MBB SOCdecoded[s-9]: uint8 0-100% (dashboard SOC, ~8-9% higher than BMS true SOC)
MBB Motor RPMdecodedPost-state field 3: uint32 LE. Correlated with speed field
MBB OdometerdecodedPost-state field 5: uint32 LE, value in meters. Converted to km in DB
MBB TorquedecodedPost-state field 4: uint32 LE, Nm. Gen3-exclusive metric
MBB State machinedecoded4-char ASCII: RUN/STOP/HIB/WAIT/PWSU/WAKE/CHRG/STRT (9-byte null-padded field)
MBB Temperaturesdecoded4 sensors: [s+13]=controller, [s+17]=motor, [s+21]=battery, [s+25]=ambient (uint32 LE, °C)
MBB Controller flagdecodedByte 11: 0x00=active/running, 0x6A=standby, 0x60=transitional
MBB Power limitsdecodedText events: "Disch limits pow X" / "Ch limits pow X" in watts, stored as kW
MBB Pre-state headerdecodedByte 0: type (0x69). Bytes 1-4: counter. Bytes 5-6: entry num. Bytes 7-14: padding
MBB Post-field 0partialPost-state field 0: internal metric (~400-2000), loosely thermal-correlated
MBB Entry variantsdecoded75B (standard s=36), 76B (+1 null s=37, absolute offsets), 92B (+13 extra s=40)
MBB Ride sessionsworkingRUN state + time-gap splitting + event boundaries. Stored as UnifiedSession
MBB Charge sessionsworkingCHRG + CHARGER LSS + contactor + voltage pattern. Stored as UnifiedSession
MBB Text eventsdecodedKill Sw, Key Sw, Kickstand, Immobilizer, State change, Faults, Flags, 12V charge, Limits
MBB Status entriespartial29-byte periodic power/current snapshots (correlated fields, factor 200000)
MBB Ride modemissingEco/Sport/etc. not found in Gen3 logs — possibly stored in separate dealer-only logs
BMS Cell voltagesdecodeduint16 LE at payload[13] (min) and payload[17] (max), millivolts
BMS Cell OCVdecodeduint16 LE payload[15]: IR-compensated Open Circuit Voltage, used for SOH estimation
BMS SOCdecodeduint8 payload[19], 0-100%. SOC=0 means sleeping/not computed
BMS Currentdecodedint16 LE payload[20], milliamps. Negative = charging. CC/CV taper confirmed
BMS Charging flagdecodedPayload[22-23]: 0xFF,0xFF when charging, 0x00,0x00 otherwise
BMS Load statedecodedPayload[27]: 0x78=idle, 0xFF=active. Payload[28]: bus engaged (0x01=load)
BMS Report modedecodedPayload[37]: 1=standard, 3=minimal/sleep, 7=active high-rate
BMS State codedecodedPayload[24]: progressive state machine (0x04-0x12), cycles idle, increments active
BMS Temperaturedecodeduint8 at payload[43], degrees Celsius
BMS Pack voltagedecodedDerived: (CvMin + CvMax) / 2 × 28 cells. Also available from MBB binary
BMS Charge sessionsworkingDetected from sustained negative current + SOC increase + charging flag
BMS TimestampdecodedUnix uint32 LE at entry offset 3 (same epoch as MBB)
BMS Text eventsdecodedState transitions, hibernate, faults, cell type, cellbox comms, 12V latch
BMS Remainingpartial~16 bytes padding/reserved + counters at 0-1, 38-39, sub-state at 42
Gen3 Error codespartialFault pending/cleared events parsed, meanings differ from Gen2 codes

Database Storage & Parsing Pipeline

When a log file is uploaded, a background worker parses it and stores entries in PostgreSQL (with TimescaleDB for time-series optimization). The storage strategy differs by generation:

Gen2 Parsing Flow

  1. Parse text-based entries (structured key:value pairs)
  2. Map event type (Riding/Charging/etc.) to bike_state
  3. Extract all metrics directly from text fields
  4. Calculate speed from RPM, power from V×I
  5. Store with log_generation = 2
  6. Detect ride/charge sessions from event patterns

Dedicated columns:

pack_voltage_v, battery_amps, motor_rpm,

speed_kmh, odometer_km, motor_temp_c,

controller_temp_c, ambient_temp_c, soc,

power_kw, bike_state

Gen3 Parsing Flow

  1. Decode binary payloads (state-anchored offsets for MBB, 0xB2-delimited for BMS)
  2. Extract state machine value as bike_state
  3. Convert units (mV→V, mA→A, meters→km, W→kW)
  4. Parse text events for power limits and state transitions
  5. Store with log_generation = 3
  6. Gen3-only fields promoted to dedicated columns

Gen3-exclusive columns:

bike_state, controller_active,

discharge_limit_kw, charge_limit_kw,

cell_voltage_ocv_min, is_under_load,

bms_state_code, torque_nm

Shared columns (same as Gen2):

pack_voltage_v, battery_amps, speed_kmh,

odometer_km, motor_temp_c, soc, power_kw

Gen3 Entry Types in Database

Gen3 MBB entries are heterogeneous: not every entry has every field. Binary telemetry entries have voltage, current, speed, temps — but NOT power limits. Text entries have power limits — but NOT telemetry. This is by design:

Binary Telemetry (75-92B)

V, I, SOC, speed, RPM, torque, temps, odometer, bike_state, controller_active

Text Events (Power Limits)

discharge_limit_kw, charge_limit_kw — BMS capability reports

Text Events (State/System)

State changes, faults, key/kill switch, kickstand, contactor events

Gen3 log format details are based on community reverse-engineering of production log files from SR/F, SR/S, and DSR/X motorcycles. All major telemetry fields have been decoded. A few secondary bytes (~16 in BMS, status entries in MBB) remain as padding/reserved. Last verified: February 2026. Contributions welcome!