Data formats
OpenBikeComputer uses binary objects for device data. The device reads these objects through a random-access byte interface. It does not parse host data formats during normal operation.
The files in specs/ are the normative contracts. obc-formats defines shared constants and byte primitives. Reader and writer crates own parsing, caching, and conversion policy.
Format summary
| Format | Current version | Use | Main consumer |
|---|---|---|---|
| OBCM | 14 | Map, POIs, navigation graph, and optional terrain | Device |
| OBCR | 3 | Route geometry, statistics, and waypoints | Device |
| Ride object | 3 | Recorded samples and summary | Device and companion |
| OBCT | 1 | Terrain height raster | Device and map tools |
| OBCW | 1 | Hourly weather and rain frames | Device |
| OBCG | 1 | Published precipitation grid frame | Companion and host tools |
| OBCC | Schema 2 | Map-builder catalog | Website and desktop app |
| OBCA | 1 | Cell and assembly rules | Map tools |
All multi-byte values use little-endian order unless a specification says otherwise. Coordinates use signed integer microdegrees. Each format stores offsets and counts. Readers use checked arithmetic and reject unsupported versions.
OBCM — the map
OBCM v14 is the only supported map version. One OBCM object contains all map data. Its global offsets are 32-bit values in scaled units. Current writers use 16-byte units. This gives the file a 64 GiB address space.
The file, front to back
The 49-byte header addresses the global sections. The style table applies to all LODs. The LOD table orders detail levels from coarse to fine. Each LOD is independent. A renderer reads only the LOD for the current meters-per-pixel value.
A LOD table entry is 18 bytes:
| Field | Type | Meaning |
|---|---|---|
| Maximum meters per pixel | f32 | Upper display threshold for this LOD |
| Index offset | u32 | Scaled offset to the quadtree |
| Node count | u32 | Number of quadtree words |
| Chunk size | u16 | Maximum chunk content size |
| Chunk count | u32 | Number of geometry chunks |
The chunk size is a capacity limit. It is not a stride. A table with chunk_count + 1 scaled offsets addresses the unit-aligned chunks.
The header
The core header fields are:
| Bytes | Field |
|---|---|
| 0–3 | Magic OBCM |
| 4 | Version 14 |
| 5–20 | Latitude/longitude bounding box |
| 21–24 | Style-table offset |
| 25 | LOD count |
| 26–29 | LOD-table offset |
| 30–31 | Marker color in RGB565 |
| 32–35 | POI-section offset |
| 36–39 | Navigation-section offset |
| 40 | Base-2 offset scale |
| 41–44 | Optional terrain offset |
| 45–48 | Optional terrain length |
The POI and navigation sections are always present. An empty section has a valid nonzero offset. A zero terrain offset and length mean that the map has no terrain.
Each style record is 8 bytes. It contains the style identifier, z-index, RGB565 color, weight, flags, and optional secondary color. Flags contain priority, dashed, secondary-color, fixed-width, and terrain-layer bits. The packer assigns style identifiers from 1 through 254. Value 0xFF ends the features in a chunk.
The quadtree index
The quadtree is a flat array of u32 words:
- A set high bit identifies a branch.
- The low 31 bits give the first of four consecutive children.
0x7FFF_FFFFidentifies an empty leaf.- Other values identify a geometry chunk.
The child order is northwest, northeast, southwest, and southeast. The reader calculates child bounds with integer floor midpoints.
Features: an anchor, then deltas
A feature stores an anchor relative to its leaf. Subsequent points use signed coordinate deltas. One flag selects 8-bit or 16-bit delta pairs.
The reader validates the complete feature before it publishes geometry. An invalid or over-capacity feature is dropped as one unit. The reader does not return truncated polygons or lines.
A compact header uses an 8-bit point count and two 16-bit anchor components. A wide header uses a 16-bit point count and two 32-bit anchor components. Polygon holes follow the exterior ring. The even-odd fill rule uses all rings.
POIs: a nearest-list, not a map layer
The map has one POI quadtree for each category. The category comes from the selected directory entry. It is not repeated in each record.
A POI record is 36 bytes. It contains coordinates, subtype, a 24-byte printable-ASCII name, and HoursRef. The same indexes support nearest-item and route-corridor queries.
Opening hours: a pooled weekly schedule
Each schedule contains two intervals for each weekday. Times use 15-minute units. HoursRef = 0xFFFF means that no parsed schedule is available. Seasonal or unsupported source rules set schedule flags.
The navigation graph: a routable network
The navigation section uses 512-byte chunks. Its 40-byte directory addresses these regions:
- Profile table
- Node quadtree and junction chunks
- Edge geometry pool
- Sparse snap-anchor quadtree and chunks
Each junction record includes its neighbor coordinates. The router can calculate its heuristic without another read. Each directional neighbor entry also stores way kind, cost, and integrated ascent.
Edges longer than 300 m get sparse lookup anchors. The anchors make each accepted road discoverable within the 251 m lookup radius. The router then projects the endpoint onto the complete stored polyline.
The route search uses node records only. It reads edge geometry for exact endpoint projection and final route output. For routing behavior and limits, see the router seam.
OBCR — the route
OBCR v3 is the only supported route version. A route is one ordered polyline with elevations. The header also stores exact route statistics. An optional table stores named waypoints.
The file
The 128-byte header contains the route name, bounds, start point, statistics, and section offsets. Each 44-byte chunk-index entry contains its anchor, bounds, cumulative statistics, byte offset, and point count. Each route point record stores longitude delta, latitude delta, and absolute elevation.
Waypoints: a category and a side
The converter maps GPX symbols and types to canonical waypoint categories. It projects each waypoint onto the route. The stored distance uses the route axis. The signed lateral offset shows which side of the route contains the waypoint.
Chunks, seams, and deltas
A route chunk starts with an absolute anchor. Its remaining points use 16-bit coordinate deltas. Adjacent chunks repeat their shared boundary point. This rule prevents visible gaps.
Exact stats, decimated geometry
The converter calculates totals from all input points. It can decimate the stored geometry after this calculation. Distance, ascent, descent, and elevation range remain exact.
Recorded rides — the v3 ride object
Each 20-byte sample contains position, elevation, flags, time, heart rate, cadence, and power. A segment-start flag separates discontinuous track segments. Finalization appends a fixed summary footer. The device can recover a summary without scanning all samples.
The byte contract is in the BLE interface specification. Shared vectors include ride-v3.bin.
OBCT — the terrain raster
OBCT v1 stores orthometric heights as signed 16-bit meters. Value -32768 means NODATA. The sample posting and cell size are header values.
A tile contains 16 × 16 samples and is exactly 512 bytes. Tiles and cells use row-major order. Rows increase latitude. The first sample is at the minimum corner.
The 32-byte header defines the lattice and a rectangular cell directory. Each nonzero directory entry addresses one cell block. The device applies bilinear interpolation. If one required corner is NODATA, the sample result is unavailable.
Published terrain cells use the .obcd extension. An assembled OBCM map contains one OBCT container in its terrain region. The map reader gives that region to the OBCT reader as a byte-source window.
OBCW — provider-neutral weather
OBCW v1 contains a 112-byte header, 24 hourly records, rain-frame descriptors, tile directories, and tile data. The header contains generation, request, time, bounds, offsets, and a whole-object CRC-32. Hourly record i describes the interval that starts i hours after valid_from.
Rain frames use their actual UTC validity times. Each rain tile contains 16 × 16 four-bit intensity values. The format supports canonical raw and run-length encodings. Missing precipitation is different from dry precipitation.
obc-weather validates the complete object. It decodes one tile into caller-owned memory. See OBCW_Spec.md for byte fields and rejection rules.
Upstream of the phone: OBCG
OBCG v1 is the published precipitation-grid format. One object contains one frame for one geographic shard. The device does not read OBCG.
An OBCG object contains:
- A self-checked 128-byte header
- A paged tile directory with page CRCs
- Tile payloads with individual CRCs
- A whole-object CRC
A range client reads only directory pages and tiles that intersect its corridor. OBCG supports raw, run-length, and DEFLATE tile codecs. The companion decodes OBCG and writes device-safe OBCW tiles. The device does not include a DEFLATE decoder.
The service manifest selects current objects and states freshness, geometry, presence, and attribution. See OBCG_Spec.md.
Streaming: resident vs on-demand
All device readers use ByteSource:
pub trait ByteSource {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<(), Error>;
fn len(&self) -> u64;
}
The device implementation reads a flat-store object. The simulator and browser demo import OBCM into the same flat store, then read the committed map object. Their media differ: a temporary sparse file on the simulator and sparse memory pages in the browser. Other host objects still use their existing file or memory repositories. The u64 offset supports large OBCM objects.
OBCM keeps its header, styles, and LOD table in memory. It streams quadtree blocks and geometry chunks. OBCR keeps its small flat index in memory and streams geometry. OBCT keeps its header in memory and uses a four-tile cache. OBCW validates and decodes in bounded windows.
The catalog — the map builder's source of truth
OBCC schema 2 is the map-builder catalog. The device does not read it. The root document publishes:
- One map schema
- Presentation-only skins
- Named region selections
- One cell index for each band
- Optional terrain metadata and index
- Source and license information
The root pins referenced objects by byte length and SHA-256. Published object keys also contain the digest. A consumer verifies each object before use.
The schema controls geometry, LODs, style identifiers, routing, and chunk size. A skin controls colors, weights, line style, z-index, priority, and marker color. A skin change does not require a cell rebake. A schema or OBCM-version change does require a consistent cell-store rebake.
Terrain cells have a separate revision. The catalog also states which terrain revision supplied navigation ascent values. See OBCC_Spec.md.
Cells and assemblies
OBCA defines the global cell grid and the assembly rules. Cells are power-of-two microdegree squares on one global origin. Each schema band assigns a cell size and a subset of map content.
The alignment trick
Exact alignment lets the assembler copy geometry chunks without decoding them. The assembler rebuilds the header, tables, POIs, opening-hours pool, and navigation graph. It also inserts the selected OBCT terrain container. Routing seam nodes merge only when their coordinates are equal.
Schema and skin
All cells in one assembly use the same schema revision and OBCM version. The assembler replaces cell presentation records with the selected skin. It does not change geometry.
One map, one file
OBCM v14 uses scaled offsets and stores terrain in the map. The assembler produces one OBCM object. It does not produce map shards or a set manifest.
Browser assembly
obcm-assemble is the shared native assembly engine. obc-web-assemble is its WebAssembly interface. The browser can stream cells, scratch data, and output through origin-private storage. The assembler verifies the completed file through the production readers.
See OBCA_Spec.md for the grid, seam, and verification rules.
Source index
- Format constants and byte I/O:
obc-formats - OBCM reader:
obc-reader - OBCR reader, converter, and router:
obc-route - OBCT reader and sampler:
obc-elevation - OBCW reader:
obc-weather - OBCM packer:
obc-pack - Terrain baker:
obc-dem - Weather-grid baker:
obc-wx-bake - Map assembler:
obcm-assemble - Catalog and assembly specifications:
OBCC_Spec.mdandOBCA_Spec.md