We occasionally get questions about the .sal capture format, and although our usual response is that it’s not stable and shouldn’t be relied on, there have been enough requests for more information (see: Provide .sal file translation through an API - Logic 2 - Ideas and Feature Requests - Saleae) that we thought it was worth creating a dedicated post where we could answer questions.
DISCLAIMER: We do not officially support or maintain compatibility with past or future version of the .sal format. The format can and will change in breaking ways. USE AT YOUR OWN RISK
Ok, now that that is out of the way, let’s talk about the format. A .sal capture itself is a zip file - rename your capture.sal to capture.zip and open it with your favorite zip tool - you’ll find:
meta.json
- a json file describing the capturedigital-#.bin
- raw digital dataanalog-#.bin
- raw analog data
That’s it. meta.json
is a JSON format that is (hopefully) fairly easy to reason about. The digital and analog formats are binary formats that require a little more work to understand.
On the ideas page, Dan has already done great work figuring out the digital format (again, see: Provide .sal file translation through an API - Logic 2 - Ideas and Feature Requests - Saleae). I’ll try to answer some of those questions here.
Why not the 0x80 of the first byte flagging? Good Question! And this is the easy format to reverse engineer.
The digital data is RLE encoded, using a variable number of bytes. The MSB of the first byte indicates whether this byte is an RLE entry (0) or a raw entry (1). In practice we never use the raw data mode, so this bit is never set.
Still don’t quite understand the relation between that metadata array entry count and the transitions/transitions count, but I don’t think I need to currently.
The metadata contains sample number to byte offset information. We use it at runtime to speed up cases where we need to search by sample number, but you can skip it. If you do think it would be helpful, the format is:
uint64 sample_number
uint64 byte_offset // into the RLE data
int32 bit_state
No comment on the 32 bits for the bit state
This is likely to change in the next year, but no short term plans to do so.
Also, I’m guessing part of the reason for the blocks is that somewhere you’re creating a separate block for each transfer up from the USB driver and you’re just serializing the list of blocks. Simple enough approach.
Yep, this is about right. The actual size and rate of the blocks will be affected by the sample rate that you are using as well.
If you have specific questions, please ask here and we’ll try to help out.
Ryan