Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

274 wiersze
7.0KB

  1. //go:build sdrplay
  2. package sdrplay
  3. /*
  4. #cgo windows LDFLAGS: -lsdrplay_api
  5. #cgo linux LDFLAGS: -lsdrplay_api
  6. #include "sdrplay_api.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. extern void goStreamCallback(short *xi, short *xq, unsigned int numSamples, void *cbContext);
  10. static void StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext) {
  11. (void)params;
  12. (void)reset;
  13. goStreamCallback(xi, xq, numSamples, cbContext);
  14. }
  15. static void EventCallback(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext) {
  16. (void)eventId; (void)tuner; (void)params; (void)cbContext;
  17. }
  18. static sdrplay_api_CallbackFnsT sdrplay_get_callbacks() {
  19. sdrplay_api_CallbackFnsT cb;
  20. memset(&cb, 0, sizeof(cb));
  21. cb.StreamACbFn = StreamACallback;
  22. cb.StreamBCbFn = NULL;
  23. cb.EventCbFn = EventCallback;
  24. return cb;
  25. }
  26. static void sdrplay_set_fs(sdrplay_api_DeviceParamsT *p, double fsHz) {
  27. if (p && p->devParams) p->devParams->fsFreq.fsHz = fsHz;
  28. }
  29. static void sdrplay_set_rf(sdrplay_api_DeviceParamsT *p, double rfHz) {
  30. if (p && p->rxChannelA) p->rxChannelA->tunerParams.rfFreq.rfHz = rfHz;
  31. }
  32. static void sdrplay_set_gain(sdrplay_api_DeviceParamsT *p, unsigned int grDb) {
  33. if (p && p->rxChannelA) p->rxChannelA->tunerParams.gain.gRdB = grDb;
  34. }
  35. static void sdrplay_set_if_zero(sdrplay_api_DeviceParamsT *p) {
  36. if (p && p->rxChannelA) p->rxChannelA->tunerParams.ifType = sdrplay_api_IF_Zero;
  37. }
  38. static void sdrplay_disable_agc(sdrplay_api_DeviceParamsT *p) {
  39. if (p && p->rxChannelA) p->rxChannelA->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE;
  40. }
  41. static void sdrplay_set_agc(sdrplay_api_DeviceParamsT *p, int enable) {
  42. if (!p || !p->rxChannelA) return;
  43. if (enable) {
  44. p->rxChannelA->ctrlParams.agc.enable = sdrplay_api_AGC_100HZ;
  45. } else {
  46. p->rxChannelA->ctrlParams.agc.enable = sdrplay_api_AGC_DISABLE;
  47. }
  48. }
  49. static sdrplay_api_ErrT sdrplay_update(void *dev, int reason) {
  50. return sdrplay_api_Update(dev, sdrplay_api_Tuner_A, (sdrplay_api_ReasonForUpdateT)reason, sdrplay_api_Update_Ext1_None);
  51. }
  52. */
  53. import "C"
  54. import (
  55. "errors"
  56. "fmt"
  57. "runtime/cgo"
  58. "sync"
  59. "time"
  60. "unsafe"
  61. "sdr-visual-suite/internal/sdr"
  62. )
  63. type Source struct {
  64. mu sync.Mutex
  65. dev C.sdrplay_api_DeviceT
  66. params *C.sdrplay_api_DeviceParamsT
  67. ch chan []complex64
  68. handle cgo.Handle
  69. open bool
  70. sampleRate int
  71. centerHz float64
  72. gainDb float64
  73. agc bool
  74. buf []complex64
  75. }
  76. func New(sampleRate int, centerHz float64, gainDb float64) (sdr.Source, error) {
  77. s := &Source{
  78. ch: make(chan []complex64, 16),
  79. sampleRate: sampleRate,
  80. centerHz: centerHz,
  81. gainDb: gainDb,
  82. }
  83. s.handle = cgo.NewHandle(s)
  84. return s, s.configure(sampleRate, centerHz, gainDb)
  85. }
  86. func (s *Source) configure(sampleRate int, centerHz float64, gainDb float64) error {
  87. if err := cErr(C.sdrplay_api_Open()); err != nil {
  88. return fmt.Errorf("sdrplay_api_Open: %w", err)
  89. }
  90. s.open = true
  91. var numDevs C.uint
  92. var devices [8]C.sdrplay_api_DeviceT
  93. if err := cErr(C.sdrplay_api_GetDevices(&devices[0], &numDevs, C.uint(len(devices)))); err != nil {
  94. return fmt.Errorf("sdrplay_api_GetDevices: %w", err)
  95. }
  96. if numDevs == 0 {
  97. return errors.New("no SDRplay devices found")
  98. }
  99. s.dev = devices[0]
  100. if err := cErr(C.sdrplay_api_SelectDevice(&s.dev)); err != nil {
  101. return fmt.Errorf("sdrplay_api_SelectDevice: %w", err)
  102. }
  103. var params *C.sdrplay_api_DeviceParamsT
  104. if err := cErr(C.sdrplay_api_GetDeviceParams(s.dev.dev, &params)); err != nil {
  105. return fmt.Errorf("sdrplay_api_GetDeviceParams: %w", err)
  106. }
  107. s.params = params
  108. C.sdrplay_set_fs(s.params, C.double(sampleRate))
  109. C.sdrplay_set_rf(s.params, C.double(centerHz))
  110. C.sdrplay_set_gain(s.params, C.uint(gainDb))
  111. C.sdrplay_set_if_zero(s.params)
  112. C.sdrplay_disable_agc(s.params)
  113. cb := C.sdrplay_get_callbacks()
  114. if err := cErr(C.sdrplay_api_Init(s.dev.dev, &cb, unsafe.Pointer(uintptr(s.handle)))); err != nil {
  115. return fmt.Errorf("sdrplay_api_Init: %w", err)
  116. }
  117. return nil
  118. }
  119. func (s *Source) Start() error { return nil }
  120. func (s *Source) UpdateConfig(sampleRate int, centerHz float64, gainDb float64, agc bool) error {
  121. s.mu.Lock()
  122. defer s.mu.Unlock()
  123. if s.params == nil {
  124. return errors.New("sdrplay not initialized")
  125. }
  126. updateReasons := C.int(0)
  127. if sampleRate > 0 && sampleRate != s.sampleRate {
  128. C.sdrplay_set_fs(s.params, C.double(sampleRate))
  129. updateReasons |= C.int(C.sdrplay_api_Update_Dev_Fs)
  130. s.sampleRate = sampleRate
  131. }
  132. if centerHz != 0 && centerHz != s.centerHz {
  133. C.sdrplay_set_rf(s.params, C.double(centerHz))
  134. updateReasons |= C.int(C.sdrplay_api_Update_Tuner_Frf)
  135. s.centerHz = centerHz
  136. }
  137. if gainDb != s.gainDb {
  138. C.sdrplay_set_gain(s.params, C.uint(gainDb))
  139. updateReasons |= C.int(C.sdrplay_api_Update_Tuner_Gr)
  140. s.gainDb = gainDb
  141. }
  142. if agc != s.agc {
  143. if agc {
  144. C.sdrplay_set_agc(s.params, 1)
  145. } else {
  146. C.sdrplay_set_agc(s.params, 0)
  147. }
  148. updateReasons |= C.int(C.sdrplay_api_Update_Ctrl_Agc)
  149. s.agc = agc
  150. }
  151. if updateReasons == 0 {
  152. return nil
  153. }
  154. if err := cErr(C.sdrplay_update(unsafe.Pointer(s.dev.dev), C.int(updateReasons))); err != nil {
  155. return err
  156. }
  157. return nil
  158. }
  159. func (s *Source) Stop() error {
  160. s.mu.Lock()
  161. defer s.mu.Unlock()
  162. if s.params != nil {
  163. _ = cErr(C.sdrplay_api_Uninit(s.dev.dev))
  164. s.params = nil
  165. }
  166. if s.open {
  167. _ = cErr(C.sdrplay_api_ReleaseDevice(&s.dev))
  168. _ = cErr(C.sdrplay_api_Close())
  169. s.open = false
  170. }
  171. if s.handle != 0 {
  172. s.handle.Delete()
  173. s.handle = 0
  174. }
  175. return nil
  176. }
  177. func (s *Source) ReadIQ(n int) ([]complex64, error) {
  178. deadline := time.Now().Add(1500 * time.Millisecond)
  179. for {
  180. s.mu.Lock()
  181. if len(s.buf) >= n {
  182. out := make([]complex64, n)
  183. copy(out, s.buf[:n])
  184. s.buf = s.buf[n:]
  185. s.mu.Unlock()
  186. return out, nil
  187. }
  188. s.mu.Unlock()
  189. remaining := time.Until(deadline)
  190. if remaining <= 0 {
  191. s.mu.Lock()
  192. if len(s.buf) > 0 {
  193. out := make([]complex64, len(s.buf))
  194. copy(out, s.buf)
  195. s.buf = nil
  196. s.mu.Unlock()
  197. return out, errors.New("timeout waiting for full IQ buffer")
  198. }
  199. s.mu.Unlock()
  200. return nil, errors.New("timeout waiting for IQ samples")
  201. }
  202. select {
  203. case buf := <-s.ch:
  204. s.mu.Lock()
  205. s.buf = append(s.buf, buf...)
  206. s.mu.Unlock()
  207. case <-time.After(remaining / 4):
  208. }
  209. }
  210. }
  211. //export goStreamCallback
  212. func goStreamCallback(xi *C.short, xq *C.short, numSamples C.uint, ctx unsafe.Pointer) {
  213. h := cgo.Handle(uintptr(ctx))
  214. src, ok := h.Value().(*Source)
  215. if !ok || src == nil {
  216. return
  217. }
  218. n := int(numSamples)
  219. if n <= 0 {
  220. return
  221. }
  222. iq := make([]complex64, n)
  223. xiSlice := unsafe.Slice((*int16)(unsafe.Pointer(xi)), n)
  224. xqSlice := unsafe.Slice((*int16)(unsafe.Pointer(xq)), n)
  225. const scale = 1.0 / 32768.0
  226. for i := 0; i < n; i++ {
  227. re := float32(float64(xiSlice[i]) * scale)
  228. im := float32(float64(xqSlice[i]) * scale)
  229. iq[i] = complex(re, im)
  230. }
  231. select {
  232. case src.ch <- iq:
  233. default:
  234. // Drop if consumer is slow.
  235. }
  236. }
  237. func cErr(err C.sdrplay_api_ErrT) error {
  238. if err == C.sdrplay_api_Success {
  239. return nil
  240. }
  241. return errors.New(C.GoString(C.sdrplay_api_GetErrorString(err)))
  242. }