rds

package
v0.783.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 29, 2026 License: AGPL-3.0 Imports: 2 Imported by: 0

Documentation

Overview

Package rds decodes RDS / RBDS (Radio Data System) groups — the digital sub-carrier (57 kHz) on FM broadcast that carries the station's Programme Service name, RadioText, programme type, traffic flags and (for North American RBDS) the call sign. It is the data an SDR / rtl_fm + redsea pipeline pulls off any FM station, and a staple of broadcast-RF forensics.

Wrap-vs-native judgement

Native. RDS is fully public (IEC 62106 / NRSC-4 RBDS). A group
is four 16-bit blocks (A=PI, B=type+flags, C, D); the decode is
pure bit-field extraction plus two small lookup tables (the G0
character set and the programme-type names) and the RBDS
PI->call-sign arithmetic. No DSP and no crypto — the operator
pastes the post-demod block hex (redsea's `0xAAAA'BBBB'CCCC'DDDD`
form, or plain 16-hex-per-group) and reads the station data. No
new dependency, no shell-out; the reference decoder (redsea) is
reimplemented here, not wrapped.

What this covers

  • Block A: Programme Identification (PI) code, and the RBDS four-letter call sign derived from it (K/W stations).
  • Block B: group type (0A..15B), TP (traffic-programme) flag, and the 5-bit programme type with both the RDS (European) and RBDS (North American) name tables.
  • Group 0A/0B: Programme Service name (8 chars, assembled across the four segments) plus the TA (traffic announcement), MS (music/speech) and DI (decoder-identification) flags.
  • Group 2A/2B: RadioText (up to 64 chars, assembled across segments, truncated at the 0x0D terminator), with the A/B text flag.
  • Group 1A: Programme Item Number (the day + time the current programme started), the linkage flag, and the slow-labelling variants — extended country code (raw), language (named), TMC identification, SLC broadcaster bits and the emergency-warning field.
  • Group 10A: Programme Type Name (the 8-character long-form programme-type label, assembled across its two segments).
  • Group 0A alternative frequencies: the flat, de-duplicated VHF frequency list (EN 50067 Annex D) the station simulcasts on, plus the advertised AF count.
  • The RDS G0 default character set (IEC 62106 Annex E) for the Programme Service, RadioText and Programme Type Name.

Deliberately deferred

Clock-time (group 4A) — the reference decoder's output is
timezone/implementation dependent, so there is no trustworthy
deterministic oracle to verify a port against. The AF Method B
same-programme vs regional-variant structuring (a Method B
station's flat list still contains its tuned frequency), Open
Data Applications / TMC (3A / 8A), Enhanced Other Networks (14),
the ECC->country-name table (the raw extended country code is
surfaced) and the legacy three-letter / nationally-linked RBDS
call signs are not decoded; the group type is still reported so
nothing is silently dropped.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Group

type Group struct {
	BlocksHex string `json:"blocks_hex"`
	PI        string `json:"pi"`
	GroupType string `json:"group_type"`
	TP        bool   `json:"tp"`
	PTY       int    `json:"pty"`
	PTYName   string `json:"pty_name"`

	// Group 0 (Programme Service)
	TA            *bool  `json:"traffic_announcement,omitempty"`
	MusicSpeech   string `json:"music_speech,omitempty"`
	DI            string `json:"decoder_identification,omitempty"`
	PSSegment     string `json:"ps_segment,omitempty"`
	PSSegmentAddr *int   `json:"ps_segment_address,omitempty"`

	// Group 2 (RadioText)
	RadioTextAB      string `json:"radiotext_ab,omitempty"`
	RadioTextSegment string `json:"radiotext_segment,omitempty"`

	// Group 1 (programme item number + slow labelling)
	ProgItemNumber     *int   `json:"prog_item_number,omitempty"`
	ProgItemDay        *int   `json:"prog_item_day,omitempty"`
	ProgItemTime       string `json:"prog_item_time,omitempty"`
	HasLinkage         *bool  `json:"has_linkage,omitempty"`
	ECC                string `json:"extended_country_code,omitempty"`
	CountryCodeNibble  *int   `json:"pi_country_code,omitempty"`
	Language           string `json:"language,omitempty"`
	TMCID              *int   `json:"tmc_id,omitempty"`
	EWS                *int   `json:"ews,omitempty"`
	SLCBroadcasterBits string `json:"slc_broadcaster_bits,omitempty"`

	// Group 10 (Programme Type Name)
	PTYNSegment string `json:"ptyn_segment,omitempty"`

	Note string `json:"note,omitempty"`
}

Group is the decode of a single 4-block RDS group.

type Options

type Options struct {
	// RBDS selects the North American RBDS programme-type names and
	// enables PI->call-sign derivation. Default (false) uses the
	// European RDS programme-type names.
	RBDS bool
}

Options controls table selection.

type Result

type Result struct {
	GroupCount        int      `json:"group_count"`
	PI                string   `json:"pi,omitempty"`
	Callsign          string   `json:"callsign,omitempty"`
	ProgrammeService  string   `json:"programme_service,omitempty"`
	RadioText         string   `json:"radiotext,omitempty"`
	ProgrammeTypeName string   `json:"programme_type_name,omitempty"`
	AltFrequenciesKHz []int    `json:"alternative_frequencies_khz,omitempty"`
	AFCount           *int     `json:"af_count,omitempty"`
	Groups            []Group  `json:"groups"`
	Notes             []string `json:"notes,omitempty"`
}

Result is the decoded view of one or more RDS groups.

func Decode

func Decode(hexStr string, opts Options) (*Result, error)

Decode parses a sequence of RDS groups from hex. Each group is four 16-bit blocks (16 hex digits); the redsea `0x….'….'….'….` form, plain concatenated hex, and ':'/'-'/'_'/whitespace/comma separators are all accepted.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL