File: rf_path.c

package info (click to toggle)
hackrf 2015.07.2-10~bpo8%2B1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 28,556 kB
  • sloc: ansic: 13,893; python: 696; vhdl: 218; sh: 32; makefile: 15
file content (337 lines) | stat: -rw-r--r-- 11,375 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/*
 * Copyright 2012 Jared Boone
 * Copyright 2013 Benjamin Vernoux
 *
 * This file is part of HackRF.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

#include "rf_path.h"

#include <libopencm3/lpc43xx/scu.h>

#include <hackrf_core.h>

#include <rffc5071.h>
#include <max2837.h>
#include <max5864.h>
#include <sgpio.h>

#if (defined JAWBREAKER || defined HACKRF_ONE)
/*
 * RF switches on Jawbreaker are controlled by General Purpose Outputs (GPO) on
 * the RFFC5072.
 *
 * On HackRF One, the same signals are controlled by GPIO on the LPC.
 * SWITCHCTRL_NO_TX_AMP_PWR and SWITCHCTRL_NO_RX_AMP_PWR are not normally used
 * on HackRF One as the amplifier power is instead controlled only by
 * SWITCHCTRL_AMP_BYPASS.
 */
#define SWITCHCTRL_NO_TX_AMP_PWR (1 << 0) /* GPO1 turn off TX amp power */
#define SWITCHCTRL_AMP_BYPASS    (1 << 1) /* GPO2 bypass amp section */
#define SWITCHCTRL_TX            (1 << 2) /* GPO3 1 for TX mode, 0 for RX mode */
#define SWITCHCTRL_MIX_BYPASS    (1 << 3) /* GPO4 bypass RFFC5072 mixer section */
#define SWITCHCTRL_HP            (1 << 4) /* GPO5 1 for high-pass, 0 for low-pass */
#define SWITCHCTRL_NO_RX_AMP_PWR (1 << 5) /* GPO6 turn off RX amp power */

/*
 GPO6  GPO5  GPO4 GPO3  GPO2  GPO1
!RXAMP  HP  MIXBP  TX  AMPBP !TXAMP  Mix mode   Amp mode
   1    X     1    1     1      1    TX bypass  Bypass
   1    X     1    1     0      0    TX bypass  TX amplified
   1    1     0    1     1      1    TX high    Bypass
   1    1     0    1     0      0    TX high    TX amplified
   1    0     0    1     1      1    TX low     Bypass
   1    0     0    1     0      0    TX low     TX amplified
   1    X     1    0     1      1    RX bypass  Bypass
   0    X     1    0     0      1    RX bypass  RX amplified
   1    1     0    0     1      1    RX high    Bypass
   0    1     0    0     0      1    RX high    RX amplified
   1    0     0    0     1      1    RX low     Bypass
   0    0     0    0     0      1    RX low     RX amplified
*/

/*
 * Safe (initial) switch settings turn off both amplifiers and enable both amp
 * bypass and mixer bypass.
 */
#define SWITCHCTRL_SAFE (SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_TX | SWITCHCTRL_MIX_BYPASS | SWITCHCTRL_HP | SWITCHCTRL_NO_RX_AMP_PWR)
#endif

uint8_t switchctrl = SWITCHCTRL_SAFE;

/*
 * Antenna port power on HackRF One is controlled by GPO1 on the RFFC5072.
 * This is the only thing we use RFFC5072 GPO for on HackRF One.  The value of
 * SWITCHCTRL_NO_ANT_PWR does not correspond to the GPO1 bit in the gpo
 * register.
 */
#define SWITCHCTRL_ANT_PWR (1 << 6) /* turn on antenna port power */

#ifdef HACKRF_ONE
static void switchctrl_set_hackrf_one(rf_path_t* const rf_path, uint8_t ctrl) {
	if (ctrl & SWITCHCTRL_TX) {
		gpio_set(rf_path->gpio_tx);
		gpio_clear(rf_path->gpio_rx);
	} else {
		gpio_clear(rf_path->gpio_tx);
		gpio_set(rf_path->gpio_rx);
	}

	if (ctrl & SWITCHCTRL_MIX_BYPASS) {
		gpio_set(rf_path->gpio_mix_bypass);
		gpio_clear(rf_path->gpio_no_mix_bypass);
		if (ctrl & SWITCHCTRL_TX) {
			gpio_set(rf_path->gpio_tx_mix_bp);
			gpio_clear(rf_path->gpio_rx_mix_bp);
		} else {
			gpio_clear(rf_path->gpio_tx_mix_bp);
			gpio_set(rf_path->gpio_rx_mix_bp);
		}
	} else {
		gpio_clear(rf_path->gpio_mix_bypass);
		gpio_set(rf_path->gpio_no_mix_bypass);
		gpio_clear(rf_path->gpio_tx_mix_bp);
		gpio_clear(rf_path->gpio_rx_mix_bp);
	}

	if (ctrl & SWITCHCTRL_HP) {
		gpio_set(rf_path->gpio_hp);
		gpio_clear(rf_path->gpio_lp);
	} else {
		gpio_clear(rf_path->gpio_hp);
		gpio_set(rf_path->gpio_lp);
	}

	if (ctrl & SWITCHCTRL_AMP_BYPASS) {
		gpio_set(rf_path->gpio_amp_bypass);
		gpio_clear(rf_path->gpio_tx_amp);
		gpio_set(rf_path->gpio_no_tx_amp_pwr);
		gpio_clear(rf_path->gpio_rx_amp);
		gpio_set(rf_path->gpio_no_rx_amp_pwr);
	} else if (ctrl & SWITCHCTRL_TX) {
		gpio_clear(rf_path->gpio_amp_bypass);
		gpio_set(rf_path->gpio_tx_amp);
		gpio_clear(rf_path->gpio_no_tx_amp_pwr);
		gpio_clear(rf_path->gpio_rx_amp);
		gpio_set(rf_path->gpio_no_rx_amp_pwr);
	} else {
		gpio_clear(rf_path->gpio_amp_bypass);
		gpio_clear(rf_path->gpio_tx_amp);
		gpio_set(rf_path->gpio_no_tx_amp_pwr);
		gpio_set(rf_path->gpio_rx_amp);
		gpio_clear(rf_path->gpio_no_rx_amp_pwr);
	}

	/*
	 * These normally shouldn't be set post-Jawbreaker, but they can be
	 * used to explicitly turn off power to the amplifiers while AMP_BYPASS
	 * is unset:
	 */
	if (ctrl & SWITCHCTRL_NO_TX_AMP_PWR)
		gpio_set(rf_path->gpio_no_tx_amp_pwr);
	if (ctrl & SWITCHCTRL_NO_RX_AMP_PWR)
		gpio_set(rf_path->gpio_no_rx_amp_pwr);

	if (ctrl & SWITCHCTRL_ANT_PWR) {
		rffc5071_set_gpo(&rffc5072, 0x00); /* turn on antenna power by clearing GPO1 */
	} else {
		rffc5071_set_gpo(&rffc5072, 0x01); /* turn off antenna power by setting GPO1 */
	}
}
#endif

static void switchctrl_set(rf_path_t* const rf_path, const uint8_t gpo) {
#ifdef JAWBREAKER
	rffc5071_set_gpo(&rffc5072, gpo);
#elif HACKRF_ONE
	switchctrl_set_hackrf_one(rf_path, gpo);
#else
	(void)gpo;
#endif
}

void rf_path_pin_setup(rf_path_t* const rf_path) {
#ifdef HACKRF_ONE
	/* Configure RF switch control signals */
	scu_pinmux(SCU_HP,             SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_LP,             SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_TX_MIX_BP,      SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_NO_MIX_BYPASS,  SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_RX_MIX_BP,      SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_TX_AMP,         SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_TX,             SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
	scu_pinmux(SCU_MIX_BYPASS,     SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
	scu_pinmux(SCU_RX,             SCU_GPIO_FAST | SCU_CONF_FUNCTION4);
	scu_pinmux(SCU_NO_TX_AMP_PWR,  SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_AMP_BYPASS,     SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_RX_AMP,         SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
	scu_pinmux(SCU_NO_RX_AMP_PWR,  SCU_GPIO_FAST | SCU_CONF_FUNCTION0);

	/* Configure RF power supply (VAA) switch */
	scu_pinmux(SCU_NO_VAA_ENABLE,  SCU_GPIO_FAST | SCU_CONF_FUNCTION0);

	/* Configure RF switch control signals as outputs */
	gpio_output(rf_path->gpio_amp_bypass);
	gpio_output(rf_path->gpio_no_mix_bypass);
	gpio_output(rf_path->gpio_rx_amp);
	gpio_output(rf_path->gpio_no_rx_amp_pwr);
	gpio_output(rf_path->gpio_hp);
	gpio_output(rf_path->gpio_lp);
	gpio_output(rf_path->gpio_tx_mix_bp);
	gpio_output(rf_path->gpio_rx_mix_bp);
	gpio_output(rf_path->gpio_tx_amp);
	gpio_output(rf_path->gpio_no_tx_amp_pwr);
	gpio_output(rf_path->gpio_tx);
	gpio_output(rf_path->gpio_mix_bypass);
	gpio_output(rf_path->gpio_rx);

	/*
	 * Safe (initial) switch settings turn off both amplifiers and antenna port
	 * power and enable both amp bypass and mixer bypass.
	 */
	switchctrl_set(rf_path, SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_MIX_BYPASS);
#endif
}

void rf_path_init(rf_path_t* const rf_path) {
	ssp1_set_mode_max5864();
	max5864_setup(&max5864);
	max5864_shutdown(&max5864);
	
	ssp1_set_mode_max2837();
	max2837_setup(&max2837);
	max2837_start(&max2837);
	
	rffc5071_setup(&rffc5072);
	switchctrl_set(rf_path, switchctrl);
}

void rf_path_set_direction(rf_path_t* const rf_path, const rf_path_direction_t direction) {
	/* Turn off TX and RX amplifiers, then enable based on direction and bypass state. */
	rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
	switch(direction) {
	case RF_PATH_DIRECTION_TX:
		rf_path->switchctrl |= SWITCHCTRL_TX;
		if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
			/* TX amplifier is in path, be sure to enable TX amplifier. */
			rf_path->switchctrl &= ~SWITCHCTRL_NO_TX_AMP_PWR;
		}
		rffc5071_tx(&rffc5072);
		if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
			rffc5071_disable(&rffc5072);
		} else {
			rffc5071_enable(&rffc5072);
		}
		ssp1_set_mode_max5864();
		max5864_tx(&max5864);
		ssp1_set_mode_max2837();
		max2837_tx(&max2837);
		sgpio_configure(&sgpio_config, SGPIO_DIRECTION_TX);
		break;
	
	case RF_PATH_DIRECTION_RX:
		rf_path->switchctrl &= ~SWITCHCTRL_TX;
		if( (rf_path->switchctrl & SWITCHCTRL_AMP_BYPASS) == 0 ) {
			/* RX amplifier is in path, be sure to enable RX amplifier. */
			rf_path->switchctrl &= ~SWITCHCTRL_NO_RX_AMP_PWR;
		}
		rffc5071_rx(&rffc5072);
		if( rf_path->switchctrl & SWITCHCTRL_MIX_BYPASS ) {
			rffc5071_disable(&rffc5072);
		} else {
			rffc5071_enable(&rffc5072);
		}
		ssp1_set_mode_max5864();
		max5864_rx(&max5864);
		ssp1_set_mode_max2837();
		max2837_rx(&max2837);
		sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
		break;
		
	case RF_PATH_DIRECTION_OFF:
	default:
#ifdef HACKRF_ONE
		rf_path_set_antenna(rf_path, 0);
#endif
		rf_path_set_lna(rf_path, 0);
		/* Set RF path to receive direction when "off" */
		rf_path->switchctrl &= ~SWITCHCTRL_TX;
		rffc5071_disable(&rffc5072);
		ssp1_set_mode_max5864();
		max5864_standby(&max5864);
		ssp1_set_mode_max2837();
		max2837_set_mode(&max2837, MAX2837_MODE_STANDBY);
		sgpio_configure(&sgpio_config, SGPIO_DIRECTION_RX);
		break;
	}

	switchctrl_set(rf_path, rf_path->switchctrl);
}

void rf_path_set_filter(rf_path_t* const rf_path, const rf_path_filter_t filter) {
	switch(filter) {
	default:
	case RF_PATH_FILTER_BYPASS:
		rf_path->switchctrl |= SWITCHCTRL_MIX_BYPASS;
		rffc5071_disable(&rffc5072);
		break;
		
	case RF_PATH_FILTER_LOW_PASS:
		rf_path->switchctrl &= ~(SWITCHCTRL_HP | SWITCHCTRL_MIX_BYPASS);
		rffc5071_enable(&rffc5072);
		break;
		
	case RF_PATH_FILTER_HIGH_PASS:
		rf_path->switchctrl &= ~SWITCHCTRL_MIX_BYPASS;
		rf_path->switchctrl |= SWITCHCTRL_HP;
		rffc5071_enable(&rffc5072);
		break;
	}

	switchctrl_set(rf_path, rf_path->switchctrl);
}

void rf_path_set_lna(rf_path_t* const rf_path, const uint_fast8_t enable) {
	if( enable ) {
		if( rf_path->switchctrl & SWITCHCTRL_TX ) {
			/* AMP_BYPASS=0, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=0 */
			rf_path->switchctrl |= SWITCHCTRL_NO_RX_AMP_PWR;
			rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR);
		} else {
			/* AMP_BYPASS=0, NO_RX_AMP_PWR=0, NO_TX_AMP_PWR=1 */
			rf_path->switchctrl |= SWITCHCTRL_NO_TX_AMP_PWR;
			rf_path->switchctrl &= ~(SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_RX_AMP_PWR);
		}
	} else {
		/* AMP_BYPASS=1, NO_RX_AMP_PWR=1, NO_TX_AMP_PWR=1 */
		rf_path->switchctrl |= SWITCHCTRL_AMP_BYPASS | SWITCHCTRL_NO_TX_AMP_PWR | SWITCHCTRL_NO_RX_AMP_PWR;
	}
	
	switchctrl_set(rf_path, rf_path->switchctrl);
}

/* antenna port power control */
void rf_path_set_antenna(rf_path_t* const rf_path, const uint_fast8_t enable) {
	if (enable) {
		rf_path->switchctrl |= SWITCHCTRL_ANT_PWR;
	} else {
		rf_path->switchctrl &= ~(SWITCHCTRL_ANT_PWR);
	}

	switchctrl_set(rf_path, rf_path->switchctrl);
}