If you work on DAB data services like EPG, SLS (slideshow), BWS (broadcast website), Journaline or TPEG, this article might be worth reading.

As a programmer of software for the DAB radio standard you surely have often faced problems that have their roots in the lots of options the standard leaves open.
One of those problems is the proper handling of the CRC-flag that is broadcast within the MSC data group header. I will cover that in this short article.

If you concentrate on stationary radios this considerations may not be much important, but mobile receivers (think of automotive) may benefit a lot from a little deeper understanding.

In short, an MSC data group is a standard structure to carry data chunks of up to 8191 bytes within DAB ensembles. Different transport mechanisms are used to carry such datagroups.
An MSC datagroup consists of one mandatory header, some optional headers, a data field and an optional CRC placed behind the data field.
! Worth to note: an entire data group with all headers, data field and CRC may be a little larger than 8 KB (i.e. larger than 8192 bytes), which can easily be overseen when defining static buffers !!

Unfortunately the CRC is optional.
Even worse, the information whether there is a CRC or not is transmitted within the data group itself; it is the second bit within the mandatory MSC data group header.

What is the problem with that definition?
Since the CRC-flag is part of the data to be protected it may (in principal) as easily be corrupted as any other bit of the data group.
If the flag happens to switch from a transmitted ‘1’ to a received ‘0’ the receiver has to assume that there is no CRC placed behind the data field.
The receiver has to accept the data with all risks.

Of course the best would have been to simply make the CRC mandatory. At least the CRC-flag should be meta-data transmitted elsewhere at a high protection level (e.g. in FIG0/13 for all data groups of a data application) instead of being part of the data transmission itself.
But useless to complain about, we have to find ways to accept as much data groups as possible while discovering as many transmission errors as possible.

Obviously there is no problem if the CRC flag switches from ‘0’ to ‘1’. In that case the receiver would do a CRC check against a non existing CRC and that would most likely fail; good so far because the data group is corrupted, at least in one bit.

To be as smart as possible with the other case we have to examine the lower level transport mechanisms.

An MSC data group may be broadcast within the X-PAD channel of an audio stream sub-channel or within a data sub-channel using packets. Let’s look at each in detail.

X-PAD

In X-PAD an MSC datagroup is concatenated from a series of subfields. The X-PAD application-type transmitted within the content-indicator-list of an X-PAD field (kind of a content description) tells whether a subfield belongs to a specific application (means  here: to a specific datagroup series) and whether it is the first subfield of a datagroup or a continuation.
An additional length-indicator immediately precedes the first subfield and tells the overall length of the datagroup to come.

In case of UEP four bytes of the entire X-PAD field within an audio frame belong to the better protected part of the frame. If the first byte of the first subfield of a datagroup happens to be part of this better protected area, then the CRC flag will most likely be valid (if the current receiving quality is measured to be reasonably good).
This will always be the case if short X-PAD is used, with variable size X-PAD however it may or may not be so.

There is no additional protection for an X-PAD subfield!

DAB+ specific:
if you know whether the X-PAD data comes from an AAC audio stream (DAB+) instead of normal DAB when you do the CRC check, you could be more optimistic about the reliability of the CRC flag, because X-PAD in AAC is generally better protected.

Packet mode

In packet mode an MSC data group is concatenated from a series of packets within a data sub-channel. The packet-address tells whether a packet belongs to a specific application (means here: to a specific series of datagroups).

There is no extra length indicator, so the overall size of the data group simply is the sum of the ‘ useful data ’ of all packets.

A first-flag, a last-flag and a continuity-index help in starting a concatenation, continue a concatenation and finish a concatenation.
The continuity index (modulo 4) allows to discover a packet disruption in most cases.

Each packet has it’s own (mandatory!) CRC that protects each single packet.

What does this mean

In packet mode we can rely on the CRC-flag, since the start of a data group is safely identified by the first-flag and all packets are CRC protected.

So if there should be a data group with a CRC flag = ‘0’ that comes from packet mode, the data group should be accepted.

Delaying checks to higher protocol layers

In general it is good practice to handle each protocol layer independently and thus replaceable. That means, a layer should work the same way regardless how a lower level or any upper level is implemented.

But datagroup concatenation is somewhat different for X-PAD or packet mode as lower levels anyway. Further we mentioned above that we could benefit from some knowledge about lower level specifics with respect to the reliability of the CRC flag.
Possibly some upper level extensions could help too?

The MSC datagroup is one layer in a protocol stack that is normally followed by higher layers. Datagroups are directly used by Journaline for example or are fed into MOT decoders in case of Slideshow , EPG, BWS  and TPEG in some areas.

The MOT protocol defines an additional segmentation header containing two fields and one of these is the SegmentSize field. The segment size is the size of the usable data chunk within a datagroup that will be part of an MOT entity (normally a file). So we could suppose, that the datagroup should have a size of SegmentSize + all headers + CRC (if it exists).
So one could easily check if the datagroup is big enough to carry the CRC or not. However, nobody tells that a datagroup must not be bigger as needed.
I found one sentence in the spec.:
“ Note that some MOT decoders may ignore both parameters of the Segmentation header â€
– if so, those decoders could only function properly if the datagroup size matches exactly.
I would never trust such vague statements when it’s about DAB.

So I think we could not be sure that additional data (more as needed to carry a chunk of SegmentSize ) is a safe indication that there is a CRC. However if there are less than two additional bytes it is a safe indication that there is no CRC or a transmission error (e.g. a wrong SegmentSize ); an MOT decoder would accept that datagroup only if the CRC flag is set to 0.

Of course we should never implement any MOT specific knowledge into the datagroup concatenation. We could however delegate the CRC checking to upper layers, in this example to the MOT decoder.
I do not think it’s worth it, but I did not try.
The disadvantages are that the datagroup concatenation is not complete, that the CRC check has to be implemented at several places, and that erroneous data is moved in the system further than needed.

With a little help from statistics

It may also help to do some statistics and keep the results for one liefecycle or even persistent (persistent information has to be verified as soon as possible).
If we receive all (or most) datagroups of a service with a CRC, then we may assume that each single datagroup has one. The same should be true for the opposite.

When we start with no statistics available and receive the first datagroup with a valid CRC, then we may assume this service to be one with a CRC. If we receive one with a CRC-flag = 0 later, we consequently treat it as corrupted.

When we receive the first datagroupt with a CRC-flag = 0, we should wait for some more datagroups to verify this.
If there is enough memory, we should not drop the first datagroups but keep them for consumption after this verification.
This may, unfortunately, produce annoying delays since we do never know when the next datagroup will be broadcast.

Although there is no such rule, a providers datagroup generator will most likely not optimize in a way that it uses CRC if it fits into a frame and none if not.

However, the standard explicitly assigns the CRC-flag to each individual datagroup, not to a service, so we can never be sure.

Experiences

I have definitely seen CRC-flag corruptions in car radios when transmitted in X-PAD and those corruptions were not rare.

Ignoring them can confuse upper layers very seriously. On the other hand, dropping too many datagroups will result in a bad user experience; it’s annoying, for example, if a cheap receiver shows a more fluid slideshow performance as yours does. Robustness and performance are somewhat contradictionary in this case.

I spent a lot of time in making my MOT or TPEG decoders smart enough to keep out any kind of malicious input. I had to develop generators that produce datagroups with all kinds of risky data and metadata to verify that.
On the contrary, obeying the standard too strict here (with all thousand legal possibilities) could easily cause the rejection of datagroups that other receivers don’t drop.