Wideband autonomous SDR analysis engine forked from sdr-visual-suite
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

144 行
3.5KB

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "sdr-wideband-suite/internal/config"
  6. "sdr-wideband-suite/internal/sdr"
  7. "sdr-wideband-suite/internal/telemetry"
  8. )
  9. func (m *sourceManager) Restart(cfg config.Config) error {
  10. start := time.Now()
  11. m.mu.Lock()
  12. defer m.mu.Unlock()
  13. old := m.src
  14. _ = old.Stop()
  15. next, err := m.newSource(cfg)
  16. if err != nil {
  17. _ = old.Start()
  18. m.src = old
  19. if m.telemetry != nil {
  20. m.telemetry.IncCounter("source.restart.error", 1, nil)
  21. m.telemetry.Event("source_restart_failed", "warn", "source restart failed", nil, map[string]any{"error": err.Error()})
  22. }
  23. return err
  24. }
  25. if err := next.Start(); err != nil {
  26. _ = next.Stop()
  27. _ = old.Start()
  28. m.src = old
  29. if m.telemetry != nil {
  30. m.telemetry.IncCounter("source.restart.error", 1, nil)
  31. m.telemetry.Event("source_restart_failed", "warn", "source restart failed", nil, map[string]any{"error": err.Error()})
  32. }
  33. return err
  34. }
  35. m.src = next
  36. if m.telemetry != nil {
  37. m.telemetry.IncCounter("source.restart.count", 1, nil)
  38. m.telemetry.Observe("source.restart.duration_ms", float64(time.Since(start).Milliseconds()), nil)
  39. }
  40. return nil
  41. }
  42. func (m *sourceManager) Stats() sdr.SourceStats {
  43. m.mu.RLock()
  44. defer m.mu.RUnlock()
  45. if sp, ok := m.src.(sdr.StatsProvider); ok {
  46. return sp.Stats()
  47. }
  48. return sdr.SourceStats{}
  49. }
  50. func (m *sourceManager) Flush() {
  51. m.mu.RLock()
  52. defer m.mu.RUnlock()
  53. if fl, ok := m.src.(sdr.Flushable); ok {
  54. fl.Flush()
  55. }
  56. }
  57. func newSourceManager(src sdr.Source, newSource func(cfg config.Config) (sdr.Source, error)) *sourceManager {
  58. return newSourceManagerWithTelemetry(src, newSource, nil)
  59. }
  60. func newSourceManagerWithTelemetry(src sdr.Source, newSource func(cfg config.Config) (sdr.Source, error), coll *telemetry.Collector) *sourceManager {
  61. return &sourceManager{src: src, newSource: newSource, telemetry: coll}
  62. }
  63. func (m *sourceManager) Start() error {
  64. m.mu.RLock()
  65. defer m.mu.RUnlock()
  66. return m.src.Start()
  67. }
  68. func (m *sourceManager) Stop() error {
  69. m.mu.RLock()
  70. defer m.mu.RUnlock()
  71. return m.src.Stop()
  72. }
  73. func (m *sourceManager) ReadIQ(n int) ([]complex64, error) {
  74. waitStart := time.Now()
  75. m.mu.RLock()
  76. wait := time.Since(waitStart)
  77. defer m.mu.RUnlock()
  78. if m.telemetry != nil {
  79. m.telemetry.Observe("source.lock_wait_ms", float64(wait.Microseconds())/1000.0, telemetry.TagsFromPairs("lock", "read"))
  80. if wait > 2*time.Millisecond {
  81. m.telemetry.IncCounter("source.lock_contention.count", 1, telemetry.TagsFromPairs("lock", "read"))
  82. }
  83. }
  84. readStart := time.Now()
  85. out, err := m.src.ReadIQ(n)
  86. if m.telemetry != nil {
  87. tags := telemetry.TagsFromPairs("requested", fmt.Sprintf("%d", n))
  88. m.telemetry.Observe("source.read.duration_ms", float64(time.Since(readStart).Microseconds())/1000.0, tags)
  89. m.telemetry.SetGauge("source.read.samples", float64(len(out)), nil)
  90. if err != nil {
  91. m.telemetry.IncCounter("source.read.error", 1, nil)
  92. }
  93. }
  94. return out, err
  95. }
  96. func (m *sourceManager) ApplyConfig(cfg config.Config) error {
  97. m.mu.Lock()
  98. defer m.mu.Unlock()
  99. if updatable, ok := m.src.(sdr.ConfigurableSource); ok {
  100. if err := updatable.UpdateConfig(cfg.SampleRate, cfg.CenterHz, cfg.GainDb, cfg.AGC, cfg.TunerBwKHz); err == nil {
  101. return nil
  102. }
  103. }
  104. old := m.src
  105. _ = old.Stop()
  106. next, err := m.newSource(cfg)
  107. if err != nil {
  108. _ = old.Start()
  109. return err
  110. }
  111. if err := next.Start(); err != nil {
  112. _ = next.Stop()
  113. _ = old.Start()
  114. return err
  115. }
  116. m.src = next
  117. return nil
  118. }
  119. func pushDSPUpdate(ch chan dspUpdate, update dspUpdate) {
  120. select {
  121. case ch <- update:
  122. default:
  123. select {
  124. case <-ch:
  125. default:
  126. }
  127. ch <- update
  128. }
  129. }