25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

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