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

278 行
7.1KB

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