From 163016f55f8b59d23d3742b709f647c1cd59eecc Mon Sep 17 00:00:00 2001 From: Eray Arslan Date: Thu, 30 Jul 2020 21:46:41 +0300 Subject: [PATCH] le leleyeleyleyle witcher --- bladerf.go | 34 ++++--- bladerf_test.go | 232 ++++++++++++------------------------------------ go.mod | 8 +- go.sum | 54 +++++++++++ 4 files changed, 142 insertions(+), 186 deletions(-) diff --git a/bladerf.go b/bladerf.go index 9e22f55..9cd0ff4 100644 --- a/bladerf.go +++ b/bladerf.go @@ -324,14 +324,31 @@ func GetSampleRateRange(bladeRF *BladeRF, module IOModule) (int, int, int, error return int(bfRange.min), int(bfRange.max), int(bfRange.step), nil } -func SetBandwidth(bladeRF *BladeRF, module IOModule, bandwidth int) { - C.bladerf_set_bandwidth((*bladeRF).bladeRF, C.bladerf_module(module), C.uint(bandwidth), nil) +func SetBandwidth(bladeRF *BladeRF, module IOModule, bandwidth int) (int, error) { + var actual C.bladerf_bandwidth + return int(actual), GetError(C.bladerf_set_bandwidth((*bladeRF).bladeRF, C.bladerf_module(module), C.uint(bandwidth), &actual)) } func SetGain(bladeRF *BladeRF, module IOModule, gain int) error { return GetError(C.bladerf_set_gain((*bladeRF).bladeRF, C.bladerf_module(module), C.int(gain))) } +func GetGainMode(bladeRF *BladeRF, module IOModule) (GainMode, error) { + var mode C.bladerf_gain_mode + + err := GetError(C.bladerf_get_gain_mode((*bladeRF).bladeRF, C.bladerf_module(module), &mode)) + result := GainMode(int(mode)) + if err == nil { + return result, nil + } + + return -1, err +} + +func SetGainMode(bladeRF *BladeRF, module IOModule, mode GainMode) error { + return GetError(C.bladerf_set_gain_mode((*bladeRF).bladeRF, C.bladerf_module(module), C.bladerf_gain_mode(mode))) +} + func EnableModule(bladeRF *BladeRF, direction Direction) error { return GetError(C.bladerf_enable_module((*bladeRF).bladeRF, C.bladerf_module(direction), true)) } @@ -347,29 +364,22 @@ func do_work() bool { return call >= 5000 } -func process_sample(addr unsafe.Pointer, size uint) { - -} - -func SyncRX(bladeRF *BladeRF) []int16 { +func SyncRX(bladeRF *BladeRF, bufferSize uintptr) []int16 { var metadata C.struct_bladerf_metadata var buff *C.int16_t size := unsafe.Sizeof(*buff) - start := C.malloc(C.size_t(size * 10000 * 2 * 1)) + start := C.malloc(C.size_t(size * bufferSize * 2 * 1)) var err error var done bool var results []int16 for err == nil && !done { - err = GetError(C.bladerf_sync_rx((*bladeRF).bladeRF, start, 10000, &metadata, 5000)) + err = GetError(C.bladerf_sync_rx((*bladeRF).bladeRF, start, C.uint(bufferSize), &metadata, 32)) if err == nil { done = do_work() if done { - println("DONE!") - process_sample(start, uint(metadata.actual_count)) - for i := 0; i < (int(metadata.actual_count)); i++ { n := (*C.int16_t)(unsafe.Pointer(uintptr(start) + (size * uintptr(i)))) results = append(results, int16(*n)) diff --git a/bladerf_test.go b/bladerf_test.go index fc5c929..a1becfe 100644 --- a/bladerf_test.go +++ b/bladerf_test.go @@ -4,138 +4,40 @@ import ( "bladerf/log" "fmt" "github.com/gordonklaus/portaudio" + fifo "github.com/racerxdl/go.fifo" + "github.com/racerxdl/segdsp/demodcore" log2 "log" - "math" "os" "os/signal" "testing" ) -type agcState struct { - gainNum int32 - gainDen int32 - gainMax int32 - peakTarget int - attackStep int - decayStep int - err int -} +const audioBufferSize = 8192 / 2 -type demodState struct { - lowpassed []int16 - rateIn int - rateOut int - rateOut2 int - nowR int16 - nowJ int16 - preR int16 - preJ int16 - prevIndex int - // min 1, max 256 - downsample int - postDownsample int - outputScale int - squelchLevel int - conseqSquelch int - squelchHits int - customAtan int - deemph bool - deemphA int - nowLpr int - prevLprIndex int - modeDemod func(fm *demodState) - agcEnable bool - agc agcState -} +var audioStream *portaudio.Stream +var audioFifo = fifo.NewQueue() -func polarDiscriminant(ar, aj, br, bj int) int { - var cr, cj int - var angle float64 - cr = ar*br - aj*-bj - cj = aj*br + ar*-bj - angle = math.Atan2(float64(cj), float64(cr)) - return int(angle / math.Pi * (1 << 14)) -} +var demodulator demodcore.DemodCore -func fastAtan2(y, x int) int { - var pi4, pi34, yabs, angle int - pi4 = 1 << 12 - pi34 = 3 * (1 << 12) // note pi = 1<<14 - if x == 0 && y == 0 { - return 0 - } - yabs = y - if yabs < 0 { - yabs = -yabs - } - if x >= 0 { - angle = pi4 - pi4*(x-yabs)/(x+yabs) +func ProcessAudio(out []float32) { + if audioFifo.Len() > 0 { + var z = audioFifo.Next().([]float32) + copy(out, z) } else { - angle = pi34 - pi4*(x+yabs)/(yabs-x) - } - if y < 0 { - return -angle - } - return angle -} - -func polarDiscFast(ar, aj, br, bj int) int { - var cr, cj int - cr = ar*br - aj*-bj - cj = aj*br + ar*-bj - return fastAtan2(cj, cr) -} - -var d = demodState{ - rateIn: 170000, - rateOut: 170000, - rateOut2: 32000, - customAtan: 1, - deemph: true, - squelchLevel: 0, -} - -func fmDemod(fm *demodState) { - var i, pcm int - lp := fm.lowpassed - lpLen := len(fm.lowpassed) - pr := fm.preR - pj := fm.preJ - for i = 2; i < (lpLen - 1); i += 2 { - switch fm.customAtan { - case 0: - pcm = polarDiscriminant(int(lp[i]), int(lp[i+1]), int(pr), int(pj)) - case 1: - pcm = polarDiscFast(int(lp[i]), int(lp[i+1]), int(pr), int(pj)) + for i := range out { + out[i] = 0 } - pr = lp[i] - pj = lp[i+1] - - fm.lowpassed[i/2] = int16(pcm) } - fm.preR = pr - fm.preJ = pj - fm.lowpassed = fm.lowpassed[:lpLen/2] } -func lowPass(d *demodState) { - var i, i2 int - for i < len(d.lowpassed) { - d.nowR += d.lowpassed[i] - d.nowJ += d.lowpassed[i+1] - i += 2 - d.prevIndex++ - if d.prevIndex < d.downsample { - continue - } - d.lowpassed[i2] = d.nowR // * d.output_scale; - d.lowpassed[i2+1] = d.nowJ // * d.output_scale; - d.prevIndex = 0 - d.nowR = 0 - d.nowJ = 0 - i2 += 2 +func GetFinalData(input []int16) []complex64 { + var complexFloat = make([]complex64, len(input)/2) + + for i := 0; i < len(complexFloat); i++ { + complexFloat[i] = complex(float32(input[2*i])/2048, float32(input[2*i+1])/2048) } - d.lowpassed = d.lowpassed[:i2] + + return complexFloat } func TestBladeRF(t *testing.T) { @@ -160,16 +62,9 @@ func TestBladeRF(t *testing.T) { Close(rf) } -type echo struct { - *portaudio.Stream - buffer []float32 - i int -} - func TestStream(t *testing.T) { var err error - sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, os.Kill) @@ -185,26 +80,30 @@ func TestStream(t *testing.T) { rf := OpenWithDevInfo(devices[0]) defer Close(rf) - err = SetFrequency(&rf, IORX, 90800000) + err = SetFrequency(&rf, IORX, 96600000) if err != nil { log2.Fatal(err) } - min, max, step, errRange := GetSampleRateRange(&rf, IORX) - if errRange != nil { + min, max, step, err := GetSampleRateRange(&rf, IORX) + if err != nil { + log2.Fatal(err) + } + fmt.Printf("Min: %d, Max: %d, Step: %d\n", min, max, step) + err = SetSampleRate(&rf, IORX, 4e6) + if err != nil { + log2.Fatal(err) + } + err = SyncConfig(&rf, RX_X1, SC16_Q11, 16, audioBufferSize, 8, 32) + if err != nil { + log2.Fatal(err) + } + + actual, err := SetBandwidth(&rf, IORX, 240000) + if err != nil { log2.Fatal(err) } else { - fmt.Printf("Min: %d, Max: %d, Step: %d\n", min, max, step) - } - - err = SetSampleRate(&rf, IORX, max) - if err != nil { - log2.Fatal(err) - } - - err = SyncConfig(&rf, RX_X1, SC16_Q11, 32, 8192, 8, 3500) - if err != nil { - log2.Fatal(err) + println(actual) } err = EnableModule(&rf, RX) @@ -212,51 +111,38 @@ func TestStream(t *testing.T) { log2.Fatal(err) } - err = SetGain(&rf, IORX, 9) + err = SetGainMode(&rf, IORX, Hybrid_AGC) if err != nil { log2.Fatal(err) } - p := make([]int16, 10000) + demodulator = demodcore.MakeWBFMDemodulator(uint32(2e6), 80e3, 48000) - results := SyncRX(&rf) - //var complexFloat = make([]float32, 10000) + portaudio.Initialize() + h, _ := portaudio.DefaultHostApi() - //for i := 0; i < 10000 ; i++ { - // complexFloat[i] = float32(results[2*i])/float32(2048) + float32(results[2*i+1])/float32(2048.0) - //} + p := portaudio.LowLatencyParameters(nil, h.DefaultOutputDevice) + p.Input.Channels = 0 + p.Output.Channels = 1 + p.SampleRate = 48000 + p.FramesPerBuffer = audioBufferSize - d.lowpassed = results - fmDemod(&d) - lowPass(&d) - - err = DisableModule(&rf, RX) - if err != nil { - log2.Fatal(err) - } - - out := make([]int16, 8192) - - e := &echo{buffer: make([]float32, 10000)} - - e.Stream, err = portaudio.OpenDefaultStream(0, 1, 10000, len(d.lowpassed), &out) - defer stream.Close() - - stream.Start() - - defer stream.Close() - defer stream.Stop() + audioStream, _ = portaudio.OpenStream(p, ProcessAudio) + _ = audioStream.Start() for { - out = d.lowpassed - stream.Write() - select { - case <-sig: - return - default: + out := demodulator.Work(GetFinalData(SyncRX(&rf, audioBufferSize))) + + if out != nil { + var o = out.(demodcore.DemodData) + var nBf = make([]float32, len(o.Data)) + copy(nBf, o.Data) + var buffs = len(nBf) / audioBufferSize + for i := 0; i < buffs; i++ { + audioFifo.Add(nBf[audioBufferSize*i : audioBufferSize*(i+1)]) + } } } - } func TestAsyncStream(t *testing.T) { @@ -272,7 +158,7 @@ func TestAsyncStream(t *testing.T) { rf := OpenWithDevInfo(devices[0]) defer Close(rf) - SetSampleRate(&rf, IORX, 1000000) + SetSampleRate(&rf, IORX, 4000000) EnableModule(&rf, RX) rxStream := InitStream(&rf, SC16_Q11, 32, 32768, 16) diff --git a/go.mod b/go.mod index 9bba979..ff68acc 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,10 @@ module bladerf go 1.13 -require github.com/gordonklaus/portaudio v0.0.0-20180817120803-00e7307ccd93 +require ( + github.com/gordonklaus/portaudio v0.0.0-20180817120803-00e7307ccd93 + github.com/mattetti/audio v0.0.0-20190404201502-c6aebeb78429 + github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38 + github.com/racerxdl/go.fifo v0.0.0-20180604061744-c6aa83afe374 + github.com/racerxdl/segdsp v0.0.0-20190413213320-dfaea7c39d3a +) diff --git a/go.sum b/go.sum index 83210d8..d63ed93 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,56 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-gl/gl v0.0.0-20180407155706-68e253793080/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= +github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/gordonklaus/portaudio v0.0.0-20180817120803-00e7307ccd93 h1:TSG+DyZBnazM22ZHyHLeUkzM34ClkJRjIWHTq4btvek= github.com/gordonklaus/portaudio v0.0.0-20180817120803-00e7307ccd93/go.mod h1:HfYnZi/ARQKG0dwH5HNDmPCHdLiFiBf+SI7DbhW7et4= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/llgcode/draw2d v0.0.0-20180825133448-f52c8a71aff0/go.mod h1:mVa0dA29Db2S4LVqDYLlsePDzRJLDfdhVZiI15uY0FA= +github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb/go.mod h1:1l8ky+Ew27CMX29uG+a2hNOKpeNYEQjjtiALiBlFQbY= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/mattetti/audio v0.0.0-20190404201502-c6aebeb78429 h1:5YWANgpchDSYJ0R6i3ODpZ4KN/1Jm9MZcFDtAtegjNM= +github.com/mattetti/audio v0.0.0-20190404201502-c6aebeb78429/go.mod h1:LlQmBGkOuV/SKzEDXBPKauvN2UqCgzXO2XjecTGj40s= +github.com/mattn/go-pointer v0.0.0-20180825124634-49522c3f3791/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= +github.com/myriadrf/limedrv v0.0.0-20190225221912-8583a26e3fce/go.mod h1:/SXVBJBHAVLlvLU1B1n0a0QPcZBtqF1VpH5POPZzuBw= +github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38 h1:4Upfs5rLQdx7KwBct3bmPYAhWsDDJdx660gYb7Lv9TQ= +github.com/oov/audio v0.0.0-20171004131523-88a2be6dbe38/go.mod h1:Xj06yMta9R1RSKiHmxL0Bo2TB8wiKVnMgA0KVopHHkk= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quan-to/slog v0.0.0-20190317205605-56a2b4159924/go.mod h1:xc9X6JvWjqAAIox9u4uuolisjwl/GbfkktH6f+nOgqU= +github.com/racerxdl/fastconvert v0.0.0-20190129064530-871b6f6cd82a/go.mod h1:V4kP6uu5nqjDVGhlYMtT/7JG7WJjXnipMGcQ8PFeUqU= +github.com/racerxdl/go.fifo v0.0.0-20180604061744-c6aa83afe374 h1:P2TDDsGEWzzfhAnthdQc+Vwmv/+xEKHwoNFF3Swl6X0= +github.com/racerxdl/go.fifo v0.0.0-20180604061744-c6aa83afe374/go.mod h1:CvYWG6Py4TRzGCUVX2n8+CjE6mrME/+kHkkGmbDA5zw= +github.com/racerxdl/radioserver v0.0.0-20190316070955-f8953f368ce1/go.mod h1:cSQupBUlkn/QhajTmf6QMErp3PbTVT5Xdd5DSiE0hAI= +github.com/racerxdl/radioserver v0.0.0-20190324175745-bd3bd7179419/go.mod h1:N4ejKokz1jnGfAd3KNgO8E6YMCMP4ZgaHXBEdHBQrP8= +github.com/racerxdl/segdsp v0.0.0-20190321214158-1cd3e325e91a/go.mod h1:nQDTqJjqr+YsSQw+CVY58Xag4KVqfoi6TgkSXMHlUO4= +github.com/racerxdl/segdsp v0.0.0-20190413213320-dfaea7c39d3a h1:2QJXxaBOGMsjoZ++ecsek0SE/V4bbraCITBNVji4+4M= +github.com/racerxdl/segdsp v0.0.0-20190413213320-dfaea7c39d3a/go.mod h1:NXNN9LqX1oeK6+o+xm+Dz8ANz+i1uILw4HsL0sq5tzE= +github.com/racerxdl/spy2go v0.0.0-20190103011754-14102c047be5/go.mod h1:ioS4oIwJsgrSeKKPATMpsbJQdi4p2Xsbg3V5j2nCOzM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190322120337-addf6b3196f6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=