瀏覽代碼

feat: use configured RDS PI code in encoder pipeline

tags/v0.5.0-pre
Jan Svabenik 1 月之前
父節點
當前提交
7a893e5632
共有 3 個檔案被更改,包括 56 行新增1 行删除
  1. +17
    -1
      internal/offline/generator.go
  2. +28
    -0
      internal/offline/generator_test.go
  3. +11
    -0
      internal/rds/encoder_test.go

+ 17
- 1
internal/offline/generator.go 查看文件

@@ -5,6 +5,8 @@ import (
"encoding/binary"
"fmt"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/jan/fm-rds-tx/internal/audio"
@@ -44,6 +46,20 @@ func (g *Generator) sourceFor(sampleRate float64) (frameSource, SourceInfo) {
return audio.NewConfiguredToneSource(sampleRate, g.cfg.Audio.ToneLeftHz, g.cfg.Audio.ToneRightHz, g.cfg.Audio.ToneAmplitude), SourceInfo{Kind: "tones", SampleRate: sampleRate, Detail: "generated"}
}

func parsePI(pi string) uint16 {
trimmed := strings.TrimSpace(pi)
if trimmed == "" {
return 0x1234
}
trimmed = strings.TrimPrefix(trimmed, "0x")
trimmed = strings.TrimPrefix(trimmed, "0X")
v, err := strconv.ParseUint(trimmed, 16, 16)
if err != nil {
return 0x1234
}
return uint16(v)
}

func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame {
sampleRate := float64(g.cfg.FM.CompositeRateHz)
if sampleRate <= 0 {
@@ -80,7 +96,7 @@ func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame

// RDS encoder (standards-grade group framing + CRC + diff encoding)
rdsEnc, _ := rds.NewEncoder(rds.RDSConfig{
PI: 0x1234,
PI: parsePI(g.cfg.RDS.PI),
PS: g.cfg.RDS.PS,
RT: g.cfg.RDS.RadioText,
PTY: uint8(g.cfg.RDS.PTY),


+ 28
- 0
internal/offline/generator_test.go 查看文件

@@ -126,3 +126,31 @@ func TestLimiterPreventsClipping(t *testing.T) {
}
}
}

func TestParsePI(t *testing.T) {
tests := []struct {
name string
in string
want uint16
}{
{name: "plain hex", in: "1234", want: 0x1234},
{name: "0x prefix", in: "0xBEEF", want: 0xBEEF},
{name: "uppercase prefix", in: "0XCAFE", want: 0xCAFE},
{name: "whitespace", in: " 0x2345 ", want: 0x2345},
{name: "empty fallback", in: "", want: 0x1234},
{name: "invalid fallback", in: "nope", want: 0x1234},
}
for _, tt := range tests {
if got := parsePI(tt.in); got != tt.want {
t.Fatalf("%s: got 0x%04X want 0x%04X", tt.name, got, tt.want)
}
}
}

func TestGeneratorUsesConfiguredPI(t *testing.T) {
cfg := cfgpkg.Default()
cfg.RDS.PI = "BEEF"
if got := parsePI(cfg.RDS.PI); got != 0xBEEF {
t.Fatalf("configured PI was not parsed as expected: got 0x%04X", got)
}
}

+ 11
- 0
internal/rds/encoder_test.go 查看文件

@@ -53,6 +53,17 @@ func TestBuildGroup2ABlockCount(t *testing.T) {
}
}

func TestBuildGroupUsesConfiguredPI(t *testing.T) {
g0 := buildGroup0A(0xBEEF, 0, false, false, 0, "TESTFM")
if g0[0] != 0xBEEF {
t.Fatalf("group0A block A not configured PI: %x", g0[0])
}
g2 := buildGroup2A(0xCAFE, 0, false, false, 0, "Hello World")
if g2[0] != 0xCAFE {
t.Fatalf("group2A block A not configured PI: %x", g2[0])
}
}

func TestEncoderGenerate(t *testing.T) {
cfg := DefaultConfig()
cfg.SampleRate = 228000


Loading…
取消
儲存