Skip to content

Commit 0ba92b8

Browse files
committed
hackrf_transfer: add fixed-point support for frequency and sample rate
1 parent b4674d6 commit 0ba92b8

1 file changed

Lines changed: 119 additions & 42 deletions

File tree

host/hackrf-tools/src/hackrf_transfer.c

Lines changed: 119 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ typedef struct {
194194

195195
t_u64toa ascii_u64_data[4];
196196

197+
typedef struct {
198+
char data[U64TOA_MAX_DIGIT + 1];
199+
} t_fp64toa;
200+
201+
t_fp64toa ascii_fp64_data[4];
202+
197203
static float TimevalDiff(const struct timeval* a, const struct timeval* b)
198204
{
199205
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
@@ -255,23 +261,23 @@ int parse_u32(char* s, uint32_t* const value)
255261
}
256262
}
257263

258-
/* Parse frequencies as doubles to take advantage of notation parsing */
259-
int parse_frequency_i64(char* optarg, char* endptr, int64_t* value)
264+
int parse_frequency_u32(char* optarg, char* endptr, uint32_t* value)
260265
{
261-
*value = (int64_t) strtod(optarg, &endptr);
266+
*value = (uint32_t) strtod(optarg, &endptr);
262267
if (optarg == endptr) {
263268
return HACKRF_ERROR_INVALID_PARAM;
264269
}
265270
return HACKRF_SUCCESS;
266271
}
267272

268-
int parse_frequency_u32(char* optarg, char* endptr, uint32_t* value)
273+
int parse_frequency_fp(char* optarg, char* endptr, fp_40_24_t* value)
269274
{
270-
*value = (uint32_t) strtod(optarg, &endptr);
271-
if (optarg == endptr) {
272-
return HACKRF_ERROR_INVALID_PARAM;
273-
}
274-
return HACKRF_SUCCESS;
275+
return hackrf_str_to_fp64(24, optarg, endptr, value);
276+
}
277+
278+
int parse_sample_rate_fp(char* optarg, char* endptr, fp_28_36_t* value)
279+
{
280+
return hackrf_str_to_fp64(36, optarg, endptr, value);
275281
}
276282

277283
static char* stringrev(char* str)
@@ -319,6 +325,51 @@ char* u64toa(uint64_t val, t_u64toa* str)
319325
return res;
320326
}
321327

328+
char* fp64toa(uint8_t Qn, uint64_t value, t_fp64toa* str)
329+
{
330+
uint64_t mask = (1ULL << Qn) - 1;
331+
uint64_t m = value >> Qn;
332+
uint64_t n = (Qn == 0) ? 0 : value & mask;
333+
uint8_t precision = ceil((double) Qn * log10(2.0));
334+
335+
// format integer component
336+
char* p = str->data;
337+
p += sprintf(p, "%" PRIu64, m);
338+
339+
if (precision == 0 || n == 0) {
340+
*p = '\0';
341+
return str->data;
342+
}
343+
*p++ = '.';
344+
345+
// format fractional component
346+
uint8_t i;
347+
for (i = 0; i < precision; i++) {
348+
n *= 10;
349+
char c = '0' + (n >> Qn);
350+
*p++ = c;
351+
n &= mask;
352+
}
353+
354+
// trim trailing zeros
355+
while (p > str->data && p[-1] == '0') {
356+
--p;
357+
}
358+
*p = '\0';
359+
360+
return str->data;
361+
}
362+
363+
char* frequency_fp64toa(uint64_t value, t_fp64toa* str)
364+
{
365+
return fp64toa(24, value, str);
366+
}
367+
368+
char* sample_rate_fp64toa(uint64_t value, t_fp64toa* str)
369+
{
370+
return fp64toa(36, value, str);
371+
}
372+
322373
static volatile bool do_exit = false;
323374
static volatile bool interrupted = false;
324375
static volatile bool tx_complete = false;
@@ -351,13 +402,16 @@ struct timeval time_start;
351402
struct timeval t_start;
352403

353404
bool automatic_tuning = false;
354-
int64_t freq_hz;
405+
uint64_t freq_hz;
406+
fp_40_24_t freq_fp_hz;
355407

356408
bool if_freq = false;
357-
int64_t if_freq_hz;
409+
uint64_t if_freq_hz;
410+
fp_40_24_t if_freq_fp_hz;
358411

359412
bool lo_freq = false;
360-
int64_t lo_freq_hz = DEFAULT_LO_HZ;
413+
uint64_t lo_freq_hz = DEFAULT_LO_HZ;
414+
fp_40_24_t lo_freq_fp_hz = FREQ_FP_HZ(DEFAULT_LO_HZ);
361415

362416
bool image_reject = false;
363417
uint32_t image_reject_selection;
@@ -369,7 +423,8 @@ bool antenna = false;
369423
uint32_t antenna_enable;
370424

371425
bool sample_rate = false;
372-
uint32_t sample_rate_hz;
426+
fp_28_36_t sample_rate_fp_hz;
427+
uint64_t sample_rate_hz;
373428

374429
bool force_ranges = false;
375430

@@ -778,17 +833,20 @@ int main(int argc, char** argv)
778833
break;
779834

780835
case 'f':
781-
result = parse_frequency_i64(optarg, endptr, &freq_hz);
836+
result = parse_frequency_fp(optarg, endptr, &freq_fp_hz);
837+
freq_hz = FP_FREQ_HZ(freq_fp_hz);
782838
automatic_tuning = true;
783839
break;
784840

785841
case 'i':
786-
result = parse_frequency_i64(optarg, endptr, &if_freq_hz);
842+
result = parse_frequency_fp(optarg, endptr, &if_freq_fp_hz);
843+
if_freq_hz = FP_FREQ_HZ(if_freq_fp_hz);
787844
if_freq = true;
788845
break;
789846

790847
case 'o':
791-
result = parse_frequency_i64(optarg, endptr, &lo_freq_hz);
848+
result = parse_frequency_fp(optarg, endptr, &lo_freq_fp_hz);
849+
lo_freq_hz = FP_FREQ_HZ(lo_freq_fp_hz);
792850
lo_freq = true;
793851
break;
794852

@@ -820,7 +878,8 @@ int main(int argc, char** argv)
820878
break;
821879

822880
case 's':
823-
result = parse_frequency_u32(optarg, endptr, &sample_rate_hz);
881+
result = parse_sample_rate_fp(optarg, endptr, &sample_rate_fp_hz);
882+
sample_rate_hz = FP_SR_HZ(sample_rate_fp_hz);
824883
sample_rate = true;
825884
break;
826885

@@ -919,7 +978,8 @@ int main(int argc, char** argv)
919978
usage();
920979
return EXIT_FAILURE;
921980
}
922-
if (((if_freq_hz > IF_MAX_HZ) || (if_freq_hz < IF_MIN_HZ)) &&
981+
if (((FP_FREQ_HZ(if_freq_fp_hz) > IF_MAX_HZ) ||
982+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_MIN_HZ)) &&
923983
!force_ranges) {
924984
fprintf(stderr,
925985
"argument error: if_freq_hz should be between %s and %s.\n",
@@ -928,15 +988,17 @@ int main(int argc, char** argv)
928988
usage();
929989
return EXIT_FAILURE;
930990
}
931-
if ((if_freq_hz > IF_ABS_MAX_HZ) || (if_freq_hz < IF_ABS_MIN_HZ)) {
991+
if ((FP_FREQ_HZ(if_freq_fp_hz) > IF_ABS_MAX_HZ) ||
992+
(FP_FREQ_HZ(if_freq_fp_hz) < IF_ABS_MIN_HZ)) {
932993
fprintf(stderr,
933994
"argument error: if_freq_hz must be between %s and %s.\n",
934995
u64toa(IF_ABS_MIN_HZ, &ascii_u64_data[0]),
935996
u64toa(IF_ABS_MAX_HZ, &ascii_u64_data[1]));
936997
usage();
937998
return EXIT_FAILURE;
938999
}
939-
if ((lo_freq_hz > LO_MAX_HZ) || (lo_freq_hz < LO_MIN_HZ)) {
1000+
if ((FP_FREQ_HZ(lo_freq_fp_hz) > LO_MAX_HZ) ||
1001+
(FP_FREQ_HZ(lo_freq_fp_hz) < LO_MIN_HZ)) {
9401002
fprintf(stderr,
9411003
"argument error: lo_freq_hz shall be between %s and %s.\n",
9421004
u64toa(LO_MIN_HZ, &ascii_u64_data[0]),
@@ -958,23 +1020,31 @@ int main(int argc, char** argv)
9581020
switch (image_reject_selection) {
9591021
case RF_PATH_FILTER_BYPASS:
9601022
freq_hz = if_freq_hz;
1023+
freq_fp_hz = if_freq_fp_hz;
9611024
break;
9621025
case RF_PATH_FILTER_LOW_PASS:
9631026
freq_hz = (int64_t) labs((long int) (if_freq_hz - lo_freq_hz));
1027+
// TODO check
1028+
freq_fp_hz = (if_freq_fp_hz > lo_freq_fp_hz) ?
1029+
if_freq_fp_hz - lo_freq_fp_hz :
1030+
lo_freq_fp_hz - if_freq_fp_hz;
9641031
break;
9651032
case RF_PATH_FILTER_HIGH_PASS:
9661033
freq_hz = if_freq_hz + lo_freq_hz;
1034+
freq_fp_hz = if_freq_fp_hz + lo_freq_fp_hz;
9671035
break;
9681036
default:
9691037
freq_hz = DEFAULT_FREQ_HZ;
1038+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9701039
break;
9711040
}
9721041
fprintf(stderr,
9731042
"explicit tuning specified for %s Hz.\n",
974-
u64toa(freq_hz, &ascii_u64_data[0]));
1043+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]));
9751044

9761045
} else if (automatic_tuning) {
977-
if (((freq_hz > FREQ_MAX_HZ) || (freq_hz < FREQ_MIN_HZ)) &&
1046+
if (((FP_FREQ_HZ(freq_fp_hz) > FREQ_MAX_HZ) ||
1047+
(FP_FREQ_HZ(freq_fp_hz) < FREQ_MIN_HZ)) &&
9781048
!force_ranges) {
9791049
fprintf(stderr,
9801050
"argument error: freq_hz should be between %s and %s.\n",
@@ -983,7 +1053,7 @@ int main(int argc, char** argv)
9831053
usage();
9841054
return EXIT_FAILURE;
9851055
}
986-
if (freq_hz > FREQ_ABS_MAX_HZ) {
1056+
if (FP_FREQ_HZ(freq_fp_hz) > FREQ_ABS_MAX_HZ) {
9871057
fprintf(stderr,
9881058
"argument error: freq_hz must be between %s and %s.\n",
9891059
u64toa(FREQ_ABS_MIN_HZ, &ascii_u64_data[0]),
@@ -994,6 +1064,7 @@ int main(int argc, char** argv)
9941064
} else {
9951065
/* Use default freq */
9961066
freq_hz = DEFAULT_FREQ_HZ;
1067+
freq_fp_hz = FREQ_FP_HZ(DEFAULT_FREQ_HZ);
9971068
automatic_tuning = true;
9981069
}
9991070

@@ -1015,15 +1086,18 @@ int main(int argc, char** argv)
10151086
}
10161087

10171088
if (sample_rate) {
1018-
if (sample_rate_hz > SAMPLE_RATE_MAX_HZ && !force_ranges) {
1089+
fprintf(stderr,
1090+
"Setting sample rate to: %s Hz\n",
1091+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]));
1092+
if (FP_SR_HZ(sample_rate_fp_hz) > SAMPLE_RATE_MAX_HZ && !force_ranges) {
10191093
fprintf(stderr,
10201094
"argument error: sample_rate_hz should be less than or equal to %u Hz/%.03f MHz\n",
10211095
SAMPLE_RATE_MAX_HZ,
10221096
(float) (SAMPLE_RATE_MAX_HZ / FREQ_ONE_MHZ));
10231097
usage();
10241098
return EXIT_FAILURE;
10251099
}
1026-
if (sample_rate_hz < SAMPLE_RATE_MIN_HZ && !force_ranges) {
1100+
if (FP_SR_HZ(sample_rate_fp_hz) < SAMPLE_RATE_MIN_HZ && !force_ranges) {
10271101
fprintf(stderr,
10281102
"argument error: sample_rate_hz should be greater than or equal to %u Hz/%.03f MHz\n",
10291103
SAMPLE_RATE_MIN_HZ,
@@ -1033,6 +1107,7 @@ int main(int argc, char** argv)
10331107
}
10341108
} else {
10351109
sample_rate_hz = DEFAULT_SAMPLE_RATE_HZ;
1110+
sample_rate_fp_hz = SR_FP_HZ(DEFAULT_SAMPLE_RATE_HZ);
10361111
}
10371112

10381113
if (baseband_filter_bw) {
@@ -1100,7 +1175,7 @@ int main(int argc, char** argv)
11001175
PATH_FILE_MAX_LEN,
11011176
"HackRF_%sZ_%ukHz_IQ.wav",
11021177
date_time,
1103-
(uint32_t) (freq_hz / (1000ull)));
1178+
(uint32_t) (FP_FREQ_HZ(freq_fp_hz) / (1000ull)));
11041179
path = path_file;
11051180
fprintf(stderr, "Receive wav file: %s\n", path);
11061181
}
@@ -1116,6 +1191,7 @@ int main(int argc, char** argv)
11161191

11171192
// Change the freq and sample rate to correct the crystal clock error.
11181193
if (crystal_correct) {
1194+
// TODO this needs to be implemented for FP
11191195
sample_rate_hz =
11201196
(uint32_t) ((double) sample_rate_hz * (1000000 - crystal_correct_ppm) / 1000000 + 0.5);
11211197
freq_hz = freq_hz * (1000000 - crystal_correct_ppm) / 1000000;
@@ -1192,13 +1268,13 @@ int main(int argc, char** argv)
11921268
#endif
11931269

11941270
fprintf(stderr,
1195-
"call hackrf_set_sample_rate(%u Hz/%.03f MHz)\n",
1196-
sample_rate_hz,
1197-
((float) sample_rate_hz / (float) FREQ_ONE_MHZ));
1198-
result = hackrf_set_sample_rate(device, sample_rate_hz);
1271+
"call hackrf_radio_set_sample_rate(%s Hz/%.03f MHz)\n",
1272+
sample_rate_fp64toa(sample_rate_fp_hz, &ascii_fp64_data[0]),
1273+
((float) FP_SR_HZ(sample_rate_fp_hz) / (float) FREQ_ONE_MHZ));
1274+
result = hackrf_radio_set_sample_rate(device, sample_rate_fp_hz);
11991275
if (result != HACKRF_SUCCESS) {
12001276
fprintf(stderr,
1201-
"hackrf_set_sample_rate() failed: %s (%d)\n",
1277+
"hackrf_radio_set_sample_rate() failed: %s (%d)\n",
12021278
hackrf_error_name(result),
12031279
result);
12041280
usage();
@@ -1246,13 +1322,13 @@ int main(int argc, char** argv)
12461322

12471323
if (automatic_tuning) {
12481324
fprintf(stderr,
1249-
"call hackrf_set_freq(%s Hz/%.03f MHz)\n",
1250-
u64toa(freq_hz, &ascii_u64_data[0]),
1251-
((double) freq_hz / (double) FREQ_ONE_MHZ));
1252-
result = hackrf_set_freq(device, freq_hz);
1325+
"call hackrf_radio_set_frequency(%s Hz/%.03f MHz)\n",
1326+
frequency_fp64toa(freq_fp_hz, &ascii_fp64_data[0]),
1327+
((float) FP_FREQ_HZ(freq_fp_hz) / (float) FREQ_ONE_MHZ));
1328+
result = hackrf_radio_set_frequency(device, freq_fp_hz);
12531329
if (result != HACKRF_SUCCESS) {
12541330
fprintf(stderr,
1255-
"hackrf_set_freq() failed: %s (%d)\n",
1331+
"hackrf_radio_set_frequency() failed: %s (%d)\n",
12561332
hackrf_error_name(result),
12571333
result);
12581334
usage();
@@ -1261,13 +1337,13 @@ int main(int argc, char** argv)
12611337
} else {
12621338
fprintf(stderr,
12631339
"call hackrf_set_freq_explicit() with %s Hz IF, %s Hz LO, %s\n",
1264-
u64toa(if_freq_hz, &ascii_u64_data[0]),
1265-
u64toa(lo_freq_hz, &ascii_u64_data[1]),
1340+
frequency_fp64toa(if_freq_fp_hz, &ascii_fp64_data[0]),
1341+
frequency_fp64toa(lo_freq_fp_hz, &ascii_fp64_data[0]),
12661342
hackrf_filter_path_name(image_reject_selection));
1267-
result = hackrf_set_freq_explicit(
1343+
result = hackrf_radio_set_frequency_explicit(
12681344
device,
1269-
if_freq_hz,
1270-
lo_freq_hz,
1345+
if_freq_fp_hz,
1346+
lo_freq_fp_hz,
12711347
image_reject_selection);
12721348
if (result != HACKRF_SUCCESS) {
12731349
fprintf(stderr,
@@ -1532,7 +1608,8 @@ int main(int argc, char** argv)
15321608
file_pos = ftell(file);
15331609
/* Update Wav Header */
15341610
wave_file_hdr.hdr.size = file_pos - 8;
1535-
wave_file_hdr.fmt_chunk.dwSamplesPerSec = sample_rate_hz;
1611+
wave_file_hdr.fmt_chunk.dwSamplesPerSec =
1612+
FP_SR_HZ(sample_rate_fp_hz);
15361613
wave_file_hdr.fmt_chunk.dwAvgBytesPerSec =
15371614
wave_file_hdr.fmt_chunk.dwSamplesPerSec * 2;
15381615
wave_file_hdr.data_chunk.chunkSize =

0 commit comments

Comments
 (0)