Compare commits
	
		
			1 commit
		
	
	
		
			master
			...
			headphones
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 83bb953842 | 
					 10 changed files with 555 additions and 495 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -1,3 +1,2 @@ | |||
| /build/ | ||||
| /grc/*.py | ||||
| /.cache/ | ||||
|  |  | |||
|  | @ -32,4 +32,4 @@ See the [blog post](https://blog.porucha.net/2024/pico-sdr/) for more informatio | |||
| 
 | ||||
| 4. Open `grc/PicoSDR-WBFM.grc` in GNU Radio Companion, adjust carrier frequency to match your favorite FM radio station and press `F6`. | ||||
| 
 | ||||
| 5. Alternatively [gqrx](https://www.gqrx.dk/) works fine with `rtl_tcp` input mode. Maximum sample rate seem to be 400 ksps, above that the samples are dropped. Make sure to adjust LNA gain to +30 dB. It's not accurate, but it does control bias strength which in turn does affect analog gain. | ||||
| 5. Alternatively [gqrx](https://www.gqrx.dk/) works fine with `rtl_tcp` input mode. Maximum sample rate seem to be 400 ksps, above that the samples are dropped. | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ blocks: | |||
|   id: variable | ||||
|   parameters: | ||||
|     comment: '' | ||||
|     value: '200_000' | ||||
|     value: '192_000' | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|  | @ -78,7 +78,7 @@ blocks: | |||
|   parameters: | ||||
|     affinity: '' | ||||
|     alias: '' | ||||
|     audio_decimation: '8' | ||||
|     audio_decimation: '4' | ||||
|     comment: '' | ||||
|     deemph_tau: 75e-6 | ||||
|     maxoutbuf: '0' | ||||
|  | @ -100,7 +100,7 @@ blocks: | |||
|     device_name: '' | ||||
|     num_inputs: '2' | ||||
|     ok_to_block: 'True' | ||||
|     samp_rate: samp_rate // 8 | ||||
|     samp_rate: samp_rate // 4 | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|  | @ -150,15 +150,15 @@ blocks: | |||
|     alias: '' | ||||
|     beta: '6.76' | ||||
|     comment: '' | ||||
|     cutoff_freq: samp_rate / 16 | ||||
|     decim: '8' | ||||
|     cutoff_freq: samp_rate / 8 | ||||
|     decim: '4' | ||||
|     gain: '1' | ||||
|     interp: '1' | ||||
|     maxoutbuf: '0' | ||||
|     minoutbuf: '0' | ||||
|     samp_rate: samp_rate | ||||
|     type: fir_filter_fff | ||||
|     width: samp_rate / 16 | ||||
|     width: samp_rate / 8 | ||||
|     win: window.WIN_HAMMING | ||||
|   states: | ||||
|     bus_sink: false | ||||
|  | @ -205,7 +205,7 @@ blocks: | |||
|     ant8: '' | ||||
|     ant9: '' | ||||
|     args: '"rtl_tcp"' | ||||
|     bb_gain0: '0' | ||||
|     bb_gain0: '20' | ||||
|     bb_gain1: '20' | ||||
|     bb_gain10: '20' | ||||
|     bb_gain11: '20' | ||||
|  | @ -374,7 +374,7 @@ blocks: | |||
|     freq7: 100e6 | ||||
|     freq8: 100e6 | ||||
|     freq9: 100e6 | ||||
|     gain0: '0' | ||||
|     gain0: '10' | ||||
|     gain1: '10' | ||||
|     gain10: '10' | ||||
|     gain11: '10' | ||||
|  | @ -438,7 +438,7 @@ blocks: | |||
|     gain_mode7: 'False' | ||||
|     gain_mode8: 'False' | ||||
|     gain_mode9: 'False' | ||||
|     if_gain0: '0' | ||||
|     if_gain0: '20' | ||||
|     if_gain1: '20' | ||||
|     if_gain10: '20' | ||||
|     if_gain11: '20' | ||||
|  | @ -677,7 +677,7 @@ blocks: | |||
|     name: '"FM Demodulation"' | ||||
|     nconnections: '1' | ||||
|     size: '512' | ||||
|     srate: samp_rate // 8 | ||||
|     srate: samp_rate // (2 ** 3) | ||||
|     stemplot: 'False' | ||||
|     style1: '1' | ||||
|     style10: '1' | ||||
|  | @ -856,4 +856,4 @@ connections: | |||
| 
 | ||||
| metadata: | ||||
|   file_format: 1 | ||||
|   grc_version: 3.10.11.0 | ||||
|   grc_version: 3.10.9.2 | ||||
|  |  | |||
							
								
								
									
										148
									
								
								grc/PicoSDR.grc
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								grc/PicoSDR.grc
									
									
									
									
									
								
							|  | @ -37,7 +37,7 @@ blocks: | |||
|   id: variable | ||||
|   parameters: | ||||
|     comment: '' | ||||
|     value: 169.5e6 | ||||
|     value: '40_680_000' | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|  | @ -45,60 +45,16 @@ blocks: | |||
|     coordinate: [168, 8.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: decimation | ||||
|   id: variable | ||||
|   parameters: | ||||
|     comment: '' | ||||
|     value: '16' | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [368, 8.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: rf_rate | ||||
|   id: variable | ||||
|   parameters: | ||||
|     comment: '' | ||||
|     value: '400_000' | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [280, 8.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: samp_rate | ||||
|   id: variable | ||||
|   parameters: | ||||
|     comment: '' | ||||
|     value: rf_rate // decimation | ||||
|     value: '50_000' | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [472, 8.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: analog_agc_xx_0 | ||||
|   id: analog_agc_xx | ||||
|   parameters: | ||||
|     affinity: '' | ||||
|     alias: '' | ||||
|     comment: '' | ||||
|     gain: '1.0' | ||||
|     max_gain: '1' | ||||
|     maxoutbuf: '0' | ||||
|     minoutbuf: '0' | ||||
|     rate: 1e-4 | ||||
|     reference: '0.707' | ||||
|     type: complex | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [632, 312.0] | ||||
|     coordinate: [264, 8.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: analog_quadrature_demod_cf_0 | ||||
|  | @ -114,26 +70,9 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [912, 616.0] | ||||
|     coordinate: [640, 536.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: blocks_freqshift_cc_0 | ||||
|   id: blocks_freqshift_cc | ||||
|   parameters: | ||||
|     affinity: '' | ||||
|     alias: '' | ||||
|     comment: '' | ||||
|     freq: '0' | ||||
|     maxoutbuf: '0' | ||||
|     minoutbuf: '0' | ||||
|     sample_rate: rf_rate | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [256, 328.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: blocks_message_debug_0 | ||||
|   id: blocks_message_debug | ||||
|   parameters: | ||||
|  | @ -146,7 +85,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [1200, 112.0] | ||||
|     coordinate: [928, 32.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: blocks_probe_rate_0 | ||||
|  | @ -166,7 +105,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [912, 120.0] | ||||
|     coordinate: [640, 40.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: digital_costas_loop_cc_0 | ||||
|  | @ -179,38 +118,14 @@ blocks: | |||
|     minoutbuf: '0' | ||||
|     order: '2' | ||||
|     use_snr: 'False' | ||||
|     w: math.pi / 100 | ||||
|     w: 2 * math.pi / 100 | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [912, 424.0] | ||||
|     coordinate: [640, 344.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: low_pass_filter_0 | ||||
|   id: low_pass_filter | ||||
|   parameters: | ||||
|     affinity: '' | ||||
|     alias: '' | ||||
|     beta: '6.76' | ||||
|     comment: '' | ||||
|     cutoff_freq: samp_rate / 4 | ||||
|     decim: decimation | ||||
|     gain: '1' | ||||
|     interp: '1' | ||||
|     maxoutbuf: '0' | ||||
|     minoutbuf: '0' | ||||
|     samp_rate: rf_rate | ||||
|     type: fir_filter_ccf | ||||
|     width: samp_rate / 4 | ||||
|     win: window.WIN_HAMMING | ||||
|   states: | ||||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [440, 284.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: osmosdr_source_0 | ||||
|   id: osmosdr_source | ||||
|   parameters: | ||||
|  | @ -249,7 +164,7 @@ blocks: | |||
|     ant8: '' | ||||
|     ant9: '' | ||||
|     args: '"rtl_tcp"' | ||||
|     bb_gain0: '0' | ||||
|     bb_gain0: '20' | ||||
|     bb_gain1: '20' | ||||
|     bb_gain10: '20' | ||||
|     bb_gain11: '20' | ||||
|  | @ -418,7 +333,7 @@ blocks: | |||
|     freq7: 100e6 | ||||
|     freq8: 100e6 | ||||
|     freq9: 100e6 | ||||
|     gain0: '0' | ||||
|     gain0: '10' | ||||
|     gain1: '10' | ||||
|     gain10: '10' | ||||
|     gain11: '10' | ||||
|  | @ -482,7 +397,7 @@ blocks: | |||
|     gain_mode7: 'False' | ||||
|     gain_mode8: 'False' | ||||
|     gain_mode9: 'False' | ||||
|     if_gain0: '0' | ||||
|     if_gain0: '20' | ||||
|     if_gain1: '20' | ||||
|     if_gain10: '20' | ||||
|     if_gain11: '20' | ||||
|  | @ -550,7 +465,7 @@ blocks: | |||
|     minoutbuf: '0' | ||||
|     nchan: '1' | ||||
|     num_mboards: '1' | ||||
|     sample_rate: rf_rate | ||||
|     sample_rate: samp_rate | ||||
|     sync: sync | ||||
|     time_source0: '' | ||||
|     time_source1: '' | ||||
|  | @ -565,7 +480,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [8, 244.0] | ||||
|     coordinate: [152, 164.0] | ||||
|     rotation: 0 | ||||
|     state: enabled | ||||
| - name: qtgui_const_sink_x_0 | ||||
|  | @ -657,7 +572,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [1200, 408.0] | ||||
|     coordinate: [928, 328.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: qtgui_time_sink_x_0 | ||||
|  | @ -717,7 +632,7 @@ blocks: | |||
|     nconnections: '1' | ||||
|     size: '256' | ||||
|     srate: samp_rate | ||||
|     stemplot: 'True' | ||||
|     stemplot: 'False' | ||||
|     style1: '1' | ||||
|     style10: '1' | ||||
|     style2: '1' | ||||
|  | @ -754,7 +669,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [912, 312.0] | ||||
|     coordinate: [640, 232.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: qtgui_time_sink_x_0_0 | ||||
|  | @ -814,7 +729,7 @@ blocks: | |||
|     nconnections: '1' | ||||
|     size: '256' | ||||
|     srate: samp_rate | ||||
|     stemplot: 'True' | ||||
|     stemplot: 'False' | ||||
|     style1: '1' | ||||
|     style10: '1' | ||||
|     style2: '1' | ||||
|  | @ -833,7 +748,7 @@ blocks: | |||
|     tr_tag: '""' | ||||
|     type: float | ||||
|     update_time: 1/30 | ||||
|     width1: '2' | ||||
|     width1: '1' | ||||
|     width10: '1' | ||||
|     width2: '1' | ||||
|     width3: '1' | ||||
|  | @ -851,7 +766,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [1200, 592.0] | ||||
|     coordinate: [928, 512.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: qtgui_time_sink_x_0_1 | ||||
|  | @ -911,7 +826,7 @@ blocks: | |||
|     nconnections: '1' | ||||
|     size: '256' | ||||
|     srate: samp_rate | ||||
|     stemplot: 'True' | ||||
|     stemplot: 'False' | ||||
|     style1: '1' | ||||
|     style10: '1' | ||||
|     style2: '1' | ||||
|  | @ -930,9 +845,9 @@ blocks: | |||
|     tr_tag: '""' | ||||
|     type: complex | ||||
|     update_time: 1/30 | ||||
|     width1: '2' | ||||
|     width1: '1' | ||||
|     width10: '1' | ||||
|     width2: '2' | ||||
|     width2: '1' | ||||
|     width3: '1' | ||||
|     width4: '1' | ||||
|     width5: '1' | ||||
|  | @ -948,7 +863,7 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [1200, 480.0] | ||||
|     coordinate: [928, 400.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| - name: qtgui_waterfall_sink_x_0_0 | ||||
|  | @ -1009,24 +924,21 @@ blocks: | |||
|     bus_sink: false | ||||
|     bus_source: false | ||||
|     bus_structure: null | ||||
|     coordinate: [912, 208.0] | ||||
|     coordinate: [640, 128.0] | ||||
|     rotation: 0 | ||||
|     state: true | ||||
| 
 | ||||
| connections: | ||||
| - [analog_agc_xx_0, '0', analog_quadrature_demod_cf_0, '0'] | ||||
| - [analog_agc_xx_0, '0', blocks_probe_rate_0, '0'] | ||||
| - [analog_agc_xx_0, '0', digital_costas_loop_cc_0, '0'] | ||||
| - [analog_agc_xx_0, '0', qtgui_time_sink_x_0, '0'] | ||||
| - [analog_agc_xx_0, '0', qtgui_waterfall_sink_x_0_0, '0'] | ||||
| - [analog_quadrature_demod_cf_0, '0', qtgui_time_sink_x_0_0, '0'] | ||||
| - [blocks_freqshift_cc_0, '0', low_pass_filter_0, '0'] | ||||
| - [blocks_probe_rate_0, rate, blocks_message_debug_0, print] | ||||
| - [digital_costas_loop_cc_0, '0', qtgui_const_sink_x_0, '0'] | ||||
| - [digital_costas_loop_cc_0, '0', qtgui_time_sink_x_0_1, '0'] | ||||
| - [low_pass_filter_0, '0', analog_agc_xx_0, '0'] | ||||
| - [osmosdr_source_0, '0', blocks_freqshift_cc_0, '0'] | ||||
| - [osmosdr_source_0, '0', analog_quadrature_demod_cf_0, '0'] | ||||
| - [osmosdr_source_0, '0', blocks_probe_rate_0, '0'] | ||||
| - [osmosdr_source_0, '0', digital_costas_loop_cc_0, '0'] | ||||
| - [osmosdr_source_0, '0', qtgui_time_sink_x_0, '0'] | ||||
| - [osmosdr_source_0, '0', qtgui_waterfall_sink_x_0_0, '0'] | ||||
| 
 | ||||
| metadata: | ||||
|   file_format: 1 | ||||
|   grc_version: 3.10.11.0 | ||||
|   grc_version: 3.10.9.2 | ||||
|  |  | |||
|  | @ -1,2 +0,0 @@ | |||
| CompileFlags: | ||||
|   CompilationDatabase: ../build | ||||
|  | @ -1,5 +1,4 @@ | |||
| cmake_minimum_required(VERSION 3.21) | ||||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||
| 
 | ||||
| include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										50
									
								
								src/cordic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/cordic.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| #pragma once | ||||
| 
 | ||||
| /*
 | ||||
|  * Copyright (c) 2020 STMicroelectronics. | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * This software component is licensed by ST under BSD 3-Clause license, | ||||
|  * the "License"; You may not use this file except in compliance with the | ||||
|  * License. You may obtain a copy of the License at: | ||||
|  * | ||||
|  * https://opensource.org/licenses/BSD-3-Clause
 | ||||
|  */ | ||||
| 
 | ||||
| #define CORDIC_MAXITER 9 | ||||
| #define CORDIC_PI 0x10000000 | ||||
| 
 | ||||
| static int CORDIC_ZTBL[] = { 0x04000000, 0x025C80A4, 0x013F670B, 0x00A2223B, 0x005161A8, 0x0028BAFC, | ||||
| 			     0x00145EC4, 0x000A2F8B, 0x000517CA, 0x00028BE6, 0x000145F3, 0x0000A2FA, | ||||
| 			     0x0000517D, 0x000028BE, 0x0000145F, 0x00000A30 }; | ||||
| 
 | ||||
| inline static __attribute__((__unused__)) int fast_atan2(int y, int x) | ||||
| { | ||||
| 	int k, tx, z = 0, fl = 0; | ||||
| 
 | ||||
| 	if (x < 0) { | ||||
| 		fl = ((y > 0) ? +1 : -1); | ||||
| 		x = -x; | ||||
| 		y = -y; | ||||
| 	} | ||||
| 
 | ||||
| 	for (k = 0; k < CORDIC_MAXITER; k++) { | ||||
| 		tx = x; | ||||
| 
 | ||||
| 		if (y <= 0) { | ||||
| 			x -= (y >> k); | ||||
| 			y += (tx >> k); | ||||
| 			z -= CORDIC_ZTBL[k]; | ||||
| 		} else { | ||||
| 			x += (y >> k); | ||||
| 			y -= (tx >> k); | ||||
| 			z += CORDIC_ZTBL[k]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (fl != 0) { | ||||
| 		z += fl * CORDIC_PI; | ||||
| 	} | ||||
| 
 | ||||
| 	return z; | ||||
| } | ||||
							
								
								
									
										805
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										805
									
								
								src/main.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										2
									
								
								src/vendor/pico-stdio-usb-simple
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/vendor/pico-stdio-usb-simple
									
									
									
									
										vendored
									
									
								
							|  | @ -1 +1 @@ | |||
| Subproject commit ed4858dda407ec66626aade9b7c6ad6016539f4c | ||||
| Subproject commit b6b09e34b844326a156bc6734146a88111138473 | ||||
|  | @ -1,15 +1,8 @@ | |||
| #!/usr/bin/env python | ||||
| 
 | ||||
| import struct | ||||
| from socket import ( | ||||
|     AF_INET6, | ||||
|     MSG_DONTWAIT, | ||||
|     SO_REUSEADDR, | ||||
|     SO_SNDBUF, | ||||
|     SOCK_STREAM, | ||||
|     SOL_SOCKET, | ||||
|     socket, | ||||
| ) | ||||
| from socket import (AF_INET, MSG_DONTWAIT, SO_REUSEADDR, SO_SNDBUF, | ||||
|                     SOCK_STREAM, SOL_SOCKET, socket) | ||||
| 
 | ||||
| import click | ||||
| import serial | ||||
|  | @ -44,12 +37,12 @@ def describe(cmd: int, arg: int): | |||
| @click.option("-f", "--frequency", default=88200000, help="Frequency to tune to") | ||||
| @click.option("-d", "--device", default="/dev/ttyACM0", help="Serial port device") | ||||
| def bridge(frequency, device): | ||||
|     sock = socket(AF_INET6, SOCK_STREAM) | ||||
|     sock = socket(AF_INET, SOCK_STREAM) | ||||
|     sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) | ||||
|     sock.setsockopt(SOL_SOCKET, SO_SNDBUF, 1024 * 100) | ||||
| 
 | ||||
|     print("Posing as rtl_tcp at tcp://localhost:1234") | ||||
|     sock.bind(("::", 1234)) | ||||
|     print("Posing as rtl_tcp at tcp://127.0.0.1:1234") | ||||
|     sock.bind(("127.0.0.1", 1234)) | ||||
|     sock.listen(3) | ||||
| 
 | ||||
|     while True: | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue