Overview
An .osdpcap file is JSON Lines: UTF-8 text with one JSON object per line. Each object is a record of one OSDP packet, a command or a reply, exactly as it crossed the wire. Records are written in the order the packets were seen. The format is defined by the OSDP Capture Format specification in libosdp-conformance; this page describes version 1.
These tools write it:
- The OSDP.Net ACU and PD Consoles, in the
capturesfolder beside the app. - The OSDP.Net library, when a connection is started with tracing on (
{connection id}.osdpcapin the working directory), or from your own code withOSDPCaptureFileWriter. - OSDP Bench, when you export a packet trace as an OSDP Capture.
- libosdp-conformance.
Record fields
Every record has all six fields, and every value is written as a JSON string, numbers included.
| Field | Value |
|---|---|
timeSec | Whole seconds since the Unix epoch, UTC, in decimal. For example "1792944000". |
timeNano | Nanoseconds within that second, "000000000" to "999999999", zero-padded to nine digits. OSDP.Net tools record to 100 ns. |
io | Which way the packet went, seen from the tool that wrote the file:
"output" it sent the packet, "input" it received the packet, "trace" it watched the line without taking part.
So in an ACU Console capture commands are output and replies are input; in a PD Console capture it's the other way round. |
data | The bytes off the wire as hex, normally one whole packet from the start-of-message byte 53 through the checksum or CRC. OSDP.Net tools separate the bytes with dashes ("53-00-08-00-05-60-DA-99"); libosdp-conformance uses spaces. Leading FF mark bytes may be included. Secure Channel packets are recorded as sent, still encrypted. |
osdpTraceVersion | The format version. This page describes version "1". |
osdpSource | The tool that wrote the record, such as "ACUConsole", "PDConsole", "OSDP.Net", "OSDP-Bench" or "libosdp-conformance 0.91-5". |
Example
An ACU polling the reader at address 0 and the reader's acknowledgement 21 ms later:
{"timeSec":"1792944000","timeNano":"125000000","io":"output","data":"53-00-08-00-05-60-DA-99","osdpTraceVersion":"1","osdpSource":"ACUConsole"}
{"timeSec":"1792944000","timeNano":"146000000","io":"input","data":"53-80-08-00-05-40-68-9F","osdpTraceVersion":"1","osdpSource":"ACUConsole"}
The first packet is osdp_POLL (60) to address 00; the second is osdp_ACK (40) from the same device, with the reply bit set in its address byte (80). Both have sequence number 1 and a CRC-16.
JSON Schema
One line of an .osdpcap file, as JSON Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "osdpcap record",
"type": "object",
"required": ["timeSec", "timeNano", "io", "data", "osdpTraceVersion", "osdpSource"],
"properties": {
"timeSec": { "type": "string", "pattern": "^[0-9]+$" },
"timeNano": { "type": "string", "pattern": "^[0-9]{1,9}$" },
"io": { "enum": ["output", "input", "trace"] },
"data": { "type": "string", "pattern": "^[\\s\\-:]*([0-9A-Fa-f]{2}[\\s\\-:]*)+$" },
"osdpTraceVersion": { "const": "1" },
"osdpSource": { "type": "string" }
}
}
What the Capture Analyzer accepts
The analyzer reads captures more leniently than the specification requires, so files from tools that bend the format still work:
- Files up to 25 MB. Blank lines are skipped.
- The first line must be a JSON object. A decoded
.txttrace is not an .osdpcap file. - Lines that can't be read are counted and reported in the analysis rather than failing the upload.
- A record needs only
timeSecanddata; a missingtimeNanois taken as 0.timeSecandtimeNanomay also be JSON numbers. - Commands and replies are told apart by the reply bit in each packet's address byte, so
ioisn't needed to decode a capture. - Each
datavalue must hold one packet with an even number of hex digits; any separator is ignored.
Writing captures from your own code
With OSDP.Net, OSDPCaptureFileWriter writes records in this format:
using OSDP.Net.Tracing;
using var capture = new OSDPCaptureFileWriter("reader.osdpcap", "MyTool");
capture.WritePacket(commandBytes, TraceDirection.Output);
capture.WritePacket(replyBytes, TraceDirection.Input);
Pass capture.WriteTrace as the tracer when starting a ControlPanel connection to record every packet on the bus.